Skip to content

Instantly share code, notes, and snippets.

@FloooD
Created March 9, 2011 22:52
Show Gist options
  • Select an option

  • Save FloooD/863184 to your computer and use it in GitHub Desktop.

Select an option

Save FloooD/863184 to your computer and use it in GitHub Desktop.
Lua Lag Comp v1.0.1 + wallbang mod
----------------------------------------------------------------
--LUA Lag Compensation + wallbanging by FlooD-------------------
----------------------------------------------------------------
--thx to Jermuk for his custom server, which first encouraged---
-- me to make lag compensation.------------------------------
--thx to lasthope and def3ct for initial testing.---------------
--thx to 3rr0r for ideas and suggestions for refining the code.-
----------------------------------------------------------------
--visit cs2d.nl/index.php?mod=board&action=thread&where=120 for-
-- the lastest version and information-----------------------
----------------------------------------------------------------
--[[initialization, arrays, reseting]]--------------------------
WB_DMG = 0.6 --damage reduction upon each wall collision
WB_RANGE = 0.3 --range reduction upon each wall collision
math.randomseed(os.time())
math.randomseed(os.time() * math.sin(os.time() * math.random()))
ping = {} --array of filtered pings of living players
mode = {{}, {}, {}} --glock burst, famas burst, zoom
buffer = {{}, {}} --buffer of current and past positions in x and y coordinates
enable = {} --whether lag comp is enabled for one player
disabled = {} --weapons whose bullets are not compensated
for i, v in ipairs({0, 47, 51, 72, 73, 75, 76, 77, 86, 87, 253, 254, 255}) do
disabled[v] = true
end
armor = {} --special armor protection values
for i, v in ipairs({25, 50, 75, 50, 95}) do
armor[200 + i] = 1 - (v / 100)
end
function reset(id)
mode[1][id] = 0
mode[2][id] = 0
mode[3][id] = 0
buffer[1][id] = {}
buffer[2][id] = {}
ping[id] = nil
end
function clear(id)
reset(id)
enable[id] = 1
end
for i = 1, 32 do --initial
clear(i)
end
addhook("leave", "clear")
addhook("die", "reset")
function updateping(id)
local actualping = player(id, "ping")
local lastping = ping[id]
if not lastping then lastping = 0 end
if actualping then
if actualping - lastping <= 30 or lastping == 0 then --regular
ping[id] = actualping
else --spike is "damped"
ping[id] = 0.7 * lastping + 0.3 * actualping
end
end
end
addhook("spawn", "updateping")
----------------------------------------------------------------
--[[periodic functions]]----------------------------------------
frame = 1
BUFFER_SIZE = 25
function updatebuffer()
frame = frame + 1
for i in pairs(ping) do
buffer[1][i][frame], buffer[2][i][frame] = player(i, "x"), player(i, "y")
buffer[1][i][frame - BUFFER_SIZE], buffer[2][i][frame - BUFFER_SIZE] = nil, nil
end
end
addhook("always", "updatebuffer")
function onsecond()
for i in pairs(ping) do
updateping(i)
end
end
addhook("second", "onsecond")
----------------------------------------------------------------
--[[new hit system]]--------------------------------------------
addhook("hit", "onhit")
function onhit(v, id, wpn)
if disabled[wpn] or id == 0 or enable[id] ~= 1 then --preserve cs2d's internal hit system in these cases
return 0
end
return 1
end
addhook("attack", "onattack")
function onattack(id)
local wpn = player(id, "weapon")
if disabled[wpn] or enable[id] ~= 1 then --preserve cs2d's internal hit system in these cases
return
end
local dmg = itemtype(wpn, "dmg") * game("mp_damagefactor")
if (wpn == 2 and mode[1][id] == 1) or (wpn == 39 and mode[2][id] == 1) then --burst weapons
dmg = math.floor(dmg * 0.64 + 0.5)
local rot1 = player(id, "rot") - 6 + 12 * math.random()
local rot2 = player(id, "rot") + 6 + 8 * math.random()
local rot3 = player(id, "rot") - 6 - 8 * math.random()
simulate_attack(id, wpn, dmg, rot1)
simulate_attack(id, wpn, dmg, rot2)
simulate_attack(id, wpn, dmg, rot3)
return
elseif wpn == 10 or wpn == 11 then
for i=1,5 do
simulate_attack(id, wpn, dmg, player(id, "rot") - 20 + 40 * math.random(), 180)
end
return
end
if mode[3][id] == 1 then --scoped weapons
dmg = itemtype(wpn, "dmg_z1") * game("mp_damagefactor")
elseif mode[3][id] == 2 then
dmg = itemtype(wpn, "dmg_z2") * game("mp_damagefactor")
end
local rot = player(id, "rot") + itemtype(wpn, "dispersion") * (2 * math.random() - 1)
simulate_attack(id, wpn, dmg, rot)
end
addhook("attack2", "onattack2")
function onattack2(id, m)
local wpn = player(id, "weapon")
if wpn == 50 or wpn == 69 then
if enable[id] == 1 then
simulate_attack(id, wpn, itemtype(wpn, "dmg_z1") * game("mp_damagefactor"))
end
----------------------------------------------------------------
--[[syncs burst/zoom for each player to actual cs2d burst/zoom]]
elseif wpn == 2 then
mode[1][id] = m
elseif wpn == 39 then
mode[2][id] = m
elseif wpn ~= 32 and wpn >= 31 and wpn <= 37 then
mode[3][id] = m
end
end
addhook("reload", "unzoom")
addhook("select", "unzoom")
function unzoom(id)
mode[3][id] = 0
end
addhook("drop", "ondrop")
function ondrop(id,iid,wpn,ain,a,m)
mode[3][id] = 0
if wpn == 2 then
mode[1][id] = 0
elseif wpn == 39 then
mode[2][id] = 0
end
end
addhook("collect", "oncollect")
function oncollect(id,iid,wpn,ain,a,m)
if wpn == 2 then
mode[1][id] = m
elseif wpn == 39 then
mode[2][id] = m
end
end
----------------------------------------------------------------
--[[bullet simulation]]-----------------------------------------
--[[simulates the shooting of a bullet of damage (dmg) from
(wpn) by (id) with angle (rot) and range (range). it has two
parts. part 1 finds bullet's path before hitting a wall; part 2
calculates hits on other players (with lag compensation).]]
function simulate_attack(id, wpn, dmg, rot, range)
if not wpn then wpn = player(id, "weapon") end
if not dmg then dmg = itemtype(wpn, "dmg") * game("mp_damagefactor") end
if not rot then rot = player(id, "rot") end
if not range then range = itemtype(wpn, "range") end
local start_x = player(id, "x")
local start_y = player(id, "y")
local impact_x = {}
local impact_y = {}
local end_x = start_x + (3 * range) * math.sin(math.rad(rot))
local end_y = start_y - (3 * range) * math.cos(math.rad(rot))
local tile_x = math.floor(start_x / 32)
local tile_y = math.floor(start_y / 32)
--part 1 - find the intersection of the bullet with the walls it hits.
local inc_x, inc_y --specifies the direction in which to search.
if rot < 0 then
inc_x = -1
elseif rot > 0 and rot ~= 180 then
inc_x = 1
end
if math.abs(rot) > 90 then
inc_y = 1
elseif math.abs(rot) < 90 then
inc_y = -1
end
while true do
if tile(tile_x, tile_y, "wall") then
local i_x, i_y = intersect(start_x, start_y, end_x, end_y, topixel(tile_x), topixel(tile_y), 16)
if not (i_x and i_y) then break end
impact_x[#impact_x + 1] = i_x
impact_y[#impact_y + 1] = i_y
end_x = end_x * WB_RANGE + i_x * (1 - WB_RANGE)
end_y = end_y * WB_RANGE + i_y * (1 - WB_RANGE)
end
local temp_x, temp_y = tile_x, tile_y
if inc_x and intersect(start_x, start_y, end_x, end_y, topixel(temp_x + inc_x), topixel(temp_y), 16) then
tile_x = temp_x + inc_x
end
if inc_y and intersect(start_x, start_y, end_x, end_y, topixel(temp_x), topixel(temp_y + inc_y), 16) then
tile_y = temp_y + inc_y
end
if tile_x == temp_x and tile_y == temp_y then
break
end
end
local collisions = #impact_x
impact_x[#impact_x + 1] = end_x
impact_y[#impact_y + 1] = end_y
impact_x[0] = start_x
impact_y[0] = start_y
--part 2 - detect hits
local frames = math.floor(ping[id] / 20)
if frames > (BUFFER_SIZE - 1) then
frames = (BUFFER_SIZE - 1)
end
local victims = {}
if game("sv_friendlyfire") == "0" and game("sv_gamemode") ~= "1" then
for i in pairs(ping) do
if player(i, "team") ~= player(id, "team") then
victims[i] = true
end
end
else
for i in pairs(ping) do
victims[i] = true
end
victims[id] = nil
end
for n = 0, collisions do
for i in pairs(victims) do
if intersect(impact_x[n], impact_y[n], impact_x[n + 1], impact_y[n + 1], buffer[1][i][frame - frames], buffer[2][i][frame - frames], 12) then
parse("sv_sound2 "..id.." player/hit"..math.ceil(3 * math.random())..".wav")
parse("sv_sound2 "..i.." player/hit"..math.ceil(3 * math.random())..".wav")
local newhealth
local newarmor = player(i, "armor")
if newarmor <= 200 then
newarmor = newarmor - dmg
if newarmor < 0 then
newarmor = 0
end
newhealth = player(i, "health") - (dmg - math.floor(game("mp_kevlar") * (player(i, "armor") - newarmor)))
parse("setarmor "..i.." "..newarmor)
else --special armor values
newhealth = player(i, "health") - math.floor((dmg * (armor[newarmor] or 1)))
end
if newhealth > 0 then
parse("sethealth "..i.." "..newhealth)
else
parse("customkill "..id.." "..itemtype(wpn, "name").." "..i)
end
end
end
dmg = dmg * WB_DMG
end
end
--the following three functions are used in simulate_attack.
--converts a tile number to the tile's center pixel.
function topixel(tile)
return (tile * 32) + 16
end
--quick test to see if i is in between s and e. used in intersect().
function isinorder(s, i, e)
return (e >= i and i >= s) or (e <= i and i <= s)
end
--[[returns the first point of intersection between a box centered at (bx, by) with
half side length (bl) and a line segment starting from (sx, sy) and ending at (ex, ey).
if the line segment is enclosed by the box, (ex, ey) is returned.]]
function intersect(sx, sy, ex, ey, bx, by, bl)
if not (bx and by) then return end --fixes rare lua error
if math.abs(sx - bx) <= bl and math.abs(sy - by) <= bl then
if math.abs(ex - bx) <= bl and math.abs(ey - by) <= bl then
return ex, ey
else
sx, sy, ex, ey = ex, ey, sx, sy
end
end
local i_x, i_y
if ey > sy then
i_y = by - bl
elseif ey < sy then
i_y = by + bl
end
if i_y and isinorder(sy, i_y, ey) then
i_x = ((ex - sx) * i_y + (sx * ey - sy * ex)) / (ey - sy)
if math.abs(i_x - bx) <= bl and isinorder(sx, i_x, ex) then
return i_x, i_y
end
end
if ex > sx then
i_x = bx - bl
elseif ex < sx then
i_x = bx + bl
end
if i_x and isinorder(sx, i_x, ex) then
i_y = ((ey - sy) * i_x + (sy * ex - sx * ey)) / (ex - sx)
if math.abs(i_y - by) <= bl and isinorder(sy, i_y, ey) then
return i_x, i_y
end
end
end
----------------------------------------------------------------
--[[debug stuff]]-----------------------------------------------
addhook("serveraction","onserveraction")
function onserveraction(id, action)
if action == 2 then
if enable[id] == 1 then
enable[id] = 0
msg2(id, "©255100000Lag comp. disabled (for yourself).")
else
enable[id] = 1
msg2(id, "©255100000Lag comp. enabled (for yourself).")
end
elseif action == 1 then
msg2(id, "©255100000current ping: "..(ping[id] or (player(id, "ping").." (dead)")))
end
end
----------------------------------------------------------------
@brandonto
Copy link

Hey FlooD... Silent here! Wow I started programming recently for Engineering and I went back looking for cs2d lua scripts... and I somehow found you here!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment