Fallout 2 mod F2: damage calculation change, a FIX (v3 by my count)

Discussion in 'Fallout General Modding' started by Glovz, Jul 10, 2013.

  1. Glovz

    Glovz Vault Dweller
    Modder

    Sep 16, 2005
    F2: damage calculation change, a FIX v5

    The latest version of my FIX has been thoroughly tested by NovaRain (one of this forum's most enthusiastic mod testers). It still follows the original ideas I had for this FIX, but now optimized and as efficient as possible.


    Notes below:

    My understanding of the game engine; as it applies to this change, is built on other great modders work:
    --- ravachol, first to expose the damage calculation in the exe
    --- Kanhef, Haenlomal, and Timeslip, exposing even more of the inner workings of the exe
    --- Cubik2k, leading the way in discussions and attempting to change the damage calculation
    --- all other contributers to threads that have discussed the problem and ways it could be solved in this forum

    What I understand of the damage calculation in the exe:
    (assumptions are based on knowing if they were anything else then the calculation would fail badly)
    - it adds the DR modifier from the attacking critter's ammo (loaded in its weapon) to the DR value in the target critters armor (starting at line 004249A1 when debugging the exe from the killap's RP - the tool I use is OllyDbg)
    --- I don't know what the DR modifier value is if the attacking critter is not using a weapon or if the weapon does not use ammo, assumed to be 0 in this case

    - it checks if the new sum is greater than or equal to 0, if not it sets this new value to 0

    - if greater than or equal to 0, it then checks if the new sum is less than or equal to 100, if not it sets this new value to 100

    - the new value is then stored for later use
    --- armorDR+ammoDRM - at this point the value is between 0 and 100 inclusive

    - it then multiplies the Critical Multiplier (CM) by the attacking critter's ammo damage multiplier (X)
    --- CM is by default 2 or if the hit was determined to be a critical hit (happens somewhere before this) is set to a value from the critical hit table (I assume)
    --- X is either 1, 2, or 3 based on known ammo types
    --- I don't know what the X value is if the attacking critter is not using a weapon or if the weapon does not use ammo, assumed to be 1 in this case

    - it then multiplies the attacking critter's ammo damage divisor (Y) by a value (I wish I knew what - ravachol mentioned the value was 1, but I have not confirmed this is always the case)
    --- mystery value (MV)???
    --- Y is either 1 or 2 based on known ammo types
    --- I don't know what the Y value is if the attacking critter is not using a weapon or if the weapon does not use ammo, assumed to be 1 in this case

    - it then gets the number of hits the target critter took
    --- I assume if multiple targets were hit from a burst weapon that it is tracked elsewhere and once one target is handled, the next is sent through

    - it then clears a counter thats tracks the number of hits processed

    - it then stores the X*CM value for later

    - it then checks if the number of hits is less than or equal to 0, if not it skips all else
    --- I assume it then returns to see if there was another target hit or initiates the next critters/players turn

    - if the number of hits is greater than 0, it then gets the range bonus (RB)
    --- I assume RB to be default 0 unless the critter/player has the Bonus Ranged Damage perk

    - it then adds RB to the raw random damage value (RD)
    --- RD is dependant on the damage min.-max. of the attacking critter's weapon or whatever an unarmed critter is capable of

    - it then multiplies this new value (ND) by X*CM

    - it then checks if MV*Y is 0, if it is then it skips ahead
    --- this leads me to believe that either MV or Y may be allowed to be 0 when called in
    --- I suspect MV is what may be allowed to be 0 and if so then maybe it's associated to a weapon perk???

    - it MV*Y is greater than 0, it then divides ND by MV*Y

    - it then divides the new ND value by 2
    --- this seems to be done because for whatever reason CM is by default 2 and always multiplied in thus to negate an increase in damage when there was no critical hit, divide by 2
    --- when CM is not 2, this should also mean values in the critical hit table should always be even, as odd numbers would produce a decimal which would be dropped, I have not confirmed this

    - it then multiples the new ND value by the combat difficulty setting value (CD)
    --- CD appears to be either 72, 100, or 112
    --- given the way the CD value is used, I assume if the player chose a setting of Easy then CD=112 and if Hard then CD=72, this is counter intuitive but it would not work correctly the other way around

    - it then divides the new ND value by 100
    --- this is meant to cause CD to be used as a percentage
    --- unfortunately, again there is no rounding, any decimal value (remainder) is dropped after division

    - it then subtracts the armor's damage threshold (armorDT) from the new ND value

    - it checks if the new ND value is less than or equal to 0, if it is then it skips ahead to increment the counter
    --- I assume it counts this as a hit with no damage, given the counter is increased but nothing is added to damage taken by the target

    - if the ND value is greater than 0, it then holds on to this value, and separately multiplies this value by armorDR+ammoDRM
    --- ND1 and ND2=ND1*armorDR+ammoDRM

    - it then divides ND2 by 100
    --- this is meant to cause armorDR+ammoDRM to be used as a percentage of damage resisted
    --- unfortunately, again there is no rounding, any decimal value (remainder) is dropped after division

    - it then subtracts ND2 from ND1
    --- ND=ND1-ND2

    - it then checks if ND the new ND value is less than or equal to 0, if it is then it skips ahead
    --- I assume it counts this as a hit with no damage, given the counter is increased but nothing is added to damage taken by the target

    - if the ND value is greater than 0, it then adds that value to the total damage the target will take

    - it then increments the counter
    --- this is where it skips ahead to if at the checks mentioned previously damage was 0 or less

    - it then compares the counter value to the number of hits the target critter was going to take, if the counter value is less than the number of hits it loops back and starts again

    - if the counter is equal to the number of hits then the damage calculation for that specific target critter is complete

    Summarized without counter:
    ND = net damage value
    RD = random damage value produced from weapons hit damage range
    RB = ranged bonus (RB=0 unless the player has Bonus Ranged Damage perk)
    CM = critical hit damage multiplier (if no critical hit then CM=2, otherwise assigned value from critical hit table)
    armorDR = armor damage resistance value
    armorDT = armor damage threshold value
    ammoX = ammo dividend
    ammoY = ammo divisor
    ammoDRM = ammo resistance modifier (only value allowed to be negative or positive in the equation)
    CD = combat difficulty multiplier
    MV = mystery value

    armorDR+ammoDRM
    if armorDR+ammoDRM >= 0 then skip next step
    armorDR+ammoDRM=0
    if armorDR+ammoDRM <= 100 then skip next step
    armorDR+ammoDRM=100
    X*CM
    MV*Y
    ND=RD+RB
    ND=ND*(X*CM)
    if MV*Y <= 0 then skip next step
    ND=ND/(MV*Y)
    ND=ND/2
    ND=ND*CD
    ND=ND/100
    ND=ND-armorDT
    if ND <=0 then skip for no damage, repeat loop or exit
    N1=ND
    N2=ND*armorDR+ammoDRM
    N2=N2/100
    ND=N1-N2
    if ND <=0 then skip for no damage, repeat loop or exit
    TD=TD+ND
    Based on what I know of the original damage calculation I believe there are several major flaws:
    1- Division is not using decimals or rounding numbers
    2- The critical multiplier is applied too early in my opinion; how does one score a critical hit if it's unknown whether the hit got through the target's armor damage threshold or got past the target's armor damage resistance yet?
    3- The ammo multiplier is applied incorrectly in my opinion; first, multiplying the damage value directly implies that the ammo itself somehow increases the min.-max. damage potential of the weapon (I disagree with this) and second, how is damage multiplied if it's unknown whether the hit got through the target's armor damage threshold or got past the target's armor damage resistance yet?
    4- The ammo divisor is applied incorrectly in my opinion; dividing the damage by the ammo divisor only reduces the damage, why would anything about ammo be designed to reduce damage?
    5- The difficulty setting is applied too early in my opinion; again, how do you apply something that is to either make the damage more or less if it's unknown whether you got by the target's armor yet?

    Here's how I approached each of the flaws:
    1- I have removed division; instead I applied division by using subtraction in a loop, tracking the number of times through the loop (the quotient) and the remainder, I use the remainder to determine if the quotient should be rounded up (quotient+1)
    2- The critical multiplier (CM) is only applied after it is determined that the hit got through the target's armor
    --- how else can a hit be considered critical unless it got past armor to hurt a supposedly sensitive spot on the target
    3- The ammo multiplier (X) to me seemed out of place, so I compared all the ammo in the game
    --- it seemed that JHP ammo was the one (for the most part) which had an X value greater than 1
    --- so knowing JHP, was not designed to penetrate armor but rather when it did to fragment and cause more damage, I chose to use X to reduce the target's armor damage resistance
    4- The ammo divisor (Y) to me seemed again out of place, so again I compared all the ammo in the game
    --- it semed that AP ammo was the one (for the most part) which had a Y value greater than 1
    --- so knowing AP, was designed to penetrate armor but not fragment, I chose to use Y to reduce the target's armor damage threshold
    5- The combat difficulty setting (CD) felt wrong to apply like CM, if Easy or Hard were selected
    --- so I looked at treating it as a decrease or increase to the target's armor damage resistence value, -20 for Easy and +20 for Hard
    --- I tested a similiar decrease or increase to the target's armor damage threshold, and it had no meaningful affect

    Some consequences and realizations to my approach:
    1- Some ammo which has X greater than 1 and Y greater than 1, gets both advantages (currently only 2mm EC and 4.7mm caseless)
    2- Some of the ammo does not follow the expected X and Y values for it's type (ex. HN AP needler cartridge has X=2 and Y=1, Rocket AP has X=1 and Y=1)
    --- I consider this a bug in the ammo
    3- After seeing the output of my rough calculation tool, I've come to the following conclusions:
    --- the 9mm ammo is bugged, it was not intended to be AP ammo (X=1 and Y=2), it should have been JHP ammo (X=2 and Y=1)
    --- the HN AP needler cartridge ammo is bugged, it was not intended to be JHP ammo (X=2 and Y=1), it should have been AP ammo (X=1 and Y=2)
    --- the Cell ammo (both kinds) is bugged, it does nothing to modify the target's armor values, it should have been like JHP ammo in values (X=2 and Y=1)
    --- other ammo that might be considered bugged following the same case as Cell ammo are: .45 Caliber, 9mm ball, 12 gauge shotgun shells, HN Needler cartridge
    4- All weapons that use an ammo with X and Y values of 1 and an ammoDRM of 0 have no advantage whatsoever against the target's armor damage threshold and damage resistance (in the original calculation and mine)
    --- this is why Laser weapons don't do much damage, its not the weapon, it's the ammo and the fact that most armor in the game have high laser damage resistance
    5- I may be close to what the original devs had intended
    --- ammo was always meant to affect how the target's armor reacted to a hit, not how it might increase the min.-max. of a weapon's damage potential
    6- Ammo values are the biggest factor in whether a weapon is good or not, second is the weapon's min.-max.
    7- Ammo, weapons, and armor values need tweaking; to my previous point, ammo more so than anything else

    HTML/Javascript rough calculation tool --- http://di.proximitystore.com/newCalculator.html
    The rough calculation tool should be straight forward; you pick the ammo type, combat difficulty setting, and/or to have what I think the ammo value could be turned on or off
    The min.-max. is set to what is possible for the weapons that use that ammo
    (ex. if you pick .223 FMJ, use the weapon reference link and you'll see the .223 pistol has a min.=20 and a max.=30, all values for 20-30 would apply to that weapon)
    Choosing "None" for ammo type is the same as unarmed or a melee weapon that is not powered

    My damage calculation:
    (the following is based on what I've built in HTML/Javascript)
    fo2dmgcalc_glovz2.png
    assertions:
    1- armor cannot have a negative damage threshold
    2- armor cannot have a negative damage resistance
    3- ammo cannot add damage resistance
    4- in the exe a setting of Easy has CD greater than 100, and Hard less than 100

    if armDT is less than 0 then armDT is set to 0
    if amY is less than or equal to 0 then amY is set to 1
    armDT is divided by amY
    ND=RD-armDT
    if armDR is less than 0 then armDR is set to 0
    if amDRM is greater than 0 then amDRM=0-armDRM
    if CD is greater than 100 then CD is set to -20
    if CD is less than 100 then CD is set to 20
    armDR=armDR+amDRM+CD
    if amX is less than or equal to 0 then amX is set to 1
    armDR is divided by amX
    if armDR is greater than 0 then temp=(ND*armDR)/100, ND=ND-temp
    if armDR is less than or equal to 0 then temp=(ND*small bonus percent)/100, ND=ND+temp
    if ND is less than 0 then ND=0


    (assembly version) if multiple hits it loops back through for each, just as the original did

    Assembly code version of calculator to be included in sfall (simplified version) --- http://di.proximitystore.com/assemblyCode.txt
    just rename the file to AmmoMod.cpp, overwrite existing file in sfall and compile

    Here is a link to the script plus ini JimTheDinosaur initially provided and that NovaRain tweaked, which allows you to set your own ammoX, ammoY, ammoDRM, and acM to be used with any damage calculation (original, my mod, or anyone elses) --- http://di.proximitystore.com/Glovz_Fix2.zip (initial values are set to what I think works best with my fix turned on)


    Much appreciated Jim and NovaRain! :)

    EDIT:
    The new version is still DamageFormula=1 in the ini file for sfall, but now DamageFormula=2 is the new version plus a small tweak.

    I changed the way the critical multiplier is applied in the second version to Critical Damage = Net Damage + (Net Damage * 25% * Critical Multiplier)

    I always thought the critical multiplier was a little heavy handed, so this change reduces it bit. Makes things more interesting. ;)
     
    Last edited: Apr 21, 2014
  2. JimTheDinosaur

    JimTheDinosaur Vault Dweller
    Modder

    Mar 17, 2013
    Just some commentary as I'm testing:

    -I'm pretty sure 9mm ball should have some advantage over 9mm (JHP) against armor, with you it's just always inferior (a funny inversion of the original though).

    -I like the new 10mmAP/JHP in general, but maybe you could consider making JHP a bit more effective against unarmored and less against armored (right now with an average 10 damage shot against combat armor JHP is still the better choice).

    -I'm pretty sure you've insanely overpowered .223 FMJ, a 35 damage shot now actually does more damage against APAII (38, instead of 7 in the original formula).

    - I think you've made a mistake with the .44 FMJ/JHP; they do the same amount of damage against unarmored, and for all other scenarios FMJ is far superior. I think you're better off just more or less using the same relative values as AP/JHP.

    -Do Gauss Weapons really need further overpowering (it's not that much, but still...)?

    Rest looks very nice! Good job dude :D
     
  3. Glovz

    Glovz Vault Dweller
    Modder

    Sep 16, 2005
    Are you reviewing with modified ammo values on or off? I think you're reviewing with it on.

    I will take your feedback and tweak the modified ammo values.

    But please review how the damage calculation behaves with the original ammo values as well. I'm hoping my change improves the game without modifying the ammo and later with your help and/or others, through tweaking ammo, weapons, and armor, possibly improve balance.
     
  4. JimTheDinosaur

    JimTheDinosaur Vault Dweller
    Modder

    Mar 17, 2013
    On.

    What do you mean exactly? When I use the modification on setting it already compares it with the original formula. Or did you mean compare it with your own original formula?
     
  5. JimTheDinosaur

    JimTheDinosaur Vault Dweller
    Modder

    Mar 17, 2013
    Couple more comments (sorry I don't comment on the formula in general, but I think any potential problems with it are best found by just going through examples):

    - You did something weird with rockets, explosive (non-ap) rockets now occasionally do more than three times the damage against maximum armored opponents than in the original. The formula for ap rockets seems good (only now it's always inferior to explosive rockets).

    -You did the same weird inversion as with 9mm with the needler cartridges: instead of AP being overpowered, you overpowered the regular one (the regular one has the same armor piercing value as the AP one, namely -10, maybe you meant 10?)

    -Did flamethrower fuel really need this much powering up? Never used it that much myself, but going on a damage of 60 from 13 against APAII to 43 seems pretty drastic. Also, this might expose a small problem with your formula, because Flamethrower fuel mark II, despite having -15 DM added, does the exact same damage, namely 43, in this scenario).

    -Doubling up microfusion cell damage? Is that a good idea? A max turbo plasma rifle hit of 70 now does 77 against APAII instead of 21. What's your reason for that?

    Still, I think in general it looks like a good formula and that the issues I have with it can be tweaked with different DM values. Again, good stuff!
     
  6. Glovz

    Glovz Vault Dweller
    Modder

    Sep 16, 2005
    The chart on the left is the original damage calculation using the original ammo values (always) and the chart on the right is my change to the damage calculation using either the the original ammo values or the modified ammo values.

    I know I haven't explained the exact workings of my change yet, but do compare the outputs. I want opinions on whether it feels under powered or overpowered, but taking into consideration the original calculations flaws it should be understood weapons using JHP ammo were originally overpowered and weapons using AP ammo and/or X=1, Y=1, ammoDRM=0 ammo was underpowered.

    Even without modifying the ammo values I think I've taking the calculation in the right direction but there is always room for improvement. :)

    EDIT:
    Found a couple of small bugs in my javascript code - I updated the file - the output makes more sense now.

    EDIT2:
    I also updated the modified ammo values
     
  7. Glovz

    Glovz Vault Dweller
    Modder

    Sep 16, 2005
    Found bugs in my javascript - fixed them. I believe the fixes address your concerns.

    But now the code is getting a little out of control.

    I need to re-examine it again to see if it can be refactored and reduced. But the output now is very close to what I think works, so it's what I'll still be aiming for.
     
  8. JimTheDinosaur

    JimTheDinosaur Vault Dweller
    Modder

    Mar 17, 2013
    'Fraid I can't go over them again on account of going on holidays in a bit, but keep up the good work!
     
  9. Glovz

    Glovz Vault Dweller
    Modder

    Sep 16, 2005
    The prototype calculator has been updated for corrections to the math and modded ammo values.

    http://di.proximitystore.com/newCalculator_2.html

    I will now be working on documenting and producing this calculator in assembly to be added to sfall.

    I also did some digging where I went wrong with my previous version; besides not realizing the division was not using decimals, I messed up when the calculation should have started. This was the cause of the zero values. :(

    The version I'm producing now takes into account misunderstandings of the assembly code I had before; so there should be no logic issues, and I've triple checked the math to be sure division by subtraction is done correctly.

    When reviewing the output of the prototype, please remember that without the modded ammo values selected to be on, the output for damage will still be somewhat unbalanced.

    EDIT:
    I have now updated the first post with a description my new calculation
     
  10. Glovz

    Glovz Vault Dweller
    Modder

    Sep 16, 2005
    I have now added a link to the assembly code version of the calculator that will replace my previous version in sfall eventually.

    Here is the link:
    http://di.proximitystore.com/assemblyCode.txt

    I will be manually tracing through it a few time to ensure I have it right before asking Timeslip to add it into sfall, but hopefully I got it mostly right the first time. :)

    Anyone familiar with assembly code is welcome to review it as well.
     
  11. gvx

    gvx First time out of the vault

    Apr 4, 2008
    cmp ebx,0x0; // compare the number of hits to 0
    jle DamageFunctionReturn; // exit
    begin:

    jle ???



    opCSubCJmp:
    mov edx,0x1; // set the new armorDR value to 1
    mov ebp,edx; // set the temp value
    opASubCJmp:
    mov edx,ebx; // set temp value
    imul edx,ebp; // multiply the ND value by the armorDR value
    cmp edx,0x64; // compare the temp value to 100
    jl opASubDJmp; // if the temp value is less than 100 then goto opASubDJmp
    mov ebp,0x0; // set and store the quotient value to 0
    beginDivEJmp:
    add ebp,0x1; // add 1 to the quotient value
    sub edx,0x64; // subtract 100 from the temp value
    cmp edx,0x64; // compare the remainder value to 100
    jge beginDivEJmp; // if the remainder value is greater or equal to 100 then goto beginDivEJmp
    cmp edx,0x33; // compare the remainder value to 51
    jl aCheckDivEJmp; // if the remainder value is less than 51 goto aCheckDivEJmp
    add ebp,0x1; // add 1 to the quotient value
    aCheckDivEJmp:
    sub ebx,ebp; // subtract the damage resisted value from the ND value
    jmp cJmp; // goto cJmp
    opASubDJmp:
    cmp edx,0x33; // compare the remainder value to 51
    jl cJmp; // if the remainder value is less than 51 goto cJmp
    sub ebx,0x1; // subtract 1 from the ND value
    jmp cJmp; // goto cJmp


    opASubDJmp: ?? Once again
     
  12. Glovz

    Glovz Vault Dweller
    Modder

    Sep 16, 2005
    jle = jump if the value is less than or equal to what it is being compared to

    at the point you are asking about its checking that the value of the 'number of hits' to zero, if the number of hits is zero (or less somehow) then there is no need to calculate anything

    the other chunk of code you are looking at is to subtract the amount of damage the target's armor resisted from the overall possible damage amount to end up with the net damage amount, the amount of damage the target will actually take

    also remember you are looking at some division by subtraction there and it will/does look funky - even to me ;)

    EDIT:
    Sorry - forget to address the last part

    the reason the code looks like it repeats itself a lot is because; first I don't know how to create functions that can be called with sfall, second assembly is a really simple language and doesn't allow for calling and jumping back to when you been when where you been is different from the previous time the call was made (a little confusing but I don't have a better way to describe it)

    calls to jump are equivalent to if statements in case that helps
     
  13. gvx

    gvx First time out of the vault

    Apr 4, 2008
    I mean C compiler error!

    cmp ebx,0x0; // compare the number of hits to 0
    jle DamageFunctionReturn; // exit
    begin:

    Error 1 error C2415: improper operand type

    Error 2 error C2412: 'opASubDJmp': case-insensitive label has redefined
     
  14. Glovz

    Glovz Vault Dweller
    Modder

    Sep 16, 2005
    Oh! I haven't finished tracing through the code, so yes there may be some bugs.

    And yes, I haven't had a chance to attempt compiling it either yet.

    I will look into it and hopefully update the file soon.

    EDIT:
    The file I linked to also does not list where the code needs to start from/be inject at - I will add that in the next version as well for those who want to compile and test it
     
  15. Glovz

    Glovz Vault Dweller
    Modder

    Sep 16, 2005
    ok - I still have not finished tracing through the code but I believe I did fix the problem gvx identified

    I upload a new version at the same url:
    http://di.proximitystore.com/assemblyCode.txt

    if you download this file and rename it AmmoMod.cpp you should be able to attempt compiling it with sfall and test it out in game with DamageFormula=1 in the ddraw.ini file

    I will be testing this myself at some later time; hopefully this weekend, but if anyone wants to give it try please let me know what find and/or think
     
  16. gvx

    gvx First time out of the vault

    Apr 4, 2008
    Still the same

    1> AmmoMod.cpp 1> d: \ dropbox \ fallout Tools \ sfall \ sfall-xp \ sfall \ ammomod.cpp (35): error C2415: improper operand type
     
  17. Glovz

    Glovz Vault Dweller
    Modder

    Sep 16, 2005
    ok - I updated again - this is just a guess but maybe "begin" is a reserved word, so I changed that - but if it's choking on jle then it's possible the cmp command when comparing a value to 0 is no good for the compiler and that should not be the case

    if it is then then I have to change all the lines that compare a value to 0 to the test command, which will do the same thing but again should not be needed
     
  18. gvx

    gvx First time out of the vault

    Apr 4, 2008
    Still the same error

    cmp ebx,0x0; // compare the number of hits to 0
    jle DamageFunctionReturn; // exit

    may modify to

    cmp ebx,0x0; // compare the number of hits to 0
    jg begin;
    jmp DamageFunctionReturn; // exit
     
  19. Glovz

    Glovz Vault Dweller
    Modder

    Sep 16, 2005
    Changing this way does not make any sense, the jle command is straight out of the exe, if jle does not work at this line in my code then it will not work anywhere in my code

    did you try this change and did the compiler pass without error?
     
  20. gvx

    gvx First time out of the vault

    Apr 4, 2008
    change to

    cmp ebx,0x0; // compare the number of hits to 0
    jg begin;
    jmp DamageFunctionReturn; // exit

    It compiles successfully