diff options
author | Bryan Bishop <kanzure@gmail.com> | 2012-01-24 12:11:56 -0600 |
---|---|---|
committer | Bryan Bishop <kanzure@gmail.com> | 2012-01-24 12:11:56 -0600 |
commit | cf0d22fa2eee87ba6349e35ce153dfe511cbc130 (patch) | |
tree | e891090ff8216480900b5a5a2622281f4e3d30f0 | |
parent | 79c24d9c93e1e07b20e35a4d1cd87fa845861d3c (diff) | |
parent | 187642e9051b000e5ad3d6de84697410c7022869 (diff) |
merge YamaArashi/pokered
hg-commit-id: a3767c66df56
-rw-r--r-- | common.asm | 444 | ||||
-rw-r--r-- | constants.asm | 100 |
2 files changed, 527 insertions, 17 deletions
@@ -24942,15 +24942,71 @@ HighCriticalMoves: ; 0x3e08e db $FF ; 0x3e093 -INCBIN "baserom.gbc",$3e093,$3e0df - $3e093 +; function to determine if Counter hits and if so, how much damage it does +HandleCounterMove: ; 6093 + ld a,[H_WHOSETURN] ; whose turn + and a +; player's turn + ld hl,W_ENEMYSELECTEDMOVE + ld de,W_ENEMYMOVEPOWER + ld a,[W_PLAYERSELECTEDMOVE] + jr z,.next\@ +; enemy's turn + ld hl,W_PLAYERSELECTEDMOVE + ld de,W_PLAYERMOVEPOWER + ld a,[W_ENEMYSELECTEDMOVE] +.next\@ + cp a,COUNTER + ret nz ; return if not using Counter + ld a,$01 + ld [W_MOVEMISSED],a ; initialize the move missed variable to true (it is set to false below if the move hits) + ld a,[hl] + cp a,COUNTER + ret z ; if the target also used Counter, miss + ld a,[de] + and a + ret z ; if the move the target used has 0 power, miss +; check if the move the target used was Normal or Fighting type + inc de + ld a,[de] + and a ; normal type + jr z,.counterableType\@ + cp a,FIGHTING + jr z,.counterableType\@ +; if the move wasn't Normal or Fighting type, miss + xor a + ret +.counterableType\@ + ld hl,W_DAMAGE + ld a,[hli] + or [hl] + ret z ; Counter misses if the target did no damage to the Counter user +; double the damage that the target did to the Counter user + ld a,[hl] + add a + ldd [hl],a + ld a,[hl] + adc a + ld [hl],a + jr nc,.noCarry\@ +; damage is capped at 0xFFFF + ld a,$ff + ld [hli],a + ld [hl],a +.noCarry\@ + xor a + ld [W_MOVEMISSED],a + call MoveHitTest ; do the normal move hit test in addition to Counter's special rules + xor a + ret ApplyDamageToEnemyPokemon: ; 60DF ld a,[W_PLAYERMOVEEFFECT] - cp a,$26 ; OHKO + cp a,OHKO_EFFECT jr z,.applyDamage\@ - cp a,$28 ; super fang's effect + cp a,SUPER_FANG_EFFECT jr z,.superFangEffect\@ - cp a,$29 ; special damage (fixed or random damage) + cp a,SPECIAL_DAMAGE_EFFECT jr z,.specialDamage\@ ld a,[W_PLAYERMOVEPOWER] and a @@ -24983,10 +25039,10 @@ ApplyDamageToEnemyPokemon: ; 60DF jr z,.storeDamage\@ cp a,NIGHT_SHADE jr z,.storeDamage\@ - ld b,$14 ; Sonic Boom damage + ld b,SONICBOOM_DAMAGE cp a,SONICBOOM jr z,.storeDamage\@ - ld b,$28 ; Dragon Rage damage + ld b,DRAGON_RAGE_DAMAGE cp a,DRAGON_RAGE jr z,.storeDamage\@ ; Psywave @@ -24995,7 +25051,7 @@ ApplyDamageToEnemyPokemon: ; 60DF srl a add b ld b,a ; b = level * 1.5 -; loop until a random number between 1 and b is found +; loop until a random number in the range [1, b) is found .loop\@ call $6e9b ; random number and a @@ -25018,7 +25074,7 @@ ApplyDamageToEnemyPokemon: ; 60DF jr z,.done\@ ; we're done if damage is 0 ld a,[W_ENEMYBATTSTATUS2] bit 4,a ; does the enemy have a substitute? - jp nz,$625e + jp nz,AttackSubstitute ; subtract the damage from the pokemon's current HP ; also, save the current HP at $CEEB ld a,[hld] @@ -25035,7 +25091,7 @@ ApplyDamageToEnemyPokemon: ; 60DF ld [W_ENEMYMONCURHP],a jr nc,.animateHpBar\@ ; if more damage was done than the current HP, zero the HP and set the damage -; equal to how much HP the pokemon had before fainting +; equal to how much HP the pokemon had before the attack ld a,[$ceec] ld [hli],a ld a,[$ceeb] @@ -25063,15 +25119,179 @@ ApplyDamageToEnemyPokemon: ; 60DF .done\@ jp $4d5a ; redraw pokemon names and HP bars -INCBIN "baserom.gbc",$3e1a0,$3e2ac - $3e1a0 +ApplyDamageToPlayerPokemon: ; 61A0 + ld a,[W_ENEMYMOVEEFFECT] + cp a,OHKO_EFFECT + jr z,.applyDamage\@ + cp a,SUPER_FANG_EFFECT + jr z,.superFangEffect\@ + cp a,SPECIAL_DAMAGE_EFFECT + jr z,.specialDamage\@ + ld a,[W_ENEMYMOVEPOWER] + and a + jp z,.done\@ + jr .applyDamage\@ +.superFangEffect\@ +; set the damage to half the target's HP + ld hl,W_PLAYERMONCURHP + ld de,W_DAMAGE + ld a,[hli] + srl a + ld [de],a + inc de + ld b,a + ld a,[hl] + rr a + ld [de],a + or b + jr nz,.applyDamage\@ +; make sure Super Fang's damage is always at least 1 + ld a,$01 + ld [de],a + jr .applyDamage\@ +.specialDamage\@ + ld hl,W_ENEMYMONLEVEL + ld a,[hl] + ld b,a + ld a,[W_ENEMYMOVENUM] + cp a,SEISMIC_TOSS + jr z,.storeDamage\@ + cp a,NIGHT_SHADE + jr z,.storeDamage\@ + ld b,SONICBOOM_DAMAGE + cp a,SONICBOOM + jr z,.storeDamage\@ + ld b,DRAGON_RAGE_DAMAGE + cp a,DRAGON_RAGE + jr z,.storeDamage\@ +; Psywave + ld a,[hl] + ld b,a + srl a + add b + ld b,a ; b = attacker's level * 1.5 +; loop until a random number in the range [0, b) is found +; this differs from the range when the player attacks, which is [1, b) +; it's possible for the enemy to do 0 damage with Psywave, but the player always does at least 1 damage +.loop\@ + call $6e9b ; random number + cp b + jr nc,.loop\@ + ld b,a +.storeDamage\@ + ld hl,W_DAMAGE + xor a + ld [hli],a + ld a,b + ld [hl],a +.applyDamage\@ + ld hl,W_DAMAGE + ld a,[hli] + ld b,a + ld a,[hl] + or b + jr z,.done\@ ; we're done if damage is 0 + ld a,[W_PLAYERBATTSTATUS2] + bit 4,a ; does the player have a substitute? + jp nz,AttackSubstitute +; subtract the damage from the pokemon's current HP +; also, save the current HP at $CEEB and the new HP at $CEED + ld a,[hld] + ld b,a + ld a,[W_PLAYERMONCURHP + 1] + ld [$ceeb],a + sub b + ld [W_PLAYERMONCURHP + 1],a + ld [$ceed],a + ld b,[hl] + ld a,[W_PLAYERMONCURHP] + ld [$ceec],a + sbc b + ld [W_PLAYERMONCURHP],a + ld [$ceee],a + jr nc,.animateHpBar\@ +; if more damage was done than the current HP, zero the HP and set the damage +; equal to how much HP the pokemon had before the attack + ld a,[$ceec] + ld [hli],a + ld a,[$ceeb] + ld [hl],a + xor a + ld hl,W_PLAYERMONCURHP + ld [hli],a + ld [hl],a + ld hl,$ceed + ld [hli],a + ld [hl],a +.animateHpBar\@ + ld hl,W_PLAYERMONMAXHP + ld a,[hli] + ld [$ceea],a + ld a,[hl] + ld [$cee9],a + ld hl,$c45e + ld a,$01 + ld [$cf94],a + ld a,$48 + call Predef ; animate the HP bar shortening +.done\@ + jp $4d5a ; redraw pokemon names and HP bars -UnnamedText_3e2ac: ; 0x3e2ac - TX_FAR _UnnamedText_3e2ac +AttackSubstitute: ; 625E + ld hl,SubstituteTookDamageText + call PrintText +; values for player turn + ld de,W_ENEMYSUBSITUTEHP + ld bc,W_ENEMYBATTSTATUS2 + ld a,[H_WHOSETURN] + and a + jr z,.applyDamageToSubstitute\@ +; values for enemy turn + ld de,W_PLAYERSUBSITUTEHP + ld bc,W_PLAYERBATTSTATUS2 +.applyDamageToSubstitute\@ + ld hl,W_DAMAGE + ld a,[hli] + and a + jr nz,.substituteBroke\@ ; damage > 0xFF always breaks substitutes +; subtract damage from HP of substitute + ld a,[de] + sub [hl] + ld [de],a + ret nc +.substituteBroke\@ + ld h,b + ld l,c + res 4,[hl] ; unset the substitute bit + ld hl,SubstituteBrokeText + call PrintText +; flip whose turn it is for the next function call + ld a,[H_WHOSETURN] + xor a,$01 + ld [H_WHOSETURN],a + ld hl,$5747 + ld b,$1e ; animate the substitute breaking + call Bankswitch ; substitute +; flip the turn back to the way it was + ld a,[H_WHOSETURN] + xor a,$01 + ld [H_WHOSETURN],a + ld hl,W_PLAYERMOVEEFFECT ; value for player's turn + and a + jr z,.nullifyEffect\@ + ld hl,W_ENEMYMOVEEFFECT ; value for enemy's turn +.nullifyEffect\@ + xor a + ld [hl],a ; zero the effect of the attacker's move + jp $4d5a ; redraw pokemon names and HP bars + +SubstituteTookDamageText: ; 0x3e2ac + TX_FAR _SubstituteTookDamageText db $50 ; 0x3e2ac + 5 bytes -UnnamedText_3e2b1: ; 0x3e2b1 - TX_FAR _UnnamedText_3e2b1 +SubstituteBrokeText: ; 0x3e2b1 + TX_FAR _SubstituteBrokeText db $50 ; 0x3e2b1 + 5 bytes @@ -25181,7 +25401,197 @@ TypeEffects: ; 6474 db DRAGON,DRAGON,20 db $FF -INCBIN "baserom.gbc",$3e56b,$3e887 - $3e56b +; some tests that need to pass for a move to hit +MoveHitTest: ; 656B +; player's turn + ld hl,W_ENEMYBATTSTATUS1 + ld de,W_PLAYERMOVEEFFECT + ld bc,W_ENEMYMONSTATUS + ld a,[H_WHOSETURN] + and a + jr z,.dreamEaterCheck\@ +; enemy's turn + ld hl,W_PLAYERBATTSTATUS1 + ld de,W_ENEMYMOVEEFFECT + ld bc,W_PLAYERMONSTATUS +.dreamEaterCheck\@ + ld a,[de] + cp a,DREAM_EATER_EFFECT + jr nz,.swiftCheck\@ + ld a,[bc] + and a,$07 ; is the target pokemon sleeping? + jp z,.moveMissed\@ +.swiftCheck\@ + ld a,[de] + cp a,SWIFT_EFFECT + ret z ; Swift never misses (interestingly, Azure Heights lists this is a myth, but it appears to be true) + call $7b79 ; substitute check (note that this overwrites a) + jr z,.checkForDigOrFlyStatus\@ +; this code is buggy. it's supposed to prevent HP draining moves from working on substitutes. +; since $7b79 overwrites a with either $00 or $01, it never works. + cp a,DRAIN_HP_EFFECT ; $03 + jp z,.moveMissed\@ + cp a,DREAM_EATER_EFFECT ; $08 + jp z,.moveMissed\@ +.checkForDigOrFlyStatus\@ + bit 6,[hl] + jp nz,.moveMissed\@ + ld a,[H_WHOSETURN] + and a + jr nz,.enemyTurn\@ +.playerTurn\@ +; this checks if the move effect is disallowed by mist + ld a,[W_PLAYERMOVEEFFECT] + cp a,$12 + jr c,.skipEnemyMistCheck\@ + cp a,$1a + jr c,.enemyMistCheck\@ + cp a,$3a + jr c,.skipEnemyMistCheck\@ + cp a,$42 + jr c,.enemyMistCheck\@ + jr .skipEnemyMistCheck\@ +.enemyMistCheck\@ +; if move effect is from $12 to $19 inclusive or $3a to $41 inclusive +; i.e. the following moves +; GROWL, TAIL WHIP, LEER, STRING SHOT, SAND-ATTACK, SMOKESCREEN, KINESIS, +; FLASH, CONVERSION, HAZE*, SCREECH, LIGHT SCREEN*, REFLECT* +; the moves that are marked with an asterisk are not affected since this +; function is not called when those moves are used +; XXX are there are any others like those three? + ld a,[W_ENEMYBATTSTATUS2] + bit 1,a + jp nz,.moveMissed\@ +.skipEnemyMistCheck\@ + ld a,[W_PLAYERBATTSTATUS2] + bit 0,a ; is the player using X Accuracy? + ret nz ; if so, always hit regardless of accuracy/evasion + jr .calcHitChance\@ +.enemyTurn\@ + ld a,[W_ENEMYMOVEEFFECT] + cp a,$12 + jr c,.skipPlayerMistCheck\@ + cp a,$1a + jr c,.playerMistCheck\@ + cp a,$3a + jr c,.skipPlayerMistCheck\@ + cp a,$42 + jr c,.playerMistCheck\@ + jr .skipPlayerMistCheck\@ +.playerMistCheck\@ +; similar to enemy mist check + ld a,[W_PLAYERBATTSTATUS2] + bit 1,a + jp nz,.moveMissed\@ +.skipPlayerMistCheck\@ + ld a,[W_ENEMYBATTSTATUS2] + bit 0,a ; is the enemy using X Accuracy? + ret nz ; if so, always hit regardless of accuracy/evasion +.calcHitChance\@ + call CalcHitChance ; scale the move accuracy according to attacker's accuracy and target's evasion + ld a,[W_PLAYERMOVEACCURACY] + ld b,a + ld a,[H_WHOSETURN] + and a + jr z,.doAccuracyCheck\@ + ld a,[W_ENEMYMOVEACCURACY] + ld b,a +.doAccuracyCheck\@ +; if the random number generated is greater than or equal to the scaled accuracy, the move misses +; note that this means that even the highest accuracy is still just a 255/256 chance, not 100% + call $6e9b ; random number + cp b + jr nc,.moveMissed\@ + ret +.moveMissed\@ + xor a + ld hl,W_DAMAGE ; zero the damage + ld [hli],a + ld [hl],a + inc a + ld [W_MOVEMISSED],a + ld a,[H_WHOSETURN] + and a + jr z,.playerTurn2\@ +.enemyTurn2\@ + ld hl,W_ENEMYBATTSTATUS1 + res 5,[hl] ; end multi-turn attack e.g. wrap + ret +.playerTurn2\@ + ld hl,W_PLAYERBATTSTATUS1 + res 5,[hl] ; end multi-turn attack e.g. wrap + ret + +; values for player turn +CalcHitChance: ; 6624 + ld hl,W_PLAYERMOVEACCURACY + ld a,[H_WHOSETURN] + and a + ld a,[W_PLAYERMONACCURACYMOD] + ld b,a + ld a,[W_ENEMYMONEVASIONMOD] + ld c,a + jr z,.next\@ +; values for enemy turn + ld hl,W_ENEMYMOVEACCURACY + ld a,[W_ENEMYMONACCURACYMOD] + ld b,a + ld a,[W_PLAYERMONEVASIONMOD] + ld c,a +.next\@ + ld a,$0e + sub c + ld c,a ; c = 14 - EVASIONMOD (this "reflects" the value over 7, so that an increase in the target's evasion decreases the hit chance instead of increasing the hit chance) +; zero the high bytes of the multiplicand + xor a + ld [$ff96],a + ld [$ff97],a + ld a,[hl] + ld [$ff98],a ; set multiplicand to move accuracy + push hl + ld d,$02 ; loop has two iterations +; loop to do the calculations, the first iteration multiplies by the accuracy ratio and the second iteration multiplies by the evasion ratio +.loop\@ + push bc + ld hl,$76cb ; stat modifier ratios + dec b + sla b + ld c,b + ld b,$00 + add hl,bc ; hl = address of stat modifier ratio + pop bc + ld a,[hli] + ld [$ff99],a ; set multiplier to the numerator of the ratio + call $38ac ; multiply + ld a,[hl] + ld [$ff99],a ; set divisor to the the denominator of the ratio (the dividend is the product of the previous multiplication) + ld b,$04 ; number of significant bytes in the dividend + call $38b9 ; divide + ld a,[$ff98] + ld b,a + ld a,[$ff97] + or b + jp nz,.nextCalculation\@ +; make sure the result is always at least one + ld [$ff97],a + ld a,$01 + ld [$ff98],a +.nextCalculation\@ + ld b,c + dec d + jr nz,.loop\@ + ld a,[$ff97] + and a ; is the calculated hit chance over 0xFF? + ld a,[$ff98] + jr z,.storeAccuracy\@ +; if calculated hit chance over 0xFF + ld a,$ff ; set the hit chance to 0xFF +.storeAccuracy\@ + pop hl + ld [hl],a ; store the hit chance in the move accuracy variable + ret + +INCBIN "baserom.gbc",$3e687,$3e887 - $3e687 UnnamedText_3e887: ; 0x3e887 TX_FAR _UnnamedText_3e887 @@ -56703,13 +57113,13 @@ _UnnamedText_3ddca: ; 0x89b32 db "ignored orders!", $58 ; 0x89b32 + 21 bytes -_UnnamedText_3e2ac: ; 0x89b47 +_SubstituteTookDamageText: ; 0x89b47 db $0, "The SUBSTITUTE", $4f db "took damage for", $55 db $59, "!", $58 ; 0x89b47 + 35 bytes -_UnnamedText_3e2b1: ; 0x89b6a +_SubstituteBrokeText: ; 0x89b6a db $0, $59, "'s", $4f db "SUBSTITUTE broke!", $58 ; 0x89b6a + 22 bytes diff --git a/constants.asm b/constants.asm index 8cb95bcd..e743c934 100644 --- a/constants.asm +++ b/constants.asm @@ -89,11 +89,36 @@ TX_RAM: MACRO ; wram locations +; current HP of player and enemy substitutes +W_PLAYERSUBSITUTEHP EQU $CCD7 +W_ENEMYSUBSITUTEHP EQU $CCD8 + W_PLAYERSELECTEDMOVE EQU $CCDC W_ENEMYSELECTEDMOVE EQU $CCDD W_AICOUNT EQU $CCDF ; number of times remaining that AI action can occur +; stat modifiers for the player's current pokemon +; value can range from 1 - 13 ($1 to $D) +; 7 is normal + +W_PLAYERMONATTACKMOD EQU $CD1A +W_PLAYERMONDEFENSEMOD EQU $CD1B +W_PLAYERMONSPEEDMOD EQU $CD1C +W_PLAYERMONSPECIALMOD EQU $CD1D +W_PLAYERMONACCURACYMOD EQU $CD1E +W_PLAYERMONEVASIONMOD EQU $CD1F + +; stat modifiers for the enemy's current pokemon +; value can range from 1 - 13 ($1 to $D) +; 7 is normal +W_ENEMYMONATTACKMOD EQU $CD2E +W_ENEMYMONDEFENSEMOD EQU $CD2F +W_ENEMYMONSPEEDMOD EQU $CD30 +W_ENEMYMONSPECIALMOD EQU $CD31 +W_ENEMYMONACCURACYMOD EQU $CD32 +W_ENEMYMONEVASIONMOD EQU $CD33 + W_WHICHTRADE EQU $CD3D ; which entry from TradeMons to select W_WHICHPOKEMON EQU $CF92 ; which pokemon you selected @@ -1172,6 +1197,81 @@ TM_48 EQU $F8 TM_49 EQU $F9 TM_50 EQU $FA +; tentative move effect constants +; {stat}_(UP|DOWN)(1|2) means that the move raises the user's (or lowers the target's) corresponding stat modifier by 1 (or 2) stages +; {status condition}_side_effect means that the move has a side chance of causing that condition +; {status condition}_effect means that the move causes the status condition every time it hits the target +POISON_SIDE_EFFECT1 EQU $02 +DRAIN_HP_EFFECT EQU $03 +BURN_SIDE_EFFECT1 EQU $04 +FREEZE_SIDE_EFFECT EQU $05 +PARALYZE_SIDE_EFFECT1 EQU $06 +EXPLODE_EFFECT EQU $07 ; Explosion, Self Destruct +DREAM_EATER_EFFECT EQU $08 +MIRROR_MOVE_EFFECT EQU $09 +ATTACK_UP1_EFFECT EQU $0A +DEFENSE_UP1_EFFECT EQU $0B +SPECIAL_UP1_EFFECT EQU $0D +EVASION_UP1_EFFECT EQU $0F +PAY_DAY_EFFECT EQU $10 +SWIFT_EFFECT EQU $11 +ATTACK_DOWN1_EFFECT EQU $12 +DEFENSE_DOWN1_EFFECT EQU $13 +SPEED_DOWN1_EFFECT EQU $14 +ACCURACY_DOWN1_EFFECT EQU $16 +CONVERSION_EFFECT EQU $18 +HAZE_EFFECT EQU $19 +BIDE_EFFECT EQU $1A +THRASH_PETAL_DANCE_EFFECT EQU $1B +SWITCH_AND_TELEPORT_EFFECT EQU $1C +TWO_TO_FIVE_ATTACKS_EFFECT EQU $1D +FLINCH_SIDE_EFFECT1 EQU $1F +SLEEP_EFFECT EQU $20 +POISON_SIDE_EFFECT2 EQU $21 +BURN_SIDE_EFFECT2 EQU $22 +PARALYZE_SIDE_EFFECT2 EQU $24 +FLINCH_SIDE_EFFECT2 EQU $25 +OHKO_EFFECT EQU $26 ; moves like Horn Drill +CHARGE_EFFECT EQU $27 ; moves like Solar Beam +SUPER_FANG_EFFECT EQU $28 +SPECIAL_DAMAGE_EFFECT EQU $29 ; Seismic Toss, Night Shade, Sonic Boom, Dragon Rage, Psywave +TRAPPING_EFFECT EQU $2A ; moves like Wrap +FLY_EFFECT EQU $2B +ATTACK_TWICE_EFFECT EQU $2C +JUMP_KICK_EFFECT EQU $2D ; Jump Kick and Hi Jump Kick effect +MIST_EFFECT EQU $2E +FOCUS_ENERGY_EFFECT EQU $2F +RECOIL_EFFECT EQU $30 ; moves like Double Edge +CONFUSION_EFFECT EQU $31 ; Confuse Ray, Supersonic (not the move Confusion) +ATTACK_UP2_EFFECT EQU $32 +DEFENSE_UP2_EFFECT EQU $33 +SPEED_UP2_EFFECT EQU $34 +SPECIAL_UP2_EFFECT EQU $35 +HEAL_EFFECT EQU $38 ; Recover, Softboiled, Rest +TRANSFORM_EFFECT EQU $39 +DEFENSE_DOWN2_EFFECT EQU $3B +LIGHT_SCREEN_EFFECT EQU $40 +REFLECT_EFFECT EQU $41 +POISON_EFFECT EQU $42 +PARALYZE_EFFECT EQU $43 +ATTACK_DOWN_SIDE_EFFECT EQU $44 +DEFENSE_DOWN_SIDE_EFFECT EQU $45 +SPEED_DOWN_SIDE_EFFECT EQU $46 +SPECIAL_DOWN_SIDE_EFFECT EQU $47 +CONFUSION_SIDE_EFFECT EQU $4C +TWINEEDLE_EFFECT EQU $4D +SUBSTITUTE_EFFECT EQU $4F +HYPER_BEAM_EFFECT EQU $50 +RAGE_EFFECT EQU $51 +MIMIC_EFFECT EQU $52 +METRONOME_EFFECT EQU $53 +LEECH_SEED_EFFECT EQU $54 +SPLASH_EFFECT EQU $55 +DISABLE_EFFECT EQU $56 + +; fixed damage constants +SONICBOOM_DAMAGE EQU 20 +DRAGON_RAGE_DAMAGE EQU 40 ; move name constants POUND EQU $01 |