This commit is contained in:
Bivurnum 2026-03-21 23:38:08 +01:00 committed by GitHub
commit 12ebf1cb83
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
46 changed files with 3269 additions and 149 deletions

View File

@ -2832,6 +2832,21 @@
.byte \status
.endm
@ Makes the player and selected object (if there is one) face one another.
.macro facetogether
callnative ScriptFaceEachOther
.endm
@ Starts an Overworld Wild Encounter with a selected object, if possible.
.macro tryoverworldwildencounter
callnative StartWildBattleWithOWE
.endm
@ Start a scripted approach for an overworld wild encounter towards the player.
.macro overworldwildencounterapproach
callnative OWEApproachForBattle
.endm
@ FRLG

View File

@ -1737,3 +1737,4 @@ EventScript_PalletTown_PlayersHouse_2F_TurnOnPC::
.include "data/scripts/dexnav.inc"
.include "data/scripts/battle_frontier.inc"
.include "data/scripts/apricorn_tree.inc"
.include "data/scripts/wild_encounter.inc"

View File

@ -87,6 +87,7 @@ gFieldEffectScriptPointers::
.4byte gFldEffScript_SmileyFaceIcon @ FLDEFF_SMILEY_FACE_ICON
.4byte gFieldEffectScript_HallOfFameRecordFrlg @ FLDEFF_HALL_OF_FAME_RECORD_FRLG
.4byte gFldEffScript_PhotoFlash @ FLDEFF_PHOTO_FLASH
.4byte gFieldEffectScript_OWE_SpawnAnim @ FLDEFF_OW_ENCOUNTER_SPAWN_ANIM
gFieldEffectScript_ExclamationMarkIcon1::
field_eff_callnative FldEff_ExclamationMarkIcon
@ -415,3 +416,7 @@ gFieldEffectScript_HallOfFameRecordFrlg::
gFldEffScript_PhotoFlash::
field_eff_callnative FldEff_PhotoFlash
field_eff_end
gFieldEffectScript_OWE_SpawnAnim::
field_eff_callnative FldEff_OWE_SpawnAnim
field_eff_end

View File

@ -0,0 +1,11 @@
InteractWithOverworldWildEncounter::
lock
overworldwildencounterapproach
applymovement VAR_LAST_TALKED, Common_Movement_ExclamationMark
facetogether
playmoncry VAR_0x8004, CRY_MODE_DOUBLES
waitmoncry
tryoverworldwildencounter
waitstate
end

View File

@ -47,6 +47,7 @@
- [Struct Pokemon Generation](tutorials/mon_generation.md)
- [How to use FRLG](tutorials/how_to_frlg.md)
- [How to delete vanilla maps](tutorials/how_to_delete_vanilla_maps.md)
- [How to use Overworld Wild Encounters](tutorials/how_to_overworld_wild_encounters.md)
- [Changelog](./CHANGELOG.md)
- [1.15.x]()
- [Version 1.15.0](changelogs/1.15.x/1.15.0.md)

View File

@ -0,0 +1,117 @@
# Overworld Wild Encounters Tutorial
## OWE Spawning
Overworld Wild Encounters (OWEs), refer to the wild encounters that can be seen as object events in the overworld, prior to engaging in battle with them. They use either the `WILD_AREA_LAND` or `WILD_AREA_WATER` encounter tables by default. OWEs come in two types, Generated or Manual.
### Generated OWEs
Generated OWEs are spawned automatically when `WE_OW_ENCOUNTERS` is set to `TRUE`, being spawned on a random encounter tile near the player, with the encounter table used dependant on it. These are considered low priority OWEs, and automatically populate a level, species, gender and shinyness exactly how a vanilla wild encounter would, or can even be a special spawn, but more on those later.
> Setting `OW_GFX_COMPRESS` to `FALSE` will free more space in VRAM, allowing for more large OWEs to spawn, and reducing the chance of running into a tiles error when trying to spawn Generated OWEs.
### Manual OWEs
Manual OWEs are created by the developer as any other object event would be and are defined by having the `.trainerType` set to `TRAINER_TYPE_OW_WILD_ENCOUNTER`. These can be fully customised by the developer, with the level, species, gender and shinyness all able to be specified. The level can be set by filling the desired value in the `trainerRange_berryTreeId`. The latter three are specified by the `graphicsId` of the object, for example;
- `OBJ_EVENT_GFX_SPECIES(BULBASAUR)` will produce a male, non-shiny Bulbasaur.
- `OBJ_EVENT_GFX_SPECIES_SHINY(CHARMANDER)` will produce a male, shiny Charmander.
- `OBJ_EVENT_GFX_SPECIES_FEMALE(SQUIRTLE)` will produce a female, non-shiny Squirtle.
- `OBJ_EVENT_GFX_SPECIES_SHINY_FEMALE(PIKACHU)` will produce a female, shiny Pikachu.
However, Manual OWEs do not have to be defined fully, leaving any of the level, species, gender, shinyness or script unspecified will revert to default behaviours. If left blank, the level or species will be generated from the relevant encounter table. Leaving the shinyness blank will revert to default shiny odds, although this can still be affected by `P_FLAG_FORCE_SHINY` and `P_FLAG_FORCE_NO_SHINY`. Setting the `OBJ_EVENT_MON` bit of the `graphicsId`, but not the `OBJ_EVENT_MON_FEMALE` will result in a male encounter, setting both will result in a female encounter, as seen above, but setting neither will randomise the gender based on species. A species can be defined with a random gender by just using the species define. A specific script can be specified, but if not the default OWE encounter script will be used.
Assuming the following `graphicsId` have `.trainerType` set to `TRAINER_TYPE_OW_WILD_ENCOUNTER`;
- `SPECIES_EEVEE` will result in an Eevee with a randomised level, gender and shinyness, using the default encounter script.
- `OBJ_EVENT_GFX_SPECIES(NONE)` will result in a male randomised species of randomised level, gender and shinyness, using the default encounter script.
- `OBJ_EVENT_GFX_SPECIES_SHINY_FEMALE(NONE)` will result in a female, shiny randomised species with randomised level and gender, using the default encounter script.
As level and species are potentially taken from the Wild Encounter Header, there is an `assertf` to let developers know when an invalid value is used. If the resultant level is invalid, it will be set to `MIN_LEVEL` (1). If the species is invalid, a replacement object will be created using `OBJ_EVENT_GFX_BOY_1`, this will not be an OWE of any kind.
No matter how much of a Manual OWE is defined, it is considered a high priority OWE, and treated as a regular object event in all ways other than ones outlined above. They will always spawn, regardless of level or abilties of player Pokémon. However, they cannot be special spawns.
> When a manual OWE is removed, for whatever reason, it's flag is also set. Because of this, we recommend giving them temporary flags so they can be reset on leaving the map.
### Special Spawns
Special spawns can be one of three types, in decreasing priority: A Roamer, Feebas, or Mass Outbreak Encounter. Generated OWEs can have any of these, however, Manual OWEs can only have the Feebas Special Spawn. These work exactly as they would normally;
- If a Roamer is on the route and is able to spawn, then it may appear where a Generated OWE would.
- If any OWE spawns on a tile where a Feebas special fishing spot is, it may appear is a Feebas (only if `WE_OWE_FEEBAS_SPOTS` is TRUE).
- If a Generated OWE spawns on a route that has a mass outbreak occuring, it may spawn as an encounter from that mass outbreak.
`OWE_MAX_ROAMERS` limits the max number of total roamers to 253 in order to fit the relevant info within the `ObjectEvent` struct.
### Restricted Despawning
There are three configs that can be used to restrict the despawning of Generated OWEs.
- If `WE_OWE_PREVENT_SHINY_DESPAWN` is set to `TRUE`, any Generated OWE that spawns as shiny will not be despawned if they go outside of the viewable area. They can still be despawned off-screen if the player goes to another map. This config also ensures that shiny Generated OWEs will never be despawned and replaced if `WE_OWE_SPAWN_REPLACEMENT` is `TRUE`.
- If `WE_OWE_PREVENT_FEEBAS_DESPAWN` is set to `TRUE`, any Generated OWE that is a Feebas spawned from a Feebas fishing spot will follow the same rules as `WE_OWE_PREVENT_SHINY_DESPAWN` above.
- If `WE_OWE_DESPAWN_ON_ENTER_TOWN` is set to `TRUE`, all Generated OWEs will be instantly despawned upon the player crossing a map connection into a map with a map type of either `MAP_TYPE_TOWN` or `MAP_TYPE_CITY`, like what happens in Scarlet/Violet.
None of these three configs can prevent the forceful despawning of OWEs to free up limited resources, as is explained in the next section.
## High Priority and Low Priority OWEs
Low Priority OWEs may not be spawned or even be destroyed in certain situations. There are checks to prevent these from spawning if it would fail, including for the number of event objects, palettes and object tiles. There are also similar checks, when spawning object events other than Low Priotity OWEs. These checks will despawn the oldest of Low Priority OWEs when other objects event are attempting to be spawned and Low Priority OWEs are using these resources. Low Priority OWEs may also be destroyed by NPC object events colliding with them due to their movements or the OWE being in the way of a trainer interaction. High priority OWEs are treated as regular objects and will not be destroyed in the ways outlined above, but may cause the destruction of Generated OWEs and will not face spawning restrictions.
These despawn conditions will overwrite the restrictive despawns mentioned above.
## Encountering an OWE
Any collision between the player and the OWE will start an encounter. An encounter will also start if the player interacts with the OWE with the A button.
If the `WE_OWE_APPROACH_FOR_BATTLE` config is `TRUE`, the OWE will take steps to be right next to the player before the battle begins. Otherwise, the objects will be frozen and the battle will start immediately.
A player on land is able to interact with an OWE in the water, only by pressing the A button.
## Repel and Lure Behaviours
Repels will prevent the spawning of generated OWEs that are a lower level than the player's lead Pokemon. Lower level generated OWEs that have already been spawned will be immediately despawned when a repel is used. Existing generated OWEs can also be despawned if the player switches a higher level Pokemon to the front of the party if a repel is already active.
Lures increasse the frequency of generated OWE spawning.
## OWE Behaviour Types
The behaviors that these OWEs have is set up to be customizable for each individual species. By default, every species is set to `OWE_IGNORE_PLAYER`. To add a different behavior to a species, find their species struct in their `gen_X_families.h` file in the `src/data/pokemon/species_info` folder and add a `.overworldEncounterBehavior = <BEHAVIOR>` to it. `<BEHAVIOR>` should be replaced with the behavior you want them to use. For example, if I wanted to add the `OWE_FLEE_PLAYER_NORMAL` behavior to Mudkip I would open `gen_3_families.h`, find the struct for `SPECIES_MUDKIP`, and add `.overworldEncounterBehavior = OWE_FLEE_PLAYER_NORMAL` to the end of it like so:
```diff
.eggMoveLearnset = sMudkipEggMoveLearnset,
.evolutions = EVOLUTION({EVO_LEVEL, 16, SPECIES_MARSHTOMP}),
+ .overworldEncounterBehavior = OWE_FLEE_PLAYER_NORMAL
},
[SPECIES_MARSHTOMP] =
{
.baseHP = 70,
```
The behaviors themselves are defined in `src/data/pokemon/wild_encounter_overworld_behavior.h`. These are the customizable parameters:
- `movementType` is the movement type you want the object event to have. More on these in the next section.
- `viewDistance` is the number of tiles away the mon is able to notice the player in the cardinal directions (similar to the sight distance of trainers).
- `viewWidth` is the total width of the area in which the mon will notice the player. For example, if `viewWidth` is set to `3`, the mon will be able to detect the player if they are within 1 tile of either side of the line of sight.
- `activeDistance` is the max distance away from the mon that the player can be before the mon loses track of them and goes back to wandering.
- `idleSpeed` is the speed at which the mon will take a step while wandering (player is not noticed). This must be one of the values in `enum SpeedOWE`.
- `activeSpeed` is the speed at which the mon will take a step while active (player has been noticed). This must be one of the values in `enum SpeedOWE`.
If any of these parameters are not defined, they will be automatically assigned the value of `0`.
A small number of premade behaviors have been provided and are ready to use. You can add as many new custom behaviors as you like, but make sure to add each behavior to `enum OverworldWildEncounterBehaviors`, making sure that `OWE_SPECIES_BEHAVIOR_COUNT` is always at the end.
The same behavior can be used for multiple different species.
## OWE Movements
While OWE objects can be given any movement type, there are several different custom movement types that were made specifically for OWEs:
- The basic one is `MOVEMENT_TYPE_WANDER_AROUND_OWE`. All of the other OWE movement types start with this behavior and differentiate into other behavior when they notice the player. Similar to `MOVEMENT_TYPE_WANDER_AROUND`, the object will take steps in random directions at random intervals. The main difference here is that the object will never turn more than 90 degrees from their current facing direction when taking a step. OWEs with this movement type will completely ignore the player until they are directly collided/interacted with.
- `MOVEMENT_TYPE_CHASE_PLAYER_OWE` will switch the OWE to chasing down the player when it notices the player. The OWE is still blocked by collision, but does have the intelligence to walk around small obstacles. They will go back to wandering if the player goes outside of their sight radius.
- `MOVEMENT_TYPE_FLEE_PLAYER_OWE` will switch the OWE to fleeing from the player when it notices the player. They use the same pathfinding logic as `MOVEMENT_TYPE_CHASE_PLAYER_OWE`, but in the opposite direction from the player. They will go back to wandering if the player goes outside of their sight radius. If `WE_OWE_FLEE_DESPAWN` is set to `TRUE`, the fleeing OWE will despawn if it is unable to take a step for a short amount of time (ie, if they are cornered).
- `MOVEMENT_TYPE_WATCH_PLAYER_OWE` will switch the OWE to stand in place and always face in the direction of the player's location when the player is noticed by it. They will go back to wandering if the player goes outside of their sight radius.
- `MOVEMENT_TYPE_APPROACH_PLAYER_OWE` will switch the OWE to approach the player as if curious when it notices the player. The OWE will try to keep a one tile gap between itself and the player. They may also occasionally do an excited hop. They will go back to wandering if the player goes outside of their sight radius.
- `MOVEMENT_TYPE_DESPAWN_OWE` will make the OWE do a very brief animation of surprise and then instantly despawn when it notices the player.
### Restricted Movements
There are two configs that can restrict the movement of OWEs. Both are `TRUE` by default.
- `WE_OWE_RESTRICT_METATILE` will restrict OWE movement to the metatile type they spawned on. For example, if an OWE spawns in a grass patch they will not be able to leave that grass patch.
- `WE_OWE_RESTRICT_MAP` will prevent OWEs from leaving the map that they were spawned in.
Regardless of configs, OWEs cannot move from water onto land, or vice versa.
### How Data is Saved
Some existing members of the `ObjectEvent` struct have been repurposed for OWEs. This has no effect on the existing functionality outside of OWEs.
```
struct ObjectEvent
{
u8 warpArrowSpriteId; // Stores roamer status for Overworld Encounters, as well as some bit flags.
u8 trainerRange_berryTreeId; // Stores the level for Overworld Encounters.
u8 playerCopyableMovement; // Stores the age for Overworld Encounters.
}
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 606 B

View File

@ -7,7 +7,7 @@ void CallBattlePyramidFunction(void);
u16 LocalIdToPyramidTrainerId(u8 localId);
bool8 GetBattlePyramidTrainerFlag(u8 eventId);
void MarkApproachingPyramidTrainersAsBattled(void);
void GenerateBattlePyramidWildMon(void);
void GenerateBattlePyramidWildMon(enum Species forceSpecies);
u8 GetPyramidRunMultiplier(void);
u8 CurrentBattlePyramidLocation(void);
bool8 InBattlePyramid_(void);

View File

@ -49,14 +49,14 @@
// Overworld Pokémon
#define OW_POKEMON_OBJECT_EVENTS TRUE // Adds Object Event fields for every species. Can be used for NPCs using the OBJ_EVENT_GFX_SPECIES macro (eg. OBJ_EVENT_GFX_SPECIES(BULBASAUR))
#define OW_SUBSTITUTE_PLACEHOLDER TRUE // Use a substitute OW for Pokémon that are missing overworld sprites
#define OW_LARGE_OW_SUPPORT TRUE // If true, adds a small amount of overhead to OW code so that large (48x48, 64x64) OWs will display correctly under bridges, etc.
#define OW_LARGE_OW_SUPPORT TRUE // If TRUE, adds a small amount of overhead to OW code so that large (48x48, 64x64) OWs will display correctly under bridges, etc.
#define OW_PKMN_OBJECTS_SHARE_PALETTES FALSE // [WIP!! NOT ALL PALETTES HAVE BEEN ADJUSTED FOR THIS!!] If TRUE, follower palettes are taken from battle sprites.
#define OW_GFX_COMPRESS TRUE // Adds support for compressed OW graphics, (Also compresses pokemon follower graphics).
// IMPORTANT: Gfx are loaded into VRAM to avoid continous decompression. If you require more VRAM or want to use a lot of overworld Pokémon at once, you should disable this config.
// Compressed gfx are incompatible with non-power-of-two sprite sizes:
// (You should not use 48x48 sprites/tables for compressed gfx)
// 16x32, 32x32, 64x64 etc are fine
#define OW_MON_WANDER_WALK TRUE // If true, OW pokemon with MOVEMENT_TYPE_WANDER will walk-in-place in between steps.
#define OW_MON_WANDER_WALK TRUE // If TRUE, OW Pokémon with MOVEMENT_TYPE_WANDER will walk-in-place in between steps.
// Follower Pokémon
#define OW_FOLLOWERS_ENABLED FALSE // Enables follower Pokémon, HGSS style. Requires OW_POKEMON_OBJECT_EVENTS. Note that additional scripting may be required for them to be fully supported!
#define OW_FOLLOWERS_BOBBING TRUE // If TRUE, follower Pokémon will bob up and down during their idle & walking animations
@ -148,4 +148,15 @@
// Trainer Rematches
#define OW_REMATCH_BADGE_COUNT 5 // Number of badges necessary before the match call or vs seeker features allow rematches
// Ambient Cries
// Constants
#define OW_AMBIENT_CRIES_NONE 0 // Do not play ambient cries.
#define OW_AMBIENT_CRIES_VANILLA 1 // Play ambient cries taken from encounter tables, as in vanilla.
#define OW_AMBIENT_CRIES_OWE_PRIORITY 2 // Play ambient cries based on active Overworld Wild Encounters, reverting to vanilla cries if none are present.
#define OW_AMBIENT_CRIES_OWE_ONLY 3 // Play ambient cries based on active Overworld Wild Encounters only.
// Overworld Wild Encounters will play ambient cries based on their location relative to the player.
// Configuration
#define OW_AMBIENT_CRIES OW_AMBIENT_CRIES_VANILLA // Selects how ambient cries are played, if at all. As in vanilla, no matter what is chosen, cries will not play if the player is not on a map with Land or Water encounter tables.
#endif // GUARD_CONFIG_OVERWORLD_H

View File

@ -0,0 +1,30 @@
#ifndef GUARD_CONFIG_WILD_ENCOUNTER_OW_H
#define GUARD_CONFIG_WILD_ENCOUNTER_OW_H
// Vanilla
#define WE_VANILLA_RANDOM TRUE // If TRUE, Pokémon can randomly spawn on tiles that can trigger wild encounters, as in vanilla.
// Overworld Wild Encounters (OWEs)
#define WE_OW_ENCOUNTERS FALSE // If TRUE, OW Pokémon can spawn as Overworld Wild Encounters on the current map. Requires OW_POKEMON_OBJECT_EVENTS.
// If WE_OW_ENCOUNTERS is TRUE, it is recommended that OW_GFX_COMPRESS be set to FALSE to prevent VRAM issues.
#define WE_OWE_FLAG_DISABLED 0 // Replace 0 with a flag to use it to enable/disable generated OWEs.
#define WE_OWE_SPECIAL_ONLY FALSE // If TRUE, generated OWEs can only be special spawns.
#define WE_OWE_BATTLE_PIKE TRUE // If TRUE, OWEs can spawn in the Battle Pike, if FALSE random encounters will be enabled instead. Requires WE_OW_ENCOUNTERS to be TRUE.
#define WE_OWE_BATTLE_PYRAMID TRUE // If TRUE, OWEs can spawn in the Battle Pyramid, if FALSE random encounters will be enabled instead. Requires WE_OW_ENCOUNTERS to be TRUE.
#define WE_OWE_RESTRICT_METATILE TRUE // If TRUE, OWEs will stay within tiles with the same encounter metatile behavior as the one it is currently on, if any.
#define WE_OWE_RESTRICT_MAP TRUE // If TRUE, OWEs will stay within their current map bounds.
#define WE_OWE_UNRESTRICT_SIGHT FALSE // If TRUE, OWEs will ignore all movement restrictions when they can see the player.
#define WE_OWE_SPAWN_REPLACEMENT FALSE // If TRUE, the oldest OWE objects will despawn after a short time and be replaced with a new spawn if possible.
#define WE_OWE_FLEE_DESPAWN TRUE // If TRUE, a fleeing OWE will despawn if it is unable to take a step for a short time.
#define WE_OWE_SHINY_SPARKLE FALSE // If TRUE, shiny OWEs will spawn with a sparkle animation and play the shiny sound effect.
#define WE_OWE_FEEBAS_SPOTS FALSE // If TRUE, any spot that could result in a Feebas fishing encounter can spawn a Feebas OWE.
#define WE_OWE_DESPAWN_SOUND FALSE // If TRUE, plays SE_FLEE when an OWE despawns.
#define WE_OWE_APPROACH_FOR_BATTLE TRUE // If TRUE, OWEs will take steps to be right next to the player before the battle starts.
#define WE_OWE_PREVENT_SHINY_DESPAWN FALSE // If TRUE, shiny OWEs will not be despawned when off-screen if on the same map as the player, or be replaced if WE_OWE_SPAWN_REPLACEMENT is TRUE.
#define WE_OWE_PREVENT_FEEBAS_DESPAWN FALSE // If TRUE, Feebas OWEs spawned from special Feebas fishing spots (when WE_OWE_FEEBAS_SPOTS is TRUE) will not be despawned when off-screen if on the same map as the player, or be replaced if WE_OWE_SPAWN_REPLACEMENT is TRUE.
#define WE_OWE_DESPAWN_ON_ENTER_TOWN TRUE // If TRUE, despawns all OWEs upon entering a city (MAP_TYPE_CITY) or town (MAP_TYPE_TOWN).
#define WE_OWE_REPEL_DEXNAV_COLLISION FALSE // If TRUE, OWEs can still be triggered by a collision if a Repel or the DexNav is active.
// Should move others from config/overworld.h here?
#endif // GUARD_CONFIG_WILD_ENCOUNTER_OW_H

View File

@ -85,7 +85,13 @@
#define MOVEMENT_TYPE_WALK_SLOWLY_IN_PLACE_RIGHT 0x50
#define MOVEMENT_TYPE_FOLLOW_PLAYER 0x51
#define MOVEMENT_TYPE_WANDER_AROUND_SLOWER 0x52
#define NUM_MOVEMENT_TYPES 0x53
#define MOVEMENT_TYPE_WANDER_AROUND_OWE 0x53
#define MOVEMENT_TYPE_CHASE_PLAYER_OWE 0x54
#define MOVEMENT_TYPE_FLEE_PLAYER_OWE 0x55
#define MOVEMENT_TYPE_WATCH_PLAYER_OWE 0x56
#define MOVEMENT_TYPE_APPROACH_PLAYER_OWE 0x57
#define MOVEMENT_TYPE_DESPAWN_OWE 0x58
#define NUM_MOVEMENT_TYPES 0x59
#define MOVEMENT_ACTION_FACE_DOWN 0x0
#define MOVEMENT_ACTION_FACE_UP 0x1

View File

@ -491,28 +491,26 @@ enum
#define OBJ_KIND_NORMAL 0
#define OBJ_KIND_CLONE 255 // Exclusive to FRLG
// Special object event local ids
// Used for link player OWs in CreateLinkPlayerSprite
#define OBJ_EVENT_ID_DYNAMIC_BASE 0xF0
// Each object event template gets an ID that can be used to refer to it in scripts and elsewhere.
// This is referred to as the "local id" (and it's really just 1 + its index in the templates array).
// There are a few special IDs reserved for objects that don't have templates in the map data -- one for the player
// in regular offline play, five for linked players while playing Berry Blender, and one for an invisible object that
// can be spawned for the camera to track instead of the player. Additionally, the value 0 is reserved as an "empty" indicator.
#define LOCALID_NONE 0
#define LOCALID_CAMERA 127
#define LOCALID_BERRY_BLENDER_PLAYER_END 240 // This will use 5 (MAX_RFU_PLAYERS) IDs ending at 240, i.e. 236-240
#define LOCALID_FOLLOWING_POKEMON 254
#define LOCALID_PLAYER 255
#define OBJ_EVENT_ID_FOLLOWER 0xFE
#define OBJ_EVENT_ID_NPC_FOLLOWER 0xFD
#define LOCALID_NONE 0
#define LOCALID_CAMERA 127
#define LOCALID_BERRY_BLENDER_PLAYER_END 240 // This will use 5 (MAX_RFU_PLAYERS) IDs ending at 240, i.e. 236-240
#define LOCALID_OW_ENCOUNTER_END 252 // This will use 4 (OWE_SPAWNS_MAX) IDs ending at 252, i.e. 249-252
#define LOCALID_FOLLOWING_POKEMON 254
#define LOCALID_PLAYER 255
#define OBJ_EVENT_ID_FOLLOWER 0xFE
#define OBJ_EVENT_ID_NPC_FOLLOWER 0xFD
// Aliases for old names. "object event id" normally refers to an index into gObjectEvents, which these are not.
// Used for link player OWs in CreateLinkPlayerSprite
#define OBJ_EVENT_ID_DYNAMIC_BASE 0xF0
#define OBJ_EVENT_ID_CAMERA LOCALID_CAMERA
#define OBJ_EVENT_ID_PLAYER LOCALID_PLAYER
#define OBJ_EVENT_ID_DYNAMIC_BASE 0xF0
// Moved from src/event_object_movement.c so that they're accesible from other files.
#define OBJ_EVENT_PAL_TAG_BRENDAN 0x1100

View File

@ -83,6 +83,7 @@
#define FLDEFF_SMILEY_FACE_ICON 78
#define FLDEFF_HALL_OF_FAME_RECORD_FRLG 79
#define FLDEFF_PHOTO_FLASH 80
#define FLDEFF_OW_ENCOUNTER_SPAWN_ANIM 81
#define FLDEFFOBJ_SHADOW_S 0
#define FLDEFFOBJ_SHADOW_M 1
@ -129,6 +130,7 @@
#define FLDEFFOBJ_ROCK_CLIMB_DUST 42
#define FLDEFFOBJ_ORAS_DOWSE_BRENDAN 43
#define FLDEFFOBJ_ORAS_DOWSE_MAY 44
#define FLDEFFOBJ_SHINY_SPARKLE 45
#define FLDEFF_PAL_TAG_CUT_GRASS 0x1000
#define FLDEFF_PAL_TAG_SECRET_POWER_TREE 0x1003

View File

@ -28,6 +28,7 @@
#include "config/overworld.h"
#include "config/pokemon.h"
#include "config/summary_screen.h"
#include "config/wild_encounter.h"
// Invalid Versions show as "----------" in Gen 4 and Gen 5's summary screen.
// In Gens 6 and 7, invalid versions instead show "a distant land" in the summary screen.

View File

@ -5,5 +5,6 @@
#define TRAINER_TYPE_NORMAL 1
#define TRAINER_TYPE_SEE_ALL_DIRECTIONS 2
#define TRAINER_TYPE_BURIED 3
#define TRAINER_TYPE_OW_WILD_ENCOUNTER 0xFF
#endif // GUARD_CONSTANTS_TRAINER_TYPES_H

View File

@ -9,4 +9,7 @@
#define NUM_ALTERING_CAVE_TABLES 9
#define WILD_CHECK_REPEL (1 << 0)
#define WILD_CHECK_KEEN_EYE (1 << 1)
#endif // GUARD_CONSTANTS_WILD_ENCOUNTER_H

View File

@ -123,6 +123,11 @@ extern const u8 gReflectionEffectPaletteMap[];
extern const struct SpriteFrameImage gPicTable_PechaBerryTree[];
extern const struct SpritePalette gSpritePalette_GeneralFieldEffect0;
extern const struct SpritePalette gSpritePalette_GeneralFieldEffect1;
extern const enum Direction gStandardDirections[];
void ResetObjectEvents(void);
u8 GetMoveDirectionAnimNum(enum Direction direction);
u8 GetObjectEventIdByLocalIdAndMap(u8 localId, u8 mapNum, u8 mapGroupId);
@ -182,17 +187,20 @@ void InitObjectEventPalettes(u8 reflectionType);
void UpdateObjectEventCurrentMovement(struct ObjectEvent *objectEvent, struct Sprite *sprite, bool8 (*callback)(struct ObjectEvent *, struct Sprite *));
bool8 ObjectEventFaceOppositeDirection(struct ObjectEvent *objectEvent, enum Direction direction);
enum Direction GetOppositeDirection(enum Direction direction);
enum Direction GetNinetyDegreeDirection(enum Direction direction, bool32 clockwise);
u8 GetWalkInPlaceFasterMovementAction(u32);
u8 GetWalkInPlaceFastMovementAction(u32);
u8 GetWalkInPlaceNormalMovementAction(u32);
u8 GetWalkInPlaceSlowMovementAction(u32);
enum Collision GetCollisionAtCoords(struct ObjectEvent *objectEvent, s16 x, s16 y, enum Direction dir);
bool8 IsMetatileDirectionallyImpassable(struct ObjectEvent *objectEvent, s16 x, s16 y, enum Direction direction);
u32 GetObjectObjectCollidesWith(struct ObjectEvent *objectEvent, s16 x, s16 y, bool32 addCoords);
void MoveCoords(enum Direction direction, s16 *x, s16 *y);
bool8 ObjectEventIsHeldMovementActive(struct ObjectEvent *objectEvent);
u8 ObjectEventClearHeldMovementIfFinished(struct ObjectEvent *objectEvent);
u8 GetObjectEventIdByPosition(u16 x, u16 y, u8 elevation);
void SetTrainerMovementType(struct ObjectEvent *objectEvent, u8 movementType);
u8 GetCollisionInDirection(struct ObjectEvent *, enum Direction);
u8 GetTrainerFacingDirectionMovementType(enum Direction direction);
const u8 *GetObjectEventScriptPointerByObjectEventId(u8 objectEventId);
u8 GetCollisionFlagsAtCoords(struct ObjectEvent *objectEvent, s16 x, s16 y, enum Direction direction);
@ -260,11 +268,17 @@ u8 GetObjectEventBerryTreeId(u8 objectEventId);
void SetBerryTreeJustPicked(u8 mapId, u8 mapNumber, u8 mapGroup);
bool8 IsBerryTreeSparkling(u8 localId, u8 mapNum, u8 mapGroup);
const struct ObjectEventTemplate *GetObjectEventTemplateByLocalIdAndMap(u8 localId, u8 mapNum, u8 mapGroup);
u16 LoadSheetGraphicsInfo(const struct ObjectEventGraphicsInfo *info, u16 uuid, struct Sprite *sprite);
u8 TrySpawnObjectEventTemplate(const struct ObjectEventTemplate *objectEventTemplate, u8 mapNum, u8 mapGroup, s16 cameraX, s16 cameraY);
bool8 GetFollowerInfo(u32 *species, bool32 *shiny, bool32 *female);
const struct ObjectEventGraphicsInfo *SpeciesToGraphicsInfo(enum Species species, bool32 shiny, bool32 female);
u32 LoadDynamicFollowerPalette(enum Species species, bool32 shiny, bool32 female);
u16 GetObjectEventFlagIdByLocalIdAndMap(u8 localId, u8 mapNum, u8 mapGroup);
void CopyObjectGraphicsInfoToSpriteTemplate(u16 graphicsId, void (*callback)(struct Sprite *), struct SpriteTemplate *spriteTemplate, const struct SubspriteTable **subspriteTables);
bool8 AreElevationsCompatible(u8, u8);
enum Direction DetermineObjectEventDirectionFromObject(struct ObjectEvent *objectOne, struct ObjectEvent *objectTwo);
void ObjectEventsTurnToEachOther(struct ObjectEvent *objectOne, struct ObjectEvent *objectTwo);
void UpdateObjectEventCoords(struct ObjectEvent *objectEvent, s16 dx, s16 dy);
void MovementType_None(struct Sprite *sprite);
void MovementType_LookAround(struct Sprite *sprite);
@ -521,4 +535,37 @@ bool8 PlayerIsUnderWaterfall(struct ObjectEvent *objectEvent);
u8 GetObjectEventApricornTreeId(u8 objectEventId);
// Overworld Wild Encounter
bool8 MovementAction_OverworldEncounterSpawn(enum SpawnDespawnTypeOWE spawnAnimType, struct ObjectEvent *objEvent);
void MovementType_OverworldWildEncounter_WanderAround(struct Sprite *sprite);
void MovementType_OverworldWildEncounter_ChasePlayer(struct Sprite *sprite);
void MovementType_OverworldWildEncounter_FleePlayer(struct Sprite *sprite);
void MovementType_OverworldWildEncounter_WatchPlayer(struct Sprite *sprite);
void MovementType_OverworldWildEncounter_ApproachPlayer(struct Sprite *sprite);
void MovementType_OverworldWildEncounter_Despawn(struct Sprite *sprite);
u8 MovementType_OverworldWildEncounter_WanderAround_Step2(struct ObjectEvent *objectEvent, struct Sprite *sprite);
u8 MovementType_OverworldWildEncounter_WanderAround_Step3(struct ObjectEvent *objectEvent, struct Sprite *sprite);
u8 MovementType_OverworldWildEncounter_WanderAround_Step4(struct ObjectEvent *objectEvent, struct Sprite *sprite);
u8 MovementType_OverworldWildEncounter_WanderAround_Step5(struct ObjectEvent *objectEvent, struct Sprite *sprite);
u8 MovementType_OverworldWildEncounter_Common_Step7(struct ObjectEvent *objectEvent, struct Sprite *sprite);
u8 MovementType_OverworldWildEncounter_ChasePlayer_Step8(struct ObjectEvent *objectEvent, struct Sprite *sprite);
u8 MovementType_OverworldWildEncounter_Common_Step9(struct ObjectEvent *objectEvent, struct Sprite *sprite);
u8 MovementType_OverworldWildEncounter_ChasePlayer_Step10(struct ObjectEvent *objectEvent, struct Sprite *sprite);
u8 MovementType_OverworldWildEncounter_ChasePlayer_Step11(struct ObjectEvent *objectEvent, struct Sprite *sprite);
u8 MovementType_OverworldWildEncounter_Common_Step12(struct ObjectEvent *objectEvent, struct Sprite *sprite);
u8 MovementType_OverworldWildEncounter_FleePlayer_Step8(struct ObjectEvent *objectEvent, struct Sprite *sprite);
u8 MovementType_OverworldWildEncounter_FleePlayer_Step10(struct ObjectEvent *objectEvent, struct Sprite *sprite);
u8 MovementType_OverworldWildEncounter_FleePlayer_Step11(struct ObjectEvent *objectEvent, struct Sprite *sprite);
u8 MovementType_OverworldWildEncounter_WatchPlayer_Step8(struct ObjectEvent *objectEvent, struct Sprite *sprite);
u8 MovementType_OverworldWildEncounter_WatchPlayer_Step10(struct ObjectEvent *objectEvent, struct Sprite *sprite);
u8 MovementType_OverworldWildEncounter_WatchPlayer_Step11(struct ObjectEvent *objectEvent, struct Sprite *sprite);
u8 MovementType_OverworldWildEncounter_ApproachPlayer_Step8(struct ObjectEvent *objectEvent, struct Sprite *sprite);
u8 MovementType_OverworldWildEncounter_ApproachPlayer_Step10(struct ObjectEvent *objectEvent, struct Sprite *sprite);
u8 MovementType_OverworldWildEncounter_ApproachPlayer_Step11(struct ObjectEvent *objectEvent, struct Sprite *sprite);
u8 MovementType_OverworldWildEncounter_Despawn_Step8(struct ObjectEvent *objectEvent, struct Sprite *sprite);
u8 MovementType_OverworldWildEncounter_Despawn_Step10(struct ObjectEvent *objectEvent, struct Sprite *sprite);
u8 MovementType_OverworldWildEncounter_Despawn_Step11(struct ObjectEvent *objectEvent, struct Sprite *sprite);
#endif //GUARD_EVENT_OBJECT_MOVEMENT_H

View File

@ -1,6 +1,8 @@
#ifndef GUARD_FIELD_EFFECTS_H
#define GUARD_FIELD_EFFECTS_H
#include "field_weather.h"
extern const struct SpritePalette gNewGameBirchObjectPaletteInfo;
extern const struct SpriteTemplate gNewGameBirchObjectTemplate;
extern const struct OamData gNewGameBirchOamAttributes;
@ -23,6 +25,7 @@ void MultiplyInvertedPaletteRGBComponents(u16 i, u8 r, u8 g, u8 b);
void FieldEffectActiveListAdd(u8 id);
void FieldEffectScript_LoadTiles(u8 **script);
void FieldEffectScript_LoadFadedPalette(u8 **script);
void FieldEffect_LoadFadedPalette(struct SpritePalette *palette, enum ColorMapType colorMap);
void FieldEffectScript_LoadPalette(u8 **script);
void FieldEffectScript_CallNative(u8 **script, u32 *val);
void FieldEffectFreeGraphicsResources(struct Sprite *sprite);

View File

@ -62,6 +62,8 @@ void CopySecondaryTilesetToVram(struct MapLayout const *mapLayout);
const struct MapHeader *const GetMapHeaderFromConnection(const struct MapConnection *connection);
const struct MapConnection *GetMapConnectionAtPos(s16 x, s16 y);
void MapGridSetMetatileImpassabilityAt(int x, int y, bool32 impassable);
bool32 AreCoordsInsideMap(u8 mapGroup, u8 mapNum, s16 x, s16 y);
bool32 AreCoordsInsidePlayerMap(s16 x, s16 y);
// field_region_map.c
void FieldInitRegionMap(MainCallback callback);

View File

@ -3,6 +3,7 @@
#include "contest_effect.h"
#include "sprite.h"
#include "wild_encounter_ow.h"
#include "constants/battle.h"
#include "constants/cries.h"
#include "constants/egg_ids.h"
@ -518,6 +519,7 @@ struct SpeciesInfo /*0xC4*/
#endif //P_GENDER_DIFFERENCES
#endif //OW_PKMN_OBJECTS_SHARE_PALETTES
#endif //OW_POKEMON_OBJECT_EVENTS
enum OverworldWildEncounterBehaviors overworldEncounterBehavior;
};
struct EggData
@ -731,6 +733,7 @@ void ZeroMonData(struct Pokemon *mon);
void ZeroPlayerPartyMons(void);
void ZeroEnemyPartyMons(void);
u32 GetMonPersonality(enum Species species, u8 gender, u8 nature, u8 unownLetter);
bool32 ComputePlayerShinyOdds(u32 personality, u32 value);
void CreateMon(struct Pokemon *mon, enum Species species, u8 level, u32 personality, struct OriginalTrainerId);
void CreateRandomMon(struct Pokemon *mon, enum Species species, u8 level);
void CreateRandomMonWithIVs(struct Pokemon *mon, enum Species species, u8 level, u8 fixedIv);
@ -944,5 +947,11 @@ struct BoxPokemon *GetSelectedBoxMonFromPcOrParty(void);
u32 GiveScriptedMonToPlayer(struct Pokemon *mon, u8 slot);
void ChangePokemonNicknameWithCallback(void (*callback)(void));
bool32 HasShedinjaHPHandling(enum Species species);
u32 OWE_GetMovementTypeFromSpecies(enum Species speciesId);
u32 OWE_GetViewDistanceFromSpecies(enum Species speciesId);
u32 OWE_GetViewWidthFromSpecies(enum Species speciesId);
u32 OWE_GetViewActiveDistanceFromSpecies(enum Species speciesId);
enum SpeedOWE OWE_GetIdleSpeedFromSpecies(enum Species speciesId);
enum SpeedOWE OWE_GetActiveSpeedFromSpecies(enum Species);
#endif // GUARD_POKEMON_H

View File

@ -307,6 +307,7 @@ u16 LoadSpriteSheet(const struct SpriteSheet *sheet);
u16 LoadSpriteSheetByTemplate(const struct SpriteTemplate *template, u32 frame, s32 offset);
void LoadSpriteSheets(const struct SpriteSheet *sheets);
s16 AllocSpriteTiles(u16 tileCount);
bool32 CanAllocSpriteTiles(u16 tileCount);
void FreeSpriteTilesByTag(u16 tag);
void FreeSpriteTileRanges(void);
u16 GetSpriteTileStartByTag(u16 tag);
@ -339,5 +340,6 @@ void SetupSpritesForTextPrinting(u8 *spriteIds, const u32 **spriteSrc, u32 numSp
u32 *GetSrcPtrFromSprite(struct Sprite *sprite);
u32 GetSpriteWidth(struct Sprite *sprite);
u32 GetSpriteHeight(struct Sprite *sprite);
u32 CountFreePaletteSlots(void);
#endif //GUARD_SPRITE_H

View File

@ -3,6 +3,7 @@
#include "rtc.h"
#include "constants/wild_encounter.h"
#include "wild_encounter_ow.h"
#define HEADER_NONE 0xFFFF
@ -45,10 +46,14 @@ struct WildPokemonHeader
extern const struct WildPokemonHeader gWildMonHeaders[];
extern const struct WildPokemonHeader gBattlePikeWildMonHeaders[];
extern const struct WildPokemonHeader gBattlePyramidWildMonHeaders[];
extern const struct WildPokemon gWildFeebas;
extern bool8 gIsFishingEncounter;
extern bool8 gIsSurfingEncounter;
extern u8 gChainFishingDexNavStreak;
u8 ChooseWildMonLevel(const struct WildPokemon *wildPokemon, u8 wildMonIndex, enum WildPokemonArea area);
void DisableWildEncounters(bool8 disabled);
bool8 StandardWildEncounter(u16 curMetatileBehavior, u16 prevMetatileBehavior);
bool8 SweetScentWildEncounter(void);
@ -57,11 +62,18 @@ void FishingWildEncounter(u8 rod);
u16 GetLocalWildMon(bool8 *isWaterMon);
u16 GetLocalWaterMon(void);
bool8 UpdateRepelCounter(void);
bool8 IsWildLevelAllowedByRepel(u8 wildLevel);
bool8 IsAbilityAllowingEncounter(u8 level);
bool8 TryDoDoubleWildBattle(void);
bool8 StandardWildEncounter_Debug(void);
u32 CalculateChainFishingShinyRolls(void);
void CreateWildMon(enum Species species, u8 level);
bool8 TryGenerateWildMon(const struct WildPokemonInfo *wildMonInfo, enum WildPokemonArea area, u8 flags);
bool8 SetUpMassOutbreakEncounter(u8 flags);
bool8 DoMassOutbreakEncounterTest(void);
bool8 AreLegendariesInSootopolisPreventingEncounters(void);
u16 GetCurrentMapWildMonHeaderId(void);
bool8 CheckFeebasAtCoords(s16 x, s16 y);
u32 ChooseWildMonIndex_Land(void);
u32 ChooseWildMonIndex_Water(void);
u32 ChooseWildMonIndex_Rocks(void);

View File

@ -0,0 +1,93 @@
#ifndef GUARD_WILD_ENCOUNTER_OW_H
#define GUARD_WILD_ENCOUNTER_OW_H
#define OWE_APPROACH_DISTANCE 2
#define OWE_APPROACH_JUMP_TIMER_MIN 16
#define OWE_APPROACH_JUMP_TIMER_MAX 64
#define OWE_FLEE_COLLISION_TIME 6 // If a fleeing mon is unable to take a step for this many tries it will despawn. (Multiply this value by 16 to get number of frames.)
#define OWE_DESPAWN_FRAMES 30 // Number of frames before a mon despawns after noticing the player (OWE_BEHAVIOR_DESPAWN)
enum SpawnDespawnTypeOWE
{
OWE_SPAWN_ANIM_GRASS,
OWE_SPAWN_ANIM_LONG_GRASS,
OWE_SPAWN_ANIM_WATER,
OWE_SPAWN_ANIM_UNDERWATER,
OWE_SPAWN_ANIM_CAVE,
OWE_SPAWN_ANIM_SHINY
};
enum TypeOWE
{
OWE_ANY,
OWE_GENERATED,
OWE_MANUAL
};
// OWE_SPEED_FASTER seems to visually bug out sometimes.
enum SpeedOWE
{
OWE_SPEED_NORMAL,
OWE_SPEED_SLOW,
OWE_SPEED_FAST,
OWE_SPEED_FASTER
};
struct BehaviorOWE
{
u32 movementType:8;
u32 viewDistance:4;
u32 viewWidth:4;
u32 activeDistance:4;
u32 padding:12;
enum SpeedOWE idleSpeed;
enum SpeedOWE activeSpeed;
};
enum __attribute__((packed)) OverworldWildEncounterBehaviors
{
OWE_IGNORE_PLAYER,
OWE_CHASE_PLAYER_SLOW,
OWE_FLEE_PLAYER_NORMAL,
OWE_WATCH_PLAYER_NORMAL,
OWE_APPROACH_PLAYER_SLOW,
OWE_DESPAWN_ON_NOTICE,
OWE_SPECIES_BEHAVIOR_COUNT
};
void OverworldWildEncounters_CB(void);
bool32 IsOverworldWildEncounter(struct ObjectEvent *owe, enum TypeOWE oweType);
void StartWildBattleWithOWE(void);
void SetInstantOWESpawnTimer(void);
void SetMinimumOWESpawnTimer(void);
void TryTriggerOverworldWilEncounter(struct ObjectEvent *obstacle, struct ObjectEvent *collider);
bool32 ShouldRunDefaultOWEScript(u32 objectEventId);
void OnOverworldWildEncounterSpawn(struct ObjectEvent *owe);
void OnOverworldWildEncounterDespawn(struct ObjectEvent *owe);
bool32 IsOWEDespawnExempt(struct ObjectEvent *owe);
bool32 DespawnOWEDueToNPCCollision(struct ObjectEvent *curObject, struct ObjectEvent *owe);
u32 DespawnOWEDueToTrainerSight(u32 collision, s32 x, s32 y);
void DespwnAllOverworldWildEncounters(enum TypeOWE oweType, u32 flags);
bool32 TryAndDespawnOldestGeneratedOWE_Object(u32 localId, u8 *objectEventId);
void TryAndDespawnOldestGeneratedOWE_Palette(void);
void DespawnOWEOnBattleStart(void);
void TryDespawnOWEsCrossingMapConnection(void);
void RestoreSavedOWEBehaviorState(struct ObjectEvent *owe, struct Sprite *sprite);
void SetSavedOWEMovementState(struct ObjectEvent *owe);
void ClearSavedOWEMovementState(struct ObjectEvent *owe);
bool32 CheckRestrictedOWEMovement(struct ObjectEvent *owe, enum Direction direction);
bool32 CanAwareOWESeePlayer(struct ObjectEvent *owe);
bool32 IsPlayerInsideOWEActiveDistance(struct ObjectEvent *owe);
bool32 IsOWENextToPlayer(struct ObjectEvent *owe);
enum Direction DirectionOfOWEToPlayerFromCollision(struct ObjectEvent *owe);
u32 GetApproachingOWEDistanceToPlayer(struct ObjectEvent *owe, bool32 *equalDistances);
u32 GetOWEWalkMovementActionInDirectionWithSpeed(enum Direction direction, u32 speed);
void OWEApproachForBattle(void);
void PlayAmbientOWECry(void);
u32 GetNumberOfActiveOWEs(enum TypeOWE oweType);
const struct ObjectEventTemplate TryGetObjectEventTemplateForOWE(const struct ObjectEventTemplate *template);
struct SpritePalette GetOWESpawnDespawnAnimFldEffPalette(enum SpawnDespawnTypeOWE spawnAnim);
extern const u8 InteractWithOverworldWildEncounter[];
#endif // GUARD_WILD_ENCOUNTER_OW_H

View File

@ -1169,6 +1169,9 @@ $(FLDEFFGFXDIR)/secret_power_tree.4bpp: %.4bpp: %.png
$(FLDEFFGFXDIR)/record_mix_lights.4bpp: %.4bpp: %.png
$(GFX) $< $@ -mwidth 4 -mheight 1
$(FLDEFFGFXDIR)/shiny_sparkle.4bpp: %.4bpp: %.png
$(GFX) $< $@ -mwidth 2 -mheight 4
$(POKEMONGFXDIR)/question_mark/overworld.4bpp: %.4bpp: %.png
$(GFX) $< $@ -mwidth 4 -mheight 4

View File

@ -1395,7 +1395,7 @@ static bool32 CheckBattlePyramidEvoRequirement(enum Species species, const u16 *
}
extern u32 GetTotalBaseStat(enum Species species);
void GenerateBattlePyramidWildMon(void)
void GenerateBattlePyramidWildMon(enum Species forceSpecies)
{
u8 name[POKEMON_NAME_LENGTH + 1];
int i, j;
@ -1403,7 +1403,7 @@ void GenerateBattlePyramidWildMon(void)
u32 lvl = gSaveBlock2Ptr->frontier.lvlMode;
u16 round = (gSaveBlock2Ptr->frontier.pyramidWinStreaks[lvl] / 7) % TOTAL_PYRAMID_ROUNDS;
const struct BattlePyramidRequirement *reqs = &sBattlePyramidRequirementsByRound[round];
enum Species species;
enum Species species = forceSpecies;
u32 bstLim;
u16 *moves = NULL;
u16 *abilities = NULL;
@ -1423,7 +1423,8 @@ void GenerateBattlePyramidWildMon(void)
while (1)
{
species = Random() % NUM_SPECIES;
if (!forceSpecies)
species = Random() % NUM_SPECIES;
// check if base species
if (GET_BASE_SPECIES_ID(species) != species)
@ -1567,7 +1568,7 @@ void GenerateBattlePyramidWildMon(void)
CalculateMonStats(&gEnemyParty[0]);
}
#else
void GenerateBattlePyramidWildMon(void)
void GenerateBattlePyramidWildMon(enum Species forceSpecies)
{
u8 name[POKEMON_NAME_LENGTH + 1];
int i;

View File

@ -45,6 +45,7 @@
#include "item.h"
#include "script.h"
#include "field_name_box.h"
#include "wild_encounter_ow.h"
#include "constants/battle_frontier.h"
#include "constants/battle_setup.h"
#include "constants/event_objects.h"
@ -259,6 +260,7 @@ static void Task_BattleStart(u8 taskId)
SetMainCallback2(CB2_InitBattle);
RestartWildEncounterImmunitySteps();
ClearPoisonStepCounter();
DespawnOWEOnBattleStart();
DestroyTask(taskId);
}
break;

View File

@ -34,6 +34,7 @@ extern const struct SpriteTemplate gFieldEffectObjectTemplate_AshPuff;
extern const struct SpriteTemplate gFieldEffectObjectTemplate_AshLaunch;
extern const struct SpriteTemplate gFieldEffectObjectTemplate_Bubbles;
extern const struct SpriteTemplate gFieldEffectObjectTemplate_SmallSparkle;
extern const struct SpriteTemplate gFieldEffectObjectTemplate_ShinySparkle;
extern const struct SpriteTemplate gFieldEffectObjectTemplate_Rayquaza;
extern const struct SpriteTemplate gFieldEffectObjectTemplate_BallLight;
extern const struct SpriteTemplate gFieldEffectObjectTemplate_SlitherTracks;
@ -91,4 +92,5 @@ const struct SpriteTemplate *const gFieldEffectObjectTemplatePointers[] = {
[FLDEFFOBJ_ROCK_CLIMB_DUST] = &gFieldEffectObjectTemplate_RockClimbDust,
[FLDEFFOBJ_ORAS_DOWSE_BRENDAN] = &gFieldEffectObjectTemplate_ORASDowsingBrendan,
[FLDEFFOBJ_ORAS_DOWSE_MAY] = &gFieldEffectObjectTemplate_ORASDowsingMay,
[FLDEFFOBJ_SHINY_SPARKLE] = &gFieldEffectObjectTemplate_ShinySparkle,
};

View File

@ -1398,3 +1398,42 @@ const struct SpriteTemplate gFieldEffectObjectTemplate_RockClimbDust = {
};
const struct SpritePalette gSpritePalette_BigDust = {gFieldEffectPal_DustCloud, FLDEFF_PAL_TAG_DUST_CLOUD};
static const struct SpriteFrameImage sPicTable_ShinySparkle[] = {
overworld_frame(gFieldEffectObjectPic_ShinySparkle, 2, 4, 0),
overworld_frame(gFieldEffectObjectPic_ShinySparkle, 2, 4, 1),
overworld_frame(gFieldEffectObjectPic_ShinySparkle, 2, 4, 2),
overworld_frame(gFieldEffectObjectPic_ShinySparkle, 2, 4, 3),
overworld_frame(gFieldEffectObjectPic_ShinySparkle, 2, 4, 4),
overworld_frame(gFieldEffectObjectPic_ShinySparkle, 2, 4, 5),
overworld_frame(gFieldEffectObjectPic_ShinySparkle, 2, 4, 6),
overworld_frame(gFieldEffectObjectPic_ShinySparkle, 2, 4, 7),
};
static const union AnimCmd sAnim_ShinySparkle[] =
{
ANIMCMD_FRAME(0, 4),
ANIMCMD_FRAME(1, 4),
ANIMCMD_FRAME(2, 4),
ANIMCMD_FRAME(3, 6),
ANIMCMD_FRAME(4, 6),
ANIMCMD_FRAME(5, 4),
ANIMCMD_FRAME(6, 4),
ANIMCMD_FRAME(7, 4),
ANIMCMD_END,
};
static const union AnimCmd *const sAnimTable_ShinySparkle[] =
{
sAnim_ShinySparkle,
};
const struct SpriteTemplate gFieldEffectObjectTemplate_ShinySparkle = {
.tileTag = TAG_NONE,
.paletteTag = FLDEFF_PAL_TAG_GENERAL_0,
.oam = &gObjectEventBaseOam_16x32,
.anims = sAnimTable_ShinySparkle,
.images = sPicTable_ShinySparkle,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = UpdateBubblesFieldEffect,
};

View File

@ -1758,3 +1758,72 @@ u8 (*const gMovementActionFuncs_SpinRight[])(struct ObjectEvent *, struct Sprite
MovementAction_SpinRight_Step1,
MovementAction_PauseSpriteAnim,
};
#define OWE_WANDER_AROUND_COMMON_STEPS \
MovementType_WanderAround_Step0, \
MovementType_WanderAround_Step1, \
MovementType_OverworldWildEncounter_WanderAround_Step2, \
MovementType_OverworldWildEncounter_WanderAround_Step3, \
MovementType_OverworldWildEncounter_WanderAround_Step4, \
MovementType_OverworldWildEncounter_WanderAround_Step5, \
MovementType_WanderAround_Step6
u8 (*const gMovementTypeFuncs_WanderAround_OverworldWildEncounter[])(struct ObjectEvent *, struct Sprite *) =
{
OWE_WANDER_AROUND_COMMON_STEPS,
};
u8 (*const gMovementTypeFuncs_ChasePlayer_OverworldWildEncounter[])(struct ObjectEvent *, struct Sprite *) =
{
OWE_WANDER_AROUND_COMMON_STEPS,
MovementType_OverworldWildEncounter_Common_Step7,
MovementType_OverworldWildEncounter_ChasePlayer_Step8,
MovementType_OverworldWildEncounter_Common_Step9,
MovementType_OverworldWildEncounter_ChasePlayer_Step10,
MovementType_OverworldWildEncounter_ChasePlayer_Step11,
MovementType_OverworldWildEncounter_Common_Step12,
};
u8 (*const gMovementTypeFuncs_FleePlayer_OverworldWildEncounter[])(struct ObjectEvent *, struct Sprite *) =
{
OWE_WANDER_AROUND_COMMON_STEPS,
MovementType_OverworldWildEncounter_Common_Step7,
MovementType_OverworldWildEncounter_FleePlayer_Step8,
MovementType_OverworldWildEncounter_Common_Step9,
MovementType_OverworldWildEncounter_FleePlayer_Step10,
MovementType_OverworldWildEncounter_FleePlayer_Step11,
MovementType_OverworldWildEncounter_Common_Step12,
};
u8 (*const gMovementTypeFuncs_WatchPlayer_OverworldWildEncounter[])(struct ObjectEvent *, struct Sprite *) =
{
OWE_WANDER_AROUND_COMMON_STEPS,
MovementType_OverworldWildEncounter_Common_Step7,
MovementType_OverworldWildEncounter_WatchPlayer_Step8,
MovementType_OverworldWildEncounter_Common_Step9,
MovementType_OverworldWildEncounter_WatchPlayer_Step10,
MovementType_OverworldWildEncounter_WatchPlayer_Step11,
MovementType_OverworldWildEncounter_Common_Step12,
};
u8 (*const gMovementTypeFuncs_ApproachPlayer_OverworldWildEncounter[])(struct ObjectEvent *, struct Sprite *) =
{
OWE_WANDER_AROUND_COMMON_STEPS,
MovementType_OverworldWildEncounter_Common_Step7,
MovementType_OverworldWildEncounter_ApproachPlayer_Step8,
MovementType_OverworldWildEncounter_Common_Step9,
MovementType_OverworldWildEncounter_ApproachPlayer_Step10,
MovementType_OverworldWildEncounter_ApproachPlayer_Step11,
MovementType_OverworldWildEncounter_Common_Step12,
};
u8 (*const gMovementTypeFuncs_Despawn_OverworldWildEncounter[])(struct ObjectEvent *, struct Sprite *) =
{
OWE_WANDER_AROUND_COMMON_STEPS,
MovementType_OverworldWildEncounter_Common_Step7,
MovementType_OverworldWildEncounter_Despawn_Step8,
MovementType_OverworldWildEncounter_Common_Step9,
MovementType_OverworldWildEncounter_Despawn_Step10,
MovementType_OverworldWildEncounter_Despawn_Step11,
MovementType_OverworldWildEncounter_Common_Step12,
};

View File

@ -468,6 +468,8 @@ const u16 gFieldEffectObjectPalette_CaveDust[] = INCBIN_U16("graphics/field_effe
const u32 gObjectEventPic_ApricornTree[] = INCBIN_U32("graphics/object_events/pics/misc/apricorn_tree.4bpp");
const u32 gFieldEffectObjectPic_ShinySparkle[] = INCBIN_U32("graphics/field_effects/pics/shiny_sparkle.4bpp");
#if IS_FRLG
const u16 gObjectEventPic_RedNormal[] = INCBIN_U16("graphics/object_events/pics/people/red/red_normal.4bpp");

View File

@ -0,0 +1,68 @@
#ifndef GUARD_WILD_ENCOUNTER_OW_SPECIES_BEHAVIOR_H
#define GUARD_WILD_ENCOUNTER_OW_SPECIES_BEHAVIOR_H
#include "wild_encounter_ow.h"
#include "constants/event_object_movement.h"
static const struct BehaviorOWE sOWESpeciesBehavior[OWE_SPECIES_BEHAVIOR_COUNT] =
{
[OWE_IGNORE_PLAYER] =
{
.movementType = MOVEMENT_TYPE_WANDER_AROUND_OWE,
.viewDistance = 4,
.viewWidth = 3,
.activeDistance = 5,
.idleSpeed = OWE_SPEED_NORMAL,
.activeSpeed = OWE_SPEED_NORMAL,
},
[OWE_CHASE_PLAYER_SLOW] =
{
.movementType = MOVEMENT_TYPE_CHASE_PLAYER_OWE,
.viewDistance = 4,
.viewWidth = 3,
.activeDistance = 5,
.idleSpeed = OWE_SPEED_SLOW,
.activeSpeed = OWE_SPEED_SLOW,
},
[OWE_FLEE_PLAYER_NORMAL] =
{
.movementType = MOVEMENT_TYPE_FLEE_PLAYER_OWE,
.viewDistance = 4,
.viewWidth = 3,
.activeDistance = 5,
.idleSpeed = OWE_SPEED_NORMAL,
.activeSpeed = OWE_SPEED_NORMAL,
},
[OWE_WATCH_PLAYER_NORMAL] =
{
.movementType = MOVEMENT_TYPE_WATCH_PLAYER_OWE,
.viewDistance = 4,
.viewWidth = 3,
.activeDistance = 5,
.idleSpeed = OWE_SPEED_NORMAL,
},
[OWE_APPROACH_PLAYER_SLOW] =
{
.movementType = MOVEMENT_TYPE_APPROACH_PLAYER_OWE,
.viewDistance = 4,
.viewWidth = 3,
.activeDistance = 5,
.idleSpeed = OWE_SPEED_NORMAL,
.activeSpeed = OWE_SPEED_SLOW,
},
[OWE_DESPAWN_ON_NOTICE] =
{
.movementType = MOVEMENT_TYPE_DESPAWN_OWE,
.viewDistance = 4,
.viewWidth = 3,
.activeDistance = 5,
.idleSpeed = OWE_SPEED_NORMAL,
}
};
#endif // GUARD_WILD_ENCOUNTER_OW_SPECIES_BEHAVIOR_H

View File

@ -1828,6 +1828,7 @@ static void CB1_DexNavSearchCallback(void)
static void Task_DexNavExitAndSearch(u8 taskId)
{
DespwnAllOverworldWildEncounters(OWE_GENERATED, 0);
DexNavGuiFreeResources();
DestroyTask(taskId);
SetMainCallback1(CB1_DexNavSearchCallback);

View File

@ -41,6 +41,7 @@
#include "trainer_hill.h"
#include "util.h"
#include "wild_encounter.h"
#include "wild_encounter_ow.h"
#include "constants/event_object_movement.h"
#include "constants/abilities.h"
#include "constants/battle.h"
@ -60,7 +61,8 @@
#define SPECIAL_LOCALIDS_START (min(LOCALID_CAMERA, \
min(LOCALID_PLAYER, \
LOCALID_BERRY_BLENDER_PLAYER_END - MAX_RFU_PLAYERS + 1)))
min(LOCALID_BERRY_BLENDER_PLAYER_END - MAX_RFU_PLAYERS + 1, \
LOCALID_OW_ENCOUNTER_END - OWE_SPAWNS_MAX + 1))))
// The object event templates on a map cannot use the special IDs listed above or they can behave unexpectedly.
// For more details on these special IDs see their definitions in 'include/constants/event_objects.h'.
@ -130,13 +132,11 @@ static bool8 ObjectEventExecSingleMovementAction(struct ObjectEvent *, struct Sp
static bool32 UpdateMonMoveInPlace(struct ObjectEvent *, struct Sprite *);
static void SetMovementDelay(struct Sprite *, s16);
static bool8 WaitForMovementDelay(struct Sprite *);
static u8 GetCollisionInDirection(struct ObjectEvent *, enum Direction);
static enum Direction GetCopyDirection(u8, enum Direction, enum Direction);
static void TryEnableObjectEventAnim(struct ObjectEvent *, struct Sprite *);
static void ObjectEventExecHeldMovementAction(struct ObjectEvent *, struct Sprite *);
static void UpdateObjectEventSpriteAnimPause(struct ObjectEvent *, struct Sprite *);
static bool8 IsCoordOutsideObjectEventMovementRange(struct ObjectEvent *, s16, s16);
static bool8 IsMetatileDirectionallyImpassable(struct ObjectEvent *, s16, s16, enum Direction);
static bool8 DoesObjectCollideWithObjectAt(struct ObjectEvent *, s16, s16);
static void UpdateObjectEventOffscreen(struct ObjectEvent *, struct Sprite *);
static void UpdateObjectEventSpriteVisibility(struct ObjectEvent *, struct Sprite *);
@ -212,10 +212,8 @@ static u8 DoJumpSpriteMovement(struct Sprite *);
static u8 DoJumpSpecialSpriteMovement(struct Sprite *);
static void CreateLevitateMovementTask(struct ObjectEvent *);
static void DestroyLevitateMovementTask(u8);
static u32 LoadDynamicFollowerPalette(enum Species species, bool32 shiny, bool32 female);
const struct ObjectEventGraphicsInfo *SpeciesToGraphicsInfo(enum Species species, bool32 shiny, bool32 female);
static bool8 NpcTakeStep(struct Sprite *);
static bool8 AreElevationsCompatible(u8, u8);
static void CopyObjectGraphicsInfoToSpriteTemplate_WithMovementType(u16 graphicsId, u16 movementType, struct SpriteTemplate *spriteTemplate, const struct SubspriteTable **subspriteTables);
static u16 GetGraphicsIdForMon(enum Species species, bool32 shiny, bool32 female);
@ -345,6 +343,12 @@ static void (*const sMovementTypeCallbacks[])(struct Sprite *) =
[MOVEMENT_TYPE_WALK_SLOWLY_IN_PLACE_LEFT] = MovementType_WalkSlowlyInPlace,
[MOVEMENT_TYPE_WALK_SLOWLY_IN_PLACE_RIGHT] = MovementType_WalkSlowlyInPlace,
[MOVEMENT_TYPE_FOLLOW_PLAYER] = MovementType_FollowPlayer,
[MOVEMENT_TYPE_WANDER_AROUND_OWE] = MovementType_OverworldWildEncounter_WanderAround,
[MOVEMENT_TYPE_CHASE_PLAYER_OWE] = MovementType_OverworldWildEncounter_ChasePlayer,
[MOVEMENT_TYPE_FLEE_PLAYER_OWE] = MovementType_OverworldWildEncounter_FleePlayer,
[MOVEMENT_TYPE_WATCH_PLAYER_OWE] = MovementType_OverworldWildEncounter_WatchPlayer,
[MOVEMENT_TYPE_APPROACH_PLAYER_OWE] = MovementType_OverworldWildEncounter_ApproachPlayer,
[MOVEMENT_TYPE_DESPAWN_OWE] = MovementType_OverworldWildEncounter_Despawn,
};
static const bool8 sMovementTypeHasRange[NUM_MOVEMENT_TYPES] = {
@ -474,6 +478,12 @@ const u8 gInitialMovementTypeFacingDirections[NUM_MOVEMENT_TYPES] = {
[MOVEMENT_TYPE_WALK_SLOWLY_IN_PLACE_LEFT] = DIR_WEST,
[MOVEMENT_TYPE_WALK_SLOWLY_IN_PLACE_RIGHT] = DIR_EAST,
[MOVEMENT_TYPE_FOLLOW_PLAYER] = DIR_SOUTH,
[MOVEMENT_TYPE_WANDER_AROUND_OWE] = DIR_SOUTH,
[MOVEMENT_TYPE_CHASE_PLAYER_OWE] = DIR_SOUTH,
[MOVEMENT_TYPE_FLEE_PLAYER_OWE] = DIR_SOUTH,
[MOVEMENT_TYPE_WATCH_PLAYER_OWE] = DIR_SOUTH,
[MOVEMENT_TYPE_APPROACH_PLAYER_OWE] = DIR_SOUTH,
[MOVEMENT_TYPE_DESPAWN_OWE] = DIR_SOUTH,
};
#include "data/object_events/object_event_graphics_info_pointers.h"
@ -770,6 +780,7 @@ static const u16 *const sObjectPaletteTagSets[] = {
static const s16 sMovementDelaysMedium[] = {32, 64, 96, 128};
static const s16 sMovementDelaysLong[] = {32, 64, 128, 192}; // Unused
static const s16 sMovementDelaysShort[] = {32, 48, 64, 80};
static const s16 sMovementDelaysOWE[] = {64, 80, 96, 128};
#include "data/object_events/movement_type_func_tables.h"
@ -1284,6 +1295,19 @@ static const u8 sOppositeDirections[] = {
DIR_SOUTHEAST,
DIR_SOUTHWEST,
};
// Should this and above be enum Direction?
static const u8 sRotate90Direction[][2] =
{
[DIR_NONE] = { DIR_NONE, DIR_NONE },
[DIR_SOUTH] = { DIR_EAST, DIR_WEST },
[DIR_NORTH] = { DIR_WEST, DIR_EAST },
[DIR_WEST] = { DIR_SOUTH, DIR_NORTH },
[DIR_EAST] = { DIR_NORTH, DIR_SOUTH },
[DIR_SOUTHWEST] = { DIR_SOUTHEAST, DIR_NORTHWEST },
[DIR_SOUTHEAST] = { DIR_NORTHEAST, DIR_SOUTHWEST },
[DIR_NORTHWEST] = { DIR_SOUTHWEST, DIR_NORTHEAST },
[DIR_NORTHEAST] = { DIR_NORTHWEST, DIR_SOUTHEAST },
};
// Takes the player's original and current facing direction to get the direction that should be considered to copy.
// Note that this means an NPC who copies the player's movement changes how they copy them based on how
@ -1659,7 +1683,7 @@ static bool8 GetAvailableObjectEventId(u16 localId, u8 mapNum, u8 mapGroup, u8 *
return TRUE;
}
if (i >= OBJECT_EVENTS_COUNT)
return TRUE;
return TryAndDespawnOldestGeneratedOWE_Object(localId, objectEventId);
*objectEventId = i;
for (; i < OBJECT_EVENTS_COUNT; i++)
{
@ -1671,6 +1695,7 @@ static bool8 GetAvailableObjectEventId(u16 localId, u8 mapNum, u8 mapGroup, u8 *
void RemoveObjectEvent(struct ObjectEvent *objectEvent)
{
OnOverworldWildEncounterDespawn(objectEvent);
objectEvent->active = FALSE;
RemoveObjectEventInternal(objectEvent);
// zero potential species info
@ -1893,17 +1918,19 @@ static u8 TrySetupObjectEventSprite(const struct ObjectEventTemplate *objectEven
u8 TrySpawnObjectEventTemplate(const struct ObjectEventTemplate *objectEventTemplate, u8 mapNum, u8 mapGroup, s16 cameraX, s16 cameraY)
{
u8 objectEventId;
u16 graphicsId = objectEventTemplate->graphicsId;
struct SpriteTemplate spriteTemplate;
struct SpriteFrameImage spriteFrameImage;
const struct ObjectEventGraphicsInfo *graphicsInfo;
const struct SubspriteTable *subspriteTables = NULL;
// May be a good idea to move the if check contained by this function to outside it for clarity.
const struct ObjectEventTemplate objectEventTemplateLocal = TryGetObjectEventTemplateForOWE(objectEventTemplate);
u16 graphicsId = objectEventTemplateLocal.graphicsId;
graphicsInfo = GetObjectEventGraphicsInfo(graphicsId);
CopyObjectGraphicsInfoToSpriteTemplate_WithMovementType(graphicsId, objectEventTemplate->movementType, &spriteTemplate, &subspriteTables);
CopyObjectGraphicsInfoToSpriteTemplate_WithMovementType(graphicsId, objectEventTemplateLocal.movementType, &spriteTemplate, &subspriteTables);
spriteFrameImage.size = graphicsInfo->size;
spriteTemplate.images = &spriteFrameImage;
objectEventId = TrySetupObjectEventSprite(objectEventTemplate, &spriteTemplate, mapNum, mapGroup, cameraX, cameraY);
objectEventId = TrySetupObjectEventSprite(&objectEventTemplateLocal, &spriteTemplate, mapNum, mapGroup, cameraX, cameraY);
if (objectEventId == OBJECT_EVENTS_COUNT)
return OBJECT_EVENTS_COUNT;
@ -1911,6 +1938,7 @@ u8 TrySpawnObjectEventTemplate(const struct ObjectEventTemplate *objectEventTemp
if (subspriteTables)
SetSubspriteTables(&gSprites[gObjectEvents[objectEventId].spriteId], subspriteTables);
OnOverworldWildEncounterSpawn(&gObjectEvents[objectEventId]);
return objectEventId;
}
@ -2177,7 +2205,7 @@ const struct ObjectEventGraphicsInfo *SpeciesToGraphicsInfo(enum Species species
}
// Find, or load, the palette for the specified pokemon info
static u32 LoadDynamicFollowerPalette(enum Species species, bool32 shiny, bool32 female)
u32 LoadDynamicFollowerPalette(enum Species species, bool32 shiny, bool32 female)
{
u32 paletteNum;
// Use standalone palette, unless entry is OOB or NULL (fallback to front-sprite-based)
@ -2958,6 +2986,10 @@ static void RemoveObjectEventIfOutsideView(struct ObjectEvent *objectEvent)
if (objectEvent->initialCoords.x >= left && objectEvent->initialCoords.x <= right
&& objectEvent->initialCoords.y >= top && objectEvent->initialCoords.y <= bottom)
return;
if (IsOWEDespawnExempt(objectEvent))
return;
RemoveObjectEvent(objectEvent);
}
@ -3040,6 +3072,7 @@ static void SpawnObjectEventOnReturnToField(u8 objectEventId, s16 x, s16 y)
ResetObjectEventFldEffData(objectEvent);
SetObjectSubpriorityByElevation(objectEvent->previousElevation, sprite, 1);
RestoreSavedOWEBehaviorState(objectEvent, sprite);
}
}
@ -3474,6 +3507,19 @@ void ShiftStillObjectEventCoords(struct ObjectEvent *objectEvent)
ShiftObjectEventCoords(objectEvent, objectEvent->currentCoords.x, objectEvent->currentCoords.y);
}
void UpdateObjectEventCoords(struct ObjectEvent *objectEvent, s16 dx, s16 dy)
{
if (objectEvent->active)
{
objectEvent->initialCoords.x -= dx;
objectEvent->initialCoords.y -= dy;
objectEvent->currentCoords.x -= dx;
objectEvent->currentCoords.y -= dy;
objectEvent->previousCoords.x -= dx;
objectEvent->previousCoords.y -= dy;
}
}
void UpdateObjectEventCoordsForCameraUpdate(void)
{
u8 i;
@ -3486,15 +3532,7 @@ void UpdateObjectEventCoordsForCameraUpdate(void)
dy = gCamera.y;
for (i = 0; i < OBJECT_EVENTS_COUNT; i++)
{
if (gObjectEvents[i].active)
{
gObjectEvents[i].initialCoords.x -= dx;
gObjectEvents[i].initialCoords.y -= dy;
gObjectEvents[i].currentCoords.x -= dx;
gObjectEvents[i].currentCoords.y -= dy;
gObjectEvents[i].previousCoords.x -= dx;
gObjectEvents[i].previousCoords.y -= dy;
}
UpdateObjectEventCoords(&gObjectEvents[i], dx, dy);
}
}
}
@ -6595,7 +6633,7 @@ static bool8 IsCoordOutsideObjectEventMovementRange(struct ObjectEvent *objectEv
return FALSE;
}
static bool8 IsMetatileDirectionallyImpassable(struct ObjectEvent *objectEvent, s16 x, s16 y, enum Direction direction)
bool8 IsMetatileDirectionallyImpassable(struct ObjectEvent *objectEvent, s16 x, s16 y, enum Direction direction)
{
if (gOppositeDirectionBlockedMetatileFuncs[direction - 1](objectEvent->currentMetatileBehavior)
|| gDirectionBlockedMetatileFuncs[direction - 1](MapGridGetMetatileBehaviorAt(x, y)))
@ -6629,7 +6667,13 @@ u32 GetObjectObjectCollidesWith(struct ObjectEvent *objectEvent, s16 x, s16 y, b
if ((curObject->currentCoords.x == x && curObject->currentCoords.y == y) || (curObject->previousCoords.x == x && curObject->previousCoords.y == y))
{
if (AreElevationsCompatible(objectEvent->currentElevation, curObject->currentElevation))
{
if (DespawnOWEDueToNPCCollision(curObject, objectEvent))
continue;
TryTriggerOverworldWilEncounter(objectEvent, curObject);
return i;
}
}
}
}
@ -6961,6 +7005,15 @@ enum Direction GetOppositeDirection(enum Direction direction)
return directions[direction - 1];
}
enum Direction GetNinetyDegreeDirection(enum Direction direction, bool32 clockwise)
{
if (direction <= DIR_NONE || direction >= NELEMS(sRotate90Direction))
return DIR_NONE;
return sRotate90Direction[direction][clockwise];
}
// Takes the player's original and current direction and gives a direction the copy NPC should consider as the player's direction.
// See comments at the table's definition.
static u32 GetPlayerDirectionForCopy(u8 initDir, u8 moveDir)
@ -10083,7 +10136,7 @@ static void ObjectEventUpdateSubpriority(struct ObjectEvent *objEvent, struct Sp
SetObjectSubpriorityByElevation(objEvent->previousElevation, sprite, 1);
}
static bool8 AreElevationsCompatible(u8 a, u8 b)
bool8 AreElevationsCompatible(u8 a, u8 b)
{
if (a == ELEVATION_TRANSITION || b == ELEVATION_TRANSITION)
return TRUE;
@ -10094,6 +10147,87 @@ static bool8 AreElevationsCompatible(u8 a, u8 b)
return TRUE;
}
void ScriptFaceEachOther(struct ScriptContext *ctx)
{
struct ObjectEvent *player, *npc;
player = &gObjectEvents[gPlayerAvatar.objectEventId];
npc = &gObjectEvents[GetObjectEventIdByLocalId(gSpecialVar_LastTalked)];
ObjectEventsTurnToEachOther(player, npc);
}
enum Direction DetermineObjectEventDirectionFromObject(struct ObjectEvent *objectOne, struct ObjectEvent *objectTwo)
{
s32 dx = objectOne->currentCoords.x - objectTwo->currentCoords.x;
s32 dy = objectOne->currentCoords.y - objectTwo->currentCoords.y;
if (dx == 0 && dy == 0)
return DIR_NONE;
s32 absX = abs(dx);
s32 absY = abs(dy);
if (absX > absY && dx < 0)
return DIR_WEST;
else if (absX > absY && dx > 0)
return DIR_EAST;
else if (absY > absX && dy < 0)
return DIR_NORTH;
else if (absY > absX && dy > 0)
return DIR_SOUTH;
enum Direction directionOne, directionTwo;
if (dx < 0)
directionTwo = DIR_WEST;
else
directionTwo = DIR_EAST;
if (dy < 0)
directionOne = DIR_NORTH;
else
directionOne = DIR_SOUTH;
if (objectTwo->facingDirection == directionOne)
return directionOne;
else if (objectTwo->facingDirection == directionTwo)
return directionTwo;
return (Random() % 2) ? directionOne : directionTwo;
}
void ObjectEventsTurnToEachOther(struct ObjectEvent *objectOne, struct ObjectEvent *objectTwo)
{
enum Direction objectDirOne, objectDirTwo;
if (objectTwo->invisible == FALSE)
{
objectDirOne = DetermineObjectEventDirectionFromObject(objectOne, objectTwo);
objectDirTwo = objectDirOne;
//Flip direction.
switch (objectDirOne)
{
case DIR_NORTH:
objectDirOne = DIR_SOUTH;
break;
case DIR_SOUTH:
objectDirOne = DIR_NORTH;
break;
case DIR_WEST:
objectDirOne = DIR_EAST;
break;
case DIR_EAST:
objectDirOne = DIR_WEST;
break;
default:
break;
}
ObjectEventTurn(objectOne, objectDirOne);
ObjectEventTurn(objectTwo, objectDirTwo);
}
}
void GroundEffect_SpawnOnTallGrass(struct ObjectEvent *objEvent, struct Sprite *sprite)
{
gFieldEffectArguments[0] = objEvent->currentCoords.x;
@ -11791,3 +11925,379 @@ bool8 MovementAction_SpinRight_Step1(struct ObjectEvent *objectEvent, struct Spr
}
return FALSE;
}
bool8 MovementAction_OverworldEncounterSpawn(enum SpawnDespawnTypeOWE spawnAnimType, struct ObjectEvent *objEvent)
{
gFieldEffectArguments[0] = objEvent->currentCoords.x;
gFieldEffectArguments[1] = objEvent->currentCoords.y;
gFieldEffectArguments[2] = spawnAnimType;
FieldEffectStart(FLDEFF_OW_ENCOUNTER_SPAWN_ANIM);
return TRUE;
}
movement_type_def(MovementType_OverworldWildEncounter_WanderAround, gMovementTypeFuncs_WanderAround_OverworldWildEncounter)
bool8 MovementType_OverworldWildEncounter_WanderAround_Step2(struct ObjectEvent *objectEvent, struct Sprite *sprite)
{
if (!ObjectEventExecSingleMovementAction(objectEvent, sprite))
return FALSE;
SetMovementDelay(sprite, sMovementDelaysOWE[Random() % ARRAY_COUNT(sMovementDelaysOWE)]);
sprite->sTypeFuncId = 3;
return TRUE;
}
bool8 MovementType_OverworldWildEncounter_WanderAround_Step3(struct ObjectEvent *objectEvent, struct Sprite *sprite)
{
if (WaitForMovementDelay(sprite))
{
// resets a mid-movement sprite
ClearObjectEventMovement(objectEvent, sprite);
sprite->sTypeFuncId = 4;
return TRUE;
}
if (OW_MON_WANDER_WALK == TRUE && IS_OW_MON_OBJ(objectEvent))
UpdateMonMoveInPlace(objectEvent, sprite);
if (CanAwareOWESeePlayer(objectEvent))
sprite->sTypeFuncId = 7;
return FALSE;
}
bool8 MovementType_OverworldWildEncounter_WanderAround_Step4(struct ObjectEvent *objectEvent, struct Sprite *sprite)
{
enum Direction chosenDirection = objectEvent->movementDirection;
if ((Random() & 3) != 0)
chosenDirection = GetNinetyDegreeDirection(chosenDirection, Random() % 2);
SetObjectEventDirection(objectEvent, chosenDirection);
sprite->sTypeFuncId = 5;
if (CheckRestrictedOWEMovement(objectEvent, chosenDirection))
sprite->sTypeFuncId = 1;
return TRUE;
}
bool8 MovementType_OverworldWildEncounter_WanderAround_Step5(struct ObjectEvent *objectEvent, struct Sprite *sprite)
{
ObjectEventSetSingleMovement(objectEvent, sprite, GetOWEWalkMovementActionInDirectionWithSpeed(objectEvent->movementDirection, OWE_GetIdleSpeedFromSpecies(OW_SPECIES(objectEvent))));
objectEvent->singleMovementActive = TRUE;
sprite->sTypeFuncId = 6;
return TRUE;
}
movement_type_def(MovementType_OverworldWildEncounter_ChasePlayer, gMovementTypeFuncs_ChasePlayer_OverworldWildEncounter)
bool8 MovementType_OverworldWildEncounter_Common_Step7(struct ObjectEvent *objectEvent, struct Sprite *sprite)
{
ClearObjectEventMovement(objectEvent, sprite);
SetSavedOWEMovementState(objectEvent);
sprite->sTypeFuncId = 8;
return TRUE;
}
bool8 MovementType_OverworldWildEncounter_ChasePlayer_Step8(struct ObjectEvent *objectEvent, struct Sprite *sprite)
{
enum Direction direction = DetermineObjectEventDirectionFromObject(&gObjectEvents[gPlayerAvatar.objectEventId], objectEvent);
SetObjectEventDirection(objectEvent, direction);
if (IsOWENextToPlayer(objectEvent))
{
sprite->sTypeFuncId = 10;
return TRUE;
}
ObjectEventSetSingleMovement(objectEvent, sprite, MOVEMENT_ACTION_EMOTE_EXCLAMATION_MARK);
PlaySE(SE_PIN);
sprite->sTypeFuncId = 9;
return TRUE;
}
bool8 MovementType_OverworldWildEncounter_Common_Step9(struct ObjectEvent *objectEvent, struct Sprite *sprite)
{
if (ObjectEventExecSingleMovementAction(objectEvent, sprite))
sprite->sTypeFuncId = 10;
return TRUE;
}
bool8 MovementType_OverworldWildEncounter_ChasePlayer_Step10(struct ObjectEvent *objectEvent, struct Sprite *sprite)
{
enum Direction direction = DetermineObjectEventDirectionFromObject(&gObjectEvents[gPlayerAvatar.objectEventId], objectEvent);
SetObjectEventDirection(objectEvent, direction);
sprite->sTypeFuncId = 11;
return TRUE;
}
bool8 MovementType_OverworldWildEncounter_ChasePlayer_Step11(struct ObjectEvent *objectEvent, struct Sprite *sprite)
{
u32 speciesId = OW_SPECIES(objectEvent);
u32 movementActionId = GetOWEWalkMovementActionInDirectionWithSpeed(objectEvent->movementDirection, OWE_GetActiveSpeedFromSpecies(speciesId));
sprite->sTypeFuncId = 12;
if (CheckRestrictedOWEMovement(objectEvent, objectEvent->movementDirection))
{
s16 x = objectEvent->currentCoords.x;
s16 y = objectEvent->currentCoords.y;
MoveCoords(objectEvent->movementDirection, &x, &y);
// If colliding with the player object, don't try to walk around it.
if (GetObjectObjectCollidesWith(objectEvent, x, y, FALSE) == gPlayerAvatar.objectEventId)
{
ObjectEventSetSingleMovement(objectEvent, sprite, GetFaceDirectionMovementAction(objectEvent->facingDirection));
objectEvent->singleMovementActive = TRUE;
return FALSE;
}
enum Direction newDirection = DirectionOfOWEToPlayerFromCollision(objectEvent);
movementActionId = GetOWEWalkMovementActionInDirectionWithSpeed(newDirection, OWE_GetActiveSpeedFromSpecies(speciesId));
if (CheckRestrictedOWEMovement(objectEvent, newDirection))
movementActionId = GetWalkInPlaceNormalMovementAction(objectEvent->facingDirection);
}
ObjectEventSetSingleMovement(objectEvent, sprite, movementActionId);
objectEvent->singleMovementActive = TRUE;
return TRUE;
}
bool8 MovementType_OverworldWildEncounter_Common_Step12(struct ObjectEvent *objectEvent, struct Sprite *sprite)
{
if (ObjectEventExecSingleMovementAction(objectEvent, sprite))
{
objectEvent->singleMovementActive = FALSE;
sprite->sTypeFuncId = 10;
if (!IsPlayerInsideOWEActiveDistance(objectEvent))
{
ClearSavedOWEMovementState(objectEvent);
sprite->sTypeFuncId = 0;
}
}
return FALSE;
}
movement_type_def(MovementType_OverworldWildEncounter_FleePlayer, gMovementTypeFuncs_FleePlayer_OverworldWildEncounter)
bool8 MovementType_OverworldWildEncounter_FleePlayer_Step8(struct ObjectEvent *objectEvent, struct Sprite *sprite)
{
enum Direction direction = GetOppositeDirection(DetermineObjectEventDirectionFromObject(&gObjectEvents[gPlayerAvatar.objectEventId], objectEvent));
SetObjectEventDirection(objectEvent, direction);
ObjectEventSetSingleMovement(objectEvent, sprite, MOVEMENT_ACTION_EMOTE_EXCLAMATION_MARK);
PlaySE(SE_PIN);
sprite->sTypeFuncId = 9;
return TRUE;
}
#define sCollisionTimer sprite->data[6]
bool8 MovementType_OverworldWildEncounter_FleePlayer_Step10(struct ObjectEvent *objectEvent, struct Sprite *sprite)
{
if (WE_OWE_FLEE_DESPAWN && sCollisionTimer >= OWE_FLEE_COLLISION_TIME)
{
RemoveObjectEvent(objectEvent);
return FALSE;
}
enum Direction direction = GetOppositeDirection(DetermineObjectEventDirectionFromObject(&gObjectEvents[gPlayerAvatar.objectEventId], objectEvent));
SetObjectEventDirection(objectEvent, direction);
sprite->sTypeFuncId = 11;
return TRUE;
}
bool8 MovementType_OverworldWildEncounter_FleePlayer_Step11(struct ObjectEvent *objectEvent, struct Sprite *sprite)
{
u32 speciesId = OW_SPECIES(objectEvent);
u32 movementActionId = GetOWEWalkMovementActionInDirectionWithSpeed(objectEvent->movementDirection, OWE_GetActiveSpeedFromSpecies(speciesId));
if (CheckRestrictedOWEMovement(objectEvent, objectEvent->movementDirection))
{
enum Direction newDirection = DirectionOfOWEToPlayerFromCollision(objectEvent);
if (newDirection != objectEvent->movementDirection)
newDirection = GetOppositeDirection(newDirection);
movementActionId = GetOWEWalkMovementActionInDirectionWithSpeed(newDirection, OWE_GetActiveSpeedFromSpecies(speciesId));
if (CheckRestrictedOWEMovement(objectEvent, newDirection))
{
sCollisionTimer++;
movementActionId = GetWalkInPlaceNormalMovementAction(objectEvent->facingDirection);
}
else
{
sCollisionTimer = 0;
}
}
else
{
sCollisionTimer = 0;
}
ObjectEventSetSingleMovement(objectEvent, sprite, movementActionId);
objectEvent->singleMovementActive = TRUE;
sprite->sTypeFuncId = 12;
return TRUE;
}
#undef sCollisionTimer
movement_type_def(MovementType_OverworldWildEncounter_WatchPlayer, gMovementTypeFuncs_WatchPlayer_OverworldWildEncounter)
bool8 MovementType_OverworldWildEncounter_WatchPlayer_Step8(struct ObjectEvent *objectEvent, struct Sprite *sprite)
{
enum Direction direction = DetermineObjectEventDirectionFromObject(&gObjectEvents[gPlayerAvatar.objectEventId], objectEvent);
SetObjectEventDirection(objectEvent, direction);
sprite->sTypeFuncId = 10;
if (!IsOWENextToPlayer(objectEvent))
{
ObjectEventSetSingleMovement(objectEvent, sprite, MOVEMENT_ACTION_EMOTE_QUESTION_MARK);
sprite->sTypeFuncId = 9;
}
return TRUE;
}
bool8 MovementType_OverworldWildEncounter_WatchPlayer_Step10(struct ObjectEvent *objectEvent, struct Sprite *sprite)
{
enum Direction direction = DetermineObjectEventDirectionFromObject(&gObjectEvents[gPlayerAvatar.objectEventId], objectEvent);
SetObjectEventDirection(objectEvent, direction);
sprite->sTypeFuncId = 11;
return TRUE;
}
bool8 MovementType_OverworldWildEncounter_WatchPlayer_Step11(struct ObjectEvent *objectEvent, struct Sprite *sprite)
{
ObjectEventSetSingleMovement(objectEvent, sprite, GetWalkInPlaceNormalMovementAction(objectEvent->facingDirection));
objectEvent->singleMovementActive = TRUE;
sprite->sTypeFuncId = 12;
return TRUE;
}
movement_type_def(MovementType_OverworldWildEncounter_ApproachPlayer, gMovementTypeFuncs_ApproachPlayer_OverworldWildEncounter)
#define sJumpTimer sprite->data[7]
bool8 MovementType_OverworldWildEncounter_ApproachPlayer_Step8(struct ObjectEvent *objectEvent, struct Sprite *sprite)
{
enum Direction direction = DetermineObjectEventDirectionFromObject(&gObjectEvents[gPlayerAvatar.objectEventId], objectEvent);
SetObjectEventDirection(objectEvent, direction);
sJumpTimer = (Random() % (OWE_APPROACH_JUMP_TIMER_MAX - OWE_APPROACH_JUMP_TIMER_MIN)) + OWE_APPROACH_JUMP_TIMER_MIN;
sprite->sTypeFuncId = 10;
if (!IsOWENextToPlayer(objectEvent))
{
ObjectEventSetSingleMovement(objectEvent, sprite, MOVEMENT_ACTION_EMOTE_QUESTION_MARK);
sprite->sTypeFuncId = 9;
}
return TRUE;
}
bool8 MovementType_OverworldWildEncounter_ApproachPlayer_Step10(struct ObjectEvent *objectEvent, struct Sprite *sprite)
{
enum Direction direction = DetermineObjectEventDirectionFromObject(&gObjectEvents[gPlayerAvatar.objectEventId], objectEvent);
SetObjectEventDirection(objectEvent, direction);
sprite->sTypeFuncId = 11;
return TRUE;
}
bool8 MovementType_OverworldWildEncounter_ApproachPlayer_Step11(struct ObjectEvent *objectEvent, struct Sprite *sprite)
{
bool32 equalDistances = FALSE;
u32 distance = GetApproachingOWEDistanceToPlayer(objectEvent, &equalDistances);
u32 speciesId = OW_SPECIES(objectEvent);
u32 movementActionId;
if (distance <= 1)
{
SetObjectEventDirection(objectEvent, GetOppositeDirection(objectEvent->movementDirection));
movementActionId = GetOWEWalkMovementActionInDirectionWithSpeed(objectEvent->movementDirection, OWE_GetActiveSpeedFromSpecies(speciesId));
if (CheckRestrictedOWEMovement(objectEvent, objectEvent->movementDirection))
{
struct ObjectEvent *player = &gObjectEvents[gPlayerAvatar.objectEventId];
enum Direction newDirection = DirectionOfOWEToPlayerFromCollision(objectEvent);
if (objectEvent->currentCoords.x != player->currentCoords.x && objectEvent->currentCoords.y != player->currentCoords.y)
newDirection = GetOppositeDirection(newDirection);
movementActionId = GetOWEWalkMovementActionInDirectionWithSpeed(newDirection, OWE_GetActiveSpeedFromSpecies(speciesId));
if (CheckRestrictedOWEMovement(objectEvent, newDirection))
movementActionId = GetWalkInPlaceNormalMovementAction(objectEvent->facingDirection);
}
}
else if (distance == OWE_APPROACH_DISTANCE && !equalDistances)
{
if (sJumpTimer <= 0)
{
sJumpTimer = (Random() % (OWE_APPROACH_JUMP_TIMER_MAX - OWE_APPROACH_JUMP_TIMER_MIN)) + OWE_APPROACH_JUMP_TIMER_MIN;
movementActionId = GetJumpInPlaceMovementAction(objectEvent->facingDirection);
PlaySE(SE_LEDGE);
}
else
{
sJumpTimer--;
movementActionId = GetWalkInPlaceNormalMovementAction(objectEvent->facingDirection);
}
}
else
{
movementActionId = GetOWEWalkMovementActionInDirectionWithSpeed(objectEvent->movementDirection, OWE_GetActiveSpeedFromSpecies(speciesId));
if (CheckRestrictedOWEMovement(objectEvent, objectEvent->movementDirection))
{
s16 x = objectEvent->currentCoords.x;
s16 y = objectEvent->currentCoords.y;
MoveCoords(objectEvent->movementDirection, &x, &y);
// If colliding with the player object, don't try to walk around it.
if (GetObjectObjectCollidesWith(objectEvent, x, y, FALSE) == gPlayerAvatar.objectEventId)
{
ObjectEventSetSingleMovement(objectEvent, sprite, GetFaceDirectionMovementAction(objectEvent->facingDirection));
objectEvent->singleMovementActive = TRUE;
return FALSE;
}
enum Direction newDirection = DirectionOfOWEToPlayerFromCollision(objectEvent);
movementActionId = GetOWEWalkMovementActionInDirectionWithSpeed(newDirection, OWE_GetActiveSpeedFromSpecies(speciesId));
if (CheckRestrictedOWEMovement(objectEvent, newDirection))
movementActionId = GetWalkInPlaceNormalMovementAction(objectEvent->facingDirection);
}
sJumpTimer = (Random() % (OWE_APPROACH_JUMP_TIMER_MAX - OWE_APPROACH_JUMP_TIMER_MIN)) + OWE_APPROACH_JUMP_TIMER_MIN;
}
ObjectEventSetSingleMovement(objectEvent, sprite, movementActionId);
objectEvent->singleMovementActive = TRUE;
sprite->sTypeFuncId = 12;
return TRUE;
}
movement_type_def(MovementType_OverworldWildEncounter_Despawn, gMovementTypeFuncs_Despawn_OverworldWildEncounter)
#define sDespawnTimer sprite->data[6]
bool8 MovementType_OverworldWildEncounter_Despawn_Step8(struct ObjectEvent *objectEvent, struct Sprite *sprite)
{
enum Direction direction = DetermineObjectEventDirectionFromObject(&gObjectEvents[gPlayerAvatar.objectEventId], objectEvent);
SetObjectEventDirection(objectEvent, direction);
ObjectEventSetSingleMovement(objectEvent, sprite, MOVEMENT_ACTION_EMOTE_EXCLAMATION_MARK);
PlaySE(SE_PIN);
sDespawnTimer = 0;
sprite->sTypeFuncId = 9;
return TRUE;
}
bool8 MovementType_OverworldWildEncounter_Despawn_Step10(struct ObjectEvent *objectEvent, struct Sprite *sprite)
{
enum Direction direction = DetermineObjectEventDirectionFromObject(&gObjectEvents[gPlayerAvatar.objectEventId], objectEvent);
SetObjectEventDirection(objectEvent, direction);
sprite->sTypeFuncId = 11;
return TRUE;
}
bool8 MovementType_OverworldWildEncounter_Despawn_Step11(struct ObjectEvent *objectEvent, struct Sprite *sprite)
{
if (sDespawnTimer == OWE_DESPAWN_FRAMES)
{
RemoveObjectEvent(objectEvent);
return FALSE;
}
ObjectEventSetSingleMovement(objectEvent, sprite, GetFaceDirectionMovementAction(objectEvent->facingDirection));
objectEvent->singleMovementActive = TRUE;
sDespawnTimer++;
sprite->sTypeFuncId = 12;
return TRUE;
}
#undef sDespawnTimer

View File

@ -35,9 +35,11 @@
#include "trainer_hill.h"
#include "vs_seeker.h"
#include "wild_encounter.h"
#include "wild_encounter_ow.h"
#include "constants/event_bg.h"
#include "constants/event_objects.h"
#include "constants/field_poison.h"
#include "constants/layouts.h"
#include "constants/metatile_behaviors.h"
#include "constants/songs.h"
#include "constants/trainer_hill.h"
@ -405,6 +407,8 @@ static const u8 *GetInteractedObjectEventScript(struct MapPosition *position, u8
script = GetTrainerHillTrainerScript();
else if (PlayerHasFollowerNPC() && objectEventId == GetFollowerNPCObjectId())
script = GetFollowerNPCScriptPointer();
else if (ShouldRunDefaultOWEScript(objectEventId))
script = InteractWithOverworldWildEncounter;
else
script = GetObjectEventScriptPointerByObjectEventId(objectEventId);
@ -631,8 +635,17 @@ static const u8 *GetInteractedMetatileScript(struct MapPosition *position, u8 me
return NULL;
}
static const u8 *GetInteractedWaterScript(struct MapPosition *unused1, u8 metatileBehavior, enum Direction direction)
static const u8 *GetInteractedWaterScript(struct MapPosition *position, u8 metatileBehavior, enum Direction direction)
{
// Does this need a define for the surf elevation (1) check?
// Can be used in sElevationToSubpriority and other places too
u8 objectEventId = GetObjectEventIdByPosition(position->x, position->y, ELEVATION_SURF);
if (IsPlayerFacingSurfableFishableWater() == TRUE && ShouldRunDefaultOWEScript(objectEventId))
{
gSpecialVar_LastTalked = gObjectEvents[objectEventId].localId;
return InteractWithOverworldWildEncounter;
}
if (MetatileBehavior_IsFastWater(metatileBehavior) == TRUE && !TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_SURFING))
return EventScript_CurrentTooFast;
if (IsFieldMoveUnlocked(FIELD_MOVE_SURF) && PartyHasMonWithSurf() == TRUE && IsPlayerFacingSurfableFishableWater() == TRUE
@ -886,9 +899,26 @@ void RestartWildEncounterImmunitySteps(void)
sWildEncounterImmunitySteps = 0;
}
static bool8 CheckStandardWildEncounter(u16 metatileBehavior)
static bool32 ShouldDisableRandomEncounters(void)
{
if (FlagGet(OW_FLAG_NO_ENCOUNTER))
return TRUE;
if (!WE_VANILLA_RANDOM && WE_OW_ENCOUNTERS)
{
if (gMapHeader.mapLayoutId == LAYOUT_BATTLE_FRONTIER_BATTLE_PIKE_ROOM_WILD_MONS && !WE_OWE_BATTLE_PIKE)
return FALSE;
if (gMapHeader.mapLayoutId == LAYOUT_BATTLE_FRONTIER_BATTLE_PYRAMID_FLOOR && !WE_OWE_BATTLE_PYRAMID)
return FALSE;
}
return !WE_VANILLA_RANDOM;
}
static bool8 CheckStandardWildEncounter(u16 metatileBehavior)
{
if (ShouldDisableRandomEncounters())
return FALSE;
if (sWildEncounterImmunitySteps < 4)

View File

@ -876,6 +876,13 @@ void FieldEffectScript_LoadFadedPalette(u8 **script)
UpdateSpritePaletteWithWeather(paletteSlot, ShouldFieldEffectBeFogBlended(*script));
}
void FieldEffect_LoadFadedPalette(struct SpritePalette *palette, enum ColorMapType colorMap)
{
u32 paletteSlot = LoadSpritePalette(palette);
SetPaletteColorMapType(paletteSlot + 16, colorMap);
UpdateSpritePaletteWithWeather(paletteSlot, TRUE);
}
void FieldEffectScript_LoadPalette(u8 **script)
{
struct SpritePalette *palette = (struct SpritePalette *)FieldEffectScript_ReadWord(script);

View File

@ -11,6 +11,7 @@
#include "sound.h"
#include "sprite.h"
#include "trig.h"
#include "wild_encounter_ow.h"
#include "constants/event_objects.h"
#include "constants/field_effects.h"
#include "constants/rgb.h"
@ -64,6 +65,9 @@ void SetUpShadow(struct ObjectEvent *objectEvent)
void SetUpReflection(struct ObjectEvent *objectEvent, struct Sprite *sprite, bool8 stillReflection)
{
if (IsOverworldWildEncounter(objectEvent, OWE_GENERATED))
return;
struct Sprite *reflectionSprite;
reflectionSprite = &gSprites[CreateCopySpriteAt(sprite, sprite->x, sprite->y, 152)];
@ -1903,3 +1907,54 @@ static void UpdateGrassFieldEffectSubpriority(struct Sprite *sprite, u8 elevatio
}
}
}
u32 FldEff_OWE_SpawnAnim(void)
{
u8 spriteId;
u8 visual;
s16 xOffset = 0, yOffset = 0;
enum SpawnDespawnTypeOWE spawnAnim = gFieldEffectArguments[2];
struct SpritePalette palette = GetOWESpawnDespawnAnimFldEffPalette(spawnAnim);
switch (spawnAnim)
{
case OWE_SPAWN_ANIM_GRASS:
visual = FLDEFFOBJ_JUMP_TALL_GRASS;
yOffset = 8;
break;
case OWE_SPAWN_ANIM_LONG_GRASS:
visual = FLDEFFOBJ_JUMP_LONG_GRASS;
break;
case OWE_SPAWN_ANIM_WATER:
visual = FLDEFFOBJ_JUMP_BIG_SPLASH;
yOffset = 8;
break;
case OWE_SPAWN_ANIM_UNDERWATER:
visual = FLDEFFOBJ_BUBBLES;
break;
case OWE_SPAWN_ANIM_CAVE:
visual = FLDEFFOBJ_GROUND_IMPACT_DUST;
yOffset = 12;
break;
case OWE_SPAWN_ANIM_SHINY:
default:
visual = FLDEFFOBJ_SHINY_SPARKLE;
break;
}
FieldEffect_LoadFadedPalette(&palette, COLOR_MAP_DARK_CONTRAST);
SetSpritePosToOffsetMapCoords((s16 *)&gFieldEffectArguments[0], (s16 *)&gFieldEffectArguments[1], 8, 0);
spriteId = CreateSpriteAtEnd(gFieldEffectObjectTemplatePointers[visual], gFieldEffectArguments[0] + xOffset, gFieldEffectArguments[1] + yOffset, 0);
if (spriteId != MAX_SPRITES)
{
struct Sprite *sprite = &gSprites[spriteId];
sprite->coordOffsetEnabled = TRUE;
sprite->oam.priority = 2;
}
return spriteId;
}

View File

@ -808,6 +808,7 @@ bool8 CameraMove(int x, int y)
gSaveBlock1Ptr->pos.x += x;
gSaveBlock1Ptr->pos.y += y;
MoveMapViewToBackup(direction);
TryDespawnOWEsCrossingMapConnection();
}
return gCamera.active;
@ -1081,3 +1082,20 @@ void LoadMapTilesetPalettes(struct MapLayout const *mapLayout)
LoadSecondaryTilesetPalette(mapLayout, FALSE);
}
}
bool32 AreCoordsInsideMap(u8 mapGroup, u8 mapNum, s16 x, s16 y)
{
const struct MapLayout *layout = Overworld_GetMapHeaderByGroupAndId(mapGroup, mapNum)->mapLayout;
s32 width = layout->width + MAP_OFFSET;
s32 height = layout->height + MAP_OFFSET;
if (x >= 0 && x < width && y >= 0 && y < height)
return TRUE;
return FALSE;
}
bool32 AreCoordsInsidePlayerMap(s16 x, s16 y)
{
return AreCoordsInsideMap(gSaveBlock1Ptr->location.mapGroup, gSaveBlock1Ptr->location.mapNum, x, y);
}

View File

@ -1365,20 +1365,7 @@ void FollowerNPC_HandleSprite(void)
enum Direction DetermineFollowerNPCDirection(struct ObjectEvent *player, struct ObjectEvent *follower)
{
s32 delta_x = follower->currentCoords.x - player->currentCoords.x;
s32 delta_y = follower->currentCoords.y - player->currentCoords.y;
if (delta_x < 0)
return DIR_EAST;
else if (delta_x > 0)
return DIR_WEST;
if (delta_y < 0)
return DIR_SOUTH;
else if (delta_y > 0)
return DIR_NORTH;
return DIR_NONE;
return DetermineObjectEventDirectionFromObject(player, follower);
}
u32 GetFollowerNPCObjectId(void)
@ -1826,38 +1813,10 @@ void ScriptFaceFollowerNPC(struct ScriptContext *ctx)
if (!FNPC_ENABLE_NPC_FOLLOWERS || !PlayerHasFollowerNPC())
return;
enum Direction playerDirection, followerDirection;
struct ObjectEvent *player, *follower;
player = &gObjectEvents[gPlayerAvatar.objectEventId];
follower = &gObjectEvents[GetFollowerNPCData(FNPC_DATA_OBJ_ID)];
if (follower->invisible == FALSE)
{
playerDirection = DetermineFollowerNPCDirection(player, follower);
followerDirection = playerDirection;
//Flip direction.
switch (playerDirection)
{
case DIR_NORTH:
playerDirection = DIR_SOUTH;
break;
case DIR_SOUTH:
playerDirection = DIR_NORTH;
break;
case DIR_WEST:
playerDirection = DIR_EAST;
break;
case DIR_EAST:
playerDirection = DIR_WEST;
break;
default:
break;
}
ObjectEventTurn(player, playerDirection);
ObjectEventTurn(follower, followerDirection);
}
ObjectEventsTurnToEachOther(player, follower);
}
static const u8 *const FollowerNPCHideMovementsSpeedTable[][4] =

View File

@ -1003,6 +1003,7 @@ static void Task_UseRepel(u8 taskId)
VarSet(VAR_LAST_REPEL_LURE_USED, gSpecialVar_ItemId);
#endif
RemoveUsedItem();
SetInstantOWESpawnTimer();
if (CurrentBattlePyramidLocation() == PYRAMID_LOCATION_NONE)
DisplayItemMessage(taskId, FONT_NORMAL, gStringVar4, CloseItemMessage);
else

View File

@ -13,6 +13,7 @@
#include "save_location.h"
#include "script_pokemon_util.h"
#include "trainer_hill.h"
#include "wild_encounter_ow.h"
#include "gba/flash_internal.h"
#include "decoration_inventory.h"
#include "agb_flash.h"
@ -237,6 +238,7 @@ void LoadObjectEvents(void)
gObjectEvents[i].graphicsId & OBJ_EVENT_MON)
gObjectEvents[i].active = TRUE;
}
SetMinimumOWESpawnTimer();
}
void CopyPartyAndObjectsToSave(void)

View File

@ -69,6 +69,7 @@
#include "tv.h"
#include "scanline_effect.h"
#include "wild_encounter.h"
#include "wild_encounter_ow.h"
#include "vs_seeker.h"
#include "frontier_util.h"
#include "constants/abilities.h"
@ -925,6 +926,7 @@ void LoadMapFromCameraTransition(u8 mapGroup, u8 mapNum)
|| gMapHeader.regionMapSectionId != sLastMapSectionId)
ShowMapNamePopup();
}
SetMinimumOWESpawnTimer();
}
static void LoadMapFromWarp(bool32 a1)
@ -985,6 +987,7 @@ static void LoadMapFromWarp(bool32 a1)
UpdateTVScreensOnMap(gBackupMapLayout.width, gBackupMapLayout.height);
InitSecretBaseAppearance(TRUE);
}
SetMinimumOWESpawnTimer();
}
void ResetInitialPlayerAvatarState(void)
@ -1392,8 +1395,43 @@ void Overworld_FadeOutMapMusic(void)
FadeOutMapMusic(4);
}
static bool32 ShouldPlayAmbientCryVanillaOWE(void)
{
bool32 owePlayed = FALSE;
if (GetNumberOfActiveOWEs(OWE_ANY))
{
switch (OW_AMBIENT_CRIES)
{
case OW_AMBIENT_CRIES_OWE_ONLY:
case OW_AMBIENT_CRIES_OWE_PRIORITY:
PlayAmbientOWECry();
owePlayed = TRUE;
break;
default:
break;
}
}
switch (OW_AMBIENT_CRIES)
{
case OW_AMBIENT_CRIES_VANILLA:
return TRUE;
case OW_AMBIENT_CRIES_OWE_PRIORITY:
return !owePlayed;
default:
return FALSE;
}
}
static void PlayAmbientCry(void)
{
if (!ShouldPlayAmbientCryVanillaOWE())
return;
s16 x, y;
s8 pan;
s8 volume;
@ -1816,6 +1854,7 @@ static void OverworldBasic(void)
ApplyWeatherColorMapIfIdle(gWeatherPtr->colorMapIndex);
}
}
OverworldWildEncounters_CB();
}
// This CB2 is used when starting

View File

@ -981,6 +981,7 @@ const struct NatureInfo gNaturesInfo[NUM_NATURES] =
#include "data/pokemon/form_species_tables.h"
#include "data/pokemon/form_change_tables.h"
#include "data/pokemon/form_change_table_pointers.h"
#include "data/pokemon/wild_encounter_ow_behavior.h"
#include "data/object_events/object_event_pic_tables_followers.h"
#include "data/pokemon/species_info.h"
@ -1317,6 +1318,48 @@ void CreateMonWithIVs(struct Pokemon *mon, enum Species species, u8 level, u32 p
CalculateMonStats(mon);
}
bool32 ComputePlayerShinyOdds(u32 personality, u32 value)
{
bool32 isShiny;
if (P_FLAG_FORCE_NO_SHINY != 0 && FlagGet(P_FLAG_FORCE_NO_SHINY))
{
isShiny = FALSE;
}
else if (P_FLAG_FORCE_SHINY != 0 && FlagGet(P_FLAG_FORCE_SHINY))
{
isShiny = TRUE;
}
else if (P_ONLY_OBTAINABLE_SHINIES && (CurrentBattlePyramidLocation() != PYRAMID_LOCATION_NONE || (B_FLAG_NO_CATCHING != 0 && FlagGet(B_FLAG_NO_CATCHING))))
{
isShiny = FALSE;
}
else if (P_NO_SHINIES_WITHOUT_POKEBALLS && !HasAtLeastOnePokeBall())
{
isShiny = FALSE;
}
else
{
u32 totalRerolls = 0;
if (CheckBagHasItem(ITEM_SHINY_CHARM, 1))
totalRerolls += I_SHINY_CHARM_ADDITIONAL_ROLLS;
if (LURE_STEP_COUNT != 0)
totalRerolls += 1;
totalRerolls += CalculateChainFishingShinyRolls();
if (gDexNavSpecies)
totalRerolls += CalculateDexNavShinyRolls();
u32 shinyPersonality = personality;
while (GET_SHINY_VALUE(value, shinyPersonality) >= SHINY_ODDS && totalRerolls > 0)
{
shinyPersonality = Random32();
totalRerolls--;
}
isShiny = GET_SHINY_VALUE(value, shinyPersonality) < SHINY_ODDS;
}
return isShiny;
}
void SetBoxMonIVs(struct BoxPokemon *mon, u8 fixedIV)
{
u32 i, value;
@ -1403,42 +1446,7 @@ void CreateBoxMon(struct BoxPokemon *boxMon, enum Species species, u8 level, u32
else // Player is the OT
{
value = READ_OTID_FROM_SAVE;
if (P_FLAG_FORCE_NO_SHINY != 0 && FlagGet(P_FLAG_FORCE_NO_SHINY))
{
isShiny = FALSE;
}
else if (P_FLAG_FORCE_SHINY != 0 && FlagGet(P_FLAG_FORCE_SHINY))
{
isShiny = TRUE;
}
else if (P_ONLY_OBTAINABLE_SHINIES && (CurrentBattlePyramidLocation() != PYRAMID_LOCATION_NONE || (B_FLAG_NO_CATCHING != 0 && FlagGet(B_FLAG_NO_CATCHING))))
{
isShiny = FALSE;
}
else if (P_NO_SHINIES_WITHOUT_POKEBALLS && !HasAtLeastOnePokeBall())
{
isShiny = FALSE;
}
else
{
u32 totalRerolls = 0;
if (CheckBagHasItem(ITEM_SHINY_CHARM, 1))
totalRerolls += I_SHINY_CHARM_ADDITIONAL_ROLLS;
if (LURE_STEP_COUNT != 0)
totalRerolls += 1;
totalRerolls += CalculateChainFishingShinyRolls();
if (gDexNavSpecies)
totalRerolls += CalculateDexNavShinyRolls();
u32 shinyPersonality = personality;
while (GET_SHINY_VALUE(value, shinyPersonality) >= SHINY_ODDS && totalRerolls > 0)
{
shinyPersonality = Random32();
totalRerolls--;
}
isShiny = GET_SHINY_VALUE(value, shinyPersonality) < SHINY_ODDS;
}
isShiny = ComputePlayerShinyOdds(personality, value);
}
SetBoxMonData(boxMon, MON_DATA_PERSONALITY, &personality);
@ -7455,3 +7463,45 @@ bool32 HasShedinjaHPHandling(enum Species species)
return TRUE;
return FALSE;
}
u32 OWE_GetMovementTypeFromSpecies(enum Species speciesId)
{
speciesId = SanitizeSpeciesId(speciesId);
enum OverworldWildEncounterBehaviors behavior = gSpeciesInfo[speciesId].overworldEncounterBehavior;
return sOWESpeciesBehavior[behavior].movementType;
}
u32 OWE_GetViewDistanceFromSpecies(enum Species speciesId)
{
speciesId = SanitizeSpeciesId(speciesId);
enum OverworldWildEncounterBehaviors behavior = gSpeciesInfo[speciesId].overworldEncounterBehavior;
return sOWESpeciesBehavior[behavior].viewDistance;
}
u32 OWE_GetViewWidthFromSpecies(enum Species speciesId)
{
speciesId = SanitizeSpeciesId(speciesId);
enum OverworldWildEncounterBehaviors behavior = gSpeciesInfo[speciesId].overworldEncounterBehavior;
return sOWESpeciesBehavior[behavior].viewWidth;
}
u32 OWE_GetViewActiveDistanceFromSpecies(enum Species speciesId)
{
speciesId = SanitizeSpeciesId(speciesId);
enum OverworldWildEncounterBehaviors behavior = gSpeciesInfo[speciesId].overworldEncounterBehavior;
return sOWESpeciesBehavior[behavior].activeDistance;
}
enum SpeedOWE OWE_GetIdleSpeedFromSpecies(enum Species speciesId)
{
speciesId = SanitizeSpeciesId(speciesId);
enum OverworldWildEncounterBehaviors behavior = gSpeciesInfo[speciesId].overworldEncounterBehavior;
return sOWESpeciesBehavior[behavior].idleSpeed;
}
enum SpeedOWE OWE_GetActiveSpeedFromSpecies(enum Species speciesId)
{
speciesId = SanitizeSpeciesId(speciesId);
enum OverworldWildEncounterBehaviors behavior = gSpeciesInfo[speciesId].overworldEncounterBehavior;
return sOWESpeciesBehavior[behavior].activeSpeed;
}

View File

@ -690,6 +690,44 @@ s16 AllocSpriteTiles(u16 tileCount)
return start;
}
bool32 CanAllocSpriteTiles(u16 tileCount)
{
u16 i;
u16 numTilesFound;
if (tileCount == 0)
return TRUE;
i = gReservedSpriteTileCount;
for (;;)
{
while (SPRITE_TILE_IS_ALLOCATED(i))
{
i++;
if (i == TOTAL_OBJ_TILE_COUNT)
return FALSE;
}
numTilesFound = 1;
while (numTilesFound != tileCount)
{
i++;
if (i == TOTAL_OBJ_TILE_COUNT)
return FALSE;
if (!SPRITE_TILE_IS_ALLOCATED(i))
numTilesFound++;
else
break;
}
if (numTilesFound == tileCount)
return TRUE;
}
}
u8 SpriteTileAllocBitmapOp(u16 bit, u8 op)
{
u8 index = bit / 8;
@ -1601,14 +1639,16 @@ u32 LoadSpritePalette(const struct SpritePalette *palette)
if (index == 0xFF)
{
return 0xFF;
}
else
{
sSpritePaletteTags[index] = palette->tag;
DoLoadSpritePalette(palette->data, PLTT_ID(index));
return index;
TryAndDespawnOldestGeneratedOWE_Palette();
index = IndexOfSpritePaletteTag(TAG_NONE);
if (index == 0xFF)
return 0xFF;
}
sSpritePaletteTags[index] = palette->tag;
DoLoadSpritePalette(palette->data, PLTT_ID(index));
return index;
}
u32 LoadSpritePaletteWithTag(const u16 *pal, u16 tag)
@ -2114,3 +2154,14 @@ inline u32 GetSpriteHeight(struct Sprite *sprite)
{
return gOamDimensions[sprite->oam.shape][sprite->oam.size].height;
}
u32 CountFreePaletteSlots(void)
{
u32 i, count = 0;
for (i = gReservedSpritePaletteCount; i < 16; i++)
if (sSpritePaletteTags[i] == TAG_NONE)
count++;
return count;
}

View File

@ -723,6 +723,7 @@ static u8 CheckPathBetweenTrainerAndPlayer(struct ObjectEvent *trainerObj, u8 ap
{
// Check for collisions on approach, ignoring the "out of range" collision for regular movement
collision = GetCollisionFlagsAtCoords(trainerObj, x, y, direction);
collision = DespawnOWEDueToTrainerSight(collision, x, y);
if (collision != 0 && (collision & ~(1 << (COLLISION_OUTSIDE_RANGE - 1))))
return 0;
}

View File

@ -43,12 +43,8 @@ extern const u8 EventScript_SprayWoreOff[];
#define NUM_FISHING_SPOTS_3 149
#define NUM_FISHING_SPOTS (NUM_FISHING_SPOTS_1 + NUM_FISHING_SPOTS_2 + NUM_FISHING_SPOTS_3)
#define WILD_CHECK_REPEL (1 << 0)
#define WILD_CHECK_KEEN_EYE (1 << 1)
static u16 FeebasRandom(void);
static void FeebasSeedRng(u16 seed);
static bool8 IsWildLevelAllowedByRepel(u8 level);
static void ApplyFluteEncounterRateMod(u32 *encRate);
static void ApplyCleanseTagEncounterRateMod(u32 *encRate);
static u8 GetMaxLevelOfSpeciesInWildTable(const struct WildPokemon *wildMon, enum Species species, enum WildPokemonArea area);
@ -57,7 +53,6 @@ static bool8 TryGetAbilityInfluencedWildMonIndex(const struct WildPokemon *wildM
#else
static bool8 TryGetAbilityInfluencedWildMonIndex(const struct WildPokemon *wildMon, enum Type type, enum Ability ability, u8 *monIndex);
#endif
static bool8 IsAbilityAllowingEncounter(u8 level);
EWRAM_DATA static u8 sWildEncountersDisabled = 0;
EWRAM_DATA static u32 sFeebasRngValue = 0;
@ -67,7 +62,7 @@ EWRAM_DATA u8 gChainFishingDexNavStreak = 0;
#include "data/wild_encounters.h"
static const struct WildPokemon sWildFeebas = {20, 25, SPECIES_FEEBAS};
const struct WildPokemon gWildFeebas = {20, 25, SPECIES_FEEBAS};
static const u16 sRoute119WaterTileData[] =
{
@ -113,18 +108,16 @@ static u16 GetFeebasFishingSpotId(s16 targetX, s16 targetY, u8 section)
return spotId + 1;
}
static bool8 CheckFeebas(void)
bool8 CheckFeebasAtCoords(s16 x, s16 y)
{
u8 i;
u16 feebasSpots[NUM_FEEBAS_SPOTS];
s16 x, y;
u8 route119Section = 0;
u16 spotId;
if (gSaveBlock1Ptr->location.mapGroup == MAP_GROUP(MAP_ROUTE119)
&& gSaveBlock1Ptr->location.mapNum == MAP_NUM(MAP_ROUTE119))
{
GetXYCoordsOneStepInFrontOfPlayer(&x, &y);
x -= MAP_OFFSET;
y -= MAP_OFFSET;
@ -328,7 +321,7 @@ static u32 ChooseWildMonIndex_Fishing(u8 rod)
return wildMonIndex;
}
static u8 ChooseWildMonLevel(const struct WildPokemon *wildPokemon, u8 wildMonIndex, enum WildPokemonArea area)
u8 ChooseWildMonLevel(const struct WildPokemon *wildPokemon, u8 wildMonIndex, enum WildPokemonArea area)
{
u8 min;
u8 max;
@ -483,7 +476,7 @@ void CreateWildMon(enum Species species, u8 level)
#define TRY_GET_ABILITY_INFLUENCED_WILD_MON_INDEX(wildPokemon, type, ability, ptr, count) TryGetAbilityInfluencedWildMonIndex(wildPokemon, type, ability, ptr)
#endif
static bool8 TryGenerateWildMon(const struct WildPokemonInfo *wildMonInfo, enum WildPokemonArea area, u8 flags)
bool8 TryGenerateWildMon(const struct WildPokemonInfo *wildMonInfo, enum WildPokemonArea area, u8 flags)
{
u8 wildMonIndex = 0;
u8 level;
@ -552,7 +545,7 @@ static u16 GenerateFishingWildMon(const struct WildPokemonInfo *wildMonInfo, u8
return wildMonSpecies;
}
static bool8 SetUpMassOutbreakEncounter(u8 flags)
bool8 SetUpMassOutbreakEncounter(u8 flags)
{
u16 i;
@ -566,7 +559,7 @@ static bool8 SetUpMassOutbreakEncounter(u8 flags)
return TRUE;
}
static bool8 DoMassOutbreakEncounterTest(void)
bool8 DoMassOutbreakEncounterTest(void)
{
if (gSaveBlock1Ptr->outbreakPokemonSpecies != SPECIES_NONE
&& gSaveBlock1Ptr->location.mapNum == gSaveBlock1Ptr->outbreakLocationMapNum
@ -636,7 +629,7 @@ static bool8 AllowWildCheckOnNewMetatile(void)
return TRUE;
}
static bool8 AreLegendariesInSootopolisPreventingEncounters(void)
bool8 AreLegendariesInSootopolisPreventingEncounters(void)
{
if (gSaveBlock1Ptr->location.mapGroup != MAP_GROUP(MAP_SOOTOPOLIS_CITY)
|| gSaveBlock1Ptr->location.mapNum != MAP_NUM(MAP_SOOTOPOLIS_CITY))
@ -688,7 +681,7 @@ bool8 StandardWildEncounter(u16 curMetatileBehavior, u16 prevMetatileBehavior)
else if (TryGenerateWildMon(gBattlePyramidWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo, WILD_AREA_LAND, WILD_CHECK_KEEN_EYE) != TRUE)
return FALSE;
GenerateBattlePyramidWildMon();
GenerateBattlePyramidWildMon(SPECIES_NONE);
BattleSetup_StartWildBattle();
return TRUE;
}
@ -865,7 +858,7 @@ bool8 SweetScentWildEncounter(void)
if (TryGenerateWildMon(gBattlePyramidWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo, WILD_AREA_LAND, 0) != TRUE)
return FALSE;
GenerateBattlePyramidWildMon();
GenerateBattlePyramidWildMon(SPECIES_NONE);
BattleSetup_StartWildBattle();
return TRUE;
}
@ -932,14 +925,16 @@ void FishingWildEncounter(u8 rod)
{
enum Species species;
u32 headerId;
s16 x, y;
enum TimeOfDay timeOfDay;
gIsFishingEncounter = TRUE;
if (CheckFeebas() == TRUE)
GetXYCoordsOneStepInFrontOfPlayer(&x, &y);
if (CheckFeebasAtCoords(x, y) == TRUE)
{
u8 level = ChooseWildMonLevel(&sWildFeebas, 0, WILD_AREA_FISHING);
u8 level = ChooseWildMonLevel(&gWildFeebas, 0, WILD_AREA_FISHING);
species = sWildFeebas.species;
species = gWildFeebas.species;
CreateWildMon(species, level);
}
else
@ -1050,7 +1045,7 @@ bool8 UpdateRepelCounter(void)
return FALSE;
}
static bool8 IsWildLevelAllowedByRepel(u8 wildLevel)
bool8 IsWildLevelAllowedByRepel(u8 wildLevel)
{
u8 i;
@ -1069,7 +1064,7 @@ static bool8 IsWildLevelAllowedByRepel(u8 wildLevel)
return FALSE;
}
static bool8 IsAbilityAllowingEncounter(u8 level)
bool8 IsAbilityAllowingEncounter(u8 level)
{
enum Ability ability;

1845
src/wild_encounter_ow.c Normal file

File diff suppressed because it is too large Load Diff