-
Notifications
You must be signed in to change notification settings - Fork 1k
Physical Special Split
In generations I, II, and III, the move types determined whether the damage type was physical or special. After generation IV, any move type could be physical or special. In order to implement this, we make a list of the physical moves that should become special and a list of all the special moves that should be physical. Then during damage calculation, we check if the move used is in one of the lists.
Create the file physical_special_split.asm
in data/battle/
, and add the following to it,
PhysicalToSpecialMoves:
; Flying
db GUST
; Poison
db ACID
db SLUDGE
; Normal
db HYPER_BEAM
db RAZOR_WIND
db SWIFT
db TRI_ATTACK
db -1 ; end
SpecialToPhysicalMoves:
; Fire
db FIRE_PUNCH
; Water
db CLAMP
db CRABHAMMER
db WATERFALL
; Grass
db RAZOR_LEAF
db VINE_WHIP
; Electric
db THUNDERPUNCH
; Ice
db ICE_PUNCH
db -1 ; end
These should be all the moves in generation I that flipped damage type. If you add in a new move, and the damage type is different from the move type, then add it to the appropriate list above.
Now open up
engine/battle/core.asm
We will be modifying the GetDamageVarsForPlayerAttack
subroutine.
...
GetDamageVarsForPlayerAttack:
xor a
ld hl, wDamage ; damage to eventually inflict, initialise to zero
ldi [hl], a
ld [hl], a
ld hl, wPlayerMovePower
ld a, [hli]
and a
ld d, a ; d = move power
ret z ; return if move power is zero
ld a, [hl] ; a = [wPlayerMoveType]
cp SPECIAL ; types >= SPECIAL are all special
- jr nc, .specialAttack
+ ld a, [wPlayerMoveNum]
+ ld b, a
+ jr nc, .isSpecialActuallyPhysical
+ jr .isPhysicalActuallySpecial
+.isSpecialActuallyPhysical
+ ld hl, SpecialToPhysicalMoves
+.specialPhysicalLoop
+ ld a, [hli]
+ cp b
+ jr z, .physicalAttack
+ cp $ff ; end of list
+ jr nz, .specialPhysicalLoop ; keep checking list
+ jr .specialAttack ; Not actually a physical move
+.isPhysicalActuallySpecial
+ ld hl, PhysicalToSpecialMoves
+.physicalSpecialLoop
+ ld a, [hli]
+ cp b
+ jr z, .specialAttack ; the physical move is actually special
+ cp $ff ; end of list
+ jr nz, .physicalSpecialLoop ; keep checking list
+ ; fallthrough
.physicalAttack
ld hl, wEnemyMonDefense
ld a, [hli]
ld b, a
ld c, [hl] ; bc = enemy defense
...
We will now make a similar modification for GetDamageVarsForEnemyAttack
.
...
GetDamageVarsForEnemyAttack:
ld hl, wDamage ; damage to eventually inflict, initialise to zero
xor a
ld [hli], a
ld [hl], a
ld hl, wEnemyMovePower
ld a, [hli]
ld d, a ; d = move power
and a
ret z ; return if move power is zero
ld a, [hl] ; a = [wEnemyMoveType]
cp SPECIAL ; types >= SPECIAL are all special
- jr nc, .specialAttack
+ ld a, [wEnemyMoveNum]
+ ld b, a
+ jr nc, .isSpecialActuallyPhysical
+ jr .isPhysicalActuallySpecial
+.isSpecialActuallyPhysical
+ ld hl, SpecialToPhysicalMoves
+.specialPhysicalLoop
+ ld a, [hli]
+ cp b
+ jr z, .physicalAttack
+ cp $ff ; end of list
+ jr nz, .specialPhysicalLoop ; keep checking list
+ jr .specialAttack ; Not actually a physical move
+.isPhysicalActuallySpecial
+ ld hl, PhysicalToSpecialMoves
+.physicalSpecialLoop
+ ld a, [hli]
+ cp b
+ jr z, .specialAttack ; the physical move is actually special
+ cp $ff ; end of list
+ jr nz, .physicalSpecialLoop ; keep checking list
+ ; fallthrough
.physicalAttack
ld hl, wBattleMonDefense
ld a, [hli]
ld b, a
ld c, [hl] ; bc = player defense
...
And lastly, at the end of this subroutine, add in the INCLUDE
statement for new file.
...
.done
ld a, $1
and a
and a
ret
+INCLUDE "data/battle/physical_special_split.asm"
; get stat c of enemy mon
; c: stat to get (HP=1,Attack=2,Defense=3,Speed=4,Special=5)
GetEnemyMonStat:
...
That's it. I should mention that the changes to
engine/battle/core.asm
are not the best. There should really be a
separate subroutine that GetDamageVarsForPlayerAttack
and
GetDamageVarsForEnemyAttack
both use instead of essentially copy
pasting the same code. I haven't had a chance to get around to it yet,
but I (or anyone else) will/can update the tutorial once its changed.