Before going into the subject, i'd like to explain what motivates me to develop such a gadget.
I am a BA player and i often like to pay attention to endgame stats and check who dealt most damages and such.
After large amount of games i finally came to realise that sometimes the amount of damage dealt feels wrong, and is understated.
I looked into this and tried to figure why, and found that it was mostly due to the fact the damage dealt indirectly to enemy units is not counted in the damage dealt statistic. As an exemple, blowing a unit with a huge blow in an enemy's base wont give credit for the whole base destruction to the unit that was actuallly responsible for this. In a similar way, causing a chain reaction (i.e. wind generators or metal makers in BA) will only give you credits for the very firsts destroyed units (the ones you actually dealt direct damages to).
The notion of indirect damages doesn't seem to exist in spring, and i wanted to introduce it via a lua gadget.
For this matter, I figured the easiest way to do this was by triggering the gadget each time a unit is damaged (on the predamaged frame) and run a script that would do this:
-What is damaging unitID? -- Weapon? SelfDestruction? DeathExplosion? Debris? This is the WeaponDefID.
- Is it an allied or an enemy unit that is blowing? If it is a enemy unit, the damages will be counted properly and there is no need for a fix.
- If it is debris or deathExplosion, then it means the attacker was killed by something. -- What unit was it ? (--This is Spring.GetLastAttacker(attackerID))
- Then, we can say that the reason unitID is dying is basically the same reason attackerID is dying. It is realattacker = Spring.GetLastAttacker(attackerID)
- Nullify damages from attackerID to unitID, and add new damages from realattacker to unitID, with the same damage amount and same weaponDefID.
Because of this script, realattacker takes credits for both the unitID and attackerID kills, and not only attackerID's. Also, the next run of that script for the n+2th unit in the chain reaction and, because the lastattacker has been properly set in the last run, it will still keep the same "realattacker" for the whole chain reaction.
Here is the actual code that gets through these steps:
Code: Select all
function gadget:GetInfo()
return {
name = "DamageDealt Handler",
desc = "Handles DamageDealt Values for chainreactions",
author = "Doo",
date = "26/04/2016",
license = "GPL 2.0 or later", -- should be compatible with Spring
layer = 0,
enabled = true
}
end
if (gadgetHandler:IsSyncedCode()) then --Sync
function gadget:UnitPreDamaged(unitID, unitDefID, unitTeam, damage, paralyzer, weaponDefID, projectileID, attackerID, attackerDefID, attackerTeam)
Spring.Echo(weaponDefID)
hp = Spring.GetUnitHealth(unitID)
WeaponName = WeaponDefs[weaponDefID]["name"]
Spring.Echo(attackerDefID)
ExplodeAs = UnitDefs[attackerDefID].deathExplosion
Spring.Echo(WeaponName)
Spring.Echo(ExplodeAs)
if WeaponName == ExplodeAs then -- Checks if the unitID died in attackerID's death explosion or debris, otherwise skips)
Spring.Echo(unitID.." has been caught in "..attackerID.."'s blow")
if Spring.AreTeamsAllied(unitTeam, attackerTeam) == true then -- the gadget should not erase the damages dealt by attackerID's explosion to its enemies
Spring.Echo(unitID.." and "..attackerID.." are allied")
if Spring.GetUnitLastAttacker(attackerID) == nil then realattacker = attackerID else
realattacker = Spring.GetUnitLastAttacker(attackerID)
end
Spring.Echo("Last "..attackerID.."'s attacker was "..realattacker)
Spring.AddUnitDamage(unitID, damage, 0, realattacker, weaponDefID)
Spring.Echo("Added "..damage.." damages to "..unitID.." from "..realattacker)
return 0
end
end
end
function gadget:UnitDestroyed(unitID, unitDefID, unitTeam, attackerID, attackerDefID, attackerTeam)
Spring.Echo(attackerID.." of team "..attackerTeam.." has killed "..unitID.." of team "..unitTeam..".")
end
end
-Debris damages have no "owner". They are not attached to any attackerID nor attackerDefID and ExplodeAs = UnitDefs[attackerDefID].deathExplosion will cause an error
-Prolly related to this issue, unitIDs of dead units only stay valid for a short amount of time that is most likely less than a chain reaction duration and ExplodeAs = UnitDefs[attackerDefID].deathExplosion will cause an error, as well as Spring.AddUnitDamage(unitID, damage, 0, realattacker, weaponDefID) because both realattacker and attackerID wont be defined.
-Some units have the same selfdestructas and explodeas weaponDefIDs which would cause some mistakes in the process of giving credits to the right unit. (If such a unit is attacked before it self destructs, the unit that attacked it will take credit for the damages of the blow when it shouldn't).
I've been thinking of how to get over this.
-For now i've decided to discard debris damages until i'm able to properly run this for deathExplosions.
-For this script to run, it needs unitIDs to be defined for a longer amount of time after unit's death, is there a way to do so? or is it hardcoded in the engine and is unlikely to be changed ? -- On a side note, that also means that if the damages dealt by a unit occurs after that unit's death, it wont have any "owner" and wont be counted (i.e starbust launchers getting killed between launch and blow).
-How does SelfDestruct work. Does it deal infinite damages to a unitID with a defined weaponDefID = -5 and a defined attackerID = unitID? Is there a way to discern SelfDestruction and Death?
I would gladly welcome any advices and tips on how to get over those 3 main issues that i'm facing, or any tips regarding the code's design.