@@ -23,28 +23,33 @@ local spGetUnitHealth = Spring.GetUnitHealth
2323local spGetUnitArmored = Spring .GetUnitArmored
2424local spAddUnitDamage = Spring .AddUnitDamage
2525
26+ local DECAY_SECONDS = 40 -- how long it takes to decay 100% para to 0
27+
2628local normalDamageMult = {}
2729local wantedWeaponList = {}
2830local paraTime = {}
2931local overstunDamageMult = {}
32+ local overstunTime = {}
3033-- Note that having EMP damage decay N times faster when above 100% is mathematically
3134-- equivalent multiplying all incoming EMP damage above 100% by of 1/N.
3235
3336for wdid = 1 , # WeaponDefs do
3437 local wd = WeaponDefs [wdid ]
3538 if wd .paralyzer then
3639 wantedWeaponList [# wantedWeaponList + 1 ] = wdid
40+ paraTime [wdid ] = math.max (1 , wd .customParams .emp_paratime )
3741 else
3842 local rawDamage = tonumber (wd .customParams .raw_damage or 0 )
3943 if wd .customParams and wd .customParams .extra_damage and rawDamage > 0 then
4044 normalDamageMult [wdid ] = wd .customParams .extra_damage / rawDamage
41-
4245 -- engine rounds down, but paratime 0 means real damage
4346 paraTime [wdid ] = math.max (1 , wd .customParams .extra_paratime )
44-
4547 wantedWeaponList [# wantedWeaponList + 1 ] = wdid
4648 end
4749 end
50+ if wd .customParams and wd .customParams .overstun_time then
51+ overstunTime [wdid ] = tonumber (wd .customParams .overstun_time )
52+ end
4853 if wd .customParams and wd .customParams .overstun_damage_mult then
4954 overstunDamageMult [wdid ] = tonumber (wd .customParams .overstun_damage_mult )
5055 end
@@ -58,27 +63,41 @@ function gadget:UnitDamaged_GetWantedWeaponDef()
5863 return wantedWeaponList
5964end
6065
66+ local function GetStunDamage (weaponDefID , damage , health , maxHealth , paralyzeDamage )
67+ if not (weaponDefID and overstunDamageMult [weaponDefID ]) then
68+ return damage * maxHealth / health
69+ end
70+
71+ local rawDamage = damage * maxHealth / health
72+ if maxHealth <= paralyzeDamage then
73+ -- Spring.Echo("Above", rawDamage*overstunDamageMult[weaponDefID])
74+ return rawDamage * overstunDamageMult [weaponDefID ]
75+ end
76+ local damageGap = (maxHealth - paralyzeDamage )
77+ if rawDamage <= damageGap then
78+ -- Spring.Echo("damageGap", maxHealth, paralyzeDamage, damageGap, rawDamage)
79+ return rawDamage
80+ end
81+ -- Spring.Echo("Partial", maxHealth, paralyzeDamage, damageGap, rawDamage, damageGap + (rawDamage - damageGap)*overstunDamageMult[weaponDefID])
82+ return damageGap + (rawDamage - damageGap )* overstunDamageMult [weaponDefID ]
83+ end
84+
6185function gadget :UnitPreDamaged (unitID , unitDefID , unitTeam , damage , paralyzer ,
6286 weaponDefID , attackerID , attackerDefID , attackerTeam )
6387 if paralyzer then -- the weapon deals paralysis damage
6488 local health , maxHealth , paralyzeDamage = spGetUnitHealth (unitID )
6589 if health and maxHealth and health > 0 then -- taking no chances.
66- if not (weaponDefID and overstunDamageMult [ weaponDefID ]) then
67- return damage * maxHealth / health
68- end
69-
70- local rawDamage = damage * maxHealth / health
71- if maxHealth <= paralyzeDamage then
72- -- Spring.Echo("Above", rawDamage*overstunDamageMult[weaponDefID])
73- return rawDamage * overstunDamageMult [ weaponDefID ]
90+ local damage = GetStunDamage (weaponDefID , damage , health , maxHealth , paralyzeDamage )
91+ if overstunTime [ weaponDefID ] > 0 then
92+ -- Overstun allows units to stun for an addition time (usually 1 second) if the current stun time on the unit is within that range.
93+ local currentStunTime = ( paralyzeDamage / maxHealth - 1 ) * DECAY_SECONDS
94+ local maxTime = math.max ( paraTime [ weaponDefID ], math.min ( paraTime [ weaponDefID ], currentStunTime ) + overstunTime [ weaponDefID ])
95+ -- Solve the following for damage to limit damage by stun time:
96+ -- stun time = ((damage + paralyzeDamage)/maxHealth - 1) * DECAY_SECONDS
97+ damage = ( maxTime / DECAY_SECONDS + 1 ) * maxHealth - paralyzeDamage
7498 end
75- local damageGap = (maxHealth - paralyzeDamage )
76- if rawDamage <= damageGap then
77- -- Spring.Echo("damageGap", maxHealth, paralyzeDamage, damageGap, rawDamage)
78- return rawDamage
79- end
80- -- Spring.Echo("Partial", maxHealth, paralyzeDamage, damageGap, rawDamage, damageGap + (rawDamage - damageGap)*overstunDamageMult[weaponDefID])
81- return damageGap + (rawDamage - damageGap )* overstunDamageMult [weaponDefID ]
99+ -- Spring.Echo("damage", damage, ((damage + paralyzeDamage)/maxHealth - 1) * DECAY_SECONDS, paralyzeDamage, math.random())
100+ return damage
82101 end
83102 end
84103
88107function gadget :UnitDamaged (unitID , unitDefID , unitTeam , damage , paralyzer , weaponDefID , attackerID )
89108 local mult = normalDamageMult [weaponDefID ]
90109 if mult and not paralyzer then
91-
92110 -- Don't apply armour twice.
93111 local armored , armorMult = spGetUnitArmored (unitID )
94112 if armored then
95113 mult = mult / armorMult
96114 end
97-
98- spAddUnitDamage (unitID , mult * damage , paraTime [weaponDefID ], attackerID , weaponDefID )
115+ spAddUnitDamage (unitID , mult * damage , paraTime [weaponDefID ] + overstunTime [weaponDefID ], attackerID , weaponDefID )
99116 end
100117end
0 commit comments