Part 4 - What the actual F is going on when a monster hits you?
Part 4c - The gory details....
Note: For those of you unfamiliar with bitwise operations << means leftshift and >> means rightshift. These are binary operations that have the effect of multiplying or dividing a number. >>1 means move the bits right by 1 so 1100 (12) would become 0110 (6). >>2 means move the bits right by 2 so 1100 (12) would become 0011 (3). so the number can mean either divide or multiply (depending on if its a left or right shift) by 1=2 2=4 3=8 4=16 5=32 6=64 7=128 etc. etc.
Note2: If I use "FN" it means a function in the CSBwin code
Note3: The attacktrace I am using has been heavily modified by me, so I can work stuff out, normal CSBwin won't give you the same results.
Note4: True and false are sometimes expressed as 1 and 0. Equally true can mean
not 0 and false can mean
not non 0.
So....
One of my chars died on level 5 so I had to go back and res him - lots of worms on worm level had respawned, and here is the AttackTrace log of BOB THE BLUE (nabi) getting attacked by a worm.
MONSTER ATTACK ©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©
© Attacking BOB
© Calculating XP with (monster XP class=5) because a monster hit you...
|Entering function to Adjust skills (Reason 6) --------------------------
|
| Base XP=5 target skill=[7] XP*dungeon level multiplier (2) = 10
| [skill >=4] A monster attacked you < 4.17 seconds ago so XP*2 = 20
| skill[7] so Base skill is [0] with mastery level [7]
| skill[7] Adjusting XP: 3921+20=3941
| skill[0] new mastery level=7
| No level up
|
|Leaving function to Adjust skills -------------------------------
Getting XP for getting hit. Magenta worms XP class is 5 (
DME). The adjustSkills FN also checks to see if after adding XP to the affected skill and the base skill it is connected to, you have levelled.
© BOB's required to hit is 19
© Monsters to hit is rand(32)=23 + monsters Dex(35) + dungeon level multiplier*2 (4) - 16 = 46
© BOB's required to hit (19) is < monsters to hit roll (46) or monster passed a lucky hit chance (1 in 4)
Your character and the monsters to hit are calculated and then compared. If the monster misses, it gets a lucky 1 in 4 chance of hitting, just like characters do when they miss.
| Entering IsCharacterLucky (BOB , (luckNeeded=60))-------------------------------------
| ran bool=0 ran(100)=8, luckneeded=60
| D0 is either 0 or a rand(currentluck(42))=5
| result(0) = D0W (5)> luckNeeded (60)
| Returning result=false----------------------------------------------------
© BOB's IsCharacterLucky returned False
This is where the Luck attribute (attribute 0) is checked to see if it can get the monster to miss.
© Working out which body part to attack ©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©
© Wound=true
© Final D4=0 Final woundvalue(0)=5
© mask(D4) set to 32
The game has a bit of convoluted code to work out where the monster is attacking you. It gets a random number and "&"'s it with 112, the net result is that you have a 12.5% chance to not be attacked on a body part and an 87.5% chance to be attacked on a body part. If you do get true on a body part, it uses the same random number "&" 15 (this makes the random a 0-15 value) and checks it against monster wound values.
If Wound=false (for a body part) it will pick the left or right hand. (I think)
Magenta worms have wound values in this specific order feet=5 legs=12 torso=15 head=15 (
DME). This means that Magenta worms can never attack the head as 15 is the max and it will always be true if it gets to the torso.
Note: On monster wound values, monsters with low height have much greater chances of choosing the feet or legs to attack, like worms, rusters and screamers. Large creatures have a very small chance of picking feet or legs.
In this case, D4=0, woundvalue=5 means that it's attacking my feet, mask =32 is a conversion of D4=0 so it can pass the value to the next function(s),
© D7 Monster damage = (w_2(2*dung lev multi) (4) + STRandom(16) + D3W Monster attack power (45)) - (2*parry skill)(12) =37
© Divide D7 Monster damage by 2=18 and add rand(monster damage)[1] + rand(3)[0] =[19]
© D7 Monster damage= (D7W + STRandom(D7W)=31. D7 Monster damage/4=7. D7 Monster damage=(D7W + STRandom0_3() + 1)=11
This part is working out the base damage the monster will do. It gets divided and multiplied a bit by rands. It gets unlucky in this case as a rand of it's own damage returns only 1 from a possible 18. The monster damage should be clear enough from my log.
Entering damage character function (character=0 damage to do=11 mask=32 damage type=4--------
| Attacking body part D0W=5 (mask) D0 0=L hand 1=R hand 2=head 3=torso 4=legs 5=feet ------------------------
| Sharp attack true setting D1UW = 0x8000 (1000 0000 0000 0000)
| Entering clothing calc TAG01680a(chIdx[0], D0W | D1W[4294934533])
Now it's got the variables it needs worked out, it passes to FN damageCharacter. It's turned the mask (32) back to a 5(feet) and set the sharp bit to 1. Now it is going to hand off to FN TAG01680a (chIdx[0], D0W | D1W[4294934533]. Even though it's only 2 parameters, 3 are getting passed. chIdx=0 is referring to BOB. D0W | D1W is another bitwise operation adding the sharp bit to the possession index (the body part it wants to attack).
Entering TAG01680a(i32 chIdx(0),i32 possessionIndex(-32763))------------------------
As a signed integer, the -32763 means the top bit (sharp attack) is set (Magenta worms do use sharp attack). 32768 is the max so minus the 32763, we get our 5 (the possession index)
| D5 is holding the sharp bit=[4294934528] and possession index is [5]
| Working out if you have a shield--------------------------------------------------------
| D7=0 name index 108 desc index 99
| D0 clothing type=30
| Item had 'adds defense when held flag' set=3
It tests 0 (left hand) and 1 (right hand) for something in the clothing DB (database) that has the bit set that means "adds defence when held". I tried holding my mail hosen in my hands, but the bit was not set, so didn't work
In this case it found name index 108 in the left hand (108 is the wooden shield) and the bit was set so it continued on to the next part....
Damage calculation - stage 1 - weighting raw damage-----------------
> Variables: Str=55 chIdx=0 hand=0Raw damage (Str+rand(15)=9)=64 Item weight=14 (Maxload/16)=33
> Passed test 1 - Weapon weight (14) was <= maxload/16(33) so raw damage (raw damage + weapon weight -12)=66
> Stamina check, raw damage = 66
> Log hand=0, D0W (ouches)=0, D1W=1
> Apply limits of 0 and 100 to (raw damage/2) = 33
> Raw damage char=0 hand=0 value=33
This is the same damage check used when you hit a monster. As shields have no weapon damage, it's mostly about your STR here. Notice the "apply limits" - it can't be less than 0 or more than 100. The ouches being true will divide it by 2 and the stamina check will lop off about 25% if you are under half stamina.
I got 33.
| Entering TAG009470 (Get AC) item AC=20 item pierce resist=3 scale=1
| Scale=true (its a piercing attack) so result= AC(20)*(pierce resist(3)+4)(7) / 8 = 17
Now we are in FN TAG009470 which returns either the base AC of an item or the modified sharp attack AC if the damage type is 04. Scale being true means it's a sharp attack and will get modified.
Here I get 17 which is 7/8s of 20.
| D0L = DetermineThrowingDistance(chIdx[0], D7W possesionindex [0])=33
| D1L = TAG009470(clA2[], D5W!=0[1])17
| D0L += D1L;=50
| D1W = (UI8)(d.Byte1412[possessionIndex(5)]);1
| D0L = D0W * D1W=50
| D7(0) != possesionindex(5) so D1=5(5)
| D6(0) = D6 + (D0(50)>>D1(5)) = | Final shield absorb=1
The first 2 lines just reiterate what was previously calculated. Then they get added together and multiplied by a scaler (d.Byte1412).
d.Byte1412 is curious. It took a while to hunt it down but it's inside graphic entry 0x0232.
It's equal to;
5 for left hand
5 for right hand
4 for head
6 for torso
3 for legs
1 for feet
I originally thought it an error that it's multiplying your shield by a body position (the bold line), but now I think (maybe) it scales your shields effectiveness depending on which body part is being attacked with feet and legs being harder to defend with a shield and torso being the easiest.
If it was being fairer I would have made the code
D1W = (UI8)(d.Byte1412[D7W]);5 using the multiplier of the hand the shield is in (5) because the last step of shifting the value by 4(/16) or 5(/32) makes shields very low weight in the formula.
As you can see, it's attacking my feet (5) so I get a value of 1 and 50*1 is.... ..50
Finally it works out if the body part being attacked is the same as your shield location and sets a shifter to 4 if true or 5 if false
I got 5 because its attacking my feet, not the left hand and wow - 50>>5 (/32) = 1
1 whole absorb for my shield
The same function for the shield of darc with the torso being attacked would be;
Raw damage = 34
AC = 100
d.Byte1412=6
(34+100)*6=804
804>>5 (/32)=25
Shield of darc with the feet being attacked would have been;
(34+100)*1=141 /32 = 4
Shield of darc with the torso being attacked and STR=100 would have been;
(69+100)*6=1014 /32 = 31
Shield of darc with the feet being attacked and STR=100 would have been;
(69+100)*1=169 /32 = 5
| D7=1 name index 34 desc index 33
| Out of for loop D6W = 1
This is working out that my right hand contains a sword (name index 34) and it wants to do nothing else with it.
Now I am wondering what holding 2 shields does.
| D0 is a random=9493231 D1 is current vitality=54
| D1 is current vitality/8+1=7
| D0 & ffff=56047
| D7 (Absorb) = ((D0L mod D1W)=5)=5
| If D5 != 0 (sharp bit set) D7/2 (D5 is currently -32768)
This part is setting the base absorb. It gets a random number, gets VIT/8+1 and performs a mod on it. So basically, it can be from 0 to VIT/8.
If it's a sharp attack, it gets divided by 2.
| D7W (absorb)=2 + word64 (weapon defence modifier)=0 + shieldStrength (shield potion YA BRO)=48+ PartyShield (shield spell YA IR)=72,D6W (shield absorb)=1 = 123
Here, your almost final absorb rating is calculated.
Your base absorb, freshly calculated - I got 2 (5 divided by 2, rounded down)
Word64, this is the modifier added for defence if your action is greyed out and an action defence modifier is active. For example, if you have used block, you get +36 here. If you have used stab you get -20. If you have cast see through walls you get -15 etc. etc. - I got 0
(Hope I got it right this time, I'm sure Sophia will correct me if not

)
Next is personal shield (YA BRO), as mentioned this is cumulative, the more potions you drink, the higher it gets, with diminishing returns after 50. - I got 48, I think this was 2 PAL level YA BRO potions.
Party shield (YA IR) is much the same as the above. - I got 72, a bunch of PAL and EE shields had been cast.
And finally your shield value is added - I got a measly 1.
| Getting AC modifier of body part attacked (possesionindex [5])-------------------------
| Entering TAG009470 (Get AC) item AC=30 item pierce resist=6 scale=1
| Scale=true (its a piercing attack) so result= AC(30)*(pierce resist(6)+4)(10) / 8 = 37
Now it's doing the last part of calculating your absorb, it's grabbing the AC of the item worn in the body part being attacked.
I am wearing, well, BOB was wearing, the mail hosen in my feet slot (5) so AC is 30 and sharp resist is 6. In this case you can see the sharp formula giving me a better value than the base AC. *10/8 is the same as saying "Give me 10/8's of 30, which is 37"
| D7 (absorb) = D7 (absorb) + AC of item worn = 160
| D0W (Absorb) = ApplyLimits(0, D7W >>1, 100)= 80
| D5W (Absorb) = 80
| If D4W true (a mask was true) D5(Absorb) = (D5 (80) &0xffff)=80 / (D4 (mask true) (1) &0xffff)=1 =| D5 (Absorb)=80
My almost final absorb (123) + my armour in my foot slot (37) =160, divided by 2 within limits comes to 80. Note, another apply limits, so max is 100 and min is 0.
Not sure about the last line as it relies on D4 which is a counter which only seems to be 1 or 0 which will not change the result.
The implications;
Before your absorb is divided by 2, your first goal is to hit as close to 132 as possible. This gets you neutral - the damage the monster does will be the damage you get.
Base absorb - with 100 VIT, the best you could do here is 12 which is 0 to 6% (or 6 for a sharp attack which is 0 to 3%).. ..but it is random up to what you can get. i.e. 100 VIT means you will get between 0 and 12 somewhere.
word64 - Dependant on if you have attacked - Block will net you +36 which is 18%
Potion shield - With a few MON potions you can get to 70+ easy and stay there for some time. 35%
Party shield - With a few MON spells you can get to 70+ easy and stay there for some time. 35%
Shield - Measly - 1 to 40(ish) depending on the shield and the body part being attacked. So up to 18% if torso and shield of darc. A mid range shield like the large shield with 55 STR and the best rand role of 15 and body part attacked...
L hand=13% (gets a /16 instead of /32 if your shield is here)
R hand=6%
Head=5%
Torso=8%
Legs=4%
Feet=2%
AC of item worn - Quite good. Mid range items...
Armet (40 AC base 55 for a sharp attack) 20%/27%
Torso plate (65 AC base 65 for a sharp attack) 32%/32%
Leg plate (56 AC base 56 for a sharp attack) 32%/32%
Foot plate (37 AC base 41 for a sharp attack) 18%/20%
Plate of Lyte (125 AC base 125 for a sharp attack) 62%/62%
Plate of Darc (160 AC base 160 for a sharp attack) 80%/80%
Main calc-------------------------------------
| D0W(Absorb) = 130-D5W(old Absorb)=50. D7W(monster damage)(11) = (D0(absorb)*D7(monster damage))/64=8
This is the big one - most of the calculation done so far ends here.
Absorb = 130 - your absorb rating. 130-80 in my case = 50.
The next part scales the monster damage based on your absorb. (50*11)/64 is 8. So 50 dmg, would have been 39 dmg. 100 dmg would have been 78. So 80 absorb is about 22% reduction here.
If you had max absorb of 100 and monster damage was 100, it would be (30*100)/64= 46.8 or a 53.2% reduction.
2 cases, 1 for 11 dmg (that I had) and 100 dmg
------------11 dmg-------100 dmg--------
Absorb=0 damage=22 damage=205
Absorb=2 damage=22 damage=200
Absorb=10 damage=20 damage=187
Absorb=20 damage=18 damage=171
Absorb=30 damage=17 damage=156
Absorb=40 damage=15 damage=140
Absorb=50 damage=13 damage=125
Absorb=60 damage=12 damage=109
Absorb=64 damage=11 damage=100
Absorb=70 damage=10 damage=93
Absorb=80 damage=8 damage=78
Absorb=90 damage=6 damage=62
Absorb=98 damage=5 damage=50
Absorb=100 damage=5 damage=46
So the centre point is 64 absorb with 2 doing *2 dmg and 98 doing /2
© Determining if character gets injured--------------------------------------------------
© Testing characters vitality against random(128)+10=29
[][] Entering test attribute - attribute [4] which is [54] value to modify [29]-----------------------------
[][] D7 = 170-[54] which is [116]
[][] D7 (test result) >= 16 so (D0(29)*test result(57))/128 = [26]
[][] Tag016426(chIdx=0,attrNum=4,P3=29) = 26
This part is testing vitality to see if you will sustain an injury to the body part.
© If D7(damage)[8] > vitality test result [26] you have a chance to get injured
The worm only does 8 dmg and my test returned 26, so the part of the code that works out IF you sustain an injury is skipped.
$ Damage character 0 incremented by 8 = 8
$ d.PendingDamage[chIdx] = 8;
Returning damage charcter with value (8)------------------------------------------------
And finally, the damage is added to the queue to be done.
I was never aware when originally playing DM all those years ago that the different shield spells were so potent. Or that they stacked.
Before, at low level, I would get to the worm level and do the "square dance" so they could not hit me, knowing that a few nasty worm hits of 60+ dmg would total my characters. It's easy to see now that worm hits on badly equipped heroes with no shield spells can double the damage you take.
Now, I've tried being shielded up and it is easily possible to stand your ground and fight. It's quite different get hit for 10-30 dmg instead of 40-90 dmg.
Cheers!
Nick K.