Prev: 90B4 Up: Map Next: 917D
90DB: Attack (HIT, KILL, ATTACK, STRIKE, SMASH ...)
The fight routine. It is used both when the player attacks someone and when another character attacks (for example Thorin retaliating, or the trolls and goblins attacking Bilbo). The attacker's object record is pointed to by $B5FC, the target's by B5F8, and the weapon's (if any) by $B5FA; B5DA holds the weapon's object number, or $FF when there is none.
It uses two bytes of the 8-byte object header (see C00B): byte 5 is STRENGTH and byte 6 is DEFENCE. Some starting values: Bilbo 64/64, Thorin 104/120, Gandalf 112/136, the trolls 160/160, the goblins 72/96, Bard 96/96, the dragon 192/192, and the short strong sword has strength 64 (255 in my modified tape).
Step 1: 'you attack thorin' is printed ($90FE onwards), naming the weapon if one was used.
Step 2: the attack value is the attacker's strength (90F9), plus the weapon's strength if one was used (9102-9116), capped at 255. A weapon is only accepted if byte 0 of its record is 1 (an ordinary one-place object); otherwise the message at AE52 is printed.
Step 3: the attack value is randomised by 917D (roughly -10 to +10) and so is the target's defence (9121-$912A).
Step 4: if the randomised defence is greater than or equal to the attack, the blow does nothing: 'but the effort is wasted. his defense is too strong' (AE43).
Step 5: if the attack exceeds the defence by more than 16, the blow is fatal. The message at AD2D ('with one well placed blow you cleave his skull') is printed and bit 3 of the target's flag byte (byte 7) is set, marking it dead (9168).
Step 6: otherwise the target is wounded. The difference d (1-16) selects a message from the table at 9190 - the larger the margin the nastier the description. The code then tries to reduce the target's strength by d/2+1 and its defence by d/4+1 (914E-$9164), skipping either reduction if it would go below 0. It computes d/2 and d/4 with RRCA (rotate right) rather than SRL (shift right), though.
BUG: RRCA moves the bit shifted out of the bottom back into the top, so the halving only works when the bit being shifted out is 0. With Thorin (strength 104, defence 120) the actual results are: margins 4, 8, 12 and 16 reduce both strength and defence as intended (for example margin 8 takes him to 99/117); margins 2, 6, 10 and 14 reduce strength only; margins 3, 7, 11 and 15 do nothing at all; and margins 1, 5, 9 and 13 leave strength alone but slash his defence by about 65, to 52-55, which makes the next blow very likely to kill him.
BUG: the table at 9190 only has useful entries for differences 1 to 15. A difference of exactly 16 reads the two bytes at 91B0 (which are code, $DD $2A) as a message address, so the game interprets ROM at $2ADD as a message and prints garbage.
90DB CALL $90B4 Check the target is something that can be attacked
90DE LD A,($B5DA) Was a weapon named?
90E1 LD HL,$026F HL = the word used when there is no weapon
90E4 CP $FF
90E6 JR Z,$90F2 No weapon: skip
90E8 LD IX,($B5FA) IX = the weapon's record
90EC LD L,(IX+$08) HL = the weapon's noun (e.g. SWORD)
90EF LD H,(IX+$09)
90F2 LD ($B5ED),HL Keep it for the report ("...with the sword")
90F5 LD IX,($B5FC) IX = the attacker's record
90F9 LD B,(IX+$05) B = the attacker's strength
90FC LD A,($B5DA) Is there a weapon?
90FF INC A ($FF + 1 = 0)
9100 JR Z,$9119 No: attack with strength alone
9102 LD IY,($B5FA) IY = the weapon's record
9106 LD A,(IY+$00) Is it an ordinary object (one place)?
9109 DEC A
910A LD HL,$AE52 "you cannot kill with the X"
910D JP NZ,$72D4 No: say so and stop
9110 LD A,(IY+$05) A = the weapon's strength
9113 ADD A,B Add the attacker's strength
9114 JR NC,$9118 No overflow: fine
9116 LD A,$FF Overflow: cap it at 255
9118 LD B,A B = the attack value
9119 LD A,B
911A CALL $917D Randomise the attack value by about +/-10
911D LD B,A
911E CALL $9C99 Dry run? Then stop here: the attack would happen
9121 LD IX,($B5F8) IX = the target's record
9125 LD A,(IX+$06) A = the target's defence
9128 CALL $917D Randomise it too
912B CP B Is the defence at least as big as the attack?
912C LD HL,$AE43 "but the effort is wasted. his defense is too strong."
912F JP NC,$72D4 Yes: the blow does nothing
9132 LD C,A C = the defence
9133 ADD A,$10 Defence + 16...
9135 JR NC,$9139
9137 LD A,$FF (capped at 255)
9139 CP B ...less than the attack?
913A JR C,$9168 Yes: a fatal blow
913C LD A,B A wound. A = the margin (attack - defence, 1-16)
913D SUB C
913E RLCA Double it to index the wound messages
913F LD E,A
9140 LD D,$00
9142 LD IY,$9190 IY = the wound message table
9146 ADD IY,DE
9148 LD L,(IY+$00) HL = the message for this margin (a margin of 16 runs off the end of the table)
914B LD H,(IY+$01)
914E RRCA Halve the doubled margin twice with RRCA: margin/2, but with bit 0 rotated into bit 7 (see the bug note)
914F RRCA
9150 LD B,A B = the "half" margin
9151 CPL A = 255 - B
9152 ADD A,(IX+$05) Add the target's strength: carry only if strength > B
9155 JR NC,$915A It would go negative: leave it alone
9157 LD (IX+$05),A Otherwise strength = strength - B - 1
915A LD A,B A = the "half" margin again
915B RRCA Halve it again (RRCA again)
915C CPL A = 255 - that
915D ADD A,(IX+$06) Add the target's defence
9160 JR NC,$9165 It would go negative: leave it
9162 LD (IX+$06),A Otherwise defence = defence - (margin/4) - 1
9165 JP $72D4 Print the wound message
9168 LD HL,$AD2D "with one well placed blow <actor> cleaves <his/your> skull."
916B CALL $72D4
916E SET 3,(IX+$07) Mark the target dead
9172 LD A,($B5D9) A = the target
9175 CALL $96DD Kill it: drop its things, remove it from the character table
9178 LD A,$06 Then report "<target> is dead."
917A JP $A09C
Prev: 90B4 Up: Map Next: 917D