Quote:
Originally Posted by Fatt_Shade
OK i checked poisoning effect : 480 dwarfs i killed 120 with royal snakes and poisoned them, next turn only 32 die from poison effect (and by your explanation should be 60). Try that combination, royal snakes special attack have 100% poisoning so it`s easy to check does it work. That situation with 800 bowman and burning might be because i used hell breath on thorn hunters, and it`s not related to ishara whip.
|
Just because 120 were killed doesn't necessarily mean that 60 will be killed due to the effect.
What makes Royal Snakes more complicated is that their normal damage is physical. So a unit's physical resistance comes into play and that is the damage that will go into the features_poison function inside UNIT_FEATURES.LUA.
I'll give a little mini-tutorail about the code in there, but first let's discuss the Royal Snake's attacks. The Royal Snake's normal attack has a 30% chance to poison and its "lunge" attack a 100% chance to poison (check SNAKE_ROYAL.ATOM). However, dwarves have at least 7 resist all (I think it is 8 in impossible due to the +25% increase) and possibly more if they are with a hero. I'm not sure which situation you're dealing with, but you'll need to look at the Dwarve's resistances (or really just poison).
I'm pretty sure the flying damage numbers above the unit's head should be the damage that goes into the features_poison function.
This serves as a mini tutorial, but here's the code:
Code:
function features_poison( damage, addrage, attacker, receiver, minmax )
if ( minmax == 0 )
and damage > 0 then
--local receiver=Attack.get_target(1) -- êîãî?
local poison = tonumber( Attack.get_custom_param( "poison" ) )
poison = effect_chance( poison, "effect", "poison" )
local poison_res = Attack.act_get_res( receiver, "poison" )
local rnd = Game.Random( 100 )
local poison_chance = math.min( 100, poison * ( 1 - poison_res / 100 ) )
local poison_damage = damage * poison_chance / 200
if rnd < poison_chance
and not Attack.act_feature( receiver, "golem" ) then -- and (not Attack.act_feature(receiver,"poison_immunitet") or Attack.act_race("undead")) then
effect_poison_attack( receiver, 0, 3, poison_damage, poison_damage )
end
end
return damage, addrage
end
If you looked at my other tutorial, you'll note that minmax == 0 is a check to make sure that this is the attack being applied (and not some one else's) and then the damage just needs to be greater than 0. The Attack.get_custom_param( "poison" ) actually looks into SNAKE_ROYAL.ATOM under the custom parameters (custom_params) of whichever attack caused the damage. Note that for its baseattack the chance of poison is 30%, while lunge is 100% (these are stock TL as I didn't change the Royal Snake's ATOM).
It's possible that in your case, you're using the Royal Snake's base attack, I don't know, but let's use both examples with the Dwarve's base resistance and follow the code:
Code:
local poison = tonumber( Attack.get_custom_param( "poison" ) )
poison = effect_chance( poison, "effect", "poison" )
So with the base attack, poison = 30
With the "lunge" attack, poison = 100
The second line would apply a modifier to the chance poison if the hero had an item with a bonus here. In this case, though, I don't think I have any items with a specific poison chance bonus (this is to allow people to mod my mod in the future with their own bonuses!) so the values above aren't modified.
Next:
Code:
local poison_res = Attack.act_get_res( receiver, "poison" )
local rnd = Game.Random( 100 )
local poison_chance = math.min( 100, poison * ( 1 - poison_res / 100 ) )
local poison_damage = damage * poison_chance / 200
Next you can see that the receiver's poison resistance is queried and then a random number generated. Let's compute poison_chance for both cases assuming that the Dwarve's poison resistance is 8%.
Case 1 (base attack): poison_chance = min between( 100 and 30 * ( 1 - 8 / 100 ) ) = 27.6
Case 2 (lunge attack): poison_chance = min between( 100 and 100 * ( 1 - 8 / 100 ) ) = 92
So those are the two chances to cause poison based on whichever attack the Royal Snake is using if the Dwarve's resistance is 8%.
Code:
local poison_damage = damage * poison_chance / 200
Next, let's compute poison_damage. I don't know how much damage it said it did, but let's go off of what you stated: 120 Dwarves killed. Base hp: 80, +25% due to Impossible difficulty so health = 80 * 1.25 = 100. So as a guess, let's say the damage is 100 * 120 = 12,000 damage! Wow!
Case 1: poison_damage = 12,000 * 27.6 / 200 = 1656
Cast 2: poison_damage = 12,000 * 92 / 200 = 5520
So the chance to cause the damage goes into how effective the poisoning (in this case) is. Note that the reason why it is 200 is because I'm halving the damage (it could have just as easily been written as X / 100 / 2, but I combined the 2 values). I neglected to mention that the chance applies as well in my previous post, but this is the way it works per the code.
Code:
if rnd < poison_chance
and not Attack.act_feature( receiver, "golem" ) then -- and (not Attack.act_feature(receiver,"poison_immunitet") or Attack.act_race("undead")) then
effect_poison_attack( receiver, 0, 3, poison_damage, poison_damage )
end
This last part of the code checks to see if the unit was poisoned. For case 1: poison_chance is 27.6% and for case 2: poison_chance is 92%.
If poison is successful, then "effect_poison_attack" is called with: 1) the receiver to apply the damage to, 2) pause (this is for timing of the display, I think), 3) duration of the effect, 4) min damage, and 5) max damage.
Inside the effect_poison_attack function (inside SPELL_EFFECTS.LUA) there is a lot going on, but I essentially store the damage value on the unit (this is a neat feature of the scripting engine that the developers implemented) with the receiver's resistance used to scale up the damage back to what it would be like so:
Code:
dmg_min = dmg_min * ( 1 + poisonresist / ( 100 - poisonresist ) )
dmg_max = dmg_max * ( 1 + poisonresist / ( 100 - poisonresist ) )
Case 1: dmg_min = dmg_max = 1656 * ( 1 + 8 / ( 100 - 8 ) ) = 1800
Case 2: dmg_min = dmg_max = 5520 * ( 1 + 8 / ( 100 - 8 ) ) = 6000
This was a little wrinkle I needed to put in because of the way the damage system works. Since the damage system applies the resistance to the damage, I didn't want the damage to be reduced by the resistance twice (once when storing and then again when computing damage) so this restores the "pre-resistance" damage and stores those values (in either case) on the unit.
What happens next, is that when the receiver takes its turn the damage will be applied to the unit and the resistance will be applied - here's the code:
Code:
Attack.atk_set_damage( typedmg, dmg_min, dmg_max )
-- Each successive burn causes half damage
Attack.act_spell_param( target, effect_type, "dmg_min", dmg_min / 2, "dmg_max", dmg_max / 2 )
(Note that even though it says burn, this code is inside the new apply_effect_damage common function that I wrote inside SPELL_EFFECTS.LUA and applies damage from both burn and poison effects).
Note that atk_set_damage applies the damage type over the range specified by the mininum and maximum damage. This is an internal King's Bounty library and so when it does this, it computes the resistance of the unit and since I can't gain access to this library that's why I had to scale the damage back up by the unit's resistance because it gets (properly) scaled down by the library function.
This was quite complex and took me a while to figure out because of what "goes on under the hood" of the C/C++ library functions.
So in this case, the damages will be restored to 1656 and 5520 for cases 1 and 2, respectively as applied to the unit. and then you'll note that half 1800 and 6000 (900 and 3000) will be stored on the unit so that the next turn the same thing will happen - resistance is applied, but not twice!
Like I said above, I spent a lot of time working on this and before I did this, the damage would be reduced by the unit's resistance and then by its resistance again before damage was applied (that wasn't the way I wanted it to work!).
There is a lot more going on inside of some of the functions I've mentioned (like how to combine successive hits), but this is how it works per the code.
The funny thing is that I still don't get the same answer you do:
Case 1 apply 1656 damage to Dwarves - number killed: 1656 / 100 = 16.56 (or 16)
Case 2 apply 5520 damage to Dwarves - number killed: 5520 / 100 = 55.2 (or 55)
So in case 1 I get half what you mentioned and in case 2 quite a bit more. So you'll have to see what the Dwarve's actual resistance is and also the damage for your case, but this is how it works exactly per the code.
Anyway, I hope that explains it and this is also a mini-tutorial for how to apply a damage effect and work with the damage library.
/C\/C\