Hi, there. Thanks for reading in advance. I’ve created a module that handles kill rewards / credits in a small fighting game I’m making. This subroutine exists within the main death processing function, and handles the timeout of the the killer’s [k] killstreak. The timeout loop stops itself if the player has nine or more kills in the streak (the game has a 10 player limit) or if the player has gone 10 seconds [streakreq] without killing another target. However, with no outside influence, the subroutine shown here never ends. The loop itself stops running after about 2 seconds of runtime, and the ‘streak ended’ print never reaches the output.
I’ve double-checked countless times; there aren’t any outside influences on the variables contained within that could cause the routine to hang. After reading a few articles, I’ve learned that some applications of subroutines can exhibit odd behavior inside modules. Is this one of those cases, and if so, what must I do to remedy it?
local module = {}
local damage = {}
local recent = {}
local kills = {}
local streak = {}
local stime = {}
local ktime = {}
--
function wfc(p, o, t)
return p:WaitForChild(o, t)
end
function newC3(r, g, b)
return Color3.new(r/255, g/255, b/255)
end
--
i_n = Instance.new
v3 = Vector3.new
cfn = CFrame.new
pn = PhysicalProperties.new
bcn = BrickColor.new
c3 = Color3.new
rand = math.random
--
sss = script.Parent
data = require(wfc(sss, "DataModule"))
ps = game:GetService("PhysicsService")
ss = game:GetService("ServerStorage")
rs = game:GetService("ReplicatedStorage")
remotes = wfc(rs, "Remotes")
smsg = wfc(remotes, "ServerMessage")
gfolder = wfc(workspace, "Global")
ding = wfc(gfolder, "Died")
--
streakreq = 20
killwait = 30
jargon = {
{"DOUBLE KILL!", newC3(255, 50, 0)},
{"TRIPLE KILL!!", newC3(255, 150, 0)},
{"QUADRA-KILL!!!", newC3(255, 255, 0)},
{"PENTA-KILL!!!", newC3(150, 255, 0)},
{"HEXA-KILL!!!", newC3(50, 255, 0)},
{"SEPTA-KILL!!!", newC3(50, 255, 0)},
{"OCTA-KILL!!!", newC3(0, 255, 0)},
{"ACE!!!", newC3(0, 255, 255)},
}
--
function message(text, col)
smsg:FireAllClients(text or "NULL", col or c3(1, 1, 1))
end
function getKiller(p)
local highest = 0
local k = nil
if damage[p] then
for n,v in pairs(damage[p]) do
if v > highest then k = n; highest = v end
end
end
return k
end
function getReward(p)
local e = p:FindFirstChild("KillReward", true)
if e and e:IsA("BindableEvent") then return e end
return nil
end
function processKill(p, t, r, rq)
local k = r or p
local typ = 1
local bonus = 10
local reward = getReward(k)
local class = data:Check(k, "Game", "Settings", "Class")
local tclass = data:Check(t, "Game", "Settings", "Class")
local pclass = data:Check(p, "Game", "Settings", "Class")
kills[k] = kills[k] or {}
kills[t] = kills[t] or {}
local kp = kills[k]; kp[t] = (kp[t] or 0) + 1
local kt = kp[t]
local tp = kills[t]; tp[k] = tp[k] or 0
local tk = tp[k]
local ms = data:Check(k, "Game", "Stats", "Streak")
local ks = streak[k]; stime[k] = tick()
local GK = data:Check(k, "Game", "Stats", "KOs") + 1
local GW = data:Check(k, "Game", "Stats", "WOs")
GW = math.max(GW, 1)
local CK = data:Check(k, "Class", class, "KOs") + 1
local CW = data:Check(k, "Class", class, "WOs")
CW = math.max(CW, 1)
local GKD = math.floor((GK/GW) * 100)
local CKD = math.floor((CK/CW) * 100)
data:editGlobal(class, "KOs", 1)
data:GameEdit(k, "Stats", "KOs", 1)
data:ClassEdit(k, class, "KOs", 1)
data:GameEdit(k, "Stats", "KDR", tostring(GKD/100))
data:ClassEdit(k, class, "KDR", tostring(CKD/100))
if not ks or ks <= 0 then ks = 1
spawn(function() ------------------------------- << SUBROUTINE STARTS HERE
print('streak started')
while (tick()-stime[k]) < streakreq do wait()
print(tick()-stime[k] < streakreq)
if streak[k] >= 9 then print('overflow') break end
end
print('streak ended')
streak[k] = 0
end)
else ks = ks + 1
if ks > ms then data:GameEdit(k, "Stats", "Streak", ks - ms) end
end
if k ~= p then typ = 2
message(k.Name.." ("..class..") stole "..t.Name.." ("..tclass..") from "..p.Name.." ("..pclass..")!", newC3(255, 0, 150))
elseif rq then message(k.Name.." ("..class..") made "..t.Name.." ("..tclass..") ragequit!", newC3(255, 0, 0))
else message(k.Name.." ("..class..") destroyed "..t.Name.." ("..tclass..")!", newC3(255, 0, 0))
end
if tk > 2 then bonus = 30
message(k.Name.." ("..class..") got REVENGE on "..t.Name.." ("..tclass..")!", newC3(255, 150, 0))
elseif kt > 2 then bonus = bonus + (5 * (kt-2))
message(k.Name.." ("..class..") is DOMINATING (x"..(kt-2)..") "..t.Name.." ("..tclass..")!", newC3(255, 150, 0))
end
if ks >= 2 then local j = jargon[ks-1] or jargon[#jargon]
typ = 3; bonus = bonus * (ks - 1)
message(k.Name.." "..j[1], j[2])
end
reward:Fire(typ)
data:GameEdit(k, "Stats", "Points", bonus)
tp[k] = 0; streak[k] = ks
end
--
function module:AddDamage(p1, p2, amt)
local class = data:Check(p1, "Game", "Settings", "Class")
if amt < 0 then amt = math.abs(amt)
data:GameEdit(p1, "Stats", "Healing", amt)
data:ClassEdit(p1, class, "Healing", amt)
elseif p1 ~= p2 then recent[p2] = p1
damage[p2] = damage[p2] or {}
ktime[p2] = ktime[p2] or {}
local d = damage[p2]
d[p1] = (d[p1] or 0) + amt
local dt = ktime[p2]; local bool = (dt[p1] ~= nil)
dt[p1] = tick()
if not bool then spawn(function()
while (tick() - dt[p1]) <= killwait do wait() end
d[p1] = 0; dt[p1] = nil
end)
end
data:GameEdit(p1, "Stats", "Damage", amt)
data:ClassEdit(p1, class, "Damage", amt)
end
end
function module:ProcessDeath(p, rq)
local class = data:Check(p, "Game", "Settings", "Class")
local killer = getKiller(p)
local GK = data:Check(p, "Game", "Stats", "KOs")
local GW = data:Check(p, "Game", "Stats", "WOs") + 1
local CK = data:Check(p, "Class", class, "KOs")
local CW = data:Check(p, "Class", class, "WOs") + 1
local GKD = math.floor((GK/GW) * 100)
local CKD = math.floor((CK/CW) * 100)
data:editGlobal(class, "WOs", 1)
data:GameEdit(p, "Stats", "WOs", 1)
data:ClassEdit(p, class, "WOs", 1)
data:GameEdit(p, "Stats", "KDR", tostring(GKD/100))
data:ClassEdit(p, class, "KDR", tostring(CKD/100))
ding:Play()
if killer and killer ~= p then
processKill(killer, p, recent[p], rq)
else message(p.Name.." died!", newC3(255, 0, 0))
end
damage[p] = {}; recent[p] = nil
end
function module:reset()
print('reset')
damage = {}; recent = {}
streak = {}; stime = {}
end
--
return module