diff --git a/README.md b/README.md index 22889e48..0ae9f37b 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/data/predef_pointers.asm b/data/predef_pointers.asm index eba3a0e4..559d990d 100644 --- a/data/predef_pointers.asm +++ b/data/predef_pointers.asm @@ -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 diff --git a/engine/battle/core.asm b/engine/battle/core.asm index 71c681f1..089410b8 100644 --- a/engine/battle/core.asm +++ b/engine/battle/core.asm @@ -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 diff --git a/engine/battle/trainer_ai.asm b/engine/battle/trainer_ai.asm index a9b9342c..dca83aa9 100644 --- a/engine/battle/trainer_ai.asm +++ b/engine/battle/trainer_ai.asm @@ -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 diff --git a/engine/battle/unused_stats_functions.asm b/engine/battle/unused_stats_functions.asm index 5174adf5..d9f637ac 100644 --- a/engine/battle/unused_stats_functions.asm +++ b/engine/battle/unused_stats_functions.asm @@ -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 diff --git a/gfx/pokemon/gallery/back_sprites.png b/gfx/pokemon/gallery/back_sprites.png index acb55c8c..0596378a 100644 Binary files a/gfx/pokemon/gallery/back_sprites.png and b/gfx/pokemon/gallery/back_sprites.png differ diff --git a/gfx/pokemon/gallery/front_sprites.png b/gfx/pokemon/gallery/front_sprites.png index 8e8a44b0..0fde57ce 100644 Binary files a/gfx/pokemon/gallery/front_sprites.png and b/gfx/pokemon/gallery/front_sprites.png differ diff --git a/home/header.asm b/home/header.asm index c12a0565..b8810059 100644 --- a/home/header.asm +++ b/home/header.asm @@ -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 diff --git a/home/text_script.asm b/home/text_script.asm index 9e1ba275..458bc555 100644 --- a/home/text_script.asm +++ b/home/text_script.asm @@ -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 diff --git a/layout.link b/layout.link index 19ebf091..4c70ee45 100644 --- a/layout.link +++ b/layout.link @@ -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" diff --git a/ram/wram.asm b/ram/wram.asm index 0d9544e0..9a3d34d6 100644 --- a/ram/wram.asm +++ b/ram/wram.asm @@ -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