Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add createmon Script Cmd, Support for 2v1Wild Battles #4688

Merged
merged 6 commits into from
Jun 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 69 additions & 1 deletion asm/macros/event.inc
Original file line number Diff line number Diff line change
Expand Up @@ -997,7 +997,69 @@
@ 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, 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
callnative ScrCmd_createmon
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it correct that both script commands are named ScrCmd_createmon?

Also is there a way to combine both scripts since most of it is the same?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both just call the same function which I edited to handle the addition inputs.

As far as using the same macros.. I don't think so since most are optional, but I could be wrong

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both just call the same function which I edited to handle the addition inputs.

Right.

Though for some reason the CI fails for tests without having run any tests

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both just call the same function which I edited to handle the addition inputs.

Right.

Though for some reason the CI fails for tests without having run any tests

yeah I don't get that... its saying PARTY_SIZE is undefined, but global.h is included which includes constants/global.h where that is defined...

.byte 0
.byte 6 @ PARTY_SIZE - assign to first empty slot
.set givemon_flags, 0
.2byte \species
.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

@ creates a mon for a given party and slot
@ otherwise
.macro createmon side:req, slot:req, 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_createmon
.byte \side @ 0 - player, 1 - opponent
.byte \slot @ 0-5
.set givemon_flags, 0
.2byte \species
.2byte \level
Expand Down Expand Up @@ -2233,3 +2295,9 @@
.byte \sourceId
.byte \targetId
.endm

@ set the wild double battle flag
@ can be used in conjunection with createmon to set up a wild battle with 2 player mons vs. 1 enemy mon
.macro setwilddoubleflag
callnative ScriptSetDoubleBattleFlag
.endm
1 change: 0 additions & 1 deletion include/script_pokemon_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
#define GUARD_SCRIPT_POKEMON_UTIL_H

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);
Expand Down
5 changes: 5 additions & 0 deletions src/scrcmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -2467,3 +2467,8 @@ bool8 ScrCmd_warpwhitefade(struct ScriptContext *ctx)
ResetInitialPlayerAvatarState();
return TRUE;
}

void ScriptSetDoubleBattleFlag(struct ScriptContext *ctx)
{
sIsScriptedWildDouble = TRUE;
}
67 changes: 42 additions & 25 deletions src/script_pokemon_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,11 @@ void SetTeraType(struct ScriptContext *ctx)
SetMonData(&gPlayerParty[partyIndex], MON_DATA_TERA_TYPE, &type);
}

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)
/* Creates a Pokemon via script
* if side/slot are assigned, it will create the mon at the assigned party location
* if slot == PARTY_SIZE, it will give the mon to first available party or storage slot
*/
static u32 ScriptGiveMonParameterized(u8 side, u8 slot, 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;
Expand Down Expand Up @@ -408,34 +412,43 @@ u32 ScriptGiveMonParameterized(u16 species, u8 level, u16 item, u8 ball, u8 natu
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 (slot < PARTY_SIZE)
{
if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES, NULL) == SPECIES_NONE)
break;
}
if (i >= PARTY_SIZE)
{
sentToPc = CopyMonToPC(&mon);
if (side == 0)
CopyMon(&gPlayerParty[slot], &mon, sizeof(struct Pokemon));
else
CopyMon(&gEnemyParty[slot], &mon, sizeof(struct Pokemon));
sentToPc = MON_GIVEN_TO_PARTY;
}
else
{
sentToPc = MON_GIVEN_TO_PARTY;
CopyMon(&gPlayerParty[i], &mon, sizeof(mon));
gPlayerPartyCount = i + 1;
// 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)
if (side == 0)
{
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;
// set pokédex flags
nationalDexNum = SpeciesToNationalPokedexNum(species);
if (sentToPc != MON_CANT_GIVE)
{
GetSetPokedexFlag(nationalDexNum, FLAG_SET_SEEN);
GetSetPokedexFlag(nationalDexNum, FLAG_SET_CAUGHT);
}
}

return sentToPc;
Expand All @@ -448,13 +461,17 @@ u32 ScriptGiveMon(u16 species, u8 level, u16 item)
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_PERSONALITY, MON_GENDERLESS, evs, ivs, moves, FALSE, FALSE, NUMBER_OF_MON_TYPES);
return ScriptGiveMonParameterized(0, PARTY_SIZE, species, level, item, ITEM_POKE_BALL, NUM_NATURES, NUM_ABILITY_PERSONALITY, 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)
/* Give or create a mon to either player or opponent
*/
void ScrCmd_createmon(struct ScriptContext *ctx)
{
u8 side = ScriptReadByte(ctx);
u8 slot = ScriptReadByte(ctx);
u16 species = VarGet(ScriptReadHalfword(ctx));
u8 level = VarGet(ScriptReadHalfword(ctx));

Expand Down Expand Up @@ -488,7 +505,7 @@ void ScrCmd_givemon(struct ScriptContext *ctx)
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);
gSpecialVar_Result = ScriptGiveMonParameterized(side, slot, species, level, item, ball, nature, abilityNum, gender, evs, ivs, moves, isShiny, ggMaxFactor, teraType);
}

#undef PARSE_FLAG
Expand Down
15 changes: 15 additions & 0 deletions test/pokemon.c
Original file line number Diff line number Diff line change
Expand Up @@ -340,3 +340,18 @@ TEST("checkteratype/setteratype work")
);
EXPECT(VarGet(VAR_RESULT) == TYPE_FIRE);
}

TEST("createmon [simple]")
{
ZeroPlayerPartyMons();

RUN_OVERWORLD_SCRIPT(
createmon 1, 0, SPECIES_WOBBUFFET, 100;
createmon 1, 1, SPECIES_WYNAUT, 10;
);

EXPECT_EQ(GetMonData(&gEnemyParty[0], MON_DATA_SPECIES), SPECIES_WOBBUFFET);
EXPECT_EQ(GetMonData(&gEnemyParty[0], MON_DATA_LEVEL), 100);
EXPECT_EQ(GetMonData(&gEnemyParty[1], MON_DATA_SPECIES), SPECIES_WYNAUT);
EXPECT_EQ(GetMonData(&gEnemyParty[1], MON_DATA_LEVEL), 10);
}
Loading