ref: 3eda472a22bc0ca68e56884d7a63020b68b7bcad
parent: 9a3a6c1b53deaae0236aa8ee85d384f2d29032bb
author: YamaArashi <shadow962@live.com>
date: Mon Jan 23 23:49:20 EST 2012
disasm more battle code hg-commit-id: 6f008f9e5c9d
--- a/common.asm
+++ b/common.asm
@@ -24844,7 +24844,63 @@
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]
@@ -25083,7 +25139,197 @@
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 is 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
--- a/constants.asm
+++ b/constants.asm
@@ -94,6 +94,27 @@
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 +1193,77 @@
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
; move name constants
POUND EQU $01