Merge branch 'followers' into lighting

This commit is contained in:
Ariel A 2022-09-10 22:29:18 -04:00
commit e54c18fb8e
13 changed files with 237 additions and 89 deletions

View File

@ -2,7 +2,7 @@ name: Build ROM
on:
push:
branches: [ romhack ]
branches: [ followers ]
pull_request:
jobs:

5
.gitignore vendored
View File

@ -36,8 +36,11 @@ porymap.project.cfg
.fuse_hidden*
.ccls-cache/*
.ropeproject/
overworld/
/overworld/
/icons/
*.sna
*.diff
*.sym
*.js
agbcc/
/*.zip

View File

@ -2,18 +2,18 @@
This is a fork of the [matching decompilation](https://github.com/pret/pokeemerald) at [PRET](https://github.com/pret).
The general philosophy of this fork is to maintain vanilla behavior & compatibility where possible, especially in terms of data structures. For that reason, this fork does not increase the size of the save data structure or the object event structure, nor does it add a `nature` field to the Pokémon structure.
This fork tries to maintain vanilla compatibility whenever possible. It doesn't increase the size of any save data structure or the object event structure.
There are several branches, each with additional features compared to vanilla:
There are several branches, each with one main feature:
**romhack** branch:
**followers** branch:
* [HGSS-style pokémon followers](https://bulbapedia.bulbagarden.net/wiki/Walking_Pok%C3%A9mon#Pok.C3.A9mon_HeartGold_and_SoulSilver) for all 386 pokémon, including emotes, the 28 Unown forms and a majority of follower messages.
* Dynamic overworld palettes & reflections compatible with vanilla berry trees.
* A way to change a pokemon's nature while mangling its PID as little as possible.
* Function to change a pokemon's nature while preserving most properties of its PID.
* Function to detect newer emulators/new GBA hardware.
**icons** branch:
* Everything from the **romhack** branch.
* Everything from the **followers** branch.
* All pokemon icons updated to Gen 6, based on [this repo](https://github.com/msikma/pokesprite/tree/master/icons/pokemon/regular)
* This includes compatibility with the PC, trade, contests, mail, Battle Dome. Examples:
![PC](https://i.imgur.com/wzwJfd1.png)
@ -22,7 +22,7 @@ There are several branches, each with additional features compared to vanilla:
* Icons share palettes with front sprites, meaning that shiny pokemon will also have shiny icons!
**lighting** branch:
* Everything from the **romhack** branch.
* Everything from the **followers** branch.
* Day/night shading compatible with weather.
* GSC-style window lights.
* WIP interframe-blended lamp lights at night, i.e in Rustboro.

View File

@ -162,5 +162,7 @@
create_movement_action figure_8, MOVEMENT_ACTION_FIGURE_8
create_movement_action fly_up, MOVEMENT_ACTION_FLY_UP
create_movement_action fly_down, MOVEMENT_ACTION_FLY_DOWN
create_movement_action exit_pokeball, MOVEMENT_ACTION_EXIT_POKEBALL
create_movement_action enter_pokeball, MOVEMENT_ACTION_ENTER_POKEBALL
create_movement_action step_end, MOVEMENT_ACTION_STEP_END

7
compile_flags.txt Normal file
View File

@ -0,0 +1,7 @@
-Wimplicit -Wparentheses -Werror -O2
-lgcc
-lc
-Iinclude
-Igflib
-undef
-Itools/agbcc/include

View File

@ -495,6 +495,7 @@ SootopolisCity_EventScript_RayquazaSceneFromPokeCenter::
removeobject LOCALID_GROUDON
removeobject LOCALID_KYOGRE
addobject LOCALID_RAYQUAZA
hideobjectat LOCALID_RAYQUAZA, MAP_SOOTOPOLIS_CITY
setvar VAR_0x8004, TRUE
special Script_DoRayquazaScene
waitstate

View File

@ -74,7 +74,7 @@ EventScript_FollowerJump::
return
EnterPokeballMovement::
.byte 0x9F @ EnterPokeball
enter_pokeball
step_end
@ Movement scripts below, movements are defined in movement.inc

View File

@ -16,9 +16,14 @@ enum {
FOLLOWER_EMOTION_LENGTH,
};
// This struct is optimized for size
// Each "section" can be used to combine multiple conditions,
// i.e, species and map
// Just set the flags accordingly and use the right union member
struct __attribute__((packed)) FollowerMsgInfoExtended {
const u8 *text;
const u8 *script;
union __attribute__((packed)) {
u16 species:10;
struct __attribute__((packed)) {
@ -55,7 +60,8 @@ struct __attribute__((packed)) FollowerMsgInfoExtended {
} wt;
u16 wtFlags:2; // 1 = weather matching, 2 = song, 3 = time
u16 weight:3;
u16 textSpread:1; // if set, `text` is an array of texts instead
// if set, `text` is treated as an array of up to 4 texts instead
u16 textSpread:1;
union __attribute__((packed)) {
struct __attribute__((packed)) {
@ -63,9 +69,63 @@ struct __attribute__((packed)) FollowerMsgInfoExtended {
u16 distance:6;
} mb;
} near;
u16 nearFlags:2; // 1 = mb within '+' shape distance away
u16 nearFlags:2; // 1 = mb within '+'-shaped distance away
};
extern const struct FollowerMsgInfoExtended gFollowerConditionalMessages[];
enum {
ST_FLAGS_SPECIES = 1,
ST_FLAGS_TYPE,
ST_FLAGS_STATUS,
};
enum {
MM_FLAGS_MAPSEC = 1,
MM_FLAGS_MAP,
MM_FLAGS_MB, // (m)etatile (b)ehavior
};
enum {
WT_FLAGS_WEATHER = 1,
WT_FLAGS_MUSIC,
WT_FLAGS_TIME,
};
#define NEAR_FLAGS_MB 1
enum {
COND_MSG_CELEBI,
COND_MSG_FIRE,
COND_MSG_EVER_GRANDE,
COND_MSG_ROUTE_112,
COND_MSG_DAY_CARE,
COND_MSG_MART,
COND_MSG_VICTORY_ROAD,
COND_MSG_BIKE_SHOP,
COND_MSG_MACHINES,
COND_MSG_SAILING,
COND_MSG_PUDDLE,
COND_MSG_SAND,
COND_MSG_GRASS,
COND_MSG_FOOTPRINTS,
COND_MSG_ELEVATOR,
COND_MSG_ICE_ROOM,
COND_MSG_ROUTE_117,
COND_MSG_DRAGON_GROWL,
COND_MSG_FEAR,
COND_MSG_FIRE_RAIN,
COND_MSG_FROZEN,
COND_MSG_SEASIDE,
COND_MSG_WATERFALL,
COND_MSG_RAIN,
COND_MSG_REFLECTION,
COND_MSG_LEAVES,
COND_MSG_ICE,
COND_MSG_BURN,
COND_MSG_DAY,
COND_MSG_NIGHT,
COND_MSG_COUNT,
};
extern const struct FollowerMsgInfoExtended gFollowerConditionalMessages[COND_MSG_COUNT];
#endif //GUARD_FOLLOWER_HELPER_H

View File

@ -408,17 +408,17 @@ u8 (*const gMovementTypeFuncs_FollowPlayer[])(struct ObjectEvent *, struct Sprit
};
bool8 (*const gFollowPlayerMovementFuncs[])(struct ObjectEvent *, struct Sprite *, u8, bool8(u8)) = {
FollowablePlayerMovement_Idle,
FollowablePlayerMovement_Idle,
FollowablePlayerMovement_Step,
FollowablePlayerMovement_GoSpeed1,
FollowablePlayerMovement_GoSpeed2,
FollowablePlayerMovement_Slide,
fph_IM_DIFFERENT,
FollowablePlayerMovement_GoSpeed4,
FollowablePlayerMovement_Jump,
FollowablePlayerMovement_Idle,
FollowablePlayerMovement_Idle,
[COPY_MOVE_NONE] = FollowablePlayerMovement_Idle,
[COPY_MOVE_FACE] = FollowablePlayerMovement_Idle,
[COPY_MOVE_WALK] = FollowablePlayerMovement_Step,
[COPY_MOVE_WALK_FAST] = FollowablePlayerMovement_GoSpeed1,
[COPY_MOVE_WALK_FASTER] = FollowablePlayerMovement_GoSpeed2,
[COPY_MOVE_SLIDE] = FollowablePlayerMovement_Slide,
[COPY_MOVE_JUMP_IN_PLACE] = fph_IM_DIFFERENT,
[COPY_MOVE_JUMP] = FollowablePlayerMovement_GoSpeed4,
[COPY_MOVE_JUMP2] = FollowablePlayerMovement_Step,
[COPY_MOVE_EMPTY_1] = FollowablePlayerMovement_Idle,
[COPY_MOVE_EMPTY_2] = FollowablePlayerMovement_Idle,
};
u8 (*const gMovementTypeFuncs_CopyPlayerInGrass[])(struct ObjectEvent *, struct Sprite *) = {

View File

@ -2089,7 +2089,7 @@ bool8 ScrFunc_getfolloweraction(struct ScriptContext *ctx) // Essentially a big
}
// Match scripted conditional messages
// With 50% chance, try to match scripted conditional messages
for (i = (Random() & 1) ? 30 : 0, j = 1; i < 30; i++) {
for (i = (Random() & 1) ? COND_MSG_COUNT : 0, j = 1; i < COND_MSG_COUNT; i++) {
const struct FollowerMsgInfoExtended *info = &gFollowerConditionalMessages[i];
if (info->stFlags == 1 && species != info->st.species)
continue;
@ -5092,7 +5092,7 @@ bool8 MovementType_FollowPlayer_Shadow(struct ObjectEvent *objectEvent, struct S
MoveObjectEventToMapCoords(objectEvent, gObjectEvents[gPlayerAvatar.objectEventId].currentCoords.x, gObjectEvents[gPlayerAvatar.objectEventId].currentCoords.y);
objectEvent->triggerGroundEffectsOnMove = FALSE; // Stop endless reflection spawning
}
sprite->data[1] = 1; // Enter active state; if the player moves the follower will appear
sprite->sTypeFuncId = 1; // Enter active state; if the player moves the follower will appear
return TRUE;
}
@ -5102,7 +5102,7 @@ bool8 MovementType_FollowPlayer_Active(struct ObjectEvent *objectEvent, struct S
return FALSE;
} else if (!IsFollowerVisible()) {
if (objectEvent->invisible) { // Return to shadowing state
sprite->data[1] = 0;
sprite->sTypeFuncId = 0;
return FALSE;
}
// Animate entering pokeball
@ -5110,7 +5110,7 @@ bool8 MovementType_FollowPlayer_Active(struct ObjectEvent *objectEvent, struct S
ObjectEventSetSingleMovement(objectEvent, sprite, MOVEMENT_ACTION_ENTER_POKEBALL);
objectEvent->singleMovementActive = 1;
sprite->animCmdIndex = 0; // Needed for animCmdIndex weirdness
sprite->data[1] = 2; // movement action sets state to 0
sprite->sTypeFuncId = 2; // movement action sets state to 0
return TRUE;
}
// TODO: Remove dependence on PlayerGetCopyableMovement
@ -5128,8 +5128,8 @@ bool8 MovementType_FollowPlayer_Moving(struct ObjectEvent *objectEvent, struct S
if (ObjectEventExecSingleMovementAction(objectEvent, sprite)) {
#endif
objectEvent->singleMovementActive = 0;
if (sprite->data[1]) { // restore nonzero state
sprite->data[1] = 1;
if (sprite->sTypeFuncId) { // restore nonzero state
sprite->sTypeFuncId = 1;
}
} else if (objectEvent->movementActionId != MOVEMENT_ACTION_EXIT_POKEBALL) {
UpdateFollowerTransformEffect(objectEvent, sprite);
@ -5142,7 +5142,7 @@ bool8 FollowablePlayerMovement_Idle(struct ObjectEvent *objectEvent, struct Spri
u8 direction;
if (!objectEvent->singleMovementActive) { // walk in place
ObjectEventSetSingleMovement(objectEvent, sprite, GetWalkInPlaceNormalMovementAction(objectEvent->facingDirection));
sprite->data[1] = 1;
sprite->sTypeFuncId = 1;
objectEvent->singleMovementActive = 1;
return TRUE;
} else if (ObjectEventExecSingleMovementAction(objectEvent, sprite)) { // finish movement action
@ -5180,7 +5180,7 @@ bool8 FollowablePlayerMovement_Step(struct ObjectEvent *objectEvent, struct Spri
ObjectEventSetSingleMovement(objectEvent, sprite, MOVEMENT_ACTION_EXIT_POKEBALL);
objectEvent->singleMovementActive = 1;
sprite->animCmdIndex = 0; // Needed because of weird animCmdIndex stuff
sprite->data[1] = 2;
sprite->sTypeFuncId = 2;
return TRUE;
} else if (x == targetX && y == targetY) { // don't move if already in the player's last position
return FALSE;
@ -5188,14 +5188,19 @@ bool8 FollowablePlayerMovement_Step(struct ObjectEvent *objectEvent, struct Spri
// Follow player
direction = GetDirectionToFace(x, y, targetX, targetY);
#ifdef MB_SIDEWAYS_STAIRS_RIGHT_SIDE // https://github.com/ghoulslash/pokeemerald/tree/sideways_stairs
MoveCoords(direction, &x, &y);
#ifdef MB_SIDEWAYS_STAIRS_RIGHT_SIDE // https://github.com/ghoulslash/pokeemerald/tree/sideways_stairs
GetCollisionAtCoords(objectEvent, x, y, direction); // Sets directionOverwrite for stairs
if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_DASH)) { // Set follow speed according to player's speed
if (GetLedgeJumpDirection(x, y, direction) != DIR_NONE) // InitJumpRegular will set the proper speed
ObjectEventSetSingleMovement(objectEvent, sprite, GetJump2MovementAction(direction));
else if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_DASH)) { // Set follow speed according to player's speed
if (playerAction >= MOVEMENT_ACTION_RUN_DOWN_SLOW && playerAction <= MOVEMENT_ACTION_RUN_RIGHT_SLOW)
objectEvent->movementActionId = GetWalkNormalMovementAction(direction);
else
objectEvent->movementActionId = GetWalkFastMovementAction(direction);
} else if (PlayerGetCopyableMovement() == COPY_MOVE_JUMP2) {
ObjectEventSetSingleMovement(objectEvent, sprite, GetWalkSlowMovementAction(direction));
} else {
if (playerAction >= MOVEMENT_ACTION_WALK_SLOW_DOWN && playerAction <= MOVEMENT_ACTION_WALK_SLOW_RIGHT)
ObjectEventSetSingleMovement(objectEvent, sprite, GetWalkSlowMovementAction(direction));
@ -5204,13 +5209,18 @@ bool8 FollowablePlayerMovement_Step(struct ObjectEvent *objectEvent, struct Spri
}
sprite->sActionFuncId = 0;
#else
if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_DASH)) // Set follow speed according to player's speed
if (GetLedgeJumpDirection(x, y, direction) != DIR_NONE) // InitJumpRegular will set the proper speed
ObjectEventSetSingleMovement(objectEvent, sprite, GetJump2MovementAction(direction));
else if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_DASH)) // Set follow speed according to player's speed
ObjectEventSetSingleMovement(objectEvent, sprite, GetWalkFastMovementAction(direction));
// If *player* jumps, make step take twice as long
else if (PlayerGetCopyableMovement() == COPY_MOVE_JUMP2)
ObjectEventSetSingleMovement(objectEvent, sprite, GetWalkSlowMovementAction(direction));
else
ObjectEventSetSingleMovement(objectEvent, sprite, GetWalkNormalMovementAction(direction));
#endif
objectEvent->singleMovementActive = 1;
sprite->data[1] = 2;
sprite->sTypeFuncId = 2;
return TRUE;
}
@ -5229,7 +5239,7 @@ bool8 FollowablePlayerMovement_GoSpeed1(struct ObjectEvent *objectEvent, struct
ObjectEventSetSingleMovement(objectEvent, sprite, GetFaceDirectionMovementAction(direction));
}
objectEvent->singleMovementActive = TRUE;
sprite->data[1] = 2;
sprite->sTypeFuncId = 2;
return TRUE;
}
@ -5248,7 +5258,7 @@ bool8 FollowablePlayerMovement_GoSpeed2(struct ObjectEvent *objectEvent, struct
ObjectEventSetSingleMovement(objectEvent, sprite, GetFaceDirectionMovementAction(direction));
}
objectEvent->singleMovementActive = TRUE;
sprite->data[1] = 2;
sprite->sTypeFuncId = 2;
return TRUE;
}
@ -5267,7 +5277,7 @@ bool8 FollowablePlayerMovement_Slide(struct ObjectEvent *objectEvent, struct Spr
ObjectEventSetSingleMovement(objectEvent, sprite, GetFaceDirectionMovementAction(direction));
}
objectEvent->singleMovementActive = TRUE;
sprite->data[1] = 2;
sprite->sTypeFuncId = 2;
return TRUE;
}
@ -5279,7 +5289,7 @@ bool8 fph_IM_DIFFERENT(struct ObjectEvent *objectEvent, struct Sprite *sprite, u
direction = GetCopyDirection(gInitialMovementTypeFacingDirections[objectEvent->movementType], objectEvent->directionSequenceIndex, direction);
ObjectEventSetSingleMovement(objectEvent, sprite, GetJumpInPlaceMovementAction(direction));
objectEvent->singleMovementActive = TRUE;
sprite->data[1] = 2;
sprite->sTypeFuncId = 2;
return TRUE;
}
@ -5298,7 +5308,7 @@ bool8 FollowablePlayerMovement_GoSpeed4(struct ObjectEvent *objectEvent, struct
ObjectEventSetSingleMovement(objectEvent, sprite, GetFaceDirectionMovementAction(direction));
}
objectEvent->singleMovementActive = TRUE;
sprite->data[1] = 2;
sprite->sTypeFuncId = 2;
return TRUE;
}
@ -5314,7 +5324,7 @@ bool8 FollowablePlayerMovement_Jump(struct ObjectEvent *objectEvent, struct Spri
MoveCoordsInDirection(direction, &x, &y, 2, 2);
ObjectEventSetSingleMovement(objectEvent, sprite, GetJump2MovementAction(direction));
objectEvent->singleMovementActive = TRUE;
sprite->data[1] = 2;
sprite->sTypeFuncId = 2;
return TRUE;
}
@ -6403,6 +6413,8 @@ enum {
JUMP_TYPE_HIGH,
JUMP_TYPE_LOW,
JUMP_TYPE_NORMAL,
JUMP_TYPE_FAST,
JUMP_TYPE_FASTER,
};
static void InitJump(struct ObjectEvent *objectEvent, struct Sprite *sprite, u8 direction, u8 distance, u8 type)
@ -6426,6 +6438,13 @@ static void InitJump(struct ObjectEvent *objectEvent, struct Sprite *sprite, u8
static void InitJumpRegular(struct ObjectEvent *objectEvent, struct Sprite *sprite, u8 direction, u8 distance, u8 type)
{
// For follower only, match the anim duration of the player's movement, whether dashing, walking or jumping
if (objectEvent->localId == OBJ_EVENT_ID_FOLLOWER
&& type == JUMP_TYPE_HIGH
&& distance == JUMP_DISTANCE_FAR
// In some areas (i.e Meteor Falls), the player can jump as the follower jumps, so preserve type in this case
&& PlayerGetCopyableMovement() != COPY_MOVE_JUMP2)
type = TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_DASH) ? JUMP_TYPE_FASTER : JUMP_TYPE_FAST;
InitJump(objectEvent, sprite, direction, distance, type);
SetStepAnimHandleAlternation(objectEvent, sprite, GetMoveDirectionAnimNum(objectEvent->facingDirection));
DoShadowFieldEffect(objectEvent);
@ -9655,7 +9674,16 @@ static u8 DoJumpSpriteMovement(struct Sprite *sprite)
if (sprite->sDistance != JUMP_DISTANCE_IN_PLACE)
Step1(sprite, sprite->sDirection);
sprite->y2 = GetJumpY(sprite->sTimer >> distanceToShift[sprite->sDistance], sprite->sJumpType);
if (sprite->sJumpType == JUMP_TYPE_FASTER) {
Step3(sprite, sprite->sDirection);
sprite->y2 = GetJumpY(sprite->sTimer >> distanceToShift[sprite->sDistance], JUMP_TYPE_NORMAL);
sprite->sTimer += 3;
} else if (sprite->sJumpType == JUMP_TYPE_FAST) {
Step1(sprite, sprite->sDirection);
sprite->y2 = GetJumpY(sprite->sTimer >> distanceToShift[sprite->sDistance], JUMP_TYPE_NORMAL);
sprite->sTimer++;
} else
sprite->y2 = GetJumpY(sprite->sTimer >> distanceToShift[sprite->sDistance], sprite->sJumpType);
sprite->sTimer++;

View File

@ -27,6 +27,7 @@
#include "trig.h"
#include "util.h"
#include "constants/field_effects.h"
#include "constants/event_objects.h"
#include "constants/event_object_movement.h"
#include "constants/metatile_behaviors.h"
#include "constants/rgb.h"
@ -1421,7 +1422,7 @@ void FieldCB_FallWarpExit(void)
Overworld_PlaySpecialMapMusic();
WarpFadeInScreen();
ScriptContext2_Enable();
FreezeObjectEvents(); // TODO: How does this interact with follower pokemon?
FreezeObjectEvents();
CreateTask(Task_FallWarpFieldEffect, 0);
gFieldCallback = NULL;
}
@ -1553,6 +1554,15 @@ static bool8 FallWarpEffect_End(struct Task *task)
#define tState data[0]
#define tGoingUp data[1]
static void HideFollowerForFieldEffect(void) {
struct ObjectEvent *followerObj = GetFollowerObject();
if (!followerObj || followerObj->invisible)
return;
ClearObjectEventMovement(followerObj, &gSprites[followerObj->spriteId]);
gSprites[followerObj->spriteId].animCmdIndex = 0; // Avoids a visual glitch with follower's animation frame
ObjectEventSetHeldMovement(followerObj, MOVEMENT_ACTION_ENTER_POKEBALL);
}
void StartEscalatorWarp(u8 metatileBehavior, u8 priority)
{
u8 taskId;
@ -1573,9 +1583,10 @@ static void Task_EscalatorWarpOut(u8 taskId)
static bool8 EscalatorWarpOut_Init(struct Task *task)
{
FreezeObjectEvents(); // TODO: Follower pokemon interaction
FreezeObjectEvents();
CameraObjectReset2();
StartEscalator(task->tGoingUp);
HideFollowerForFieldEffect(); // Hide follower before warping
task->tState++;
return FALSE;
}
@ -1954,7 +1965,7 @@ static void Task_LavaridgeGymB1FWarp(u8 taskId)
static bool8 LavaridgeGymB1FWarpEffect_Init(struct Task *task, struct ObjectEvent *objectEvent, struct Sprite *sprite)
{
FreezeObjectEvents(); // TODO: Follower pokemon interaction
FreezeObjectEvents();
CameraObjectReset2();
SetCameraPanningCallback(NULL);
gPlayerAvatar.preventStep = TRUE;
@ -1962,6 +1973,8 @@ static bool8 LavaridgeGymB1FWarpEffect_Init(struct Task *task, struct ObjectEven
objectEvent->noShadow = TRUE;
task->data[1] = 1;
task->data[0]++;
if (objectEvent->localId == OBJ_EVENT_ID_PLAYER) // Hide follower before warping
HideFollowerForFieldEffect();
return TRUE;
}
@ -2072,7 +2085,7 @@ static void Task_LavaridgeGymB1FWarpExit(u8 taskId)
static bool8 LavaridgeGymB1FWarpExitEffect_Init(struct Task *task, struct ObjectEvent *objectEvent, struct Sprite *sprite)
{
CameraObjectReset2();
FreezeObjectEvents(); // TODO: Follower pokemon interaction
FreezeObjectEvents();
gPlayerAvatar.preventStep = TRUE;
objectEvent->invisible = TRUE;
task->data[0]++;
@ -2148,12 +2161,14 @@ static void Task_LavaridgeGym1FWarp(u8 taskId)
static bool8 LavaridgeGym1FWarpEffect_Init(struct Task *task, struct ObjectEvent *objectEvent, struct Sprite *sprite)
{
FreezeObjectEvents(); // TODO: Follower pokemon interaction
FreezeObjectEvents();
CameraObjectReset2();
gPlayerAvatar.preventStep = TRUE;
objectEvent->fixedPriority = 1;
objectEvent->noShadow = TRUE;
task->data[0]++;
if (objectEvent->localId == OBJ_EVENT_ID_PLAYER) // Hide follower before warping
HideFollowerForFieldEffect();
return FALSE;
}
@ -2238,7 +2253,8 @@ void SpriteCB_AshPuff(struct Sprite *sprite)
void StartEscapeRopeFieldEffect(void)
{
ScriptContext2_Enable();
FreezeObjectEvents(); // TODO: Follower pokemon interaction
FreezeObjectEvents();
HideFollowerForFieldEffect(); // hide follower before warping
CreateTask(Task_EscapeRopeWarpOut, 80);
}
@ -3001,15 +3017,10 @@ static void Task_SurfFieldEffect(u8 taskId)
static void SurfFieldEffect_Init(struct Task *task)
{
struct ObjectEvent *followerObject = GetFollowerObject();
ScriptContext2_Enable();
FreezeObjectEvents();
// Put follower into pokeball before using Surf
if (followerObject && !followerObject->invisible) {
ClearObjectEventMovement(followerObject, &gSprites[followerObject->spriteId]);
gSprites[followerObject->spriteId].animCmdIndex = 0; // Needed because of weird animCmdIndex stuff
ObjectEventSetHeldMovement(followerObject, MOVEMENT_ACTION_ENTER_POKEBALL);
}
HideFollowerForFieldEffect();
gPlayerAvatar.preventStep = TRUE;
SetPlayerAvatarStateMask(PLAYER_AVATAR_FLAG_SURFING);
PlayerGetDestCoords(&task->tDestX, &task->tDestY);

View File

@ -73,206 +73,235 @@ static const u8 sCondMsg45[] = _("Your POKéMON is staring spellbound\nat the ni
static const u8 sCondMsg46[] = _("Your POKéMON is happily gazing at\nthe beautiful, starry sky!");
static const u8* const sNightTexts[] = {sCondMsg45, sCondMsg46, NULL};
// Note that the size of this array must also be correct in event_object_movement
const struct FollowerMsgInfoExtended gFollowerConditionalMessages[30] = {
// See the struct definition in follower_helper.h for more info
const struct FollowerMsgInfoExtended gFollowerConditionalMessages[COND_MSG_COUNT] = {
[COND_MSG_CELEBI] =
{
.text = (u8*)sCelebiTexts,
.textSpread = 1,
.script = EventScript_FollowerDance,
.st = {.species = SPECIES_CELEBI},
.stFlags = 1, // MATCH_SPECIES
.stFlags = ST_FLAGS_SPECIES,
.emotion = FOLLOWER_EMOTION_NEUTRAL,
},
[COND_MSG_FIRE] =
{
.text = (u8*)sFireTexts,
.st = {.types = {.type1 = TYPE_FIRE, .type2 = TYPE_FIRE}},
.stFlags = 2, // MATCH_TYPES
.stFlags = ST_FLAGS_TYPE,
.emotion = FOLLOWER_EMOTION_NEUTRAL,
.textSpread = 1,
},
[COND_MSG_EVER_GRANDE] =
{
.text = sCondMsg06,
.script = EventScript_FollowerFaceUp,
.mm = {.map = {.mapNum = MAP_NUM(EVER_GRANDE_CITY), .mapGroup = MAP_GROUP(EVER_GRANDE_CITY)}},
.mmFlags = 2, // MATCH_MAP
.mmFlags = MM_FLAGS_MAP,
.emotion = FOLLOWER_EMOTION_HAPPY,
},
[COND_MSG_ROUTE_112] =
{
.text = sCondMsg07,
.mm = {.map = {.mapNum = MAP_NUM(ROUTE112), .mapGroup = MAP_GROUP(ROUTE112)}},
.mmFlags = 2, // MATCH_MAP
.mmFlags = MM_FLAGS_MAP,
.emotion = FOLLOWER_EMOTION_HAPPY,
},
[COND_MSG_DAY_CARE] =
{
.text = sCondMsg08,
.script = EventScript_FollowerNostalgia,
.mm = {.map = {.mapNum = MAP_NUM(ROUTE117_POKEMON_DAY_CARE), .mapGroup = MAP_GROUP(ROUTE117_POKEMON_DAY_CARE)}},
.mmFlags = 2, // MATCH_MAP
.mmFlags = MM_FLAGS_MAP,
.emotion = FOLLOWER_EMOTION_NEUTRAL,
},
[COND_MSG_MART] =
{
.text = (u8*)sShopTexts,
.textSpread = 1,
.script = EventScript_FollowerLookAround,
.wt = {.song = MUS_POKE_MART},
.wtFlags = 2, // MATCH_SONG
.wtFlags = WT_FLAGS_MUSIC,
.emotion = FOLLOWER_EMOTION_NEUTRAL,
},
[COND_MSG_VICTORY_ROAD] =
{
.text = sCondMsg11,
.wt = {.song = MUS_VICTORY_ROAD},
.wtFlags = 2, // MATCH_SONG
.wtFlags = WT_FLAGS_MUSIC,
.emotion = FOLLOWER_EMOTION_PENSIVE,
},
[COND_MSG_BIKE_SHOP] =
{
.text = sCondMsg12,
.mm = {.map = {.mapNum = MAP_NUM(MAUVILLE_CITY_BIKE_SHOP), .mapGroup = MAP_GROUP(MAUVILLE_CITY_BIKE_SHOP)}},
.mmFlags = 2, // MATCH_MAP
.mmFlags = MM_FLAGS_MAP,
.emotion = FOLLOWER_EMOTION_PENSIVE,
},
[COND_MSG_MACHINES] =
{
.text = (u8*)sMachineTexts,
.mm = {.map = {.mapNum = MAP_NUM(NEW_MAUVILLE_INSIDE), .mapGroup = MAP_GROUP(NEW_MAUVILLE_INSIDE)}},
.mmFlags = 2, // MAP
.mmFlags = MM_FLAGS_MAP,
.emotion = FOLLOWER_EMOTION_MUSIC,
.textSpread = 1,
},
[COND_MSG_SAILING] =
{
.text = (u8*)sBoatTexts,
.script = EventScript_FollowerLookAround,
.wt = {.song = MUS_SAILING},
.wtFlags = 2, // MATCH_SONG
.wtFlags = WT_FLAGS_MUSIC,
.emotion = FOLLOWER_EMOTION_MUSIC,
.textSpread = 1,
},
[COND_MSG_PUDDLE] =
{
.text = sCondMsg18,
.script = EventScript_FollowerHopping,
.mm = {.mb = {.behavior1 = MB_SHALLOW_WATER, .behavior2 = MB_PUDDLE}},
.mmFlags = 3, // MB
.mmFlags = MM_FLAGS_MB,
.emotion = FOLLOWER_EMOTION_MUSIC,
},
[COND_MSG_SAND] =
{
.text = sCondMsg19,
.mm = {.mb = {.behavior1 = MB_SAND, .behavior2 = MB_DEEP_SAND}},
.mmFlags = 3, // MB
.mmFlags = MM_FLAGS_MB,
.emotion = FOLLOWER_EMOTION_MUSIC,
},
[COND_MSG_GRASS] =
{
.text = sCondMsg20,
.mm = {.mb = {.behavior1 = MB_TALL_GRASS, .behavior2 = MB_LONG_GRASS}},
.mmFlags = 3, // MB
.mmFlags = MM_FLAGS_MB,
.emotion = FOLLOWER_EMOTION_MUSIC,
},
[COND_MSG_FOOTPRINTS] =
{
.text = sCondMsg21,
.mm = {.mb = {.behavior1 = MB_SAND, .behavior2 = MB_FOOTPRINTS}},
.mmFlags = 3, // MB
.mmFlags = MM_FLAGS_MB,
.emotion = FOLLOWER_EMOTION_MUSIC,
},
[COND_MSG_ELEVATOR] =
{
.text = (u8*)sElevatorTexts,
.textSpread = 1,
.mm = {.map = {.mapNum = MAP_NUM(LILYCOVE_CITY_DEPARTMENT_STORE_ELEVATOR), .mapGroup = MAP_GROUP(LILYCOVE_CITY_DEPARTMENT_STORE_ELEVATOR)}},
.mmFlags = 2, // MAP
.mmFlags = MM_FLAGS_MAP,
.emotion = FOLLOWER_EMOTION_SURPRISE,
},
[COND_MSG_ICE_ROOM] =
{
.text = (u8*)sColdTexts,
.textSpread = 1,
.mm = {.map = {.mapNum = MAP_NUM(SHOAL_CAVE_LOW_TIDE_ICE_ROOM), .mapGroup = MAP_GROUP(SHOAL_CAVE_LOW_TIDE_ICE_ROOM)}},
.mmFlags = 2, // MAP
.mmFlags = MM_FLAGS_MAP,
.emotion = FOLLOWER_EMOTION_SURPRISE,
},
[COND_MSG_ROUTE_117] =
{
.text = sCondMsg27,
.mm = {.map = {.mapNum = MAP_NUM(ROUTE117), .mapGroup = MAP_GROUP(ROUTE117)}},
.mmFlags = 2, // MAP
.mmFlags = MM_FLAGS_MAP,
.emotion = FOLLOWER_EMOTION_SURPRISE,
},
[COND_MSG_DRAGON_GROWL] =
{
.text = sCondMsg28,
.st = {.types = {.type1 = TYPE_DRAGON, .type2 = TYPE_DRAGON}},
.stFlags = 2, // MATCH_TYPES
.stFlags = ST_FLAGS_TYPE,
.mm = {.mapSec = {.mapSec = MAPSEC_SKY_PILLAR}},
.mmFlags = 1, // MAP_SEC
.mmFlags = MM_FLAGS_MAPSEC,
.emotion = FOLLOWER_EMOTION_UPSET,
},
[COND_MSG_FEAR] =
{
.text = (u8*)sFearTexts,
.textSpread = 1,
.st = {.types = {.type1 = TYPE_GHOST, .type2 = TYPE_NOT_TYPE1}},
.stFlags = 2, // TYPE
.stFlags = ST_FLAGS_TYPE,
.mm = {.mapSec = {.mapSec = MAPSEC_MT_PYRE}},
.mmFlags = 1, // MAP_SEC
.mmFlags = MM_FLAGS_MAPSEC,
.wt = {.song = MUS_MT_PYRE},
.wtFlags = 2, // SONG
.wtFlags = WT_FLAGS_MUSIC,
.emotion = FOLLOWER_EMOTION_UPSET,
},
[COND_MSG_FIRE_RAIN] =
{
.text = sCondMsg31,
.st = {.types = {.type1 = TYPE_FIRE, .type2 = TYPE_FIRE}},
.stFlags = 2, // TYPE
.stFlags = ST_FLAGS_TYPE,
.wt = {.weather = {.weather1 = WEATHER_RAIN, .weather2 = WEATHER_RAIN_THUNDERSTORM}},
.wtFlags = 1, // WEATHER
.wtFlags = WT_FLAGS_WEATHER,
.emotion = FOLLOWER_EMOTION_UPSET,
},
[COND_MSG_FROZEN] =
{
.text = sCondMsg32,
.st = {.status = STATUS1_FREEZE},
.stFlags = 3, // STATUS
.stFlags = ST_FLAGS_STATUS,
.emotion = FOLLOWER_EMOTION_UPSET,
},
[COND_MSG_SEASIDE] =
{
.text = (u8*)sSeaTexts,
.textSpread = 1,
.script = EventScript_FollowerFaceResult,
.near = {.mb = {.behavior = MB_OCEAN_WATER, .distance = 5}},
.nearFlags = 1, // mb
.nearFlags = NEAR_FLAGS_MB,
.emotion = FOLLOWER_EMOTION_MUSIC,
},
[COND_MSG_WATERFALL] =
{
.text = sCondMsg36,
.script = EventScript_FollowerFaceResult,
.near = {.mb = {.behavior = MB_WATERFALL, .distance = 5}},
.nearFlags = 1, // mb
.nearFlags = NEAR_FLAGS_MB,
.emotion = FOLLOWER_EMOTION_MUSIC,
},
[COND_MSG_RAIN] =
{
.text = sCondMsg37,
.st = {.types = {.type1 = TYPE_FIRE, .type2 = TYPE_NOT_TYPE1}},
.stFlags = 2, // TYPE
.stFlags = ST_FLAGS_TYPE,
.wt = {.weather = {.weather1 = WEATHER_RAIN, .weather2 = WEATHER_RAIN_THUNDERSTORM}},
.wtFlags = 1, // WEATHER
.wtFlags = WT_FLAGS_WEATHER,
.emotion = FOLLOWER_EMOTION_MUSIC,
},
[COND_MSG_REFLECTION] =
{
.text = sCondMsg38,
.script = EventScript_FollowerFaceResult,
.near = {.mb = {.behavior = MB_POND_WATER, .distance = 1}},
.nearFlags = 1, // mb
.nearFlags = NEAR_FLAGS_MB,
.emotion = FOLLOWER_EMOTION_PENSIVE,
},
[COND_MSG_LEAVES] =
{
.text = sCondMsg39,
.mm = {.mapSec = {.mapSec = MAPSEC_PETALBURG_WOODS}},
.mmFlags = 1, // MAP_SEC
.mmFlags = MM_FLAGS_MAPSEC,
.emotion = FOLLOWER_EMOTION_PENSIVE,
},
[COND_MSG_ICE] =
{
.text = (u8*)sIceTexts,
.textSpread = 1,
.script = EventScript_FollowerFaceResult,
.near = {.mb = {.behavior = MB_ICE, .distance = 1}},
.nearFlags = 1, // mb
.nearFlags = NEAR_FLAGS_MB,
.emotion = FOLLOWER_EMOTION_PENSIVE,
},
[COND_MSG_BURN] =
{
.text = sCondMsg42,
.st = {.status STATUS1_BURN},
.stFlags 3, // STATUS
.stFlags = ST_FLAGS_STATUS,
.emotion = FOLLOWER_EMOTION_SAD,
},
[COND_MSG_DAY] =
{
.text = (u8*)sDayTexts,
.textSpread = 1,
@ -280,6 +309,7 @@ const struct FollowerMsgInfoExtended gFollowerConditionalMessages[30] = {
.wtFlags = 3, // time
.emotion = FOLLOWER_EMOTION_MUSIC,
},
[COND_MSG_NIGHT] =
{
.text = (u8*)sNightTexts,
.textSpread = 1,

View File

@ -1,5 +1,6 @@
#include "global.h"
#include "rayquaza_scene.h"
#include "event_object_movement.h"
#include "sprite.h"
#include "task.h"
#include "graphics.h"
@ -15,6 +16,7 @@
#include "sound.h"
#include "constants/songs.h"
#include "constants/rgb.h"
#include "constants/event_objects.h"
#include "random.h"
/*
@ -1294,9 +1296,13 @@ void DoRayquazaScene(u8 animId, bool8 endEarly, void (*exitCallback)(void))
static void CB2_InitRayquazaScene(void)
{
u32 i;
SetVBlankHBlankCallbacksToNull();
ClearScheduledBgCopiesToVram();
ScanlineEffect_Stop();
for (i = 0; i < OBJECT_EVENTS_COUNT; i++)
if (gObjectEvents[i].graphicsId == OBJ_EVENT_GFX_RAYQUAZA)
gObjectEvents[i].invisible = FALSE;
FreeAllSpritePalettes();
ResetPaletteFade();
ResetSpriteData();