From 062c840f47e17562175f41132bfa9bd2c0c8480d Mon Sep 17 00:00:00 2001 From: Pseurae Date: Sat, 5 Oct 2024 19:31:25 +0000 Subject: [PATCH] Ability Changer NPC --- assembly/event_scripts.s | 2 + assembly/events/ability_changer.inc | 99 +++++++++++++++++++++++++++++ assembly/events/nature_changer.inc | 52 +++++++++------ config.asm | 3 + include/pokemon.h | 40 +++++++++++- linker/rodata.ld | 4 +- linker/text.ld | 3 +- main.asm | 1 + scripts/ability_changer.asm | 4 ++ scripts/bugfixes/item_names.asm | 1 + src/pokemon_menu.c | 23 ++++++- 11 files changed, 205 insertions(+), 27 deletions(-) create mode 100644 assembly/events/ability_changer.inc create mode 100644 scripts/ability_changer.asm diff --git a/assembly/event_scripts.s b/assembly/event_scripts.s index 2433b85..7291e24 100644 --- a/assembly/event_scripts.s +++ b/assembly/event_scripts.s @@ -19,6 +19,8 @@ .section .script_data, "aw", %progbits .include "assembly/events/predefs.inc" + +.include "assembly/events/ability_changer.inc" .include "assembly/events/autorun.inc" .include "assembly/events/elevator_fixing.inc" .include "assembly/events/field_moves.inc" diff --git a/assembly/events/ability_changer.inc b/assembly/events/ability_changer.inc new file mode 100644 index 0000000..734995e --- /dev/null +++ b/assembly/events/ability_changer.inc @@ -0,0 +1,99 @@ +.global EventScript_AbilityChanger + +EventScript_AbilityChanger: + lock + faceplayer + call_if_unset 0xCD, EventScript_AbilityChanger_Intro + msgbox Text_AbilityChanger_DoYouWantToChangeAbility, MSGBOX_YESNO + + compare VAR_RESULT, 0x0 + goto_if_eq EventScript_AbilityChanger_Cancel + + msgbox Text_AbilityChanger_WhichPokemon, MSGBOX_DEFAULT + + nop + nop + nop + callnative (0x80f9a0c | 1) + waitstate + + lock + + compare VAR_0x8004, 255 + goto_if_eq EventScript_AbilityChanger_Cancel + + call EventScript_AbilityChanger_CheckIfEgg + bufferpartymonnick 1, VAR_0x8004 + + call EventScript_AbilityChanger_CheckChangeAbility + + callnative BufferAlternateAbilityName + + msgbox Text_AbilityChanger_ChangePokeAbility, MSGBOX_YESNO + compare VAR_RESULT, 0x0 + goto_if_eq EventScript_AbilityChanger_Cancel + + callnative ChangePartyMonAbility + + msgbox Text_AbilityChanger_ChangedPokeAbility, MSGBOX_NPC + + release + end + +EventScript_AbilityChanger_CheckIfEgg: + specialvar_ VAR_RESULT, 0x147 + compare VAR_RESULT, SPECIES_EGG + + goto_if_eq EventScript_AbilityChanger_IsEgg + return + +EventScript_AbilityChanger_CheckChangeAbility: + callnative CheckIfSpeciesHasAlternateAbility + compare VAR_RESULT, 0x0 + goto_if_eq EventScript_AbilityChanger_CannotChangeAbility + return + +EventScript_AbilityChanger_CannotChangeAbility: + msgbox Text_AbilityChanger_CannotChangeAbility, MSGBOX_NPC + release + end + +EventScript_AbilityChanger_Intro: + msgbox Text_AbilityChanger_Intro, MSGBOX_DEFAULT + setflag 0xCD + return + +EventScript_AbilityChanger_Cancel: + msgbox Text_AbilityChanger_Cancel, MSGBOX_NPC + release + end + +EventScript_AbilityChanger_IsEgg: + msgbox Text_AbilityChanger_IsEgg, MSGBOX_NPC + release + end + +Text_AbilityChanger_Intro: + .string "Back when I used to live in the Johto\nregion, my grandma taught me how to\nchange a POKéMON's ABILITY.\p" + .string "If you want, I could try to do the\nsame to your POKéMON.$" + +Text_AbilityChanger_DoYouWantToChangeAbility: + .string "So, do you want to change one of your\nPOKéMON's ABILITY?$" + +Text_AbilityChanger_WhichPokemon: + .string "Which POKéMON's ABILITY should I try\nto change?$" + +Text_AbilityChanger_Cancel: + .string "Come back if you change your mind!$" + +Text_AbilityChanger_IsEgg: + .string "I can't change the ABILITY of an EGG!$" + +Text_AbilityChanger_CannotChangeAbility: + .string "I'm sorry, but I can't change the\nABILITY of your {STR_VAR_2}.$" + +Text_AbilityChanger_ChangePokeAbility: + .string "Do you want to change {STR_VAR_2}'s\nABILITY to {STR_VAR_1}?$" + +Text_AbilityChanger_ChangedPokeAbility: + .string "Your {STR_VAR_2}'s ABILITY has been\nturned to {STR_VAR_1}!$" diff --git a/assembly/events/nature_changer.inc b/assembly/events/nature_changer.inc index d7bb1f8..a281229 100644 --- a/assembly/events/nature_changer.inc +++ b/assembly/events/nature_changer.inc @@ -3,20 +3,23 @@ EventScript_NatureChanger: lock faceplayer - msgbox Text_Intro, MSGBOX_YESNO + call_if_unset 0x68, EventScript_NatureChanger_Intro + + nop + msgbox Text_NatureChanger_DoYouWantToChangeNature, MSGBOX_YESNO compare VAR_RESULT, 0 - goto_if_eq EventScript_NatureChangerCancel + goto_if_eq EventScript_NatureChanger_Cancel call EventScript_NatureChanger_ChoosePokemon compare VAR_0x8004, 255 - goto_if_eq EventScript_NatureChangerCancel + goto_if_eq EventScript_NatureChanger_Cancel call EventScript_NatureChanger_CheckIfEgg bufferpartymonnick 1, VAR_0x8004 EventScript_NatureChanger_SelectNature: - message Text_WhichNature + message Text_NatureChanger_WhichNature waitmessage call EventScript_NatureChanger_ShowNatureWindow @@ -24,32 +27,37 @@ EventScript_NatureChanger_SelectNature: @ B Button check compare VAR_RESULT, 127 - goto_if_eq EventScript_NatureChangerCancel + goto_if_eq EventScript_NatureChanger_Cancel @ Cancel option check compare VAR_RESULT, 25 - goto_if_eq EventScript_NatureChangerCancel + goto_if_eq EventScript_NatureChanger_Cancel callnative BufferNatureName copyvar VAR_0x8005, VAR_RESULT - msgbox Text_AreYouSure, MSGBOX_YESNO + msgbox Text_NatureChanger_AreYouSure, MSGBOX_YESNO compare VAR_RESULT, 0 goto_if_eq EventScript_NatureChanger_SelectNature callnative ChangePartyMonNature release - msgbox Text_Changed, MSGBOX_NPC + msgbox Text_NatureChanger_Changed, MSGBOX_DEFAULT end -EventScript_NatureChangerCancel: - msgbox Text_Canceled, MSGBOX_NPC +EventScript_NatureChanger_Intro: + msgbox Text_NatureChanger_Intro, MSGBOX_DEFAULT + setflag 0x68 + return + +EventScript_NatureChanger_Cancel: + msgbox Text_NatureChanger_Cancel, MSGBOX_NPC releaseall end -EventScript_NatureChangerIsEgg: - msgbox Text_IsEgg, MSGBOX_NPC +EventScript_NatureChanger_IsEgg: + msgbox Text_NatureChanger_IsEgg, MSGBOX_NPC releaseall end @@ -62,7 +70,7 @@ EventScript_NatureChanger_CheckIfEgg: specialvar_ VAR_RESULT, 0x147 compare VAR_RESULT, SPECIES_EGG - goto_if_eq EventScript_NatureChangerIsEgg + goto_if_eq EventScript_NatureChanger_IsEgg return EventScript_NatureChanger_ShowNatureWindow: @@ -70,20 +78,24 @@ EventScript_NatureChanger_ShowNatureWindow: waitstate return -Text_Intro: +Text_NatureChanger_Intro: + .string "In times like these, you should take\nadvantage of every ounce of your\nPOKéMON's power.\p" + .string "I could change the NATURE of your\nPOKéMON so that you play to its\nstrengths.$" + +Text_NatureChanger_DoYouWantToChangeNature: .string "Would you like me to change one of your\nPOKéMON's NATURE?$" -Text_WhichNature: +Text_NatureChanger_WhichNature: .string "Which nature should I give\n{STR_VAR_2}?$" -Text_Canceled: - .string "Come visit me if you have a change of\nheart.$" +Text_NatureChanger_Cancel: + .string "Feel to visit me if you have a change\nof heart.$" -Text_IsEgg: +Text_NatureChanger_IsEgg: .string "I can't change the NATURE of an EGG!$" -Text_AreYouSure: +Text_NatureChanger_AreYouSure: .string "Are you sure you want to change\n{STR_VAR_2}'s NATURE to {STR_VAR_1}?$" -Text_Changed: +Text_NatureChanger_Changed: .string "I've changed your {STR_VAR_2}'s NATURE\nto {STR_VAR_1}!$" diff --git a/config.asm b/config.asm index 96c2180..7168af0 100644 --- a/config.asm +++ b/config.asm @@ -75,6 +75,9 @@ ; Adds a Nature Changer NPC to Verdanturf's Endless Plains. .definelabel NATURE_CHANGER, 1 +; Adds a Ability Changer NPC to Slateport's Market area. +.definelabel ABILITY_CHANGER, 1 + ; Bugfixes ; -------- diff --git a/include/pokemon.h b/include/pokemon.h index 72050ab..72b30c5 100644 --- a/include/pokemon.h +++ b/include/pokemon.h @@ -35,6 +35,39 @@ struct ContestMove u8 comboMoves[4]; }; +struct PACKED BaseStats +{ + /*0x00*/ u8 baseHP; + /*0x01*/ u8 baseAttack; + /*0x02*/ u8 baseDefense; + /*0x03*/ u8 baseSpeed; + /*0x04*/ u8 baseSpAttack; + /*0x05*/ u8 baseSpDefense; + /*0x06*/ u8 type1; + /*0x07*/ u8 type2; + /*0x08*/ u8 catchRate; + /*0x09*/ u8 expYield; + /*0x0A*/ u16 evYield_HP:2; + /*0x0A*/ u16 evYield_Attack:2; + /*0x0A*/ u16 evYield_Defense:2; + /*0x0A*/ u16 evYield_Speed:2; + /*0x0B*/ u16 evYield_SpAttack:2; + /*0x0B*/ u16 evYield_SpDefense:2; + /*0x0C*/ u16 item1; + /*0x0E*/ u16 item2; + /*0x10*/ u8 genderRatio; + /*0x11*/ u8 eggCycles; + /*0x12*/ u8 friendship; + /*0x13*/ u8 growthRate; + /*0x14*/ u8 eggGroup1; + /*0x15*/ u8 eggGroup2; + /*0x16*/ u8 ability1; + /*0x17*/ u8 ability2; + /*0x18*/ u8 safariZoneFleeRate; + /*0x19*/ u8 bodyColor:7; + u8 noFlip:1; +}; + struct PACKED BoxPokemon { u32 personality; @@ -116,7 +149,7 @@ extern const struct BattleMove gBattleMoves[]; u32 LONG_CALL CanMonLearnTMHM(struct Pokemon *mon, u8 tm); bool8 LONG_CALL MonKnowsMove(struct Pokemon *mon, u16 move); u32 LONG_CALL GetMonData(struct Pokemon *mon, s32 field); -void LONG_CALL SetMonData(struct Pokemon *mon, s32 field, u32 dataArg); +void LONG_CALL SetMonData(struct Pokemon *mon, s32 field, const void *dataArg); u8 LONG_CALL CountAliveMons(u8 a1); bool8 CheckIfMonCanUseHM(struct Pokemon *mon, u16 hm); bool8 LONG_CALL CheckIfPartyCanUseTM(u16 tm); @@ -129,6 +162,7 @@ void LONG_CALL EncryptBoxMon(struct BoxPokemon *boxMon); void LONG_CALL DecryptBoxMon(struct BoxPokemon *boxMon); void LONG_CALL SetBoxMonData(struct BoxPokemon *boxMon, s32 field, u32 dataArg); void LONG_CALL CalculateMonStats(struct Pokemon *mon); +u8 LONG_CALL GetAbilityBySpecies(u16 species, bool8 altAbility); enum { @@ -143,4 +177,6 @@ enum }; extern const s8 gNatureStatTable[25][5]; -extern const u8 *const gNatureNames[25]; \ No newline at end of file +extern const u8 *const gNatureNames[25]; +extern const struct BaseStats gBaseStats[]; +extern const u8 gAbilityNames[][13]; \ No newline at end of file diff --git a/linker/rodata.ld b/linker/rodata.ld index 39f0dea..2c4c724 100644 --- a/linker/rodata.ld +++ b/linker/rodata.ld @@ -45,4 +45,6 @@ gOtherText_Pokedex = 0x842c992; gOtherText_PlayTime = 0x842c99a; gStatStageRatios = 0x8208244; -gNatureNames = 0x83c1004; \ No newline at end of file +gNatureNames = 0x83c1004; +gBaseStats = 0x81fec18; +gAbilityNames = 0x81fa248; \ No newline at end of file diff --git a/linker/text.ld b/linker/text.ld index a14d636..774e5ee 100644 --- a/linker/text.ld +++ b/linker/text.ld @@ -235,4 +235,5 @@ CreateVerticalScrollIndicators = 0x80f953c | 1; SetVerticalScrollIndicators = 0x80f979c | 1; DestroyVerticalScrollIndicator = 0x80f97e0 | 1; LoadScrollIndicatorPalette = 0x80f9818 | 1; -ClearVerticalScrollIndicatorPalettes = 0x80f944c | 1; \ No newline at end of file +ClearVerticalScrollIndicatorPalettes = 0x80f944c | 1; +GetAbilityBySpecies = 0x803db14 | 1; \ No newline at end of file diff --git a/main.asm b/main.asm index 2d7b018..8b426b7 100644 --- a/main.asm +++ b/main.asm @@ -51,6 +51,7 @@ .include "scripts/bugfixes/ss_cangrejo.asm" .include "scripts/bugfixes/text_colors.asm" +.include "scripts/ability_changer.asm" .include "scripts/autorun.asm" .include "scripts/birch_speech.asm" .include "scripts/bag_expansion.asm" diff --git a/scripts/ability_changer.asm b/scripts/ability_changer.asm new file mode 100644 index 0000000..8294953 --- /dev/null +++ b/scripts/ability_changer.asm @@ -0,0 +1,4 @@ +.if ABILITY_CHANGER +.org 0x88189F1 +s_goto EventScript_AbilityChanger +.endif \ No newline at end of file diff --git a/scripts/bugfixes/item_names.asm b/scripts/bugfixes/item_names.asm index 96f68b3..0548651 100644 --- a/scripts/bugfixes/item_names.asm +++ b/scripts/bugfixes/item_names.asm @@ -16,4 +16,5 @@ fix_item_name ITEM_SOMA, "SOMA" fix_item_name ITEM_COLOGNE, "COLOGNE" fix_item_name ITEM_SPARK_TOKEN, "SPARK TOKEN" fix_item_name ITEM_ELECTRICHONEY, "ELECTRIHONEY" +fix_item_name ITEM_PLUS_BAND, "PLUS BAND" .endif diff --git a/src/pokemon_menu.c b/src/pokemon_menu.c index 4c16126..10a0867 100644 --- a/src/pokemon_menu.c +++ b/src/pokemon_menu.c @@ -5,6 +5,7 @@ #include "random.h" #include "script_menu.h" #include "string_util.h" +#include "constants/abilities.h" #include "constants/items.h" #include "constants/pokemon.h" @@ -167,11 +168,27 @@ void ChangePartyMonNature(void) u8 partyMonIndex = gSpecialVar_0x8004; struct Pokemon *mon = &gPlayerParty[partyMonIndex]; - // DecryptBoxMon(&mon->box); mon->box.nature = nature + 1; - // mon->box.checksum = CalculateBoxMonChecksum(&mon->box); - // EncryptBoxMon(&mon->box); CalculateMonStats(mon); +} + +void CheckIfSpeciesHasAlternateAbility(void) +{ + gSpecialVar_Result = gBaseStats[gSpecialVar_Result].ability2 != ABILITY_NONE; +} + +void ChangePartyMonAbility(void) +{ + struct Pokemon *mon = &gPlayerParty[gSpecialVar_0x8004]; + u8 altAbility = !GetMonData(mon, MON_DATA_ALT_ABILITY); + SetMonData(mon, MON_DATA_ALT_ABILITY, &altAbility); + CalculateMonStats(mon); +} + +void BufferAlternateAbilityName(void) +{ + struct Pokemon *mon = &gPlayerParty[gSpecialVar_0x8004]; + StringCopy(gStringVar1, gAbilityNames[GetAbilityBySpecies(GetMonData(mon, MON_DATA_SPECIES), !GetMonData(mon, MON_DATA_ALT_ABILITY))]); } \ No newline at end of file