Port PureRGB AI

Short tests showed positive results. Revert if it fucks up anything.

PureRGB enhances Gen 1 AI in various ways, fixing notorious glitches and making it not do completely stupid things. I would use shin pokered's, but it may be too difficult for unfamiliar players, and has a bunch of outdated markers I'd have to spruce up.

Relevant changes:
- Burn effect calls have been replaced with Fire Blast's effect, replicating the burn spread use-case of Fire Blast
- Teleport references removed because pureRGB uses a unique version
- Any straggler references to effects not used in pureRGB
- Mist properly referred to as we only have one move that provides stat drop immunity.

Updated the sprite gallery too!!
This commit is contained in:
Llinos Evans 2023-09-07 02:14:38 +01:00
parent 8bd3b8a703
commit 0af5bd126b
11 changed files with 654 additions and 168 deletions

View file

@ -159,6 +159,7 @@ QoL Enhancements
- To accomodate this, Celadon Gym's trainers use their more neutral text from Crystal.
- The protagonist is also referred to in a gender neutral manner. This changes like, 2-3 lines in the whole game.
- All 151 original Pokemon, plus an additional 100, can be obtained without the use of trading or glitches, including Mew!
- PureRGB's AI enhancements are ported over; said hack was made by Vortiene. In general, it isn't as stupid as it was before.
- Bag capacity is increased from 20 to 30 items.
- Pokemon Box capacity is now 280 Pokemon with 14 boxes.
- Exp. All now works like the modern Exp. Share, giving all party members max exp. It also only has one message, though it does still take time to calculate all the exp being thrown around. It'll take around 3 seconds to calculate, sort of like saving.
@ -393,7 +394,7 @@ If you use our implementations of anything at all, it is encouraged to submit Pu
* ZumiIsawhat? - Restorations of beta OST.
* FrenchOrange - Reconstructions of various overworld beta sprites.
* Helix Chamber, RacieBeep, loumilouminosus, Orchid, GBCRetro, & catstorm26 - Prototype Pokémon sprites. Precise credits are available [here](https://cdn.discordapp.com/attachments/1014321591657709569/1015347305483878521/unknown.png).
* Vortiene/Vortyne - Reused a bit of code from their pureRGB hack. Assisted in bug fixes. Used their sprite sheet generator.
* Vortiene/Vortyne - Reused a bit of code from their pureRGB hack, including their Trainer AI. Assisted in bug fixes. Used their sprite sheet generator.
* Pigu-A, RevoSucks, walle303 - Contributors to Pokemon Anniversary Red's repository, where we reused the Green/FemC sprites and the Battle Tent.
* jojobear13 & Mateo - DV/StatExp display, move deleter, & move relearner functionality from Shin Pokered, followed [this guide](https://github.com/jojobear13/shinpokered/blob/master/how%20to%20guides/how%20to%20add%20the%20move%20relearner%26deleter.txt). Tweaks were made to make it compatible with the pokered version we worked off of.
* Rangi - Reused a bit of code from their Red* / Blue* hack to make HMs usable in the overworld, and generally being an amazing individual.

View file

@ -50,7 +50,7 @@ PredefPointers::
add_predef UpdateHPBar
add_predef HPBarLength
add_predef Diploma_TextBoxBorder
add_predef DoubleOrHalveSelectedStats
; add_predef DoubleOrHalveSelectedStats
add_predef ShowPokedexMenu
add_predef EvolutionAfterBattle
add_predef SaveSAVtoSRAM0

View file

@ -6576,7 +6576,7 @@ LoadPlayerBackPic:
; does nothing since no stats are ever selected (barring glitches)
DoubleOrHalveSelectedStats:
callfar DoubleSelectedStats
jpfar HalveSelectedStats
; jpfar HalveSelectedStats
ScrollTrainerPicAfterBattle:
jpfar _ScrollTrainerPicAfterBattle

View file

@ -98,22 +98,28 @@ AIEnemyTrainerChooseMoves:
dec c
jr nz, .filterMinimalEntries
ld hl, wBuffer ; use created temporary array as move set
ret
jr .done
.useOriginalMoveSet
ld hl, wEnemyMonMoves ; use original move set
.done
;;;;;;;;;; PureRGBnote: clear these values at the end of an AI cycle, they only apply when the player has switched or healed in a turn
xor a
ld [wAIMoveSpamAvoider], a
ld [wAITargetMonStatus], a
;;;;;;;;;;
ret
AIMoveChoiceModificationFunctionPointers:
dw AIMoveChoiceModification1
dw AIMoveChoiceModification2
dw AIMoveChoiceModification3
dw AIMoveChoiceModification4 ; unused, does nothing
dw AIMoveChoiceModification4
; discourages moves that cause no damage but only a status ailment if player's mon already has one
; PureRGBnote: CHANGED: AKA the "Dont do stupid things no player would ever do" AI subroutine, many new default AI restrictions added
; discourages moves that cause no damage but only a status ailment if player's mon already has one, or if they're immune to it
; discourages moves that after being used once won't do anything when used again (mist, leech seed, etc.)
; discourages moves that will fail due to the current enemy pokemon's state (recover at full health, one hit ko moves on faster pkmn)
AIMoveChoiceModification1:
ld a, [wBattleMonStatus]
and a
ret z ; return if no status ailment on player's mon
ld hl, wBuffer - 1 ; temp move selection array (-1 byte offset)
ld de, wEnemyMonMoves ; enemy moves
ld b, NUM_MOVES + 1
@ -126,10 +132,34 @@ AIMoveChoiceModification1:
ret z ; no more moves in move set
inc de
call ReadMove
ld a, [wEnemyMoveEffect]
cp DREAM_EATER_EFFECT
jp z, .checkAsleep
cp OHKO_EFFECT
jr z, .ohko
ld a, [wEnemyMovePower]
and a
jr nz, .nextMove
ld a, [wEnemyMoveEffect]
cp DISABLE_EFFECT
jr z, .checkDisabled
cp LEECH_SEED_EFFECT
jp z, .checkSeeded
cp FOCUS_ENERGY_EFFECT
jr z, .checkPumpedUp
cp LIGHT_SCREEN_EFFECT
jp z, .checkLightScreenUp
cp REFLECT_EFFECT
jp z, .checkReflectUp
cp MIST_EFFECT
jp z, .checkMistUp
cp CONFUSION_EFFECT
jp z, .checkConfused
cp HEAL_EFFECT
jp z, .checkFullHealth
cp MIRROR_MOVE_EFFECT
jp z, .checkNoMirrorMoveOnFirstTurn
ld a, [wEnemyMoveEffect]
push hl
push de
push bc
@ -140,25 +170,202 @@ AIMoveChoiceModification1:
pop de
pop hl
jr nc, .nextMove
.checkStatusImmunity
call CheckStatusImmunity
jr c, .discourage
.notImmune
ld a, [wAITargetMonStatus] ; set to the pokemon's current status before it gets healed or before it switches out
and a
jr nz, .discourage ; if the AI thinks the player has a status, they should avoid using status moves
; even if the player heals the status or switches out that turn
ld a, [wAIMoveSpamAvoider] ; set if we switched or healed this turn
cp 2 ; set to 2 if we switched
jr z, .nextMove ; if the AI thinks the player DOESNT have a status before they switch, we should avoid discouraging status moves
ld a, [wBattleMonStatus]
and a
jr z, .nextMove ; no need to discourage status moves if the player doesn't have a status
.discourage
ld a, [hl]
add $5 ; heavily discourage move
ld [hl], a
jr .nextMove
.ohko
call WillOHKOMoveAlwaysFail
jp nc, .nextMove
jr .discourage
.checkDisabled
ld a, [wPlayerDisabledMove] ; non-zero if the player has a disabled move
and a
jp z, .nextMove ; if it's zero don't do anything
jr .discourage ; otherwise discourage using disable while opponent is disabled already
.checkPumpedUp
ld a, [wEnemyBattleStatus2]
bit GETTING_PUMPED, a
jr nz, .discourage ; if the enemy has used focus energy don't use again
jp .nextMove
.checkAsleep
ld a, [wAITargetMonStatus]
and SLP_MASK
jp nz, .nextMove ; if we just healed sleep or switched out a sleeping pokemon,
; the AI shouldn't predict this perfectly when deciding whether to use dream eater
ld a, [wBattleMonStatus]
and SLP_MASK
jr z, .discourage ; heavily discourage, if the player isn't asleep avoid using dream eater
jp .nextMove
.checkLightScreenUp
ld a, [wEnemyBattleStatus3]
bit HAS_LIGHT_SCREEN_UP, a
jr nz, .discourage ; if the enemy has a light screen up dont use the move again
jp .nextMove
.checkReflectUp
ld a, [wEnemyBattleStatus3]
bit HAS_REFLECT_UP, a
jr nz, .discourage ; if the enemy has a reflect up dont use the move again
jp .nextMove
.checkMistUp
ld a, [wEnemyBattleStatus2]
bit PROTECTED_BY_MIST, a
jr nz, .discourage ; if the enemy has used mist, don't use it again
jp .nextMove
.checkConfused
ld a, [wPlayerBattleStatus1]
bit CONFUSED, a
jr nz, .discourage ; if the player is confused, don't use confusion-inflicting moves
jp .nextMove
.checkSeeded
call CheckSeeded
jp nc, .nextMove
jr .discourage
.checkFullHealth ; avoid using moves like recover at full health.
push hl
push de
ld hl, wEnemyMonMaxHP
ld de, wEnemyMonHP
ld a, [de]
cp [hl]
jr nz, .notFullHealth
inc hl
inc de
ld a, [de]
cp [hl]
jr nz, .notFullHealth
pop de
pop hl
jp .discourage
.notFullHealth
pop de
pop hl
jp .nextMove
.checkNoMirrorMoveOnFirstTurn
ld a, [wPlayerLastSelectedMove]
and a
jp z, .discourage ; don't use mirror move if the player has never selected a move yet
jp .nextMove
StatusAilmentMoveEffects:
db EFFECT_01 ; unused sleep effect
db SLEEP_EFFECT
db POISON_EFFECT
db PARALYZE_EFFECT
db BURN_SIDE_EFFECT2 ; Fire Blast is often used as a burn spreading tool in comp RBY!
db -1 ; end
; slightly encourage moves with specific effects.
; in particular, stat-modifying moves and other move effects
; that fall in-between
;;;;;;;;;; PureRGBnote: ADDED: function for checking if the player can have leech seed applied and whether they already have it applied
CheckSeeded:
push hl
ld a, [wPlayerBattleStatus2]
bit SEEDED, a
jr nz, .discourage ; if the enemy has used leech seed don't use again
ld a, [wAIMoveSpamAvoider]
cp 2 ; set to 2 if we switched out this turn
ld hl, wBattleMonType1
jr nz, .noSwitchOut
ld hl, wAITargetMonType1 ; stores what the AI thinks the player's type is when a switchout happens
.noSwitchOut
ld a, [hl]
cp GRASS
jr z, .discourage ; leech seed does not affect grass types
inc hl
ld a, [hl]
cp GRASS
jr z, .discourage ; leech seed does not affect grass types
pop hl
and a
ret
.discourage
pop hl
scf
ret
;;;;;;;;;;
;;;;;;;;;; PureRGBnote: ADDED: function for checking if the player's pokemon is unaffected by specific status moves.
CheckStatusImmunity:
push bc
push hl
ld a, [wEnemyMoveEffect]
cp POISON_EFFECT
ld b, POISON
jr z, .getMonTypes
cp PARALYZE_EFFECT
jr z, .checkParalyze
cp BURN_SIDE_EFFECT2
ld b, FIRE
jr z, .getMonTypes
jr .done
.checkParalyze
ld a, [wEnemyMoveType]
cp ELECTRIC
ld b, GROUND
jr nz, .done
.getMonTypes
ld a, [wAIMoveSpamAvoider] ; set if we healed status or switched out this turn
cp 2 ; it's 2 if we switched out
jr nz, .noSwitchOut
ld hl, wAITargetMonType1
jr .checkTypes
.noSwitchOut
ld hl, wBattleMonType1
.checkTypes
ld a, [hl]
cp b
jr z, .discourage
inc hl
ld a, [hl]
cp b
jr z, .discourage
.done
pop hl
pop bc
and a
ret
.discourage
pop hl
pop bc
scf
ret
;;;;;;;;;;
;;;;;;;;;; PureRGBnote: ADDED: function that allows AI to avoid OHKO moves if they will never do anything to the player's pokemon due to speed differences
WillOHKOMoveAlwaysFail:
call CompareSpeed
jr c, .userIsSlower
and a
ret
.userIsSlower
scf
ret
;;;;;;;;;;
; PureRGBnote: CHANGED: AKA the "Boost stats on the first turn" subroutine
; slightly encourage moves with specific effects on the first turn. (PureRGBnote: FIXED: used to be the second turn, made it first turn)
; this mostly means trainers will buff their pokemon a bit on the first turn
AIMoveChoiceModification2:
ld a, [wAILayer2Encouragement]
cp $1
ret nz
and a
ret nz ; choose this modifier only on the first turn
ld hl, wBuffer - 1 ; temp move selection array (-1 byte offset)
ld de, wEnemyMonMoves ; enemy moves
ld b, NUM_MOVES + 1
@ -172,35 +379,80 @@ AIMoveChoiceModification2:
inc de
call ReadMove
ld a, [wEnemyMoveEffect]
cp ATTACK_UP1_EFFECT
jr c, .nextMove
cp BIDE_EFFECT
jr c, .preferMove
cp ATTACK_UP2_EFFECT
jr c, .nextMove
cp POISON_EFFECT
jr c, .preferMove
jr .nextMove
push hl
push de
push bc
ld hl, Modifier2PreferredMoves
ld de, 1
call IsInArray
pop bc
pop de
pop hl
jr nc, .nextMove
.preferMove
dec [hl] ; slightly encourage this move
jr .nextMove
; encourages moves that are effective against the player's mon (even if non-damaging).
Modifier2PreferredMoves:
db LEECH_SEED_EFFECT
db FOCUS_ENERGY_EFFECT
db REFLECT_EFFECT
db LIGHT_SCREEN_EFFECT
db ATTACK_UP1_EFFECT
db DEFENSE_UP1_EFFECT
db SPEED_UP1_EFFECT
db SPECIAL_UP1_EFFECT
db ACCURACY_UP1_EFFECT
db EVASION_UP1_EFFECT
db ATTACK_DOWN1_EFFECT
db DEFENSE_DOWN1_EFFECT
db SPEED_DOWN1_EFFECT
db SPECIAL_DOWN1_EFFECT
db ACCURACY_DOWN1_EFFECT
db EVASION_DOWN1_EFFECT
db ATTACK_UP2_EFFECT
db DEFENSE_UP2_EFFECT
db SPEED_UP2_EFFECT
db SPECIAL_UP2_EFFECT
db ACCURACY_UP2_EFFECT
db EVASION_UP2_EFFECT
db ATTACK_DOWN2_EFFECT
db DEFENSE_DOWN2_EFFECT
db SPEED_DOWN2_EFFECT
db SPECIAL_DOWN2_EFFECT
db ACCURACY_DOWN2_EFFECT
db EVASION_DOWN2_EFFECT
db SUBSTITUTE_EFFECT
db -1 ; end
; PureRGBnote: CHANGED: AKA the "Use Effective damaging moves offensively" subroutine
; encourages moves that are effective against the player's mon if they do damage.
; discourage damaging moves that are ineffective or not very effective against the player's mon,
; unless there's no damaging move that deals at least neutral damage
; encourage effective or super effective priority moves if the pokemon is slower than the player's pokemon (but only after obtaining 5 badges)
; encourage effective or super effective draining moves to be used at low health
; PureRGBnote: FIXED: this subroutine won't cause the AI to prefer status moves
; just because their type is super effective against the opponent. Like spamming agility on a poison pokemon.
AIMoveChoiceModification3:
ld hl, wBuffer - 1 ; temp move selection array (-1 byte offset)
ld de, wEnemyMonMoves ; enemy moves
ld b, NUM_MOVES + 1
.nextMove
dec b
ret z ; processed all 4 moves
jp z, .clearPreviousTypes ; processed all 4 moves
inc hl
ld a, [de]
and a
ret z ; no more moves in move set
jp z, .clearPreviousTypes ; no more moves in move set
inc de
call ReadMove
ld a, [wEnemyMovePower]
and a
jr z, .nextMove ; ignores moves that do no damage (status moves), as we're only concerned with damaging moves for this modifier
ld a, [wAIMoveSpamAvoider] ; if we switched this turn or healed status, this is set
cp 2 ; it's 2 if we switched pokemon this turn
call nz, StoreBattleMonTypes ; in the case where we didnt switch
; we need to populate wAITargetMonType1 and wAITargetMonType2 with the current pokemon's type data
push hl
push bc
push de
@ -209,10 +461,16 @@ AIMoveChoiceModification3:
pop bc
pop hl
ld a, [wTypeEffectiveness]
cp $10
jr z, .nextMove
cp EFFECTIVE
jr z, .checkSpecificEffects
jr c, .notEffectiveMove
dec [hl] ; slightly encourage this move
;ld a, [wEnemyMoveEffect]
; check for reasons not to use a super effective move here
dec [hl] ; slightly encourage this super effective move
.checkSpecificEffects ; we'll further encourage certain moves
call EncouragePriorityIfSlow
call EncourageDrainingMoveIfLowHealth
jr .nextMove
.notEffectiveMove ; discourages non-effective moves if better moves are available
push hl
@ -252,12 +510,138 @@ AIMoveChoiceModification3:
pop de
pop hl
and a
jr z, .nextMove
jp z, .nextMove
inc [hl] ; slightly discourage this move
jr .nextMove
AIMoveChoiceModification4:
jp .nextMove
.clearPreviousTypes
xor a
ld [wAITargetMonType1], a
ld [wAITargetMonType2], a
ret
;;;;;;;;;; PureRGBnote: ADDED: function that allows AI to be aware if they are slower than the opponent. Allows them to prefer priority moves.
CompareSpeed:
push hl
push de
push bc
ld hl, wEnemyMonSpeed + 1
ld de, wBattleMonSpeed + 1
.compareSpeed
; check if current speed is higher than the target's
ld a, [de]
dec de
ld b, a
ld a, [hld]
sub b
ld a, [de]
ld b, a
ld a, [hl]
sbc b
pop bc
pop de
pop hl
ret
;;;;;;;;;;
; PureRGBnote: ADDED: encourages priority moves if the enemy's pokemon is slower than the player's and the move is neutral or super effective.
; BUT this effect is only applied after you have the soulbadge to prevent priority moves from being spammed early game.
; Applies to trainers that use AI subroutine 3
EncouragePriorityIfSlow:
ld a, [wObtainedBadges]
bit BIT_SOULBADGE, a
ret z
call CompareSpeed
ret nc
dec [hl] ; encourage the move if it's a priority move and the pokemon is slower
ret
; PureRGBnote: ADDED: if the opponent has less than 1/2 health they will prefer healing moves if they use AI subroutine 3
EncourageDrainingMoveIfLowHealth:
ld a, [wEnemyMoveEffect]
cp DRAIN_HP_EFFECT
ret nz
ld a, 2 ; 1/2 maximum hp gone
call AICheckIfHPBelowFractionWrapped
ret nc
dec [hl] ; encourage the draining move if enemy has more than half health gone
ret
; PureRGBnote: ADDED: AKA the "Apply Status and Heal when needed" subroutine
; slightly encourage moves with specific effects.
; This one will make the opponent want to use status applying moves when you don't have one.
; It also makes them want to use dream eater if you're asleep, and want to use a recovery move at low health.
AIMoveChoiceModification4:
ld hl, wBuffer - 1 ; temp move selection array (-1 byte offset)
ld de, wEnemyMonMoves ; enemy moves
ld b, NUM_MOVES + 1
.nextMove
dec b
jr z, .done ; processed all 4 moves
inc hl
ld a, [de]
and a
jr z, .done ; no more moves in move set
inc de
call ReadMove
ld a, [wEnemyMoveEffect]
cp DREAM_EATER_EFFECT
jr z, .checkOpponentAsleep
ld a, [wEnemyMovePower]
and a
jr nz, .nextMove
ld a, [wEnemyMoveEffect]
cp HEAL_EFFECT
jr z, .checkWorthHealing
push hl
push de
push bc
ld hl, Modifier4PreferredMoves
ld de, 1
call IsInArray
pop bc
pop de
pop hl
jr nc, .nextMove
ld a, [wAITargetMonStatus] ; set to nonzero if player healed battle mon's status or switched one with a status out this turn
and a
jr z, .preferMove
ld a, [hl]
add $5
ld [hl], a ; heavily discourage using a status move right after the player switched or healed
jr .nextMove
.preferMove
dec [hl] ; slightly encourage this move
jr .nextMove
.checkWorthHealing
ld a, 2 ; 1/2 maximum HP
call AICheckIfHPBelowFractionWrapped
jr c, .preferMove ; if HP is below 50% encourage using a healing move
jr .nextMove ; otherwise don't encourage it
.checkOpponentAsleep
ld a, [wAITargetMonStatus] ; set to nonzero if player healed battle mon's status or switched one with a status out this turn
and SLP_MASK
jr nz, .preferMoveEvenMore
ld a, [wAIMoveSpamAvoider] ; set if we switched or healed this turn
cp 2 ; set to 2 if we switched
jr z, .nextMove ; if the AI thinks the player IS NOT asleep before they switch, we shouldn't encourage based on the new mon's status
ld a, [wBattleMonStatus]
and SLP_MASK
jr nz, .preferMoveEvenMore ; heavier favor for dream eater if the opponent is asleep
jr .nextMove
.preferMoveEvenMore
dec [hl]
jr .preferMove
.done
ret
Modifier4PreferredMoves:
db SLEEP_EFFECT
db POISON_EFFECT
db PARALYZE_EFFECT
db BURN_SIDE_EFFECT2
db CONFUSION_EFFECT
db -1 ; end
ReadMove:
push hl
push de
@ -267,7 +651,7 @@ ReadMove:
ld bc, MOVE_LENGTH
call AddNTimes
ld de, wEnemyMoveNum
call CopyData
rst _CopyData
pop bc
pop de
pop hl
@ -298,6 +682,17 @@ TrainerAI:
ld a, [wLinkState]
cp LINK_STATE_BATTLING
ret z ; if in a link battle, we're done as well
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;shinpokerednote: FIXED: AI should not use actions (items / switching) if in a move that prevents such a thing
and a ; clear carry flag in case we return due to the next two checks, we dont want carry returned in those cases as it marks an action as being taken by the opponent.
ld a, [wEnemyBattleStatus2]
bit NEEDS_TO_RECHARGE, a
ret nz
ld a, [wEnemyBattleStatus1]
and %01110010
ret nz
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ld a, [wTrainerClass] ; what trainer class is this?
dec a
ld c, a
@ -323,7 +718,8 @@ TrainerAI:
jp hl
INCLUDE "data/trainers/ai_pointers.asm"
; when there's a +1 on the gym/e4 it's referring to the number of items to use - PvK
; PureRGBnote: CHANGED: some of these trainer-specific AI were tweaked to happen more or less often or had their item modified from vanilla.
JugglerAI:
cp 25 percent + 1
@ -336,19 +732,23 @@ BlackbeltAI:
jp AIUseXAttack
GiovanniAI:
cp 25 percent + 1
cp 20 percent + 1
ret nc
jp AIUseXAttack ; Used to use a Guard Spec. This will make the item use have a proper impact - healing doesn't feel right for a trainer fixated on strength.
ld a, [wEnemyBattleStatus2]
bit GETTING_PUMPED, a
ret nz
jp AIUseDireHit
CooltrainerMAI:
cp 25 percent + 1
cp 20 percent + 1
ret nc
jp AIUseXAttack
jp AIUseXSpecial
CooltrainerFAI:
; The intended 25% chance to consider switching applies, this fixes a bug.
; The intended 25% chance to consider switching will not apply.
; Uncomment the line below to fix this.
cp 25 percent + 1
ret nc ; fixes the bug
ret nc
ld a, 10
call AICheckIfHPBelowFraction
jp c, AIUseHyperPotion
@ -365,52 +765,41 @@ BrockAI:
jp AIUseFullHeal
MistyAI:
; cp 25 percent + 1
; ret nc
; jp AIUseXDefend old Misty AI
cp 25 percent + 1
cp 20 percent + 1
ret nc
ld a, 10
call AICheckIfHPBelowFraction
ret nc
jp AIUsePotion ; Replicates Starmie using Recover, but in a more balanced manner. Unlike other trainers that heal, Misty will do this 26% of the time instead of 51%.
jp AIUseXDefend
LtSurgeAI:
cp 25 percent + 1
cp 10 percent + 1
ret nc
jp AIUseXSpecial ; Used to be an X Speed. His party is already fast, so this seems far more appropriate.
jp AIUseXSpeed
ErikaAI:
cp 50 percent + 1
ret nc
ld a, 10
ld a, 5
call AICheckIfHPBelowFraction
ret nc
jp AIUseSuperPotion
KogaAI:
; cp 25 percent + 1
; ret nc
; jp AIUseXAttack old AI
cp 50 percent + 1
cp 10 percent + 1
ret nc
ld a, 10
call AICheckIfHPBelowFraction
ret nc
jp AIUseSuperPotion ; Koga is weird - I don't think anything fits. X Attack is certainly not the move though...
jp AIUseXAttack
BlaineAI:
cp 25 percent + 1
ret nc
ld a, 10
call AICheckIfHPBelowFraction
ret nc ; this fixes the super potion thing - PvK
jp AIUseHyperPotion ; Instead of a Super Potion though, let's give him this. More impactful for the sixth gym while staying true to the meme that everyone knows Gen 1 Blaine for.
BlaineAI: ;blaine needs to check HP. this was an oversight
cp 40 percent + 1
jr nc, .blainereturn
ld a, 2
call AICheckIfHPBelowFraction
jp c, AIUseSuperPotion
.blainereturn
ret
SabrinaAI:
cp 25 percent + 1
ret nc
ld a, 10
ld a, 5
call AICheckIfHPBelowFraction
ret nc
jp AIUseHyperPotion
@ -421,59 +810,47 @@ Rival2AI:
ld a, 5
call AICheckIfHPBelowFraction
ret nc
jp AIUsePotion
jp AIUseHyperPotion
Rival3AI:
cp 13 percent - 1
cp 40 percent - 1
ret nc
ld a, 5
call AICheckIfHPBelowFraction
ret nc
jp AIUseFullRestore
; Elite Four members will use an associated X Item or a Full Restore.
LoreleiAI:
cp 15 percent + 1
ret nc
jp AIUseXSpecial
cp 50 percent + 1
ret nc
ld a, 5
call AICheckIfHPBelowFraction
ret nc
jp AIUseFullRestore
jp AIUseHyperPotion
BrunoAI:
;cp 25 percent + 1
;cp 10 percent + 1
;ret nc
; jp AIUseXDefend old ai...???
cp 15 percent + 1
ret nc
jp AIUseXAttack
cp 50 percent + 1
ret nc
;jp AIUseXDefend
cp 30 percent + 1
jr nc, .brunoreturn
ld a, 5
call AICheckIfHPBelowFraction
ret nc
jp AIUseFullRestore
jp c, AIUseHyperPotion
.brunoreturn
ret
AgathaAI:
cp 8 percent
jp c, AISwitchIfEnoughMons
cp 15 percent + 1
ret nc
jp AIUseXAccuracy ; hahahahahahahaha
cp 50 percent + 1
ret nc
ld a, 4
call AICheckIfHPBelowFraction
ret nc
jp AIUseFullRestore
jp AIUseHyperPotion
LanceAI:
cp 15 percent + 1
ret nc
jp AIUseXSpecial
cp 50 percent + 1
ret nc
ld a, 5
@ -618,7 +995,29 @@ AISwitchIfEnoughMons:
and a
ret
SwitchEnemyMonNoText:
call SwitchEnemyMonCommon
jp SwitchEnemyMonCommon2
SwitchEnemyMon:
call SwitchEnemyMonCommon
ld hl, AIBattleWithdrawText
rst _PrintText
jp SwitchEnemyMonCommon2
SwitchEnemyMonCommon:
;;;;; shinpokerednote: CHANGED: if player using trapping move, then end their move
ld a, [wPlayerBattleStatus1]
bit USING_TRAPPING_MOVE, a
jr z, .preparewithdraw
ld hl, wPlayerBattleStatus1
res USING_TRAPPING_MOVE, [hl]
xor a
ld [wPlayerNumAttacksLeft], a
ld a, $FF
ld [wPlayerSelectedMove], a
.preparewithdraw
;;;;;
; prepare to withdraw the active monster: copy hp, number, and status to roster
@ -630,10 +1029,14 @@ SwitchEnemyMon:
ld e, l
ld hl, wEnemyMonHP
ld bc, 4
call CopyData
rst _CopyData
ret
ld hl, AIBattleWithdrawText
call PrintText
SwitchEnemyMonCommon2:
;;;;;;;;;; PureRGBnote: ADDED: clear the previous selected move here to reset disable functionality on opponent switching pokemon.
xor a
ld [wEnemyLastSelectedMoveDisable], a
;;;;;;;;;;
; This wFirstMonsNotOutYet variable is abused to prevent the player from
; switching in a new mon in response to this switch.
@ -646,6 +1049,10 @@ SwitchEnemyMon:
ld a, [wLinkState]
cp LINK_STATE_BATTLING
ret z
;shinpokerednote: FIXED: the act of switching clears hWhoseTurn, so it needs to be set back to 1
ld a, 1
ldh [hWhoseTurn], a
scf
ret
@ -659,7 +1066,7 @@ AIUseFullHeal:
ld a, FULL_HEAL
jp AIPrintItemUse
AICureStatus:
AICureStatus: ;shinpokerednote: CHANGED: modified to be more robust and also undo stat changes of brn/par
; cures the status of enemy's active pokemon
ld a, [wEnemyMonPartyPos]
ld hl, wEnemyMon1Status
@ -667,32 +1074,64 @@ AICureStatus:
call AddNTimes
xor a
ld [hl], a ; clear status in enemy team roster
ld [wEnemyMonStatus], a ; clear status of active enemy
ldh a, [hWhoseTurn]
push af
ld a, $01 ;forcibly set it to the AI's turn
ldh [hWhoseTurn], a
farcall UndoBurnParStats ;undo brn/par stat changes
pop af
ldh [hWhoseTurn], a
xor a
ld [wEnemyMonStatus], a ; clear status in active enemy data
ld hl, wEnemyBattleStatus3
res 0, [hl]
res BADLY_POISONED, [hl] ;clear toxic bit
ret
AIUseXAccuracy: ; unused
call AIPlayRestoringSFX
ld hl, wEnemyBattleStatus2
set 0, [hl]
ld a, X_ACCURACY
jp AIPrintItemUse
;AIUseXAccuracy: ; unused
; call AIPlayRestoringSFX
; ld hl, wEnemyBattleStatus2
; set 0, [hl]
; ld a, X_ACCURACY
; jp AIPrintItemUse
AIUseGuardSpec:
call AIPlayRestoringSFX
ld hl, wEnemyBattleStatus2
set 1, [hl]
ld a, GUARD_SPEC
jp AIPrintItemUse
;AIUseGuardSpec: ; PureRGBnote: CHANGED: now unused
; call AIPlayRestoringSFX
; ld hl, wEnemyBattleStatus2
; set 1, [hl]
; ld a, GUARD_SPEC
; jp AIPrintItemUse
AIUseDireHit: ; unused
AIUseDireHit:
call AIPlayRestoringSFX
ld hl, wEnemyBattleStatus2
set 2, [hl]
ld a, DIRE_HIT
jp AIPrintItemUse
; PureRGBnote: ADDED: if enemy HP is below a 1/[wUnusedC000], store 1 in wUnusedC000.
; used for checking whether the hyper ball item should guarantee success on use
AICheckIfHPBelowFractionStore::
ld a, [wUnusedC000]
call AICheckIfHPBelowFraction
jr c, .below
xor a
jr .done
.below
ld a, 1
.done
ld [wUnusedC000], a
ret
AICheckIfHPBelowFractionWrapped:
push hl
push bc
push de
call AICheckIfHPBelowFraction
pop de
pop bc
pop hl
ret
AICheckIfHPBelowFraction:
; return carry if enemy trainer's current HP is below 1 / a of the maximum
ldh [hDivisor], a
@ -737,8 +1176,7 @@ AIUseXSpeed:
AIUseXSpecial:
ld b, $D
ld a, X_SPECIAL
jr AIIncreaseStat ; this wasn't here before but it seems that this never actually happened??
;; fallthrough
; fallthrough
AIIncreaseStat:
ld [wAIItem], a
@ -751,7 +1189,7 @@ AIIncreaseStat:
ld a, [hl]
push af
push hl
ld a, XSTATITEM_DUPLICATE_ANIM
ld a, XSTATITEM_ANIM
ld [hli], a
ld [hl], b
callfar StatModifierUpEffect
@ -773,8 +1211,22 @@ AIPrintItemUse_:
ld [wd11e], a
call GetItemName
ld hl, AIBattleUseItemText
jp PrintText
jp _PrintText
AIBattleUseItemText:
text_far _AIBattleUseItemText
text_end
;;;;;;;;;; PureRGBnote: ADDED: these wram properties are used to make sure the
;;;;;;;;;; AI doesn't instantly read the player's current pokemon type after a player switches.
;;;;;;;;;; makes sure the AI doesn't appear to predict all your switch-outs of pokemon.
StoreBattleMonTypes:
push hl
ld hl, wBattleMonType
ld a, [hl] ; b = type 1 of player's pokemon
ld [wAITargetMonType1], a
inc hl
ld a, [hl] ; c = type 2 of player's pokemon
ld [wAITargetMonType2], a
pop hl
ret

View file

@ -1,4 +1,37 @@
; does nothing since no stats are ever selected (barring glitches)
; Used by the pureRGB AI
;shinpokerednote: ADDED: doubles attack if burned or quadruples speed if paralyzed.
;It's meant to be run right before healing paralysis or burn so as to
;undo the stat changes.
UndoBurnParStats:
ld hl, wBattleMonStatus
ld de, wPlayerStatsToDouble
ldh a, [hWhoseTurn]
and a
jr z, .checkburn
ld hl, wEnemyMonStatus
ld de, wEnemyStatsToDouble
.checkburn
ld a, [hl] ;load statuses
and 1 << BRN ;test for burn
jr z, .checkpar
ld a, $01
ld [de], a ;set attack to be doubled to undo the stat change of BRN
call DoubleSelectedStats
jr .return
.checkpar
ld a, [hl] ;load statuses
and 1 << PAR ;test for paralyze
jr z, .return
ld a, $04
ld [de], a ;set speed to be doubled (done twice) to undo the stat change of BRN
call DoubleSelectedStats
call DoubleSelectedStats
.return
xor a
ld [de], a ;reset the stat change bits
ret
; Reused for pureRGB AI
DoubleSelectedStats:
ldh a, [hWhoseTurn]
and a
@ -18,7 +51,6 @@ DoubleSelectedStats:
dec c
ret z
jr .loop
.doubleStat
ld a, [hl]
add a
@ -29,34 +61,34 @@ DoubleSelectedStats:
ret
; does nothing since no stats are ever selected (barring glitches)
HalveSelectedStats:
ldh a, [hWhoseTurn]
and a
ld a, [wPlayerStatsToHalve]
ld hl, wBattleMonAttack
jr z, .notEnemyTurn
ld a, [wEnemyStatsToHalve]
ld hl, wEnemyMonAttack
.notEnemyTurn
ld c, 4
ld b, a
.loop
srl b
call c, .halveStat
inc hl
inc hl
dec c
ret z
jr .loop
;HalveSelectedStats:
; ldh a, [hWhoseTurn]
; and a
; ld a, [wPlayerStatsToHalve]
; ld hl, wBattleMonAttack
; jr z, .notEnemyTurn
; ld a, [wEnemyStatsToHalve]
; ld hl, wEnemyMonAttack
;.notEnemyTurn
; ld c, 4
; ld b, a
;.loop
; srl b
; call c, .halveStat
; inc hl
; inc hl
; dec c
; ret z
; jr .loop
.halveStat
ld a, [hl]
srl a
ld [hli], a
rr [hl]
or [hl]
jr nz, .nonzeroStat
ld [hl], 1
.nonzeroStat
dec hl
ret
;.halveStat
; ld a, [hl]
; srl a
; ld [hli], a
; rr [hl]
; or [hl]
; jr nz, .nonzeroStat
; ld [hl], 1
;.nonzeroStat
;dec hl
; ret

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

After

Width:  |  Height:  |  Size: 133 KiB

View file

@ -21,14 +21,22 @@ SECTION "rst18", ROM0[$0018]
ds $20 - @, 0 ; unused
SECTION "rst20", ROM0[$0020]
rst $38
_CopyData::
jp CopyData
ds $28 - @, 0 ; unused
; PureRGBnote: MOVED: 5 extra bytes of space left here, may as well move something here that puts the space to some use
PokemonFaintedText::
text_far _PokemonFaintedText
text_end
SECTION "rst28", ROM0[$0028]
rst $38
_PrintText::
jp PrintText
ds $30 - @, 0 ; unused
; PureRGBnote: MOVED: 5 extra bytes of space left here, may as well move something here that puts the space to some use
PlayerBlackedOutText::
text_far _PlayerBlackedOutText
text_end
SECTION "rst30", ROM0[$0030]
rst $38

View file

@ -189,10 +189,6 @@ DisplayPokemonFaintedText::
call PrintText
jp AfterDisplayingTextID
PokemonFaintedText::
text_far _PokemonFaintedText
text_end
DisplayPlayerBlackedOutText::
ld hl, PlayerBlackedOutText
call PrintText
@ -201,10 +197,6 @@ DisplayPlayerBlackedOutText::
ld [wd732], a
jp HoldTextDisplayOpen
PlayerBlackedOutText::
text_far _PlayerBlackedOutText
text_end
DisplayRepelWoreOffText::
ld hl, RepelWoreOffText
call PrintText

View file

@ -68,6 +68,7 @@ ROMX $8
; "Bill's PC"
; "Audio Engine 2"
; "Music 2"
"Battle Engine 9"
ROMX $9
"Pics 1"
"Battle Engine 3"
@ -109,7 +110,6 @@ ROMX $14
"Trainer Sight"
ROMX $15
"Maps 11"
"Battle Engine 9"
"Maps 12"
ROMX $16
"Maps 13"

View file

@ -11,7 +11,8 @@ wChannel2:: channel_struct wChannel2
wChannel3:: channel_struct wChannel3
wChannel4:: channel_struct wChannel4
ds 1
; for pureRGB AI jank
wUnusedC000:: db
wCurTrackDuty:: db
wCurTrackVolumeEnvelope:: db
@ -1211,11 +1212,11 @@ wBattleMon:: battle_struct wBattleMon
wTrainerClass:: db
ds 1
wTrainerPicPointer:: dw
ds 1
; used by pureRGB AI
wEnemyLastSelectedMoveDisable:: db
wPlayerLastSelectedMove:: db
UNION
wTempMoveNameBuffer:: ds 14
@ -1225,15 +1226,17 @@ NEXTU
wLearnMoveMonName:: ds NAME_LENGTH
ENDU
ds 2
; For the pureRGB AI enhancements
wAIMoveSpamAvoider:: db
wAITargetMonStatus:: db
wAITargetMonType1:: db
wAITargetMonType2:: db
; money received after battle = base money × level of last enemy mon
wTrainerBaseMoney:: dw ; BCD
wMissableObjectCounter:: db
ds 1
; 13 bytes for the letters of the opposing trainer
; the name is terminated with $50 with possible
; unused trailing letters
@ -1347,8 +1350,6 @@ wEnemyToxicCounter:: db
; low nibble: disable turns left
wEnemyDisabledMove:: db
ds 1
UNION
; the amount of damage accumulated by the player while biding
wPlayerBideAccumulatedDamage:: dw