My first attempt to code up the main routine was a straight linear approach. There are three attack types (melee, ranged, and sorcery) so I made three separate functions for each. Here's that code, excluding some minor routines on the side:
* Damage determination
ATKDAM BLWP @RANDOM
ANDI R4,>0003
A R4,@ATKDEF+6
BLWP @RANDOM
ANDI R4,>0003
A R4,@ATKDEF+14
MOV @ATKDEF+14,R0
S @ATKDEF+6,R0
JGT ATKMD1
MOV @W1,R0
ATKMD1 MOV @ATKDEF+2,R1
A @ATKDEF+4,@PSTATE+4(R1)
MOV @ATKDEF+10,R2
A R0,@PSTATE(R2)
CLR @RESULT
B @SUBRET
* Attack routine
* @ATKTYP - attack type
* @ATKDEF,@ATKDEF+8 - attacker/defender unit (0-22 x2)
* @RESULT - Combat result
ATTACK MOV R11,*R10+
CLR @RESULT
* Check if defender is invulnerable
MOV @ATKDEF+10,R2
MOVB @PSTATE+24(R2),R0
JEQ ATTCK1
SETO @RESULT
B @SUBRET
* Get VDP arrays into memory
ATTCK1 MOV @ATKDEF+2,R0
LI R1,HIBUFF
LI R2,30
BLWP @VMBR
MOV @ATKDEF+10,R0
LI R1,HIBUFF+30
LI R2,30
BLWP @VMBR
* Determine fatigue bases
MOV @W1,@ATKDEF+4
MOV @W1,@ATKDEF+12
MOV @ATKDEF+2,R1
MOV @PSTATE+12(R1),R0
JEQ ATTCK3
ANDI R0,>00FF
JEQ ATTCK2
DEC @ATKDEF+4
JMP ATTCK3
ATTCK2 INC @ATKDEF+4
ATTCK3 MOV @PSTATE+12(R2),R0
JEQ ATTCK5
ANDI R0,>00FF
JEQ ATTCK4
DEC @ATKDEF+12
JMP ATTCK5
ATTCK4 INC @ATKDEF+12
* Set attack and defense powers
ATTCK5 CLR @ATKDEF+6
CLR @ATKDEF+14
* Check if attacker is exalted or cursed
MOV @PSTATE+8(R1),R0
JEQ ATTCK7
ANDI R0,>00FF
JEQ ATTCK6
DECT @ATKDEF+6
JMP ATTCK7
ATTCK6 INCT @ATKDEF+6
ATTCK7 MOV @PSTATE+8(R2),R0
JEQ ATTCK9
ANDI R0,>00FF
DECT @ATKDEF+14
JMP ATTCK9
ATTCK8 INCT @ATKDEF+14
* Check if defender is guarding, if so, +2 to defense power
ATTCK9 MOV @ATKDEF+8,R2
MOV @CSTATE(R2),R0
JEQ ATCK10
INCT @ATKDEF+14
* Set attacker's faded state to zero
ATCK10 MOVB @ZERO,@PSTATE+21(R1)
* Add luck to power
MOV @ATKDEF,R1
MOV @ATKDEF+8,R2
A @PLUCK(R1),@ATKDEF+6
A @PLUCK(R2),@ATKDEF+14
* Branch to attack type
MOV @ATKTYP,R1
B @AKCASE(R1)
* Attack - melee
* Get base attack/defense melee power
ATKMEL CLR @PARRY
CLR @BLOCK
MOV @ATKDEF+8,R1
SLA R1,1
BL @FDODGE
MOVB @HIBUFF,R1
SRL R1,8
A R1,@ATKDEF+6
MOVB @HIBUFF+30,R1
SRL R1,8
A R1,@ATKDEF+14
* Check player only defense elements
C @ATKDEF,@W8
JEQ ATKM1
* Check for 2H weapon
CB @HIBUFF+20,@B132
JL ATKM0
CB @HIBUFF+20,@B136
JH ATKM0
INC @ATKDEF+4
* Check if defender (player only) can parry
ATKM0 C @ATKDEF+8,@W8
JEQ ATKM1
CB @HIBUFF+50,@ZERO
JEQ ATKM0A
CB @HIBUFF+50,@B128
JEQ ATKM0A
INC @PARRY
* Check if player can block
ATKM0A CB @HIBUFF+52,@B147
JNE ATKM1
INC @BLOCK
* Check if attacker is enraged (+4 to attacker power)
ATKM1 MOV @ATKDEF+2,R1
MOVB @PSTATE+20(R1),R0
JEQ ATKM2
A @W4,@ATKDEF+6
* Check if defender is enraged (-4 to defender power)
ATKM2 MOV @ATKDEF+10,R2
MOVB @PSTATE+20(R2),R0
JEQ ATKM3
S @W4,@ATKDEF+14
* Check if defender is armored (+4 to defender power)
ATKM3 MOVB @PSTATE+16(R2),R0
JEQ ATKM4
A @W4,@ATKDEF+14
* Check for base miss
* Check if defender is blurred (50% miss chance)
ATKM4 MOVB @PSTATE+17(R2),R0
JEQ ATKM5
LI R3,2
JMP ATKM6
* Fetch base melee miss chance
ATKM5 MOVB @HIBUFF+12,R3
SRL R3,8
ATKM6 BLWP @RNDNUM
MOV R4,R4
JNE ATKM7
* Missed!
MOV @W1,@RESULT
B @SUBRET
* Check for critical
ATKM7 BLWP @RANDOM
ANDI R4,>000F
JNE ATKM8
* Critical!
MOV @ATKDEF+6,R0
SRL R0,1
A R0,@ATKDEF+6
CLR @ATKDEF+4
B @ATKDAM
* Defense checks
* Check for parry
ATKM8 C @ATKDEF+8,@W8
JEQ ATKM9
MOV @PARRY,@PARRY
JEQ ATKM10
ATKM9 MOVB @HIBUFF+45,R3
SRL R3,8
JEQ ATKM10
BLWP @RNDNUM
MOV R3,R3
JNE ATKM10
* Parried!
MOV @W2,@RESULT
MOV @ATKDEF+10,R1
A @ATKDEF+12,@PSTATE+4(R1)
B @SUBRET
* Check for block
ATKM10 C @ATKDEF+8,@W8
JEQ ATKM11
MOV @BLOCK,@BLOCK
JEQ ATKM12
ATKM11 MOVB @HIBUFF+46,R3
SRL R3,8
JEQ ATKM12
BLWP @RNDNUM
MOV R3,R3
JNE ATKM12
* Blocked!
MOV @W3,@RESULT
MOV @ATKDEF+10,R1
A @ATKDEF+12,@PSTATE+4(R1)
B @SUBRET
* Check for dodge
ATKM12 MOV @DODGE,@DODGE
JEQ ATKMDM
MOV @ATKDEF+10,R1
MOVB @PSTATE+23(R1),R0
JNE ATKMDM
MOVB @HIBUFF+47,R3
SRL R3,8
JEQ ATKMDM
BLWP @RNDNUM
MOV R3,R3
JNE ATKMDM
* Dodged!
MOV @W4,@RESULT
MOV @DODGE,R3
BLWP @RNDNUM
SLA R4,1
MOV @ATKDEF+10,R1
A @ATKDEF+12,@PSTATE+4(R1)
INC @PSTATE+4(R1)
SRL R1,3
MOV @DMOVE(R4),@UNITS(R1)
B @SUBRET
ATKMDM B @ATKDAM
* Attack - ranged
* Get base attack/defense ranged power
ATKRNG CLR @BLOCK
MOVB @HIBUFF+3,R1
SRL R1,8
A R1,@ATKDEF+6
MOVB @HIBUFF+33,R1
SRL R1,8
A R1,@ATKDEF+14
* Check player only defense elements
C @ATKDEF,@W8
JEQ ATKR1
* Check for Arbalest (-1 fatigue)
CB @HIBUFF+24,@B139
JNE ATKR0
DEC @ATKDEF+4
* Check if defender (player only) can block
* If attacker has firearm, nevermind
ATKR0 CB @HIBUFF+24,@B140
JEQ ATKR1
CB @HIBUFF+52,@B147
JNE ATKR1
INC @BLOCK
* Check if defender is shielded (+4 to defender power)
ATKR1 MOV @ATKDEF+10,R2
MOVB @PSTATE+28(R2),R0
JEQ ATKR2
A @W4,@ATKDEF+14
* Check for base miss
* Check if defender is deflecting (50% miss chance)
ATKR2 MOVB @PSTATE+27(R2),R0
JEQ ATKR3
LI R3,2
JMP ATKR4
* Fetch base ranged miss chance
ATKR3 MOVB @HIBUFF+13,R3
SRL R3,8
ATKR4 BLWP @RNDNUM
MOV R4,R4
JNE ATKR5
* Missed!
MOV @W1,@RESULT
B @SUBRET
* Check for critical
ATKR5 BLWP @RANDOM
ANDI R4,>000F
JNE ATKR6
* Critical!
MOV @ATKDEF+6,R0
SRL R0,1
A R0,@ATKDEF+6
CLR @ATKDEF+4
B @ATKDAM
* Defense checks
* Check for block
ATKR6 C @ATKDEF+8,@W8
JEQ ATKR7
MOV @BLOCK,@BLOCK
JEQ ATKRDM
ATKR7 MOVB @HIBUFF+36,R3
SRL R3,8
JEQ ATKRDM
BLWP @RNDNUM
MOV R3,R3
JNE ATKRDM
* Blocked!
MOV @W3,@RESULT
MOV @ATKDEF+10,R1
A @ATKDEF+12,@PSTATE+4(R1)
B @SUBRET
ATKRDM B @ATKDAM
* Attack - sorcery (target and area)
ATKSOR CLR @BLOCK
MOVB @HIBUFF+6,R1
SRL R1,8
A R1,@ATKDEF+6
MOVB @HIBUFF+36,R1
SRL R1,8
A R1,@ATKDEF+14
* Get spell type
LI R0,SPLDAT
BLWP @VSBR
SRL R1,4
MOVB R1,@WORK
* Check player only defense elements
C @ATKDEF,@W8
JEQ ATKS2
* Check for spell affinity
CB @HIBUFF+19,@WORK
JNE ATKS0
INCT @ATKDEF+6
DEC @ATKDEF+4
ATKS0 C @ATKDEF+8,@W8
JEQ ATKS1
CB @HIBUFF+49,@WORK
JNE ATKS1
INCT @ATKDEF+14
DEC @ATKDEF+12
* Check if defender can block
ATKS1 CB @HIBUFF+52,@B147
JL ATKS2
CB @HIBUFF+52,@B148
JH ATKS2
INC @BLOCK
* Check if defender is resolved (+4 to defender power)
ATKS2 MOV @ATKDEF+10,R2
MOVB @PSTATE+26(R2),R0
JEQ ATKS3
A @W4,@ATKDEF+14
* Check if defender is warded (50% miss chance)
ATKS3 MOVB @PSTATE+29(R2),R0
JEQ ATKS4
LI R3,2
JMP ATKS5
* Check for base sorcery miss (targeted only)
ATKS4 C @W6,@ATKTYP
JEQ ATKS7
MOVB @HIBUFF+14,R3
SRL R3,8
ATKS5 BLWP @RNDNUM
MOV R4,R4
JNE ATKS6
* Missed!
MOV @W1,@RESULT
B @SUBRET
* Check for critical (targeted only)
ATKS6 BLWP @RANDOM
ANDI R4,>000F
JNE ATKS7
* Critical!
MOV @ATKDEF+6,R0
SRL R0,1
A R0,@ATKDEF+6
CLR @ATKDEF+4
JMP ATKSDM
* Defense checks
* Check for block (area only)
ATKS7 C @W6,@ATKTYP
JNE ATKS9
C @ATKDEF+8,@W8
JEQ ATKS8
MOV @BLOCK,@BLOCK
JEQ ATKSDM
ATKS8 MOVB @HIBUFF+46,R3
SRL R3,8
JEQ ATKSDM
BLWP @RNDNUM
MOV R3,R3
JNE ATKSDM
* Blocked!
MOV @W3,@RESULT
MOV @ATKDEF+10,R1
A @ATKDEF+12,@PSTATE+4(R1)
B @SUBRET
* Check for resist (targeted only, non-damage only)
ATKS9 MOVB @HIBUFF+48,R3
SRL R3,8
JEQ ATKSDM
BLWP @RNDNUM
MOV R3,R3
JNE ATKSDM
* Resisted!
MOV @W5,@RESULT
MOV @ATKDEF+10,R1
A @ATKDEF+12,@PSTATE+4(R1)
B @SUBRET
* Damage determination
ATKSDM
B @ATKDAM
For my CRPG design, I'm less concerned about speed than I am about space. So I'm always checking the byte count any time I finish a large block of new code. This block weighs in at 1168 bytes. Ouch.
Adamantyr















