diff --git a/asm/macros/event.inc b/asm/macros/event.inc index f2af499b52..5715d91ea3 100644 --- a/asm/macros/event.inc +++ b/asm/macros/event.inc @@ -984,16 +984,62 @@ .byte \textTop .endm - @ Gives the player a Pokémon of the specified species and level, holding the specified item. The trailing 0s are unused parameters. + @ Gives the player a Pokémon of the specified species and level, and allows to customize extra parameters. @ VAR_RESULT will be set to MON_GIVEN_TO_PARTY, MON_GIVEN_TO_PC, or MON_CANT_GIVE depending on the outcome. - .macro givemon species:req, level:req, item=ITEM_NONE - .byte 0x79 + .macro givemon species:req, level:req, item, ball, nature, abilityNum, gender, hpEv, atkEv, defEv, speedEv, spAtkEv, spDefEv, hpIv, atkIv, defIv, speedIv, spAtkIv, spDefIv, move1, move2, move3, move4, isShiny, ggMaxFactor, teraType + callnative ScrCmd_givemon + .set givemon_flags, 0 .2byte \species - .byte \level - .2byte \item - .4byte 0 - .4byte 0 - .byte 0 + .2byte \level + .ifnb \item; .set givemon_flags, givemon_flags | (1 << 0); .endif + .ifnb \ball; .set givemon_flags, givemon_flags | (1 << 1); .endif + .ifnb \nature; .set givemon_flags, givemon_flags | (1 << 2); .endif + .ifnb \abilityNum; .set givemon_flags, givemon_flags | (1 << 3); .endif + .ifnb \gender; .set givemon_flags, givemon_flags | (1 << 4); .endif + .ifnb \hpEv; .set givemon_flags, givemon_flags | (1 << 5); .endif + .ifnb \atkEv; .set givemon_flags, givemon_flags | (1 << 6); .endif + .ifnb \defEv; .set givemon_flags, givemon_flags | (1 << 7); .endif + .ifnb \speedEv; .set givemon_flags, givemon_flags | (1 << 8); .endif + .ifnb \spAtkEv; .set givemon_flags, givemon_flags | (1 << 9); .endif + .ifnb \spDefEv; .set givemon_flags, givemon_flags | (1 << 10); .endif + .ifnb \hpIv; .set givemon_flags, givemon_flags | (1 << 11); .endif + .ifnb \atkIv; .set givemon_flags, givemon_flags | (1 << 12); .endif + .ifnb \defIv; .set givemon_flags, givemon_flags | (1 << 13); .endif + .ifnb \speedIv; .set givemon_flags, givemon_flags | (1 << 14); .endif + .ifnb \spAtkIv; .set givemon_flags, givemon_flags | (1 << 15); .endif + .ifnb \spDefIv; .set givemon_flags, givemon_flags | (1 << 16); .endif + .ifnb \move1; .set givemon_flags, givemon_flags | (1 << 17); .endif + .ifnb \move2; .set givemon_flags, givemon_flags | (1 << 18); .endif + .ifnb \move3; .set givemon_flags, givemon_flags | (1 << 19); .endif + .ifnb \move4; .set givemon_flags, givemon_flags | (1 << 20); .endif + .ifnb \isShiny; .set givemon_flags, givemon_flags | (1 << 21); .endif + .ifnb \ggMaxFactor; .set givemon_flags, givemon_flags | (1 << 22); .endif + .ifnb \teraType; .set givemon_flags, givemon_flags | (1 << 23); .endif + .4byte givemon_flags + .ifnb \item; .2byte \item; .endif + .ifnb \ball; .2byte \ball; .endif + .ifnb \nature; .2byte \nature; .endif + .ifnb \abilityNum; .2byte \abilityNum; .endif + .ifnb \gender; .2byte \gender; .endif + .ifnb \hpEv; .2byte \hpEv; .endif + .ifnb \atkEv; .2byte \atkEv; .endif + .ifnb \defEv; .2byte \defEv; .endif + .ifnb \speedEv; .2byte \speedEv; .endif + .ifnb \spAtkEv; .2byte \spAtkEv; .endif + .ifnb \spDefEv; .2byte \spDefEv; .endif + .ifnb \hpIv; .2byte \hpIv; .endif + .ifnb \atkIv; .2byte \atkIv; .endif + .ifnb \defIv; .2byte \defIv; .endif + .ifnb \speedIv; .2byte \speedIv; .endif + .ifnb \spAtkIv; .2byte \spAtkIv; .endif + .ifnb \spDefIv; .2byte \spDefIv; .endif + .ifnb \move1; .2byte \move1; .endif + .ifnb \move2; .2byte \move2; .endif + .ifnb \move3; .2byte \move3; .endif + .ifnb \move4; .2byte \move4; .endif + .ifnb \isShiny; .2byte \isShiny; .endif + .ifnb \ggMaxFactor; .2byte \ggMaxFactor; .endif + .ifnb \teraType; .2byte \teraType; .endif .endm @ Gives the player an Egg of the specified species. diff --git a/data/script_cmd_table.inc b/data/script_cmd_table.inc index 794662e993..28f22242ca 100644 --- a/data/script_cmd_table.inc +++ b/data/script_cmd_table.inc @@ -121,7 +121,7 @@ gScriptCmdTable:: .4byte ScrCmd_hidemonpic @ 0x76 .4byte ScrCmd_showcontestpainting @ 0x77 .4byte ScrCmd_braillemessage @ 0x78 - .4byte ScrCmd_givemon @ 0x79 + .4byte ScrCmd_nop1 @ 0x79 .4byte ScrCmd_giveegg @ 0x7a .4byte ScrCmd_setmonmove @ 0x7b .4byte ScrCmd_checkpartymove @ 0x7c diff --git a/data/scripts/debug.inc b/data/scripts/debug.inc index 4c74fc1cbd..4e0cc413ff 100644 --- a/data/scripts/debug.inc +++ b/data/scripts/debug.inc @@ -95,6 +95,48 @@ Debug_BoxFilledMessage:: Debug_BoxFilledMessage_Text: .string "Storage boxes filled!$" +Debug_EventScript_CheckEV:: + lockall + getpartysize + goto_if_eq VAR_RESULT, 0, Debug_HatchAnEgg_NoPokemon + special ChoosePartyMon + waitstate + goto_if_ge VAR_0x8004, PARTY_SIZE, Debug_EventScript_CheckEV_End + callnative Script_GetChosenMonOffensiveEV + msgbox Debug_EventScript_Text_OffensiveEV, MSGBOX_DEFAULT + callnative Script_GetChosenMonDefensiveEV + msgbox Debug_EventScript_Text_DefensiveEV, MSGBOX_DEFAULT +Debug_EventScript_CheckEV_End:: + releaseall + end + +Debug_EventScript_Text_OffensiveEV: + .string "ATK EV: {STR_VAR_1}, SPATK EV: {STR_VAR_2}, SPEED EV: {STR_VAR_3}$" + +Debug_EventScript_Text_DefensiveEV: + .string "HP EV: {STR_VAR_1}, DEF EV: {STR_VAR_2}, SPDEF EV: {STR_VAR_3}$" + +Debug_EventScript_CheckIV:: + lockall + getpartysize + goto_if_eq VAR_RESULT, 0, Debug_HatchAnEgg_NoPokemon + special ChoosePartyMon + waitstate + goto_if_ge VAR_0x8004, PARTY_SIZE, Debug_EventScript_CheckIV_End + callnative Script_GetChosenMonOffensiveIV + msgbox Debug_EventScript_Text_OffensiveIV, MSGBOX_DEFAULT + callnative Script_GetChosenMonDefensiveIV + msgbox Debug_EventScript_Text_DefensiveIV, MSGBOX_DEFAULT +Debug_EventScript_CheckIV_End:: + releaseall + end + +Debug_EventScript_Text_OffensiveIV: + .string "ATK IV: {STR_VAR_1}, SPATK IV: {STR_VAR_2}, SPEED IV: {STR_VAR_3}$" + +Debug_EventScript_Text_DefensiveIV: + .string "HP IV: {STR_VAR_1}, DEF IV: {STR_VAR_2}, SPDEF IV: {STR_VAR_3}$" + Debug_EventScript_Script_1:: end @@ -247,4 +289,3 @@ Debug_FlagsAndVarNotSetBattleConfigMessage_Text: .string "Feature unavailable! Please define a\n" .string "usable flag and a usable var in:\l" .string "'include/config/battle.h'!$" - diff --git a/data/specials.inc b/data/specials.inc index d5e659e1f9..d0efad6477 100644 --- a/data/specials.inc +++ b/data/specials.inc @@ -550,3 +550,7 @@ gSpecials:: def_special ObjectEventInteractionBerryHasWeed def_special ObjectEventInteractionBerryHasPests def_special CanWaterBerryPlot + def_special Script_GetChosenMonOffensiveEV + def_special Script_GetChosenMonDefensiveEV + def_special Script_GetChosenMonOffensiveIV + def_special Script_GetChosenMonDefensiveIV diff --git a/include/script_pokemon_util.h b/include/script_pokemon_util.h index a2e6915609..643e8d9225 100644 --- a/include/script_pokemon_util.h +++ b/include/script_pokemon_util.h @@ -1,12 +1,17 @@ #ifndef GUARD_SCRIPT_POKEMON_UTIL_H #define GUARD_SCRIPT_POKEMON_UTIL_H -u8 ScriptGiveMon(u16, u8, u16, u32, u32, u8); +u32 ScriptGiveMon(u16, u8, u16); +u32 ScriptGiveMonParameterized(u16, u8, u16, u8, u8, u8, u8, u8 *, u8 *, u16 *, bool8, bool8, u8); u8 ScriptGiveEgg(u16); void CreateScriptedWildMon(u16, u8, u16); void CreateScriptedDoubleWildMon(u16, u8, u16, u16, u8, u16); void ScriptSetMonMoveSlot(u8, u16, u8); void ReducePlayerPartyToSelectedMons(void); void HealPlayerParty(void); +void Script_GetChosenMonOffensiveEV(void); +void Script_GetChosenMonDefensiveEV(void); +void Script_GetChosenMonOffensiveIV(void); +void Script_GetChosenMonDefensiveIV(void); #endif // GUARD_SCRIPT_POKEMON_UTIL_H diff --git a/src/battle_setup.c b/src/battle_setup.c index 1b836bc7ef..2a8738bcce 100644 --- a/src/battle_setup.c +++ b/src/battle_setup.c @@ -966,7 +966,7 @@ static void CB2_GiveStarter(void) *GetVarPointer(VAR_STARTER_MON) = gSpecialVar_Result; starterMon = GetStarterPokemon(gSpecialVar_Result); - ScriptGiveMon(starterMon, 5, ITEM_NONE, 0, 0, 0); + ScriptGiveMon(starterMon, 5, ITEM_NONE); ResetTasks(); PlayBattleBGM(); SetMainCallback2(CB2_StartFirstBattle); diff --git a/src/debug.c b/src/debug.c index 70792fd569..e3506ab7f0 100644 --- a/src/debug.c +++ b/src/debug.c @@ -127,6 +127,9 @@ enum PartyDebugMenu DEBUG_PARTY_MENU_ITEM_HATCH_AN_EGG, DEBUG_PARTY_MENU_ITEM_HEAL_PARTY, DEBUG_PARTY_MENU_ITEM_POISON_MONS, + DEBUG_PARTY_MENU_ITEM_CHECK_EV, + DEBUG_PARTY_MENU_ITEM_CHECK_IV, + DEBUG_PARTY_MENU_ITEM_CLEAR_PARTY, }; enum ScriptDebugMenu @@ -389,6 +392,9 @@ static void DebugAction_Party_MoveReminder(u8 taskId); static void DebugAction_Party_HatchAnEgg(u8 taskId); static void DebugAction_Party_HealParty(u8 taskId); static void DebugAction_Party_PoisonMons(u8 taskId); +static void DebugAction_Party_CheckEV(u8 taskId); +static void DebugAction_Party_CheckIV(u8 taskId); +static void DebugAction_Party_ClearParty(u8 taskId); static void DebugAction_FlagsVars_Flags(u8 taskId); static void DebugAction_FlagsVars_FlagsSelect(u8 taskId); @@ -446,6 +452,8 @@ static void DebugAction_BerryFunctions_Weeds(u8 taskId); extern const u8 Debug_FlagsNotSetOverworldConfigMessage[]; extern const u8 Debug_FlagsNotSetBattleConfigMessage[]; extern const u8 Debug_FlagsAndVarNotSetBattleConfigMessage[]; +extern const u8 Debug_EventScript_CheckEV[]; +extern const u8 Debug_EventScript_CheckIV[]; extern const u8 Debug_EventScript_Script_1[]; extern const u8 Debug_EventScript_Script_2[]; extern const u8 Debug_EventScript_Script_3[]; @@ -541,6 +549,9 @@ static const u8 sDebugText_Party_MoveReminder[] = _("Move Reminder"); static const u8 sDebugText_Party_HatchAnEgg[] = _("Hatch an Egg"); static const u8 sDebugText_Party_HealParty[] = _("Heal party"); static const u8 sDebugText_Party_PoisonParty[] = _("Poison party"); +static const u8 sDebugText_Party_CheckEV[] = _("Check EV"); +static const u8 sDebugText_Party_CheckIV[] = _("Check IV"); +static const u8 sDebugText_Party_ClearParty[] = _("Clear Party"); // Flags/Vars Menu static const u8 sDebugText_FlagsVars_Flags[] = _("Set Flag XYZ…{CLEAR_TO 110}{RIGHT_ARROW}"); static const u8 sDebugText_FlagsVars_Flag[] = _("Flag: {STR_VAR_1}{CLEAR_TO 90}\n{STR_VAR_2}{CLEAR_TO 90}\n{STR_VAR_3}"); @@ -736,6 +747,9 @@ static const struct ListMenuItem sDebugMenu_Items_Party[] = [DEBUG_PARTY_MENU_ITEM_HATCH_AN_EGG] = {sDebugText_Party_HatchAnEgg, DEBUG_PARTY_MENU_ITEM_HATCH_AN_EGG}, [DEBUG_PARTY_MENU_ITEM_HEAL_PARTY] = {sDebugText_Party_HealParty, DEBUG_PARTY_MENU_ITEM_HEAL_PARTY}, [DEBUG_PARTY_MENU_ITEM_POISON_MONS] = {sDebugText_Party_PoisonParty, DEBUG_PARTY_MENU_ITEM_POISON_MONS}, + [DEBUG_PARTY_MENU_ITEM_CHECK_EV] = {sDebugText_Party_CheckEV, DEBUG_PARTY_MENU_ITEM_CHECK_EV}, + [DEBUG_PARTY_MENU_ITEM_CHECK_IV] = {sDebugText_Party_CheckIV, DEBUG_PARTY_MENU_ITEM_CHECK_IV}, + [DEBUG_PARTY_MENU_ITEM_CLEAR_PARTY] = {sDebugText_Party_ClearParty, DEBUG_PARTY_MENU_ITEM_CLEAR_PARTY}, }; static const struct ListMenuItem sDebugMenu_Items_Scripts[] = @@ -902,6 +916,9 @@ static void (*const sDebugMenu_Actions_Party[])(u8) = [DEBUG_PARTY_MENU_ITEM_HATCH_AN_EGG] = DebugAction_Party_HatchAnEgg, [DEBUG_PARTY_MENU_ITEM_HEAL_PARTY] = DebugAction_Party_HealParty, [DEBUG_PARTY_MENU_ITEM_POISON_MONS] = DebugAction_Party_PoisonMons, + [DEBUG_PARTY_MENU_ITEM_CHECK_EV] = DebugAction_Party_CheckEV, + [DEBUG_PARTY_MENU_ITEM_CHECK_IV] = DebugAction_Party_CheckIV, + [DEBUG_PARTY_MENU_ITEM_CLEAR_PARTY] = DebugAction_Party_ClearParty, }; static void (*const sDebugMenu_Actions_Scripts[])(u8) = @@ -3277,7 +3294,7 @@ static void DebugAction_Give_Pokemon_SelectLevel(u8 taskId) if (gTasks[taskId].tIsComplex == FALSE) { PlaySE(MUS_LEVEL_UP); - ScriptGiveMon(sDebugMonData->species, gTasks[taskId].tInput, ITEM_NONE, 0, 0, 0); + ScriptGiveMon(sDebugMonData->species, gTasks[taskId].tInput, ITEM_NONE); // Set flag for user convenience FlagSet(FLAG_SYS_POKEMON_GET); Free(sDebugMonData); @@ -5075,4 +5092,21 @@ static void DebugAction_Party_PoisonMons(u8 taskId) Debug_DestroyMenu_Full(taskId); } +static void DebugAction_Party_CheckEV(u8 taskId) +{ + Debug_DestroyMenu_Full_Script(taskId, Debug_EventScript_CheckEV); +} + +static void DebugAction_Party_CheckIV(u8 taskId) +{ + Debug_DestroyMenu_Full_Script(taskId, Debug_EventScript_CheckIV); +} + +static void DebugAction_Party_ClearParty(u8 taskId) +{ + ZeroPlayerPartyMons(); + ScriptContext_Enable(); + Debug_DestroyMenu_Full(taskId); +} + #endif //DEBUG_OVERWORLD_MENU == TRUE diff --git a/src/scrcmd.c b/src/scrcmd.c index 9ffabb6f8f..1e95c8ebd9 100644 --- a/src/scrcmd.c +++ b/src/scrcmd.c @@ -1777,19 +1777,6 @@ bool8 ScrCmd_bufferboxname(struct ScriptContext *ctx) return FALSE; } -bool8 ScrCmd_givemon(struct ScriptContext *ctx) -{ - u16 species = VarGet(ScriptReadHalfword(ctx)); - u8 level = ScriptReadByte(ctx); - u16 item = VarGet(ScriptReadHalfword(ctx)); - u32 unkParam1 = ScriptReadWord(ctx); - u32 unkParam2 = ScriptReadWord(ctx); - u8 unkParam3 = ScriptReadByte(ctx); - - gSpecialVar_Result = ScriptGiveMon(species, level, item, unkParam1, unkParam2, unkParam3); - return FALSE; -} - bool8 ScrCmd_giveegg(struct ScriptContext *ctx) { u16 species = VarGet(ScriptReadHalfword(ctx)); diff --git a/src/script_pokemon_util.c b/src/script_pokemon_util.c index ed27236e0a..f37a70a146 100644 --- a/src/script_pokemon_util.c +++ b/src/script_pokemon_util.c @@ -23,6 +23,7 @@ #include "string_util.h" #include "tv.h" #include "wild_encounter.h" +#include "constants/abilities.h" #include "constants/items.h" #include "constants/battle_frontier.h" @@ -55,46 +56,6 @@ static void HealPlayerBoxes(void) } } -u8 ScriptGiveMon(u16 species, u8 level, u16 item, u32 unused1, u32 unused2, u8 unused3) -{ - u16 nationalDexNum; - int sentToPc; - u8 heldItem[2]; - struct Pokemon mon; - u16 targetSpecies; - - if (OW_SYNCHRONIZE_NATURE >= GEN_6 && (gSpeciesInfo[species].eggGroups[0] == EGG_GROUP_NO_EGGS_DISCOVERED || OW_SYNCHRONIZE_NATURE == GEN_7)) - CreateMonWithNature(&mon, species, level, USE_RANDOM_IVS, PickWildMonNature()); - else - CreateMon(&mon, species, level, USE_RANDOM_IVS, FALSE, 0, OT_ID_PLAYER_ID, 0); - - heldItem[0] = item; - heldItem[1] = item >> 8; - SetMonData(&mon, MON_DATA_HELD_ITEM, heldItem); - - // In case a mon with a form changing item is given. Eg: SPECIES_ARCEUS_NORMAL with ITEM_SPLASH_PLATE will transform into SPECIES_ARCEUS_WATER upon gifted. - targetSpecies = GetFormChangeTargetSpecies(&mon, FORM_CHANGE_ITEM_HOLD, 0); - if (targetSpecies != SPECIES_NONE) - { - SetMonData(&mon, MON_DATA_SPECIES, &targetSpecies); - CalculateMonStats(&mon); - } - - sentToPc = GiveMonToPlayer(&mon); - nationalDexNum = SpeciesToNationalPokedexNum(species); - - // Don't set Pokédex flag for MON_CANT_GIVE - switch(sentToPc) - { - case MON_GIVEN_TO_PARTY: - case MON_GIVEN_TO_PC: - GetSetPokedexFlag(nationalDexNum, FLAG_SET_SEEN); - GetSetPokedexFlag(nationalDexNum, FLAG_SET_CAUGHT); - break; - } - return sentToPc; -} - u8 ScriptGiveEgg(u16 species) { struct Pokemon mon; @@ -327,3 +288,197 @@ void ToggleGigantamaxFactor(struct ScriptContext *ctx) gSpecialVar_Result = TRUE; } } + +u32 ScriptGiveMonParameterized(u16 species, u8 level, u16 item, u8 ball, u8 nature, u8 abilityNum, u8 gender, u8 *evs, u8 *ivs, u16 *moves, bool8 isShiny, bool8 ggMaxFactor, u8 teraType) +{ + u16 nationalDexNum; + int sentToPc; + struct Pokemon mon; + u32 i; + u8 genderRatio = gSpeciesInfo[species].genderRatio; + u16 targetSpecies; + + // check whether to use a specific nature or a random one + if (OW_SYNCHRONIZE_NATURE >= GEN_6 && (gSpeciesInfo[species].eggGroups[0] == EGG_GROUP_NO_EGGS_DISCOVERED || OW_SYNCHRONIZE_NATURE == GEN_7)) + nature = PickWildMonNature(); + else if (nature >= NUM_NATURES) + nature = Random() % NUM_NATURES; + + // create a Pokémon with basic data + if ((gender == MON_MALE && genderRatio != MON_FEMALE && genderRatio != MON_GENDERLESS) + || (gender == MON_FEMALE && genderRatio != MON_MALE && genderRatio != MON_GENDERLESS) + || (gender == MON_GENDERLESS && genderRatio == MON_GENDERLESS)) + CreateMonWithGenderNatureLetter(&mon, species, level, 32, gender, nature, 0); + else + CreateMonWithNature(&mon, species, level, 32, nature); + + // shininess + SetMonData(&mon, MON_DATA_IS_SHINY, &isShiny); + + // gigantamax factor + SetMonData(&mon, MON_DATA_GIGANTAMAX_FACTOR, &ggMaxFactor); + + // tera type + if (teraType >= NUMBER_OF_MON_TYPES) + teraType = gSpeciesInfo[species].types[0]; + SetMonData(&mon, MON_DATA_TERA_TYPE, &teraType); + + // EV and IV + for (i = 0; i < NUM_STATS; i++) + { + // EV + if (evs[i] <= MAX_PER_STAT_EVS) + SetMonData(&mon, MON_DATA_HP_EV + i, &evs[i]); + + // IV + if (ivs[i] <= MAX_PER_STAT_IVS) + SetMonData(&mon, MON_DATA_HP_IV + i, &ivs[i]); + } + CalculateMonStats(&mon); + + // moves + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i] == MOVE_NONE || moves[i] >= MOVES_COUNT) + continue; + SetMonMoveSlot(&mon, moves[i], i); + } + + // ability + if (abilityNum >= NUM_ABILITY_SLOTS || GetAbilityBySpecies(species, abilityNum) == ABILITY_NONE) + { + do { + abilityNum = Random() % NUM_ABILITY_SLOTS; // includes hidden abilities + } while (GetAbilityBySpecies(species, abilityNum) == ABILITY_NONE); + } + SetMonData(&mon, MON_DATA_ABILITY_NUM, &abilityNum); + + // ball + if (ball >= POKEBALL_COUNT) + ball = ITEM_POKE_BALL; + SetMonData(&mon, MON_DATA_POKEBALL, &ball); + + // held item + SetMonData(&mon, MON_DATA_HELD_ITEM, &item); + + // In case a mon with a form changing item is given. Eg: SPECIES_ARCEUS_NORMAL with ITEM_SPLASH_PLATE will transform into SPECIES_ARCEUS_WATER upon gifted. + targetSpecies = GetFormChangeTargetSpecies(&mon, FORM_CHANGE_ITEM_HOLD, 0); + if (targetSpecies != SPECIES_NONE) + SetMonData(&mon, MON_DATA_SPECIES, &targetSpecies); + + // assign OT name and gender + SetMonData(&mon, MON_DATA_OT_NAME, gSaveBlock2Ptr->playerName); + SetMonData(&mon, MON_DATA_OT_GENDER, &gSaveBlock2Ptr->playerGender); + + // find empty party slot to decide whether the Pokémon goes to the Player's party or the storage system. + for (i = 0; i < PARTY_SIZE; i++) + { + if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES, NULL) == SPECIES_NONE) + break; + } + if (i >= PARTY_SIZE) + { + sentToPc = CopyMonToPC(&mon); + } + else + { + sentToPc = MON_GIVEN_TO_PARTY; + CopyMon(&gPlayerParty[i], &mon, sizeof(mon)); + gPlayerPartyCount = i + 1; + } + + // set pokédex flags + nationalDexNum = SpeciesToNationalPokedexNum(species); + switch (sentToPc) + { + case MON_GIVEN_TO_PARTY: + case MON_GIVEN_TO_PC: + GetSetPokedexFlag(nationalDexNum, FLAG_SET_SEEN); + GetSetPokedexFlag(nationalDexNum, FLAG_SET_CAUGHT); + break; + case MON_CANT_GIVE: + break; + } + + return sentToPc; +} + +u32 ScriptGiveMon(u16 species, u8 level, u16 item) +{ + u8 evs[NUM_STATS] = {0, 0, 0, 0, 0, 0}; + u8 ivs[NUM_STATS] = {MAX_PER_STAT_IVS + 1, MAX_PER_STAT_IVS + 1, MAX_PER_STAT_IVS + 1, // We pass "MAX_PER_STAT_IVS + 1" here to ensure that + MAX_PER_STAT_IVS + 1, MAX_PER_STAT_IVS + 1, MAX_PER_STAT_IVS + 1}; // ScriptGiveMonParameterized won't touch the stats' IV. + u16 moves[MAX_MON_MOVES] = {MOVE_NONE, MOVE_NONE, MOVE_NONE, MOVE_NONE}; + + return ScriptGiveMonParameterized(species, level, item, ITEM_POKE_BALL, NUM_NATURES, NUM_ABILITY_SLOTS, MON_GENDERLESS, evs, ivs, moves, FALSE, FALSE, NUMBER_OF_MON_TYPES); +} + +#define PARSE_FLAG(n, default_) (flags & (1 << (n))) ? VarGet(ScriptReadHalfword(ctx)) : (default_) + +void ScrCmd_givemon(struct ScriptContext *ctx) +{ + u16 species = VarGet(ScriptReadHalfword(ctx)); + u8 level = VarGet(ScriptReadHalfword(ctx)); + + u32 flags = ScriptReadWord(ctx); + u16 item = PARSE_FLAG(0, ITEM_NONE); + u8 ball = PARSE_FLAG(1, ITEM_POKE_BALL); + u8 nature = PARSE_FLAG(2, NUM_NATURES); + u8 abilityNum = PARSE_FLAG(3, NUM_ABILITY_SLOTS); + u8 gender = PARSE_FLAG(4, MON_GENDERLESS); // TODO: Find a better way to assign a random gender. + u8 hpEv = PARSE_FLAG(5, 0); + u8 atkEv = PARSE_FLAG(6, 0); + u8 defEv = PARSE_FLAG(7, 0); + u8 speedEv = PARSE_FLAG(8, 0); + u8 spAtkEv = PARSE_FLAG(9, 0); + u8 spDefEv = PARSE_FLAG(10, 0); + u8 hpIv = PARSE_FLAG(11, Random() % MAX_PER_STAT_IVS + 1); + u8 atkIv = PARSE_FLAG(12, Random() % MAX_PER_STAT_IVS + 1); + u8 defIv = PARSE_FLAG(13, Random() % MAX_PER_STAT_IVS + 1); + u8 speedIv = PARSE_FLAG(14, Random() % MAX_PER_STAT_IVS + 1); + u8 spAtkIv = PARSE_FLAG(15, Random() % MAX_PER_STAT_IVS + 1); + u8 spDefIv = PARSE_FLAG(16, Random() % MAX_PER_STAT_IVS + 1); + u16 move1 = PARSE_FLAG(17, MOVE_NONE); + u16 move2 = PARSE_FLAG(18, MOVE_NONE); + u16 move3 = PARSE_FLAG(19, MOVE_NONE); + u16 move4 = PARSE_FLAG(20, MOVE_NONE); + bool8 isShiny = PARSE_FLAG(21, FALSE); + bool8 ggMaxFactor = PARSE_FLAG(22, FALSE); + u8 teraType = PARSE_FLAG(23, NUMBER_OF_MON_TYPES); + + u8 evs[NUM_STATS] = {hpEv, atkEv, defEv, speedEv, spAtkEv, spDefEv}; + u8 ivs[NUM_STATS] = {hpIv, atkIv, defIv, speedIv, spAtkIv, spDefIv}; + u16 moves[MAX_MON_MOVES] = {move1, move2, move3, move4}; + + gSpecialVar_Result = ScriptGiveMonParameterized(species, level, item, ball, nature, abilityNum, gender, evs, ivs, moves, isShiny, ggMaxFactor, teraType); +} + +#undef PARSE_FLAG + +void Script_GetChosenMonOffensiveEV(void) +{ + ConvertIntToDecimalStringN(gStringVar1, GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_ATK_EV), STR_CONV_MODE_LEFT_ALIGN, 3); + ConvertIntToDecimalStringN(gStringVar2, GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_SPATK_EV), STR_CONV_MODE_LEFT_ALIGN, 3); + ConvertIntToDecimalStringN(gStringVar3, GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_SPEED_EV), STR_CONV_MODE_LEFT_ALIGN, 3); +} + +void Script_GetChosenMonDefensiveEV(void) +{ + ConvertIntToDecimalStringN(gStringVar1, GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_HP_EV), STR_CONV_MODE_LEFT_ALIGN, 3); + ConvertIntToDecimalStringN(gStringVar2, GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_DEF_EV), STR_CONV_MODE_LEFT_ALIGN, 3); + ConvertIntToDecimalStringN(gStringVar3, GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_SPDEF_EV), STR_CONV_MODE_LEFT_ALIGN, 3); +} + +void Script_GetChosenMonOffensiveIV(void) +{ + ConvertIntToDecimalStringN(gStringVar1, GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_ATK_IV), STR_CONV_MODE_LEFT_ALIGN, 3); + ConvertIntToDecimalStringN(gStringVar2, GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_SPATK_IV), STR_CONV_MODE_LEFT_ALIGN, 3); + ConvertIntToDecimalStringN(gStringVar3, GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_SPEED_IV), STR_CONV_MODE_LEFT_ALIGN, 3); +} + +void Script_GetChosenMonDefensiveIV(void) +{ + ConvertIntToDecimalStringN(gStringVar1, GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_HP_IV), STR_CONV_MODE_LEFT_ALIGN, 3); + ConvertIntToDecimalStringN(gStringVar2, GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_DEF_IV), STR_CONV_MODE_LEFT_ALIGN, 3); + ConvertIntToDecimalStringN(gStringVar3, GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_SPDEF_IV), STR_CONV_MODE_LEFT_ALIGN, 3); +} diff --git a/test/pokemon.c b/test/pokemon.c index 05d6ac15e5..7cd2ab5769 100644 --- a/test/pokemon.c +++ b/test/pokemon.c @@ -180,3 +180,114 @@ TEST("togglegigantamaxfactor fails for Melmetal") EXPECT(!VarGet(VAR_RESULT)); EXPECT(!GetMonData(&gPlayerParty[0], MON_DATA_GIGANTAMAX_FACTOR)); } + +TEST("givemon [simple]") +{ + ZeroPlayerPartyMons(); + + RUN_OVERWORLD_SCRIPT( + givemon SPECIES_WOBBUFFET, 100; + ); + + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_SPECIES), SPECIES_WOBBUFFET); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_LEVEL), 100); +} + +TEST("givemon [all]") +{ + ZeroPlayerPartyMons(); + + RUN_OVERWORLD_SCRIPT( + givemon SPECIES_WOBBUFFET, 100, item=ITEM_LEFTOVERS, ball=ITEM_MASTER_BALL, nature=NATURE_BOLD, abilityNum=2, gender=MON_MALE, hpEv=1, atkEv=2, defEv=3, speedEv=4, spAtkEv=5, spDefEv=6, hpIv=7, atkIv=8, defIv=9, speedIv=10, spAtkIv=11, spDefIv=12, move1=MOVE_TACKLE, move2=MOVE_SPLASH, move3=MOVE_CELEBRATE, move4=MOVE_EXPLOSION, isShiny=TRUE, ggMaxFactor=TRUE, teraType=TYPE_FIRE; + ); + + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_SPECIES), SPECIES_WOBBUFFET); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_LEVEL), 100); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_HELD_ITEM), ITEM_LEFTOVERS); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_POKEBALL), ITEM_MASTER_BALL); + EXPECT_EQ(GetNature(&gPlayerParty[0]), NATURE_BOLD); + EXPECT_EQ(GetMonAbility(&gPlayerParty[0]), gSpeciesInfo[SPECIES_WOBBUFFET].abilities[2]); + EXPECT_EQ(GetMonGender(&gPlayerParty[0]), MON_MALE); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_HP_EV), 1); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_ATK_EV), 2); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_DEF_EV), 3); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_SPEED_EV), 4); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_SPATK_EV), 5); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_SPDEF_EV), 6); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_HP_IV), 7); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_ATK_IV), 8); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_DEF_IV), 9); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_SPEED_IV), 10); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_SPATK_IV), 11); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_SPDEF_IV), 12); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_MOVE1), MOVE_TACKLE); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_MOVE2), MOVE_SPLASH); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_MOVE3), MOVE_CELEBRATE); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_MOVE4), MOVE_EXPLOSION); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_IS_SHINY), TRUE); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_GIGANTAMAX_FACTOR), TRUE); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_TERA_TYPE), TYPE_FIRE); +} + +TEST("givemon [vars]") +{ + ZeroPlayerPartyMons(); + + VarSet(VAR_TEMP_C, SPECIES_WOBBUFFET); + VarSet(VAR_TEMP_D, 100); + VarSet(VAR_0x8000, ITEM_LEFTOVERS); + VarSet(VAR_0x8001, ITEM_MASTER_BALL); + VarSet(VAR_0x8002, NATURE_BOLD); + VarSet(VAR_0x8003, 2); + VarSet(VAR_0x8004, MON_MALE); + VarSet(VAR_0x8005, 1); + VarSet(VAR_0x8006, 2); + VarSet(VAR_0x8007, 3); + VarSet(VAR_0x8008, 4); + VarSet(VAR_0x8009, 5); + VarSet(VAR_0x800A, 6); + VarSet(VAR_0x800B, 7); + VarSet(VAR_TEMP_0, 8); + VarSet(VAR_TEMP_1, 9); + VarSet(VAR_TEMP_2, 10); + VarSet(VAR_TEMP_3, 11); + VarSet(VAR_TEMP_4, 12); + VarSet(VAR_TEMP_5, MOVE_TACKLE); + VarSet(VAR_TEMP_6, MOVE_SPLASH); + VarSet(VAR_TEMP_7, MOVE_CELEBRATE); + VarSet(VAR_TEMP_8, MOVE_EXPLOSION); + VarSet(VAR_TEMP_9, TRUE); + VarSet(VAR_TEMP_A, TRUE); + VarSet(VAR_TEMP_B, TYPE_FIRE); + + RUN_OVERWORLD_SCRIPT( + givemon VAR_TEMP_C, VAR_TEMP_D, item=VAR_0x8000, ball=VAR_0x8001, nature=VAR_0x8002, abilityNum=VAR_0x8003, gender=VAR_0x8004, hpEv=VAR_0x8005, atkEv=VAR_0x8006, defEv=VAR_0x8007, speedEv=VAR_0x8008, spAtkEv=VAR_0x8009, spDefEv=VAR_0x800A, hpIv=VAR_0x800B, atkIv=VAR_TEMP_0, defIv=VAR_TEMP_1, speedIv=VAR_TEMP_2, spAtkIv=VAR_TEMP_3, spDefIv=VAR_TEMP_4, move1=VAR_TEMP_5, move2=VAR_TEMP_6, move3=VAR_TEMP_7, move4=VAR_TEMP_8, isShiny=VAR_TEMP_9, ggMaxFactor=VAR_TEMP_A, teraType=VAR_TEMP_B; + ); + + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_SPECIES), SPECIES_WOBBUFFET); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_LEVEL), 100); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_HELD_ITEM), ITEM_LEFTOVERS); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_POKEBALL), ITEM_MASTER_BALL); + EXPECT_EQ(GetNature(&gPlayerParty[0]), NATURE_BOLD); + EXPECT_EQ(GetMonAbility(&gPlayerParty[0]), gSpeciesInfo[SPECIES_WOBBUFFET].abilities[2]); + EXPECT_EQ(GetMonGender(&gPlayerParty[0]), MON_MALE); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_HP_EV), 1); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_ATK_EV), 2); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_DEF_EV), 3); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_SPEED_EV), 4); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_SPATK_EV), 5); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_SPDEF_EV), 6); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_HP_IV), 7); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_ATK_IV), 8); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_DEF_IV), 9); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_SPEED_IV), 10); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_SPATK_IV), 11); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_SPDEF_IV), 12); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_MOVE1), MOVE_TACKLE); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_MOVE2), MOVE_SPLASH); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_MOVE3), MOVE_CELEBRATE); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_MOVE4), MOVE_EXPLOSION); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_IS_SHINY), TRUE); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_GIGANTAMAX_FACTOR), TRUE); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_TERA_TYPE), TYPE_FIRE); +}