Skip to content

Instantly share code, notes, and snippets.

@FloooD
Created May 23, 2011 18:26
Show Gist options
  • Save FloooD/987224 to your computer and use it in GitHub Desktop.
Save FloooD/987224 to your computer and use it in GitHub Desktop.
look at where other people are aiming.
----------------------------------------------------------------
--LUA Lag Compensation version 2.0 + pointer speccing 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-----------------------
----------------------------------------------------------------
math.randomseed(os.time())
math.randomseed(os.time() * math.sin(os.time() * math.random()))
ping = {}
mode = {{}, {}, {}}
buffer = {{}, {}}
pointer_loc = {{}, {}, {}}
specced = {}
for i = 1, 32 do specced[i] = {} end
disabled = {}
for i, v in ipairs({0, 47, 51, 72, 73, 75, 76, 77, 86, 87, 253, 254, 255}) do
disabled[v] = true
end
armor = {}
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] = {}
pointer_loc[1][id] = nil
pointer_loc[2][id] = nil
ping[id] = nil
clear_specs(id)
end
function clear_draw(spec)
for i = 1, 32 do
if specced[spec][i] then
freeimage(specced[spec][i])
end
end
specced[spec] = {}
end
addhook("spawn", "clear_draw")
function clear_specs(player)
for i = 1, 32 do
if specced[i][0] and specced[i][0] == player then
init_draw(i, player)
end
end
end
addhook("spawn", "clear_specs")
function clear(id)
reset(id)
clear_draw(id)
pointer_loc[3][id] = nil
end
for i = 1, 32 do 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
ping[id] = actualping
else
ping[id] = 0.7 * lastping + 0.3 * actualping
end
end
end
addhook("spawn", "updateping")
frame = 1
BUFFER_SIZE = 15
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
if pointer_loc[3][i] then reqcld(i, 0) end
end
for i = 1, 32 do
if specced[i][0] then update_draw(i) end
end
end
addhook("always", "updatebuffer")
function cl_data(id, m, x, y)
if pointer_loc[3][id] then
pointer_loc[1][id] = x
pointer_loc[2][id] = y
end
end
addhook("clientdata", "cl_data")
function onsecond()
for i in pairs(ping) do
updateping(i)
end
end
addhook("second", "onsecond")
addhook("hit", "onhit")
function onhit(v, id, wpn)
if disabled[wpn] or id == 0 then
return 0
end
return 1
end
addhook("attack", "onattack")
function onattack(id)
local wpn = player(id, "weapon")
if disabled[wpn] then return end
local rot = pointer_loc[3][id] and math.deg(math.atan2(pointer_loc[1][id] - 320, 240 - pointer_loc[2][id])) or player(id, "rot")
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
dmg = math.floor(dmg * 0.64 + 0.5)
simulate_attack(id, wpn, dmg, rot - 6 + 12 * math.random())
simulate_attack(id, wpn, dmg, rot + 6 + 8 * math.random())
simulate_attack(id, wpn, dmg, rot - 6 - 8 * math.random())
return
elseif wpn == 10 or wpn == 11 then
for i = 1, 5 do
simulate_attack(id, wpn, dmg, rot - 20 + 40 * math.random())
end
return
end
if mode[3][id] == 1 then
dmg = itemtype(wpn, "dmg_z1") * game("mp_damagefactor")
elseif mode[3][id] == 2 then
dmg = itemtype(wpn, "dmg_z2") * game("mp_damagefactor")
end
rot = 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
simulate_attack(id, wpn, itemtype(wpn, "dmg_z1") * game("mp_damagefactor"))
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)
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
function simulate_attack(id, wpn, dmg, rot)
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
local range = itemtype(wpn, "range")
local start_x = player(id, "x")
local start_y = player(id, "y")
local end_x = (3 * range) * math.sin(math.rad(rot))
local end_y = -(3 * range) * math.cos(math.rad(rot))
local tile_x = math.floor(start_x / 32)
local tile_y = math.floor(start_y / 32)
local inc_x, inc_y
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 not tile(tile_x, tile_y, "wall") do
local temp_x, temp_y = tile_x, tile_y
if inc_x and intersect(end_x, end_y, topixel(temp_x + inc_x) - start_x, topixel(temp_y) - start_y, 16) then
tile_x = temp_x + inc_x
end
if inc_y and intersect(end_x, end_y, topixel(temp_x) - start_x, topixel(temp_y + inc_y) - start_y, 16) then
tile_y = temp_y + inc_y
end
if tile_x == temp_x and tile_y == temp_y then
break
end
end
if tile(tile_x, tile_y, "wall") then
end_x, end_y = intersect(end_x, end_y, topixel(tile_x) - start_x, topixel(tile_y) - start_y, 16)
end
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 i in pairs(victims) do
if intersect(end_x, end_y, buffer[1][i][frame - frames] - start_x, buffer[2][i][frame - frames] - start_y, 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
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
end
function topixel(tile)
return (tile * 32) + 16
end
function intersect(ex, ey, bx, by, bl)
if not (bx and by) then return end
local cx, cy = (math.abs(bx) <= bl), (math.abs(by) <= bl)
if cx and cy then
if math.abs(ex - bx) <= bl and math.abs(ey - by) <= bl then
return ex, ey
end
bl = -bl
end
local ox = (ex >= 0) and bx - bl or bx + bl
local oy = (ey >= 0) and by - bl or by + bl
local flip
if (ex == 0 or (cx ~= cy or ((math.abs(ey * ox) >= math.abs(ex * oy)) == (bl < 0)))) and ((not cy) or cx) then
if ey == 0 then return end
ex, ey, bx, by, ox, oy = ey, ex, by, bx, oy, ox
flip = true
end
if (ox * ex) >= 0 and math.abs(ox) <= math.abs(ex) then
oy = ox * ey / ex
if math.abs(oy - by) <= math.abs(bl) then
if flip then return oy, ox end
return ox, oy
end
end
end
addhook("serveraction", "onserveraction")
function onserveraction(id, action)
if action == 1 then
msg2(id, "This server runs Lua Lag Compensation version 2.0.1")
msg2(id, "Your current ping: "..(ping[id] or player(id, "ping")))
elseif action == 2 then
if pointer_loc[3][id] then
pointer_loc[3][id] = nil
for i = 1, 32 do
if specced[i][0] and specced[i][0] == id then
clear_draw(i)
end
end
msg2(id, "LC: using standard rotation.")
msg2(id, "note: spectators won't be able to see your pointer position.")
else
pointer_loc[3][id] = true
msg2(id, "LC: using pointer position to calculate rotation.")
msg2(id, "LC: this fixes the rotation bug but will increase your ping by 5.")
msg2(id, "note: spectators can look at where your pointer is by saying !spec "..id)
end
end
end
POINTER="gfx/pointer.png"
HITBOX="gfx/hitbox.png"
addhook("say", "select_specced")
function select_specced(id, text)
if string.sub(text, 1, 6) == "!spec " then
if player(id, "health") > 0 then
msg2(id, "you must be a spectator for this")
return 1
end
local s = tonumber(string.sub(text, 7))
if s == 0 then
msg2(id, "you are now not spectating anyone's pointer.")
clear_draw(id)
elseif pointer_loc[3][s] then
init_draw(id, s)
else
msg2(id, "player with id "..s.." does not exist or hasn't toggled F3.")
msg2(id, "(if you want to disable pointer-spectating, say !spec 0)")
end
return 1
end
end
function init_draw(spec, player)
clear_draw(spec)
specced[spec][0] = player
end
function update_draw(spec)
if player(spec, "health") and player(spec, "health") > 0 then return end
local p = specced[spec][0]
if (not p) or not player(p, "health") or player(p, "health") == 0 then return end
local frames = math.floor(ping[p] / 20)
if frames > (BUFFER_SIZE - 1) then
frames = (BUFFER_SIZE - 1)
end
if not specced[spec][p] then
specced[spec][p] = image(POINTER, pointer_loc[1][p], pointer_loc[2][p], 2, spec)
else
imagepos(specced[spec][p], pointer_loc[1][p], pointer_loc[2][p], 0)
end
for i = 1, 32 do
if player(i, "exists") and player(i, "health") > 0 and player(i, "team") ~= player(p, "team") then
local x = buffer[1][i][frame - frames] - player(p, "x")
local y = buffer[2][i][frame - frames] - player(p, "y")
if math.abs(x) <= 320 and math.abs(y) <= 240 then
x = x + 320
y = y + 240
if specced[spec][i] then
imagepos(specced[spec][i], x, y, 0)
else
specced[spec][i] = image(HITBOX, x, y, 2, spec)
end
elseif specced[spec][i] then
freeimage(specced[spec][i])
specced[spec][i] = nil
end
elseif i ~= p and specced[spec][i] then
freeimage(specced[spec][i])
specced[spec][i] = nil
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment