This is what I tried:
-
The attackers will tell the wall they have begun attacking and for how much damage every variable seconds.
-
The wall will group attackers with other attackers with the same damage and attack rate.
-
When it is time for that group to attack, the damage is calculated something like Damage*Amount of Attackers.
So, the wall will damage itself based on groups of attackers rather than every individual attacker.
My implementation assumes all attack rates are in integer seconds because of the way I use a table to count attackers with the same damage and attack rate.
local Health = 5000
local TimeSinceExistence = 0
local AttackerGroups =
{
--[[
{
AttackRate = 20, -- seconds
Damage = 5,
TimeOffsetGroups =
{
[1] = 4, -- 0 time offset, but tables in lua start at 1
[2] = 40, -- values are the amount of attackers at this time offset
[3] = 33,
[4] = 8,
[5] = 9,
[6] = 100,
[7] = 2,
[20] = 9
}
}
--]]
}
local function DealDamage(Damage)
print('Took',Damage,'Damage')
Health = Health - Damage
end
local function GetExistingAttackGroup(AttackRate,Damage)
for i = 1, #AttackerGroups do
local AttackGroup = AttackerGroups[i]
if AttackGroup.Damage == Damage and AttackGroup.AttackRate == AttackRate then
return i
end
end
end
local function AddAttacker(AttackRate,Damage,ImmediateAttack)
print('New Attacker dealing',Damage,'damage every',AttackRate,'seconds')
local FoundExistingAttackGroup = GetExistingAttackGroup(AttackRate,Damage)
local TimeOffset = TimeSinceExistence % AttackRate + 1 -- adding 1 to match table indexes
if FoundExistingAttackGroup then
local SameAttackerCount = AttackerGroups[FoundExistingAttackGroup].TimeOffsetGroups[TimeOffset]
AttackerGroups[FoundExistingAttackGroup].TimeOffsetGroups[TimeOffset] = SameAttackerCount and SameAttackerCount+1 or 1
else
table.insert(AttackerGroups,
{
AttackRate = AttackRate,
Damage = Damage,
TimeOffsetGroups =
{
[TimeOffset] = 1
}
})
end
if ImmediateAttack then
DealDamage(Damage)
end
return TimeOffset -- for removing attacker later
end
local function RemoveAttacker(AttackRate,Damage,TimeOffset)
print('Removing Attacker dealing',Damage,'damage every',AttackRate,'seconds')
local FoundExistingAttackGroup = GetExistingAttackGroup(AttackRate,Damage)
if FoundExistingAttackGroup then
local SameAttackerCount = AttackerGroups[FoundExistingAttackGroup].TimeOffsetGroups[TimeOffset]
AttackerGroups[FoundExistingAttackGroup].TimeOffsetGroups[TimeOffset] = SameAttackerCount and SameAttackerCount-1 or nil
-- removing group from table if there are no attackers left
for OffsetTime,AttackersAmount in next, AttackerGroups[FoundExistingAttackGroup].TimeOffsetGroups do
if AttackersAmount and AttackersAmount > 0 then
return
end
end
table.remove(AttackerGroups,FoundExistingAttackGroup)
end
end
local function DealGroupDamages()
for i = 1, #AttackerGroups do
local AttackGroup = AttackerGroups[i]
for OffsetTime,AttackersAmount in next, AttackGroup.TimeOffsetGroups do
if TimeSinceExistence % AttackGroup.AttackRate + 1 == OffsetTime then
print(AttackGroup.Damage,TimeSinceExistence)
DealDamage(AttackGroup.Damage*AttackersAmount)
end
end
end
end
-- Testing code
for i = 1, math.random(1,10) do
local AttackRate,Damage = math.random(5),math.random(100)
local TimeOffset = AddAttacker(AttackRate,Damage,true)
spawn(function()
wait(math.random(10))
RemoveAttacker(AttackRate,Damage,TimeOffset)
end)
end
while wait(1) do
TimeSinceExistence = TimeSinceExistence + 1
DealGroupDamages()
print(Health,TimeSinceExistence)
end