-
Notifications
You must be signed in to change notification settings - Fork 41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Glovz rewrite to c++ #355
Comments
Glovz implemented a banker's rounding inside the formula code for integer division (except the last |
Why not just a global script? |
no matter where, the main thing is to rewrite it in a normal form. |
In my opinion everything that can be written as a script - should be. If I remember correctly everything needed (hook and all necessary parameters) already exist. Not many people care enough to mess with sfall code directly and allowing more people to read and tweak such code is healthy for community. |
OK, I think I get the main function right, still gonna do more testing though. void DamageMod::DamageGlovz(fo::ComputeAttackResult &ctd, DWORD &accumulatedDamage, long rounds, long armorDT, long armorDR, long bonusRangedDamage, long multiplyDamage, long difficulty) {
if (rounds <= 0) return;
long ammoY = fo::func::item_w_dam_div(ctd.weapon); // ammoY value (divisor)
if (ammoY <= 0) ammoY = 1;
long ammoX = fo::func::item_w_dam_mult(ctd.weapon); // ammoX value
if (ammoX <= 0) ammoX = 1;
long ammoDRM = fo::func::item_w_dr_adjust(ctd.weapon); // ammoDRM value
if (ammoDRM > 0) ammoDRM = -ammoDRM;
// start of damage calculation loop
for (long i = 0; i < rounds; i++) { // check the number of hits
long rawDamage = fo::func::item_w_damage(ctd.attacker, ctd.hitMode); // get the raw damage value
rawDamage += bonusRangedDamage; // add the bonus ranged damage value to the RD value
if (rawDamage <= 0) continue; // if raw damage <= 0, skip damage calculation and go to bottom of loop
if (armorDT > 0) { // compare the armorDT value to 0
long calcDT = DivRound(armorDT, ammoY);
rawDamage -= calcDT; // subtract the new armorDT value from the RD value
if (rawDamage <= 0) continue; // if raw damage <= 0, skip damage calculation and go to bottom of loop
}
if (armorDR > 0) { // compare the armorDR value to 0
long calcDR = armorDR;
if (difficulty > 100) { // if the CD value is greater than 100
calcDR -= 20; // subtract 20 from the armorDR value
} else if (difficulty < 100) { // if the CD value is less than 100
calcDR += 20; // add 20 to the armorDR value
}
calcDR += ammoDRM; // add the ammoDRM value to the armorDR value
calcDR = DivRound(calcDR, ammoX); // goto divTwo
if (calcDR >= 100) continue; // if armorDR >= 100, skip damage calculation and go to bottom of loop
long resistedDamage = DivRound(calcDR * rawDamage, 100); // goto divThree
rawDamage -= resistedDamage; // subtract the damage resisted value from the RD value
if (rawDamage <= 0) continue; // if raw damage <= 0, skip damage calculation and go to bottom of loop
}
// bonus damage to unarmored target
if (armorDT <= 0 && armorDR <= 0) {
if (ammoX > 1 && ammoY > 1) { // FMJ/high-end
rawDamage += DivRound(rawDamage * 15, 100); // goto divFour
} else if (ammoX > 1) { // JHP
rawDamage += DivRound(rawDamage * 20, 100); // goto divFive
} else if (ammoY > 1) { // AP
rawDamage += DivRound(rawDamage * 10, 100); // goto divSix
}
}
if (formula == 2) { // v5.1 tweak
rawDamage += DivRound(rawDamage * multiplyDamage * 25, 100); // goto divSeven
} else {
rawDamage = (rawDamage * multiplyDamage) >> 1; // divide the result by 2
}
if (rawDamage > 0) accumulatedDamage += rawDamage; // accumulate damage (make sure the final raw damage > 0)
}
} |
Why not ... /2 ? |
Oh, the original ASM uses Using
Maybe I should do a last check on rawDamage value before adding it to accumulatedDamage, as in YAAM? EDIT: updated the code with a couple more checks. |
I think there is no need. DivRound - what is the function? |
Well, just try to make sure the "overflow" case won't happen and negative value being added to accumulatedDamage.
Currently it's this one, basically the same logic as in the original ASM code: static long DivRound(long dividend, long divisor) {
if (dividend == divisor) return 1;
if (dividend < divisor) {
dividend <<= 1; // multiply by 2
return (dividend <= divisor) ? 0 : 1;
} else {
long quotient = 0;
while (dividend >= divisor) {
quotient++;
dividend -= divisor;
}
// check the remainder
if (dividend) {
dividend <<= 1; // multiply by 2
if (dividend > divisor) {
quotient++;
} else if (dividend == divisor) {
if ((quotient & 1) != 0) quotient++; // round half to even
}
}
return quotient;
}
} I run some numbers through it and the result is OK. |
Some terrible function :) long quotient = 0;
while (dividend >= divisor) {
quotient++;
dividend -= divisor;
} It seems mathematically it should be like this
|
Because of the while loop? The original idea was to use subtraction instead of division operator to do the math, and I simply replicate it in the div func. It does look a bit silly for when the dividend is much bigger than the divisor (e.g. do 100 / 2 -> loop 50 times). ; original with subtraction loop
grThan:
mov ebp, eax; // assign the divisor value
xor eax, eax; // clear value
bbbJmp:
inc eax; // add 1 to the quotient value
sub edx, ebp; // subtract the divisor value from the dividend value
cmp edx, ebp; // compare the remainder value to the divisor value
jge bbbJmp; // if the remainder value is greater or equal to the divisor value then goto bbbJmp (loop)
jz endDiv; // if the remainder value is equal to 0 then goto endDiv
...
; no loop
grThan:
;test eax, eax; // compare the divisor value to 0 (redundant?)
;jz endDiv; // avoid division by zero error
mov ebp, eax; // assign the divisor value
mov eax, edx; // assign the dividend value
cdq; // prepare for division
idiv ebp; // perform signed integer division (eax = quotient, edx = remainder)
test edx, edx; // compare the remainder value to 0
jz endDiv; // if the remainder value is equal to 0 then goto endDiv
...
I think it can be simpler: long quotient = dividend / divisor;
dividend %= divisor; // now it's the remainder |
not just because of the loop. |
Any suggestion? |
The new div function is much slimmer, thanks for the help. |
https://github.com/phobos2077/sfall/blob/f9157bee6d7919134312c6fcf0423afa9f202813/sfall/Modules/DamageMod.cpp#L35
If you have the desire you can rewrite it in c++
I once tried to do this for a very, very long time, but somehow I could not master this formula
here are my saved old beginnings. use this as a helper
The text was updated successfully, but these errors were encountered: