From 2db9ab2a2f68f66383edde08b9d731002f9a9b33 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Thu, 16 Nov 2023 13:08:47 -0500 Subject: [PATCH] Document camera sprite functions --- include/event_object_movement.h | 10 +++- src/event_object_movement.c | 102 ++++++++++++++++---------------- src/field_camera.c | 4 +- src/field_effect.c | 28 ++++----- src/field_player_avatar.c | 6 +- 5 files changed, 78 insertions(+), 72 deletions(-) diff --git a/include/event_object_movement.h b/include/event_object_movement.h index 01269cdb5eb2..2a273b79914c 100644 --- a/include/event_object_movement.h +++ b/include/event_object_movement.h @@ -71,6 +71,12 @@ enum ReflectionTypes #define GROUND_EFFECT_FLAG_HOT_SPRINGS (1 << 18) #define GROUND_EFFECT_FLAG_SEAWEED (1 << 19) +// Sprite data for the CameraObject functions +#define sCamera_FollowSpriteId data[0] +#define sCamera_State data[1] +#define sCamera_MoveX data[2] +#define sCamera_MoveY data[3] + struct StepAnimTable { const union AnimCmd *const *anims; @@ -123,7 +129,7 @@ u8 TrySpawnObjectEvent(u8 localId, u8 mapNum, u8 mapGroup); u8 SpawnSpecialObjectEventParameterized(u8 graphicsId, u8 movementBehavior, u8 localId, s16 x, s16 y, u8 elevation); u8 SpawnSpecialObjectEvent(struct ObjectEventTemplate *); void SetSpritePosToMapCoords(s16 mapX, s16 mapY, s16 *destX, s16 *destY); -void CameraObjectReset1(void); +void CameraObjectReset(void); void ObjectEventSetGraphicsId(struct ObjectEvent *, u8 graphicsId); void ObjectEventTurn(struct ObjectEvent *, u8 direction); void ObjectEventTurnByLocalIdAndMap(u8 localId, u8 mapNum, u8 mapGroup, u8 direction); @@ -211,7 +217,7 @@ u16 GetObjectPaletteTag(u8 palSlot); void UpdateObjectEventSpriteInvisibility(struct Sprite *sprite, bool8 invisible); s16 GetFigure8XOffset(s16 idx); s16 GetFigure8YOffset(s16 idx); -void CameraObjectReset2(void); +void CameraObjectFreeze(void); u8 GetObjectEventBerryTreeId(u8 objectEventId); void SetBerryTreeJustPicked(u8 mapId, u8 mapNumber, u8 mapGroup); bool8 IsBerryTreeSparkling(u8 localId, u8 mapNum, u8 mapGroup); diff --git a/src/event_object_movement.c b/src/event_object_movement.c index a181ea9f2188..5a746579d4ac 100644 --- a/src/event_object_movement.c +++ b/src/event_object_movement.c @@ -144,9 +144,9 @@ static u8 FindObjectEventPaletteIndexByTag(u16); static void _PatchObjectPalette(u16, u8); static bool8 ObjectEventDoesElevationMatch(struct ObjectEvent *, u8); static void SpriteCB_CameraObject(struct Sprite *); -static void CameraObject_0(struct Sprite *); -static void CameraObject_1(struct Sprite *); -static void CameraObject_2(struct Sprite *); +static void CameraObject_Init(struct Sprite *); +static void CameraObject_UpdateMove(struct Sprite *); +static void CameraObject_UpdateFrozen(struct Sprite *); static const struct ObjectEventTemplate *FindObjectEventTemplateByLocalId(u8, const struct ObjectEventTemplate *, u8); static void ClearObjectEventMovement(struct ObjectEvent *, struct Sprite *); static void ObjectEventSetSingleMovement(struct ObjectEvent *, struct Sprite *, u8); @@ -193,10 +193,16 @@ static const struct SpriteTemplate sCameraSpriteTemplate = { .callback = SpriteCB_CameraObject }; +enum { + CAMERA_STATE_INIT, + CAMERA_STATE_MOVE, + CAMERA_STATE_FROZEN, +}; + static void (*const sCameraObjectFuncs[])(struct Sprite *) = { - CameraObject_0, - CameraObject_1, - CameraObject_2, + [CAMERA_STATE_INIT] = CameraObject_Init, + [CAMERA_STATE_MOVE] = CameraObject_UpdateMove, + [CAMERA_STATE_FROZEN] = CameraObject_UpdateFrozen, }; #include "data/object_events/object_event_graphics.h" @@ -1836,7 +1842,7 @@ void ObjectEventSetGraphicsId(struct ObjectEvent *objectEvent, u8 graphicsId) sprite->x += 8; sprite->y += 16 + sprite->centerToCornerVecY; if (objectEvent->trackedByCamera) - CameraObjectReset1(); + CameraObjectReset(); } void ObjectEventSetGraphicsIdByLocalIdAndMap(u8 localId, u8 mapNum, u8 mapGroup, u8 graphicsId) @@ -2128,7 +2134,7 @@ void MoveObjectEventToMapCoords(struct ObjectEvent *objectEvent, s16 x, s16 y) sprite->y += 16 + sprite->centerToCornerVecY; ResetObjectEventFldEffData(objectEvent); if (objectEvent->trackedByCamera) - CameraObjectReset1(); + CameraObjectReset(); } void TryMoveObjectEventToMapCoords(u8 localId, u8 mapNum, u8 mapGroup, s16 x, s16 y) @@ -2204,15 +2210,15 @@ void UpdateObjectEventsForCameraUpdate(s16 x, s16 y) RemoveObjectEventsOutsideView(); } -#define sLinkedSpriteId data[0] -#define sState data[1] - -u8 AddCameraObject(u8 linkedSpriteId) +// The "CameraObject" functions below are responsible for an invisible sprite +// that follows the movements of a different sprite (normally the player's sprite) +// and tracks x/y movement distances for the camera so it knows where to move. +u8 AddCameraObject(u8 followSpriteId) { u8 spriteId = CreateSprite(&sCameraSpriteTemplate, 0, 0, 4); gSprites[spriteId].invisible = TRUE; - gSprites[spriteId].sLinkedSpriteId = linkedSpriteId; + gSprites[spriteId].sCamera_FollowSpriteId = followSpriteId; return spriteId; } @@ -2221,35 +2227,37 @@ static void SpriteCB_CameraObject(struct Sprite *sprite) void (*callbacks[ARRAY_COUNT(sCameraObjectFuncs)])(struct Sprite *); memcpy(callbacks, sCameraObjectFuncs, sizeof sCameraObjectFuncs); - callbacks[sprite->sState](sprite); + callbacks[sprite->sCamera_State](sprite); } -static void CameraObject_0(struct Sprite *sprite) +static void CameraObject_Init(struct Sprite *sprite) { - sprite->x = gSprites[sprite->sLinkedSpriteId].x; - sprite->y = gSprites[sprite->sLinkedSpriteId].y; + sprite->x = gSprites[sprite->sCamera_FollowSpriteId].x; + sprite->y = gSprites[sprite->sCamera_FollowSpriteId].y; sprite->invisible = TRUE; - sprite->sState = 1; - CameraObject_1(sprite); + sprite->sCamera_State = CAMERA_STATE_MOVE; + CameraObject_UpdateMove(sprite); } -static void CameraObject_1(struct Sprite *sprite) +static void CameraObject_UpdateMove(struct Sprite *sprite) { - s16 x = gSprites[sprite->sLinkedSpriteId].x; - s16 y = gSprites[sprite->sLinkedSpriteId].y; + s16 x = gSprites[sprite->sCamera_FollowSpriteId].x; + s16 y = gSprites[sprite->sCamera_FollowSpriteId].y; - sprite->data[2] = x - sprite->x; - sprite->data[3] = y - sprite->y; + sprite->sCamera_MoveX = x - sprite->x; + sprite->sCamera_MoveY = y - sprite->y; sprite->x = x; sprite->y = y; } -static void CameraObject_2(struct Sprite *sprite) +// Invisible sprite will continue to follow the parent sprite, +// but no corresponding camera movement will be shown. +static void CameraObject_UpdateFrozen(struct Sprite *sprite) { - sprite->x = gSprites[sprite->sLinkedSpriteId].x; - sprite->y = gSprites[sprite->sLinkedSpriteId].y; - sprite->data[2] = 0; - sprite->data[3] = 0; + sprite->x = gSprites[sprite->sCamera_FollowSpriteId].x; + sprite->y = gSprites[sprite->sCamera_FollowSpriteId].y; + sprite->sCamera_MoveX = 0; + sprite->sCamera_MoveY = 0; } static struct Sprite *FindCameraSprite(void) @@ -2264,51 +2272,43 @@ static struct Sprite *FindCameraSprite(void) return NULL; } -void CameraObjectReset1(void) +void CameraObjectReset(void) { - struct Sprite *camera; - - camera = FindCameraSprite(); + struct Sprite *camera = FindCameraSprite(); if (camera != NULL) { - camera->sState = 0; + camera->sCamera_State = CAMERA_STATE_INIT; camera->callback(camera); } } void CameraObjectSetFollowedSpriteId(u8 spriteId) { - struct Sprite *camera; - - camera = FindCameraSprite(); + struct Sprite *camera = FindCameraSprite(); if (camera != NULL) { - camera->sLinkedSpriteId = spriteId; - CameraObjectReset1(); + camera->sCamera_FollowSpriteId = spriteId; + CameraObjectReset(); } } static u8 UNUSED CameraObjectGetFollowedSpriteId(void) { - struct Sprite *camera; - - camera = FindCameraSprite(); + struct Sprite *camera = FindCameraSprite(); if (camera == NULL) return MAX_SPRITES; - return camera->sLinkedSpriteId; + return camera->sCamera_FollowSpriteId; } -void CameraObjectReset2(void) +void CameraObjectFreeze(void) { - // UB: Possible null dereference -#ifdef UBFIX struct Sprite *camera = FindCameraSprite(); - if (camera) - camera->sState = 2; -#else - FindCameraSprite()->sState = 2; -#endif // UBFIX +#ifdef UBFIX // Possible null dereference + if (camera == NULL) + return; +#endif + camera->sCamera_State = CAMERA_STATE_FROZEN; } u8 CopySprite(struct Sprite *sprite, s16 x, s16 y, u8 subpriority) diff --git a/src/field_camera.c b/src/field_camera.c index 3f7e29208ca5..31ebc63c0529 100644 --- a/src/field_camera.c +++ b/src/field_camera.c @@ -331,8 +331,8 @@ static void CameraUpdateCallback(struct CameraObject *fieldCamera) { if (fieldCamera->spriteId != 0) { - fieldCamera->movementSpeedX = gSprites[fieldCamera->spriteId].data[2]; - fieldCamera->movementSpeedY = gSprites[fieldCamera->spriteId].data[3]; + fieldCamera->movementSpeedX = gSprites[fieldCamera->spriteId].sCamera_MoveX; + fieldCamera->movementSpeedY = gSprites[fieldCamera->spriteId].sCamera_MoveY; } } diff --git a/src/field_effect.c b/src/field_effect.c index 86f1ca97d2e0..4c82d0f0c4bf 100644 --- a/src/field_effect.c +++ b/src/field_effect.c @@ -1444,7 +1444,7 @@ static bool8 FallWarpEffect_Init(struct Task *task) struct Sprite *playerSprite; playerObject = &gObjectEvents[gPlayerAvatar.objectEventId]; playerSprite = &gSprites[gPlayerAvatar.spriteId]; - CameraObjectReset2(); + CameraObjectFreeze(); gObjectEvents[gPlayerAvatar.objectEventId].invisible = TRUE; gPlayerAvatar.preventStep = TRUE; ObjectEventSetHeldMovement(playerObject, GetFaceDirectionMovementAction(GetPlayerFacingDirection())); @@ -1540,7 +1540,7 @@ static bool8 FallWarpEffect_End(struct Task *task) { gPlayerAvatar.preventStep = FALSE; UnlockPlayerFieldControls(); - CameraObjectReset1(); + CameraObjectReset(); UnfreezeObjectEvents(); InstallCameraPanAheadCallback(); DestroyTask(FindTaskIdByFunc(Task_FallWarpFieldEffect)); @@ -1579,7 +1579,7 @@ static void Task_EscalatorWarpOut(u8 taskId) static bool8 EscalatorWarpOut_Init(struct Task *task) { FreezeObjectEvents(); - CameraObjectReset2(); + CameraObjectFreeze(); StartEscalator(task->tGoingUp); task->tState++; return FALSE; @@ -1711,7 +1711,7 @@ static bool8 EscalatorWarpIn_Init(struct Task *task) s16 x; s16 y; u8 behavior; - CameraObjectReset2(); + CameraObjectFreeze(); objectEvent = &gObjectEvents[gPlayerAvatar.objectEventId]; ObjectEventSetHeldMovement(objectEvent, GetFaceDirectionMovementAction(DIR_EAST)); PlayerGetDestCoords(&x, &y); @@ -1811,7 +1811,7 @@ static bool8 EscalatorWarpIn_End(struct Task *task) objectEvent = &gObjectEvents[gPlayerAvatar.objectEventId]; if (ObjectEventClearHeldMovementIfFinished(objectEvent)) { - CameraObjectReset1(); + CameraObjectReset(); UnlockPlayerFieldControls(); ObjectEventSetHeldMovement(objectEvent, GetWalkNormalMovementAction(DIR_EAST)); DestroyTask(FindTaskIdByFunc(Task_EscalatorWarpIn)); @@ -1957,7 +1957,7 @@ static void Task_LavaridgeGymB1FWarp(u8 taskId) static bool8 LavaridgeGymB1FWarpEffect_Init(struct Task *task, struct ObjectEvent *objectEvent, struct Sprite *sprite) { FreezeObjectEvents(); - CameraObjectReset2(); + CameraObjectFreeze(); SetCameraPanningCallback(NULL); gPlayerAvatar.preventStep = TRUE; objectEvent->fixedPriority = 1; @@ -2072,7 +2072,7 @@ static void Task_LavaridgeGymB1FWarpExit(u8 taskId) static bool8 LavaridgeGymB1FWarpExitEffect_Init(struct Task *task, struct ObjectEvent *objectEvent, struct Sprite *sprite) { - CameraObjectReset2(); + CameraObjectFreeze(); FreezeObjectEvents(); gPlayerAvatar.preventStep = TRUE; objectEvent->invisible = TRUE; @@ -2101,7 +2101,7 @@ static bool8 LavaridgeGymB1FWarpExitEffect_PopOut(struct Task *task, struct Obje { task->data[0]++; objectEvent->invisible = FALSE; - CameraObjectReset1(); + CameraObjectReset(); PlaySE(SE_M_DIG); ObjectEventSetHeldMovement(objectEvent, GetJumpMovementAction(DIR_EAST)); } @@ -2150,7 +2150,7 @@ static void Task_LavaridgeGym1FWarp(u8 taskId) static bool8 LavaridgeGym1FWarpEffect_Init(struct Task *task, struct ObjectEvent *objectEvent, struct Sprite *sprite) { FreezeObjectEvents(); - CameraObjectReset2(); + CameraObjectFreeze(); gPlayerAvatar.preventStep = TRUE; objectEvent->fixedPriority = 1; task->data[0]++; @@ -2370,7 +2370,7 @@ static void TeleportWarpOutFieldEffect_Init(struct Task *task) { LockPlayerFieldControls(); FreezeObjectEvents(); - CameraObjectReset2(); + CameraObjectFreeze(); task->data[15] = GetPlayerFacingDirection(); task->tState++; } @@ -2452,7 +2452,7 @@ static void FieldCallback_TeleportWarpIn(void) FreezeObjectEvents(); gFieldCallback = NULL; gObjectEvents[gPlayerAvatar.objectEventId].invisible = TRUE; - CameraObjectReset2(); + CameraObjectFreeze(); CreateTask(Task_TeleportWarpIn, 0); } @@ -2536,7 +2536,7 @@ static void TeleportWarpInFieldEffect_SpinGround(struct Task *task) if ((++task->data[2]) > 4 && task->data[14] == objectEvent->facingDirection) { UnlockPlayerFieldControls(); - CameraObjectReset1(); + CameraObjectReset(); UnfreezeObjectEvents(); DestroyTask(FindTaskIdByFunc(Task_TeleportWarpIn)); } @@ -3268,7 +3268,7 @@ static void FlyOutFieldEffect_FlyOffWithBird(struct Task *task) objectEvent->inanimate = FALSE; objectEvent->hasShadow = FALSE; SetFlyBirdPlayerSpriteId(task->tBirdSpriteId, objectEvent->spriteId); - CameraObjectReset2(); + CameraObjectFreeze(); task->tState++; } } @@ -3483,7 +3483,7 @@ static void FlyInFieldEffect_BirdSwoopDown(struct Task *task) SetSurfBlob_BobState(objectEvent->fieldEffectSpriteId, BOB_NONE); } ObjectEventSetGraphicsId(objectEvent, GetPlayerAvatarGraphicsIdByStateId(PLAYER_AVATAR_STATE_SURFING)); - CameraObjectReset2(); + CameraObjectFreeze(); ObjectEventTurn(objectEvent, DIR_WEST); StartSpriteAnim(&gSprites[objectEvent->spriteId], ANIM_GET_ON_OFF_POKEMON_WEST); objectEvent->invisible = FALSE; diff --git a/src/field_player_avatar.c b/src/field_player_avatar.c index 5f4573c533b4..04aa5383bdfe 100644 --- a/src/field_player_avatar.c +++ b/src/field_player_avatar.c @@ -2093,7 +2093,7 @@ static void Task_DoPlayerSpinExit(u8 taskId) tSpeed = 1; tCurY = (u16)(sprite->y + sprite->y2) << 4; sprite->y2 = 0; - CameraObjectReset2(); + CameraObjectFreeze(); object->fixedPriority = TRUE; sprite->oam.priority = 0; sprite->subpriority = 0; @@ -2162,7 +2162,7 @@ static void Task_DoPlayerSpinEntrance(u8 taskId) tSubpriority = sprite->subpriority; tCurY = -((u16)sprite->y2 + 32) * 16; sprite->y2 = 0; - CameraObjectReset2(); + CameraObjectFreeze(); object->fixedPriority = TRUE; sprite->oam.priority = 1; sprite->subpriority = 0; @@ -2197,7 +2197,7 @@ static void Task_DoPlayerSpinEntrance(u8 taskId) object->fixedPriority = 0; sprite->oam.priority = tPriority; sprite->subpriority = tSubpriority; - CameraObjectReset1(); + CameraObjectReset(); DestroyTask(taskId); } break;