-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Useful Scripting Specials
This page will add some new scripting commands that may be useful for developing more advanced scripts.
All specials need to be added to the table in data/specials.inc
following other special definitions
Table of Contents:
- Remove All Of an Item
- Get An Object's Position
- Check an Object at a Position
- Get Seen/Caught Mon
- Set Seen/Caught Mon
- Set Mon Ball
- Check For Species
- Get An Object's Facing Direction
credits to Pawwkie
Remove all of a specific item from the player's bag, regardless of how many the player has.
- First, our scripting macro:
@ Remove all of specified item from the player's bag
.macro removeallitem itemId:req
callnative RemoveAllItem
.2byte \itemId
.endm
- Next, our special. Best suited for
src/scrcmd.c
.
void RemoveAllItem(struct ScriptContext *ctx)
{
u16 itemId = VarGet(ScriptReadHalfword(ctx));
RemoveBagItem(itemId, CountTotalItemQuantityInBag(itemId));
}
credits to ghoulslash
This command will get either the map template position, or the current position of any object.
- First, our scripting macro:
@ return current (posType = 0) or map (posType = 1) position of object to VAR_0x8007 (x), VAR_0x8008 (y)
.macro getobjectxy localId:req, posType:req
setvar VAR_0x8000, \localId
setvar VAR_0x8001, \posType
special GetObjectPosition
.endm
- Next, our special. You can add this to any .c file, I suggest src/event_object_movement or src/field_specials.c
// get position (0 for current, 1 for map) of object event, return to VAR_0x8007, VAR_0x8008
void GetObjectPosition(void)
{
u16 localId = gSpecialVar_0x8000;
u16 useTemplate = gSpecialVar_0x8001;
u16 *x = &gSpecialVar_0x8007;
u16 *y = &gSpecialVar_0x8008;
if (!useTemplate)
{
/* current position */
const u16 objId = GetObjectEventIdByLocalId(localId);
const struct ObjectEvent *objEvent = &gObjectEvents[objId];
*x = objEvent->currentCoords.x - 7; // subtract out camera size
*y = objEvent->currentCoords.y - 7;
}
else
{
const struct ObjectEventTemplate *objTemplate =
FindObjectEventTemplateByLocalId(localId,
gSaveBlock1Ptr->objectEventTemplates,
gMapHeader.events->objectEventCount);
*x = objTemplate->x;
*y = objTemplate->y;
}
}
credits to ghoulslash
Checks in any object is at a given position
- scripting macro
@ checks if there is any object at a given position
.macro checkobjectat x:req, y:req
setorcopyvar VAR_0x8005, \x
setorcopyvar VAR_0x8006, \y
specialvar VAR_RESULT, CheckObjectAtXY
.endm
- code
// special to check if there is any object at a given position
u16 CheckObjectAtXY(void)
{
u16 x = gSpecialVar_0x8005 + 7;
u16 y = gSpecialVar_0x8006 + 7;
u32 i;
for (i = 0; i < OBJECT_EVENTS_COUNT; i++)
{
if (gObjectEvents[i].active && gObjectEvents[i].currentCoords.x == x && gObjectEvents[i].currentCoords.y == y)
return TRUE;
}
return FALSE;
}
Credits to Lunos.
These commands will check the state of either the Seen or the Caught Pokédex flags of a species whose ID stored in VAR_TEMP_1
.
- First, our scripting macros:
@ Checks the state of the Pokédex Seen flag of the specified Pokemon
@ The result is stored in VAR_RESULT
.macro getseenmon species:req
setvar VAR_TEMP_1, \species
specialvar VAR_RESULT, GetSeenMon
.endm
@ Checks the state of the Pokédex Caught flag of the specified Pokemon
@ The result is stored in VAR_RESULT
.macro getcaughtmon species:req
setvar VAR_TEMP_1, \species
specialvar VAR_RESULT, GetCaughtMon
.endm
- Next, our special functions. You can add them to any .c file, although since these are meant to be used from the overworld, I suggest
src/field_specials.c
specifically.
bool8 GetSeenMon(void)
{
return GetSetPokedexFlag(SpeciesToNationalPokedexNum(VarGet(VAR_TEMP_1)), FLAG_GET_SEEN);
}
bool8 GetCaughtMon(void)
{
return GetSetPokedexFlag(SpeciesToNationalPokedexNum(VarGet(VAR_TEMP_1)), FLAG_GET_CAUGHT);
}
Keep in mind that in order to access FLAG_GET_SEEN
and FLAG_GET_CAUGHT
, you must use the #include
directive to read the contents of the include/pokedex.h
.
In other words, you need to add a #include "pokedex.h"
to the list of headers at the top of the file.
To use them, simply type either getseenmon
or getcaughtmon
in your script, followed by the species ID. For example, getcaughtmon SPECIES_MAGIKARP
.
The result (either TRUE
or FALSE
) will be stored in VAR_RESULT
.
Credits to Lunos.
These commands will set either the Seen or the Caught Pokédex flags of a species whose ID stored in VAR_TEMP_1
.
- First, our scripting macros:
@ Sets the Pokédex Seen flag of the specified Pokemon
.macro setseenmon species:req
setvar VAR_TEMP_1, \species
special SetSeenMon
.endm
@ Sets the Pokédex Caught flag of the specified Pokemon
.macro setcaughtmon species:req
setvar VAR_TEMP_1, \species
special SetCaughtMon
.endm
- Next, our special functions. You can add them to any .c file, although since these are meant to be used from the overworld, I suggest
src/field_specials.c
specifically.
void SetSeenMon(void)
{
GetSetPokedexFlag(SpeciesToNationalPokedexNum(VarGet(VAR_TEMP_1)), FLAG_SET_SEEN);
}
void SetCaughtMon(void)
{
GetSetPokedexFlag(SpeciesToNationalPokedexNum(VarGet(VAR_TEMP_1)), FLAG_SET_SEEN);
GetSetPokedexFlag(SpeciesToNationalPokedexNum(VarGet(VAR_TEMP_1)), FLAG_SET_CAUGHT);
}
Keep in mind that in order to access FLAG_SET_SEEN
and FLAG_SET_CAUGHT
, you must use the #include
directive to read the contents of the include/pokedex.h
.
In other words, you need to add a #include "pokedex.h"
to the list of headers at the top of the file.
To use them, simply type either setseenmon
or setcaughtmon
in your script, followed by the species ID. For example, setcaughtmon SPECIES_MAGIKARP
.
Credits to Lunos.
This command will let you modify the caught ball of a Pokémon that is chosen by the Player.
- First, our scripting macro:
@ Changes the caught ball of a selected Pokémon
.macro setmonball ballId:req
special ChoosePartyMon
waitstate
setvar VAR_TEMP_1, \ballId
special SetMonBall
.endm
- Next, our special function. You can add it to any .c file, although since it's meant to be used from the overworld, I suggest
src/field_specials.c
specifically.
void SetMonBall(void)
{
u16 ballId = VarGet(VAR_TEMP_1);
SetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_POKEBALL, &ballId);
}
To use it, simply type setmonball
in your script followed by the desired Poké Ball Item ID. For example, setmonball ITEM_PREMIER_BALL
.
Credits to Lunos.
This command will let you check if the Player has a specific species in their party, either silently or through the usage of the special ChoosePartyMon
.
- First, our scripting macro:
OPEN_PARTY_SCREEN = FALSE
NO_PARTY_SCREEN = TRUE
@ Check if the Player has \speciesId in their party.
.macro checkforspecies speciesId:req, silent:req, script:req
.if \silent == OPEN_PARTY_SCREEN
special ChoosePartyMon
waitstate
specialvar VAR_RESULT, ScriptGetPartyMonSpecies
goto_if_eq VAR_RESULT, \speciesId, \script
.else
setvar VAR_TEMP_1, \speciesId
specialvar VAR_RESULT, CheckPartyForMon
goto_if_eq VAR_RESULT, TRUE, \script
.endif
.endm
- Next, a special function that will allow us to silently check the entire party for our species, in case we want to do that.
bool8 CheckPartyForMon(void)
{
int i;
for (i = 0; i < CalculatePlayerPartyCount(); i++)
{
if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES) == VarGet(VAR_TEMP_1))
return TRUE;
}
return FALSE;
}
Using this macro is very easy, you just need to call it in a script and provide a species constant, a mode (silent or not) and a script to jump to if it turns out that the Player does have the specified species. If they don't, the script you used this macro in will keep running like normal.
Here's a quick example of its usage:
Route101_EventScript_RouteSign::
checkforspecies SPECIES_TORCHIC, NO_PARTY_SCREEN, Route101_EventScript_RouteSign_HasTorchic
msgbox Route101_EventScript_Text_NoTorchic, MSGBOX_DEFAULT
release
end
Route101_EventScript_RouteSign_HasTorchic::
msgbox Route101_EventScript_Text_HasTorchic, MSGBOX_DEFAULT
release
end
Route101_EventScript_Text_NoTorchic:
.string "You don't have a TORCHIC.$"
Route101_EventScript_Text_HasTorchic:
.string "You have a TORCHIC!$"
Credits to Lunos.
This command will let you check the direction at which an object event on a map is facing, which in turn allows you to handle edge cases in overworld scripts that deal with lots of movement.
- First, our scripting macro:
@ Gets the facing direction of a given event object and stores it in the variable \dest.
.macro getobjectfacingdirection evObjId:req, dest:req
setvar VAR_TEMP_1, \evObjId
specialvar \dest, Script_GetObjectFacingDirection
.endm
- Next, a special function that will return the facing direction of the event object whose Local ID (i.e. the object's ID on the current map) is stored in the temporary variable
VAR_TEMP_1
.
u8 Script_GetObjectFacingDirection(void)
{
u8 objId = GetObjectEventIdByLocalId(VarGet(VAR_TEMP_1));
return gObjectEvents[objId].facingDirection;
}
NOTE: This function can be added in src/event_object_movement.c
directly, or one can turn GetObjectEventIdByLocalId
into a global function and put it elsewhere.
And we're done.
This macro is as easy to use as the other ones in this document.
You just invoke getobjectfacingdirection
, feed it an event object's Local ID and then a variable to store their facing directon.
Here's a quick example of its usage:
Route101_EventScript_RouteSign::
getobjectfacingdirection OBJ_EVENT_ID_PLAYER, VAR_TEMP_1
goto_if_eq VAR_TEMP_1, DIR_NORTH, Route101_EventScript_RouteSign_North
goto_if_eq VAR_TEMP_1, DIR_SOUTH, Route101_EventScript_RouteSign_South
goto_if_eq VAR_TEMP_1, DIR_WEST, Route101_EventScript_RouteSign_West
goto_if_eq VAR_TEMP_1, DIR_EAST, Route101_EventScript_RouteSign_East
end
Route101_EventScript_RouteSign_North:
msgbox Route101_Text_RouteSign_North, MSGBOX_DEFAULT
release
end
Route101_EventScript_RouteSign_South:
msgbox Route101_Text_RouteSign_South, MSGBOX_DEFAULT
release
end
Route101_EventScript_RouteSign_West:
msgbox Route101_Text_RouteSign_West, MSGBOX_DEFAULT
release
end
Route101_EventScript_RouteSign_East:
msgbox Route101_Text_RouteSign_East, MSGBOX_DEFAULT
release
end
Route101_Text_RouteSign_North:
.string "The Player is facing North!$"
Route101_Text_RouteSign_South:
.string "The Player is facing South!$"
Route101_Text_RouteSign_West:
.string "The Player is facing West!$"
Route101_Text_RouteSign_East:
.string "The Player is facing East!$"