changeset 38:c8893fb9cacc

Decoded attack and damage calculations. Decoded the code that calculates attack probabilities and also the damage calculation. Also identified that several variables in the direct page MUST remain in the same order with the same spacing for the combat routines to work.
author William Astle <lost@l-w.ca>
date Sat, 27 Dec 2014 00:26:01 -0700
parents 026865a318f3
children 8fd288f0b01c
files dod.s
diffstat 1 files changed, 138 insertions(+), 89 deletions(-) [+]
line wrap: on
line diff
--- a/dod.s	Fri Dec 26 22:40:55 2014 -0700
+++ b/dod.s	Sat Dec 27 00:26:01 2014 -0700
@@ -253,14 +253,16 @@
 screendraw	rmb 2				; pointer to the parameter block of the screen to use for drawing
 V20D		rmb 2				; pointer to demo game command sequence
 objectfree	rmb 2				; pointer to next free object data slot
-linebuffptr		rmb 2				; line input buffer pointer
-playerloc	rmb 1				; current player position in maze (Y)
-V214		rmb 1				; current player position in maze (X)
+linebuffptr	rmb 2				; line input buffer pointer
+playerloc	rmb 2				; current player position in maze
 carryweight	rmb 2
+; powerlevel, V219, V21A, V21B, V21C, and damagelevel must remain in the same specific order
+; with the same spacing between them in order to match the same structure used by the creature
+; data.
 powerlevel	rmb 2				; player power
-V219		rmb 1
+V219		rmb 1				; magical attack value (player)
 V21A		rmb 1
-V21B		rmb 1
+V21B		rmb 1				; physical attack value (player)
 V21C		rmb 1
 lefthand	rmb 2				; pointer to object carried in left hand
 righthand	rmb 2				; pointer to object carried in right hand
@@ -833,22 +835,23 @@
 		stx 4,s				;*
 		rti				; return to caller
 ; SWI 0 routine
-LC384		lda effectivelight
-		tst V275
-		beq LC38E
-		lda V26F
-		clr V275
-LC38E		clrb
+; Calculate base light level in dungeon.
+LC384		lda effectivelight		; fetch effective light level in dungeon
+		tst V275			; are we checking for special lighting conditions?
+		beq LC38E			; brif not
+		lda V26F			; get "passed out" fade state
+		clr V275			; undo special light level checking
+LC38E		clrb				; default to full bright
 		suba #7
 		suba V28B
-		bge LC39F
-		decb
-		cmpa #$f9
-		ble LC39F
-		ldx #LCB96
-		ldb a,x
-LC39F		stb lightlevel
-		rts
+		bge LC39F			; brif adjusted light level >= 0
+		decb				; change to dark
+		cmpa #$f9			; are we in a special light level range?
+		ble LC39F			; brif not - use the calculated value (dark)
+		ldx #LCB96			; point to end of table of pixel masks
+		ldb a,x				; fetch value from pixel mask (1, 2, 4, 8, 16, 32)
+LC39F		stb lightlevel			; save new light level (full bright or dark)
+		rts				; return to caller
 ; SWI 1 routine
 ;***********************************************************************************************************
 ; This routine renders a line graphic from the specification stored at (X).
@@ -2702,10 +2705,10 @@
 		stb V21C
 		tfr y,x
 		ldu #powerlevel
-		jsr LD3D7
+		jsr attack
 		bmi LD099
 		playsoundimm $13
-		jsr LD40C
+		jsr damage
 LD099		checkdamage
 		jmp LD10F
 LD09E		pshs a,b,x
@@ -2990,9 +2993,9 @@
 		lda 13,u			; fetch physical offense value
 		sta V21B			; save for combat calculations
 		adda V219			; calculate sum of magical and physical damage
-		rora				; divide by 8
-		lsra
-		lsra
+		rora				;* divide by 8
+		lsra				;*
+		lsra				;*
 		ldx powerlevel			; fetch current player power
 		jsr applyscale			; apply the scale factor calculated above
 		addd damagelevel		; apply the wielding cost to play damage
@@ -3012,15 +3015,15 @@
 		sta 9,u				; set to GOLD ring
 		jsr LD638			; update object stats appropriately
 LD2F7		ldd playerloc			; get current location in dungeon
-		jsr LCF82
-		beq LD375
-		ldu #powerlevel
-		exg x,u
+		jsr LCF82			; find creature in the room
+		beq LD375			; brif no creature
+		ldu #powerlevel			; point to player power level
+		exg x,u				; swap player and creature pointers
 		lda 10,y			; fetch object type
 		cmpa #1				; is it a ring?
 		beq LD31F			; go do successful attack if so - rings never miss
-		jsr LD3D7
-		bmi LD375
+		jsr attack			; calculate if attack succeeds (attacker in X, defender in U)
+		bmi LD375			; brif attack fails
 		ldy curtorch			; do we have a torch burning?
 		beq LD319			; brif not
 		lda 9,y				; get torch type
@@ -3032,20 +3035,20 @@
 LD31F		playsoundimm $12		; play the "HIT" sound
 		renderstrimmp			; display the "!!!" for a successful hit
 		fcb $16,$f7,$b0			; packed "!!!" string
-		jsr LD40C			; calculate damage, apply to victim
-		bhi LD375
-		leax 8,u
-LD32E		ldx ,x
-		beq LD33A
-		clr 5,x
-		ldd 15,u
-		std 2,x
-		bra LD32E
+		jsr damage			; calculate damage, apply to victim
+		bhi LD375			; brif not dead
+		leax 8,u			; point to inventory head pointer
+LD32E		ldx ,x				; get next inventory item
+		beq LD33A			; brif end of inventory
+		clr 5,x				; mark item as on the floor
+		ldd 15,u			; get location of creature
+		std 2,x				; put the object there
+		bra LD32E			; go process next inventory item
 LD33A		ldx creaturecountptr		; point to creature count table for this level
 		ldb 13,u			; get type of creature killed
 		dec b,x				; reduce number of this creature type
-		clr 12,u			
-		updatedungeon
+		clr 12,u			; flag creature as dead
+		updatedungeon			; update the dungeon display
 		playsoundimm $15		; play the "kill" sound
 		ldd ,u				; fetch creature power level
 		bsr asrd3			; divide by 8
@@ -3117,54 +3120,100 @@
 		fadeout				; fade out the wizard
 		resetdisplay
 		rts
-LD3D7		pshs a,b,x,u
-		lda #15
-		sta accum0
-		ldd ,u
-		subd 10,u
-		jsr LCA12
-LD3E4		subd ,x
-		bcs LD3EC
-		dec accum0
-		bne LD3E4
-LD3EC		ldb accum0
-		subb #3
-		bpl LD3FB
-		negb
-		lda #$19
-		mul
-		jsr LCA99
-		bra LD3FE
-LD3FB		lda #10
-		mul
-LD3FE		std ,--s
-		getrandom
-		tfr a,b
-		clra
-		addd ,s++
-		subd #$7f
-		puls a,b,x,u,pc
-LD40C		pshs a,b,x,y,u
-		tfr x,y
-		ldx ,y
-		lda 2,y
-		bsr applyscale
-		tfr d,x
-		lda 3,u
-		bsr applyscale
-		addd 10,u
-		std 10,u
-		ldx ,y
-		lda 4,y
-		bsr applyscale
-		tfr d,x
-		lda 5,u
-		bsr applyscale
-		addd 10,u
-		std 10,u
-		ldx ,u
-		cmpx 10,u
-		puls a,b,x,y,u,pc
+; Calculate the probability of a successful hit.
+; Enter with the attacker info pointed to be X and the defender data pointed to by U.
+;
+; It first does the following calculation:
+; MAX(15-(4(DPOW-DDAM)/APOW),0)
+; 4(DPOW-DDAM)/APOW yields a fraction which is < 4 if the defender's remaining health is
+; less than the attacker's power or > 4 if the defender's remaining health is greater
+; than the attacker's power. This ranges from 0% to 375% in steps of 25%.
+; This result is subtracted from 15 so that low numbers mean the attacker relatively weaker
+; and higher numbers mean the attacker is relatively stronger. The final range is from 0
+; (where the defender is much stronger than the attacker) to 15 where the attacker is very
+; much stronger than the defender.
+;
+; These values are converted to a signed 16 bit number. Then an 8 bit unsigned random number
+; is added to the result. Finally, 127 is subtracted. If the final result is < 0, then the
+; attack fails. Otherwise, the attack succeeds.
+;
+; The following chart gives calculation results. V is the result of MAX(...) calculation
+; above. Pb is the base value calculated by the routine. Rl is the low end of the range
+; of the result once the random number is applied and the 127 is subtracted. Rh is the
+; high end of the range. Finally, P% is the chance of a successful hit for that result.
+;
+; V	Pb	Rl	Rh	P%
+; 0	-75	-202	53	21.1
+; 1	-50	-177	78	30.9
+; 2	-25	-152	103	40.6
+; 3	0	-127	128	50.4
+; 4	10	-117	138	54.3
+; 5	20	-107	148	58.2
+; 6	30	-97	158	62.1
+; 7	40	-87	168	66.0
+; 8	50	-77	178	69.9
+; 9	60	-67	188	73.8
+; 10	70	-57	198	77.7
+; 11	80	-47	208	81.6
+; 12	90	-37	218	85.5
+; 13	100	-27	228	89.5
+; 14	110	-17	238	93.4
+; 15	120	-7	248	97.3
+;
+; As you can see, the lower 4 values are on a steeper slope than the remaining values.
+; Otherwise, the scale is perfectly linear. Also, the worst chance of success, no matter
+; how overmached, is 21.1%. The best chance, no matter how much stronger the attacker,
+; is less than 100%.
+attack		pshs a,b,x,u			; save registers
+		lda #15				; maximum value of the V calculation
+		sta accum0			; initialze V accumulator
+		ldd ,u				; get victim power level
+		subd 10,u			; get difference between that and victim damage level (health)
+		jsr LCA12			; multiply difference by 4
+LD3E4		subd ,x				; subtract attackers power
+		bcs LD3EC			; brif we wrapped - we have our quotient
+		dec accum0			; count down quotient
+		bne LD3E4			; brif we haven't counted down to nothing
+LD3EC		ldb accum0			; get result (V as above)
+		subb #3				; one of first three values?
+		bpl LD3FB			; brif not
+		negb				; now 0 became 3, 1 became 2, and 2 became 1
+		lda #$19			;* multiply by factor (25)
+		mul				;*
+		jsr LCA99			; negate result (-75, -50, and -25)
+		bra LD3FE			; calculate attack
+LD3FB		lda #10				;* multiply by factor (10) (all others are linear going up by 10
+		mul				;* for each step
+LD3FE		std ,--s			; save probability base
+		getrandom			; get a random value
+		tfr a,b				; save random value
+		clra				; zero extend
+		addd ,s++			; add to probabilty base
+		subd #$7f			; subtract 127 so that >= 0 is a hit, < 0 is a miss
+		puls a,b,x,u,pc			; restore registers and return
+; This routine calculates the damage done by an attack. Enter with the attacker info at X and the defender
+; info at U.
+damage		pshs a,b,x,y,u			; save registers
+		tfr x,y				; save attacker pointer
+		ldx ,y				; get attacker power
+		lda 2,y				; get magical offsense power
+		bsr applyscale			; scale it
+		tfr d,x				; save result
+		lda 3,u				; get defender magical defense
+		bsr applyscale			; scale it
+		addd 10,u			; add in defenders current damage
+		std 10,u			; save new defender damage
+		ldx ,y				; get attacker power
+		lda 4,y				; get physical offense power
+		bsr applyscale			; scale it
+		tfr d,x				; save it
+		lda 5,u				; get defender's physical defense power
+		bsr applyscale			; scale it
+		addd 10,u			; add to current defender damage level
+		std 10,u			; save new damage level
+		ldx ,u				; get defender's power
+		cmpx 10,u			; compare with new damage level
+		puls a,b,x,y,u,pc		; restore registers and return
 ; Multiply X by the value in A, where the binary point in A is to the left of bit 6. Return only the
 ; integer result in D (rounded down).
 applyscale	pshs a,b,x			; save parameters and registers