Put random birds on the roofs of your towns! - Pawkkie/Team-Aquas-Asset-Repo GitHub Wiki
Very specific tutorial incoming: having bird Pokémon that randomly spawn on roofs is a stupidly easy way to add some life to your nice little towns!
Note: This tutorial uses Poryscript. If you don't use Poryscript,
you shouldjust paste the code in the Poryscript Playground to convert it back to vanilla scripting!
Solution
In Porymap
Creating the object events
Let's start by opening our map and adding several new object events, each using one of the temp flags FLAG_TEMP_X
(of course, make sure they're not using a temp flag that you're already using in your map's scripts), and placing them on roofs. Each object event should look a bit like this:
Note: If you're using the Followers feature that should very soon be released in Expansion,
OBJ_EVENT_GFX_SPECIES(TAILLOW)
will work on its own, no need for you to add new graphics.
Collisions
To have the birds display properly and to avoid them escaping from their roof (we wouldn't want that!), make sure your house's collision looks like this:
The 4
tiles correspond to the Z coordinate of the birds. That way, the birds will be free to roam on all the 4
tiles, but will not step on the regular 3
tiles.
Metatile layers
Make sure those 4
roof metatiles look like this in the tileset editor:
Since they're drawn on the middle layer and not on the top layer, the birds will not be hidden by the roof tiles!
Adding the Bird Behaviour
To add the behaviour for the birds you have two options:
-
In your town's scripts file - This method allows you to configure the behaviour more precicely per map, creating different behaviours in different areas.
-
In your src folder (C) - This method allows you to configure the same behaviour and trigger it more easily from a special/directly from C in
RunOnLoadMapScript
.
In your town's scripts file
Now let's add something like this to the mapscripts (or edit the MAP_SCRIPT_ON_LOAD
if you already have one):
mapscripts YourMap_MapScripts {
+ MAP_SCRIPT_ON_LOAD {
+ // Set all the flags used by the birds so that they start out all hidden
+ setflag(FLAG_TEMP_1)
+ setflag(FLAG_TEMP_2)
+ setflag(FLAG_TEMP_3)
+ setflag(FLAG_TEMP_4)
+ random(4)
+ switch(var(VAR_RESULT)) {
+ case 0:
+ // This will display only the bird(s) using FLAG_TEMP_1
+ clearflag(FLAG_TEMP_1)
+ case 1:
+ // This will display only the bird(s) using FLAG_TEMP_2
+ clearflag(FLAG_TEMP_2)
+ case 2:
+ clearflag(FLAG_TEMP_4)
+ case 3:
+ // Adding a little variety by having several birds at once in this case
+ clearflag(FLAG_TEMP_1)
+ clearflag(FLAG_TEMP_3)
+ }
}
Once you've added bird behaviours like this to each of your maps, you're finished.
Alternatively:
In your src folder (C)
trainer_types.h
In include/constants/trainer_types.h
add an entry that will identify your birds. For example:
+ #define TRAINER_TYPE_BIRD 4
- NOTE: ADD THIS TRAINER TYPE TO YOUR BIRD OBJECT EVENTS THAT YOU CREATED ABOVE.
field_specials.c
Once you've done so, include that header in src/field_specials.c
like so:
+ #include "constants/trainer_types.h"
As well as these files (used in the upcoming function):
+ #include "battle_pyramid.h"
+ #include "trainer_hill.h"
and then add this function to the bottom of the file:
#define MAX_BIRD_SPOTS 10
static const u8 randomBirdArray[MAX_BIRD_SPOTS + 1][4] =
{
[0] = { 0, 0, 0, 0 },
[1] = { 1, 0, 1, 0 },
[2] = { 1, 0, 1, 0 },
[3] = { 2, 1, 1, 0 },
[4] = { 2, 1, 1, 0 },
[5] = { 2, 1, 2, 0 },
[6] = { 3, 2, 2, 1 },
[7] = { 3, 2, 3, 2 },
[8] = { 4, 2, 3, 2 },
[9] = { 4, 3, 3, 2 },
[10] = { 4, 3, 4, 3 },
};
void SetRoofBirds(void)
{
u8 i;
u8 objectEventCount;
struct ObjectEventTemplate *template;
u8 birdIndexes[MAX_BIRD_SPOTS + 1] = {0};
u32 birdCount = 0;
if (gMapHeader.events != NULL)
{
if (InBattlePyramid())
objectEventCount = GetNumBattlePyramidObjectEvents();
else if (InTrainerHill())
objectEventCount = HILL_TRAINERS_PER_FLOOR;
else
objectEventCount = gMapHeader.events->objectEventCount;
for (i = 0; i < objectEventCount; i++)
{
template = &gSaveBlock1Ptr->objectEventTemplates[i];
if (template->trainerType == TRAINER_TYPE_BIRD && birdCount <= MAX_BIRD_SPOTS)
{
birdIndexes[birdCount] = i; // Store index of bird
birdCount++;
}
}
if (birdCount > 0)
{
u8 visibleCount = randomBirdArray[birdCount][Random() % 4];
Shuffle8(birdIndexes, birdCount);
// Hide random birds until only `visibleCount` remain
for (i = visibleCount; i < birdCount; i++)
{
u8 birdIndex = birdIndexes[i];
template = &gSaveBlock1Ptr->objectEventTemplates[birdIndex];
FlagSet(template->flagId);
}
}
}
}
This function identifies object events on the current map by searching for the trainerType
: TRAINER_TYPE_BIRD
. It then makes a number of those object events visible according to the behaviour defined in randomBirdArray
, where the array key is the number of bird spots on the map and the numbers are the amount of birds to make visible (chooses one of the numbers at random).
To make the function run, you have two options:
-
Turn it into a special by adding
def_special SetRoofBirds
to yourdata/specials.inc
file and calling it within the map script as part ofMAP_SCRIPT_ON_LOAD
(similar to the poryscript above). -
Call it directly in
RunOnLoadMapScript(void)
inscr/script.c
, which will make it run on every single map by default (You'll have to addextern void SetRoofBirds(void);
just above).
Result
And that's it!
Now that your birds are happily hopping around, you can customize them however you want (replacing them with Zubat at night, adding a shiny bird with a very slim chance of showing, etc). Now go, and spread the bird love in your own hack!