From 237f9d3f73552938859e84a5e3a1394864e01528 Mon Sep 17 00:00:00 2001 From: Ariel A <24759293+aarant@users.noreply.github.com> Date: Mon, 22 Aug 2022 15:29:01 -0400 Subject: [PATCH 1/8] Fixed gitignore for icons & overworld. --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 94c424e695..244f3e5610 100644 --- a/.gitignore +++ b/.gitignore @@ -36,7 +36,8 @@ porymap.project.cfg .fuse_hidden* .ccls-cache/* .ropeproject/ -overworld/ +/overworld/ +/icons/ *.sna *.diff *.sym From 8c6005055310ba044db7a1c0312f77e11dc8af0e Mon Sep 17 00:00:00 2001 From: Ariel A <24759293+aarant@users.noreply.github.com> Date: Wed, 24 Aug 2022 19:02:46 -0400 Subject: [PATCH 2/8] Added proper movement actions for exiting/entering pokeball. --- asm/macros/movement.inc | 2 ++ data/scripts/follower.inc | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/asm/macros/movement.inc b/asm/macros/movement.inc index 62618379b6..8ce8330371 100644 --- a/asm/macros/movement.inc +++ b/asm/macros/movement.inc @@ -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 diff --git a/data/scripts/follower.inc b/data/scripts/follower.inc index a8303e5ba3..77e2da5cb4 100644 --- a/data/scripts/follower.inc +++ b/data/scripts/follower.inc @@ -74,7 +74,7 @@ EventScript_FollowerJump:: return EnterPokeballMovement:: - .byte 0x9F @ EnterPokeball + enter_pokeball step_end @ Movement scripts below, movements are defined in movement.inc From 5c7ee40171843c009b453e7be8a6cc16f7a228a9 Mon Sep 17 00:00:00 2001 From: Ariel A <24759293+aarant@users.noreply.github.com> Date: Sun, 28 Aug 2022 02:16:49 -0400 Subject: [PATCH 3/8] Fixed follower ledge jumps. --- .../object_events/movement_type_func_tables.h | 22 +++---- src/event_object_movement.c | 64 +++++++++++++------ 2 files changed, 57 insertions(+), 29 deletions(-) diff --git a/src/data/object_events/movement_type_func_tables.h b/src/data/object_events/movement_type_func_tables.h index c8cce4d103..c30f7daaf7 100755 --- a/src/data/object_events/movement_type_func_tables.h +++ b/src/data/object_events/movement_type_func_tables.h @@ -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 *) = { diff --git a/src/event_object_movement.c b/src/event_object_movement.c index 7071e1baa5..9822d2ba2b 100644 --- a/src/event_object_movement.c +++ b/src/event_object_movement.c @@ -4950,7 +4950,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; } @@ -4960,7 +4960,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 @@ -4968,7 +4968,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 @@ -4986,8 +4986,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); @@ -5000,7 +5000,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 @@ -5038,7 +5038,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; @@ -5046,14 +5046,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)); @@ -5062,13 +5067,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; } @@ -5087,7 +5097,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; } @@ -5106,7 +5116,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; } @@ -5125,7 +5135,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; } @@ -5137,7 +5147,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; } @@ -5156,7 +5166,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; } @@ -5172,7 +5182,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; } @@ -6261,6 +6271,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) @@ -6284,6 +6296,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); @@ -9512,7 +9531,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++; From 66acabe5c6439ea19592cc5ce00ca92f830a536c Mon Sep 17 00:00:00 2001 From: Ariel A <24759293+aarant@users.noreply.github.com> Date: Mon, 29 Aug 2022 00:38:23 -0400 Subject: [PATCH 4/8] Refactored follower messages. --- include/follower_helper.h | 64 ++++++++++++++++++++++-- src/event_object_movement.c | 2 +- src/follower_helper.c | 98 ++++++++++++++++++++++++------------- 3 files changed, 125 insertions(+), 39 deletions(-) diff --git a/include/follower_helper.h b/include/follower_helper.h index 54b4d4d164..115242fdb9 100644 --- a/include/follower_helper.h +++ b/include/follower_helper.h @@ -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,61 @@ 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_COUNT, +}; + +extern const struct FollowerMsgInfoExtended gFollowerConditionalMessages[COND_MSG_COUNT]; #endif //GUARD_FOLLOWER_HELPER_H diff --git a/src/event_object_movement.c b/src/event_object_movement.c index 9822d2ba2b..60e0b035da 100644 --- a/src/event_object_movement.c +++ b/src/event_object_movement.c @@ -2083,7 +2083,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) ? 28 : 0, j = 1; i < 28; 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; diff --git a/src/follower_helper.c b/src/follower_helper.c index b477f1d1e9..328bd8aab0 100644 --- a/src/follower_helper.c +++ b/src/follower_helper.c @@ -66,204 +66,232 @@ static const u8 sCondMsg41[] = _("{STR_VAR_1} is touching the ice."); static const u8* const sIceTexts[] = {sCondMsg26, sCondMsg40, sCondMsg41, NULL}; static const u8 sCondMsg42[] = _("{STR_VAR_1}'s burn looks painful!"); -// Note that the size of this array must also be correct in event_object_movement -const struct FollowerMsgInfoExtended gFollowerConditionalMessages[28] = { +// 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, }, }; From 8dc6da09fa6208ec63add8f8bbf17503787d4d20 Mon Sep 17 00:00:00 2001 From: Ariel A <24759293+aarant@users.noreply.github.com> Date: Sun, 28 Aug 2022 01:07:47 -0400 Subject: [PATCH 5/8] Fixed follower interaction with Lavaridge, Escalator, Escape warps. --- src/field_effect.c | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/src/field_effect.c b/src/field_effect.c index 3ad52f20e4..196eb44b37 100644 --- a/src/field_effect.c +++ b/src/field_effect.c @@ -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" @@ -1419,7 +1420,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; } @@ -1551,6 +1552,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; @@ -1571,9 +1581,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; } @@ -1949,13 +1960,15 @@ 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; objectEvent->fixedPriority = 1; task->data[1] = 1; task->data[0]++; + if (objectEvent->localId == OBJ_EVENT_ID_PLAYER) // Hide follower before warping + HideFollowerForFieldEffect(); return TRUE; } @@ -2066,7 +2079,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]++; @@ -2142,11 +2155,13 @@ 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; task->data[0]++; + if (objectEvent->localId == OBJ_EVENT_ID_PLAYER) // Hide follower before warping + HideFollowerForFieldEffect(); return FALSE; } @@ -2231,7 +2246,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); } @@ -2994,15 +3010,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); From 17758b7d66ade2003c5606aa61ad0d66a366a442 Mon Sep 17 00:00:00 2001 From: Ariel A <24759293+aarant@users.noreply.github.com> Date: Sat, 3 Sep 2022 14:41:09 -0400 Subject: [PATCH 6/8] Updated Github metadata & build script. --- .github/workflows/build.yml | 2 +- README.md | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 25e332491e..dd145771ef 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,7 +2,7 @@ name: Build ROM on: push: - branches: [ romhack ] + branches: [ followers ] pull_request: jobs: diff --git a/README.md b/README.md index c524149913..c3648a0443 100644 --- a/README.md +++ b/README.md @@ -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. From e322475aee9c083a948db478f7e33dc147cb81d0 Mon Sep 17 00:00:00 2001 From: Ariel A <24759293+aarant@users.noreply.github.com> Date: Sat, 3 Sep 2022 19:28:10 -0400 Subject: [PATCH 7/8] Fixed Rayquaza cutscene flicker. --- data/maps/SootopolisCity/scripts.inc | 1 + src/rayquaza_scene.c | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/data/maps/SootopolisCity/scripts.inc b/data/maps/SootopolisCity/scripts.inc index 69f74880ec..af6f68555c 100644 --- a/data/maps/SootopolisCity/scripts.inc +++ b/data/maps/SootopolisCity/scripts.inc @@ -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 diff --git a/src/rayquaza_scene.c b/src/rayquaza_scene.c index 5572ef8338..df03bfaebb 100644 --- a/src/rayquaza_scene.c +++ b/src/rayquaza_scene.c @@ -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(); From 19ccc01da31d692ecdca807dac47fd38fcc8a30c Mon Sep 17 00:00:00 2001 From: Ariel A <24759293+aarant@users.noreply.github.com> Date: Sat, 10 Sep 2022 20:48:27 -0400 Subject: [PATCH 8/8] Added `clangd` compile flags & updated .gitignore. --- .gitignore | 2 ++ compile_flags.txt | 7 +++++++ 2 files changed, 9 insertions(+) create mode 100644 compile_flags.txt diff --git a/.gitignore b/.gitignore index 244f3e5610..315e6c28da 100644 --- a/.gitignore +++ b/.gitignore @@ -42,3 +42,5 @@ porymap.project.cfg *.diff *.sym *.js +agbcc/ +/*.zip diff --git a/compile_flags.txt b/compile_flags.txt new file mode 100644 index 0000000000..c1aa53cc13 --- /dev/null +++ b/compile_flags.txt @@ -0,0 +1,7 @@ +-Wimplicit -Wparentheses -Werror -O2 +-lgcc +-lc +-Iinclude +-Igflib +-undef +-Itools/agbcc/include