diff --git a/data/maps/UnionRoom/scripts.inc b/data/maps/UnionRoom/scripts.inc index c214b06d3..38b5c3dda 100644 --- a/data/maps/UnionRoom/scripts.inc +++ b/data/maps/UnionRoom/scripts.inc @@ -1,12 +1,3 @@ -.set LOCALID_UNION_ROOM_PLAYER_4, 2 -.set LOCALID_UNION_ROOM_PLAYER_8, 3 -.set LOCALID_UNION_ROOM_PLAYER_7, 4 -.set LOCALID_UNION_ROOM_PLAYER_6, 5 -.set LOCALID_UNION_ROOM_PLAYER_5, 6 -.set LOCALID_UNION_ROOM_PLAYER_3, 7 -.set LOCALID_UNION_ROOM_PLAYER_2, 8 -.set LOCALID_UNION_ROOM_PLAYER_1, 9 - UnionRoom_MapScripts:: map_script MAP_SCRIPT_ON_RESUME, UnionRoom_OnResume map_script MAP_SCRIPT_ON_TRANSITION, UnionRoom_OnTransition diff --git a/include/constants/event_objects.h b/include/constants/event_objects.h index 99d3e4209..0eac72a29 100644 --- a/include/constants/event_objects.h +++ b/include/constants/event_objects.h @@ -189,10 +189,21 @@ #define TRACKS_FOOT 1 #define TRACKS_BIKE_TIRE 2 -#define OBJ_EVENT_ID_PLAYER 0xFF -#define OBJ_EVENT_ID_CAMERA 0x7F - #define OBJ_KIND_NORMAL 0 #define OBJ_KIND_CLONE 255 +// Special object event local ids +#define OBJ_EVENT_ID_PLAYER 0xFF +#define OBJ_EVENT_ID_CAMERA 0x7F + +// Object event local ids referenced in C files +#define LOCALID_UNION_ROOM_PLAYER_4 2 +#define LOCALID_UNION_ROOM_PLAYER_8 3 +#define LOCALID_UNION_ROOM_PLAYER_7 4 +#define LOCALID_UNION_ROOM_PLAYER_6 5 +#define LOCALID_UNION_ROOM_PLAYER_5 6 +#define LOCALID_UNION_ROOM_PLAYER_3 7 +#define LOCALID_UNION_ROOM_PLAYER_2 8 +#define LOCALID_UNION_ROOM_PLAYER_1 9 + #endif // GUARD_CONSTANTS_EVENT_OBJECTS_H diff --git a/include/rfu_union_tool.h b/include/rfu_union_tool.h deleted file mode 100644 index ffecc3f8d..000000000 --- a/include/rfu_union_tool.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef GUARD_UNION_ROOM_PLAYER_AVATAR_H -#define GUARD_UNION_ROOM_PLAYER_AVATAR_H - -#include "union_room.h" - -u8 ZeroUnionObjWork(struct UnionRoomObject * ptr); -void DestroyUnionRoomPlayerObjects(void); -void CreateGroupMemberObjectsInvisible(u8 *spriteIds, s32 group); -void DestroyGroupMemberObjects(u8 *spriteIds); -void MakeGroupAssemblyAreasPassable(void); -void ScheduleUnionRoomPlayerRefresh(struct WirelessLink_URoom *uroom_p); -void HandleUnionRoomPlayerRefresh(struct WirelessLink_URoom *uroom_p); -bool32 TryInteractWithUnionRoomMember(struct RfuPlayerList *main0_p, s16 *member_p, s16 *group_p, u8 *spriteIds); -void UpdateUnionGroupMemberFacing(u32 member, u32 group, struct RfuPlayerList *main0_p); - -#endif //GUARD_UNION_ROOM_PLAYER_AVATAR_H diff --git a/include/union_room_player_avatar.h b/include/union_room_player_avatar.h new file mode 100644 index 000000000..17ace17de --- /dev/null +++ b/include/union_room_player_avatar.h @@ -0,0 +1,16 @@ +#ifndef GUARD_UNION_ROOM_PLAYER_AVATAR_H +#define GUARD_UNION_ROOM_PLAYER_AVATAR_H + +#include "union_room.h" + +u8 InitUnionRoomPlayerObjects(struct UnionRoomObject * players); +void DestroyUnionRoomPlayerObjects(void); +void CreateUnionRoomPlayerSprites(u8 *spriteIds, s32 leaderId); +void DestroyUnionRoomPlayerSprites(u8 *spriteIds); +void MakeGroupAssemblyAreasPassable(void); +void ScheduleUnionRoomPlayerRefresh(struct WirelessLink_URoom *uroom); +void HandleUnionRoomPlayerRefresh(struct WirelessLink_URoom *uroom); +bool32 TryInteractWithUnionRoomMember(struct RfuPlayerList *list, s16 *memberIdPtr, s16 *leaderIdPtr, u8 *spriteIds); +void UpdateUnionRoomMemberFacing(u32 memberId, u32 leaderId, struct RfuPlayerList *list); + +#endif //GUARD_UNION_ROOM_PLAYER_AVATAR_H diff --git a/ld_script.txt b/ld_script.txt index 546f6b5fe..5c7a3751d 100644 --- a/ld_script.txt +++ b/ld_script.txt @@ -249,7 +249,7 @@ SECTIONS { src/trainer_fan_club.o(.text); src/quest_log_events.o(.text); src/union_room.o(.text); - src/rfu_union_tool.o(.text); + src/union_room_player_avatar.o(.text); src/union_room_battle.o(.text); src/pokemon_special_anim.o(.text); src/pokemon_special_anim_scene.o(.text); @@ -542,7 +542,7 @@ SECTIONS { src/trainer_fan_club.o(.rodata); src/quest_log_events.o(.rodata); src/union_room.o(.rodata); - src/rfu_union_tool.o(.rodata); + src/union_room_player_avatar.o(.rodata); src/union_room_battle.o(.rodata); src/union_room_message.o(.rodata); src/pokemon_special_anim.o(.rodata); diff --git a/src/pokemon.c b/src/pokemon.c index 6a164028e..e3cae699c 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -34,6 +34,7 @@ #include "constants/trainers.h" #include "constants/hold_effects.h" #include "constants/battle_move_effects.h" +#include "constants/union_room.h" #define SPECIES_TO_HOENN(name) [SPECIES_##name - 1] = HOENN_DEX_##name #define SPECIES_TO_NATIONAL(name) [SPECIES_##name - 1] = NATIONAL_DEX_##name @@ -1643,7 +1644,9 @@ static const u16 sDeoxysBaseStats[] = }; #endif -const u16 gLinkPlayerFacilityClasses[] = +// The classes used by other players in the Union Room. +// These should correspond with the overworld graphics in sUnionRoomObjGfxIds +const u16 gUnionRoomFacilityClasses[NUM_UNION_ROOM_CLASSES * GENDER_COUNT] = { // Male FACILITY_CLASS_COOLTRAINER_M, @@ -6031,19 +6034,19 @@ void SetDeoxysStats(void) u16 GetUnionRoomTrainerPic(void) { u8 linkId = GetMultiplayerId() ^ 1; - u32 arrId = gLinkPlayers[linkId].trainerId & 7; - arrId |= gLinkPlayers[linkId].gender << 3; - return FacilityClassToPicIndex(gLinkPlayerFacilityClasses[arrId]); + u32 arrId = gLinkPlayers[linkId].trainerId % NUM_UNION_ROOM_CLASSES; + arrId |= gLinkPlayers[linkId].gender * NUM_UNION_ROOM_CLASSES; + return FacilityClassToPicIndex(gUnionRoomFacilityClasses[arrId]); } u16 GetUnionRoomTrainerClass(void) { u8 linkId = GetMultiplayerId() ^ 1; - u32 arrId = gLinkPlayers[linkId].trainerId & 7; - arrId |= gLinkPlayers[linkId].gender << 3; - return gFacilityClassToTrainerClass[gLinkPlayerFacilityClasses[arrId]]; + u32 arrId = gLinkPlayers[linkId].trainerId % NUM_UNION_ROOM_CLASSES; + arrId |= gLinkPlayers[linkId].gender * NUM_UNION_ROOM_CLASSES; + return gFacilityClassToTrainerClass[gUnionRoomFacilityClasses[arrId]]; } void CreateEventLegalEnemyMon(void) diff --git a/src/rfu_union_tool.c b/src/rfu_union_tool.c deleted file mode 100644 index d6e77519d..000000000 --- a/src/rfu_union_tool.c +++ /dev/null @@ -1,663 +0,0 @@ -#include "global.h" -#include "event_data.h" -#include "event_object_movement.h" -#include "field_player_avatar.h" -#include "fieldmap.h" -#include "rfu_union_tool.h" -#include "script.h" -#include "task.h" -#include "constants/event_object_movement.h" -#include "constants/union_room.h" -#include "constants/event_objects.h" - -static EWRAM_DATA struct UnionRoomObject * UnionObjWork = NULL; -static EWRAM_DATA u32 sUnionObjRefreshTimer = 0; - -static u8 StartUnionObjAnimTask(void); -static u32 RfuUnionGroupMemberIsInvisible(u32 group, u32 member); -static void UnionPartnerObjectSetFacing(s32 member, s32 group, u8 direction); - -static const u8 sUnionObjectEventGfxIds[][10] = { - [MALE] = { - OBJ_EVENT_GFX_COOLTRAINER_M, - OBJ_EVENT_GFX_BLACKBELT, - OBJ_EVENT_GFX_CAMPER, - OBJ_EVENT_GFX_YOUNGSTER, - OBJ_EVENT_GFX_BOY, - OBJ_EVENT_GFX_BUG_CATCHER, - OBJ_EVENT_GFX_MAN, - OBJ_EVENT_GFX_ROCKER - }, - [FEMALE] = { - OBJ_EVENT_GFX_COOLTRAINER_F, - OBJ_EVENT_GFX_CHANNELER, - OBJ_EVENT_GFX_PICNICKER, - OBJ_EVENT_GFX_LASS, - OBJ_EVENT_GFX_WOMAN_1, - OBJ_EVENT_GFX_BATTLE_GIRL, - OBJ_EVENT_GFX_WOMAN_2, - OBJ_EVENT_GFX_BEAUTY - } -}; - -static const s16 sUnionPartnerCoords[][2] = { - { 4, 6}, - {13, 8}, - {10, 6}, - { 1, 8}, - {13, 4}, - { 7, 4}, - { 1, 4}, - { 7, 8} -}; - -static const s8 sFacingDirectionOffsets[][2] = { - [DIR_NONE] = { 0, 0}, - [DIR_SOUTH] = { 1, 0}, - [DIR_NORTH] = { 0, -1}, - [DIR_WEST] = {-1, 0}, - [DIR_EAST] = { 0, 1} -}; - -static const u8 sOppositeFacingDirection[] = { - [DIR_NONE] = DIR_NONE, - [DIR_SOUTH] = DIR_NORTH, - [DIR_NORTH] = DIR_SOUTH, - [DIR_WEST] = DIR_EAST, - [DIR_EAST] = DIR_WEST -}; - -static const u8 sUnionGroupMemberFacings[] = { - DIR_SOUTH, - DIR_WEST, - DIR_SOUTH, - DIR_EAST, - DIR_NORTH -}; - -static const u8 sUnionRoomLocalIds[] = { - 9, - 8, - 7, - 2, - 6, - 5, - 4, - 3 -}; - -// Unused -static const u16 sHidePlayerFlags[] = { - FLAG_HIDE_UNION_ROOM_PLAYER_1, - FLAG_HIDE_UNION_ROOM_PLAYER_2, - FLAG_HIDE_UNION_ROOM_PLAYER_3, - FLAG_HIDE_UNION_ROOM_PLAYER_4, - FLAG_HIDE_UNION_ROOM_PLAYER_5, - FLAG_HIDE_UNION_ROOM_PLAYER_6, - FLAG_HIDE_UNION_ROOM_PLAYER_7, - FLAG_HIDE_UNION_ROOM_PLAYER_8 -}; - -static bool32 is_walking_or_running(void) -{ - if (gPlayerAvatar.tileTransitionState == 2 || gPlayerAvatar.tileTransitionState == 0) - { - return TRUE; - } - else - { - return FALSE; - } -} - -static u8 GetUnionRoomPlayerGraphicsId(u32 gender, u32 id) -{ - return sUnionObjectEventGfxIds[gender][id % 8]; -} - -static void GetUnionRoomPlayerFacingCoords(u32 group, u32 member, s32 * xp, s32 * yp) -{ - *xp = sUnionPartnerCoords[group][0] + sFacingDirectionOffsets[member][0] + 7; - *yp = sUnionPartnerCoords[group][1] + sFacingDirectionOffsets[member][1] + 7; -} - -static bool32 IsUnionRoomPlayerFacingTileAt(u32 group, u32 member, s32 x, s32 y) -{ - if (sUnionPartnerCoords[group][0] + sFacingDirectionOffsets[member][0] + 7 != x) - { - return FALSE; - } - else if (sUnionPartnerCoords[group][1] + sFacingDirectionOffsets[member][1] + 7 != y) - { - return FALSE; - } - else - { - return TRUE; - } -} - -static bool32 IsUnionRoomPlayerHidden(u32 player_idx) -{ - return FlagGet(FLAG_HIDE_UNION_ROOM_PLAYER_1 + player_idx); -} - -static void HideUnionRoomPlayer(u32 player_idx) -{ - FlagSet(FLAG_HIDE_UNION_ROOM_PLAYER_1 + player_idx); -} - -static void ShowUnionRoomPlayer(u32 player_idx) -{ - FlagClear(FLAG_HIDE_UNION_ROOM_PLAYER_1 + player_idx); -} - -static void SetUnionRoomPlayerGfx(u32 playerIdx, u32 gfxId) -{ - VarSet(VAR_OBJ_GFX_ID_0 + playerIdx, gfxId); -} - -static void CreateUnionRoomPlayerObjectEvent(u32 playerIdx) -{ - TrySpawnObjectEvent(sUnionRoomLocalIds[playerIdx], gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup); -} - -static void RemoveUnionRoomPlayerObjectEvent(u32 playerIdx) -{ - RemoveObjectEventByLocalIdAndMap(sUnionRoomLocalIds[playerIdx], gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup); -} - -static bool32 SetUnionRoomPlayerEnterExitMovement(u32 playerIdx, const u8 * movement) -{ - u8 objectId; - struct ObjectEvent * object; - if (TryGetObjectEventIdByLocalIdAndMap(sUnionRoomLocalIds[playerIdx], gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, &objectId)) - { - return FALSE; - } - object = &gObjectEvents[objectId]; - if (ObjectEventIsMovementOverridden(object)) - { - return FALSE; - } - if (ObjectEventSetHeldMovement(object, *movement)) - { - AGB_ASSERT_EX(0, ABSPATH("rfu_union_tool.c"), 387); - return FALSE; - } - return TRUE; -} - -static bool32 TryReleaseUnionRoomPlayerObjectEvent(u32 playerIdx) -{ - u8 objectId; - struct ObjectEvent * object; - if (TryGetObjectEventIdByLocalIdAndMap(sUnionRoomLocalIds[playerIdx], gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, &objectId)) - { - return TRUE; - } - object = &gObjectEvents[objectId]; - if (!ObjectEventClearHeldMovementIfFinished(object)) - { - return FALSE; - } - if (!ArePlayerFieldControlsLocked()) - { - UnfreezeObjectEvent(object); - } - else - { - FreezeObjectEvent(object); - } - return TRUE; -} - -u8 ZeroUnionObjWork(struct UnionRoomObject * ptr) -{ - s32 i; - - sUnionObjRefreshTimer = 0; - UnionObjWork = ptr; - AGB_ASSERT_EX(UnionObjWork != NULL, ABSPATH("rfu_union_tool.c"), 442) - for (i = 0; i < 8; i++) - { - ptr[i].state = 0; - ptr[i].gfxId = 0; - ptr[i].animState = 0; - ptr[i].schedAnim = 0; - } - return StartUnionObjAnimTask(); -} - -static const u8 sMovement_UnionPlayerExit[2] = { - MOVEMENT_ACTION_FLY_UP, - MOVEMENT_ACTION_STEP_END -}; - -static bool32 AnimateUnionRoomPlayerDespawn(s8 * a0, u32 playerIdx, struct UnionRoomObject * ptr) -{ - switch (*a0) - { - case 0: - if (SetUnionRoomPlayerEnterExitMovement(playerIdx, sMovement_UnionPlayerExit) == TRUE) - { - HideUnionRoomPlayer(playerIdx); - (*a0)++; - } - break; - case 1: - if (TryReleaseUnionRoomPlayerObjectEvent(playerIdx)) - { - RemoveUnionRoomPlayerObjectEvent(playerIdx); - HideUnionRoomPlayer(playerIdx); - *a0 = 0; - return TRUE; - } - break; - } - return FALSE; -} - -static const u8 sMovement_UnionPlayerEnter[2] = { - MOVEMENT_ACTION_FLY_DOWN, - MOVEMENT_ACTION_STEP_END -}; - -static bool32 AnimateUnionRoomPlayerSpawn(s8 * state_p, u32 playerIdx, struct UnionRoomObject * ptr) -{ - s16 x, y; - - switch (*state_p) - { - case 0: - if (!is_walking_or_running()) - { - break; - } - PlayerGetDestCoords(&x, &y); - if (IsUnionRoomPlayerFacingTileAt(playerIdx, 0, x, y) == TRUE) - { - break; - } - player_get_pos_including_state_based_drift(&x, &y); - if (IsUnionRoomPlayerFacingTileAt(playerIdx, 0, x, y) == TRUE) - { - break; - } - SetUnionRoomPlayerGfx(playerIdx, ptr->gfxId); - CreateUnionRoomPlayerObjectEvent(playerIdx); - ShowUnionRoomPlayer(playerIdx); - (*state_p)++; - // fallthrough - case 3: // incorrect? - if (SetUnionRoomPlayerEnterExitMovement(playerIdx, sMovement_UnionPlayerEnter) == 1) - { - (*state_p)++; - } - break; - case 2: - if (TryReleaseUnionRoomPlayerObjectEvent(playerIdx)) - { - *state_p = 0; - return TRUE; - } - break; - } - return FALSE; -} - -static bool32 SpawnGroupLeader(u32 playerIdx, u32 gender, u32 idMod256) -{ - struct UnionRoomObject * ptr = &UnionObjWork[playerIdx]; - AGB_ASSERT_EX(UnionObjWork != NULL, ABSPATH("rfu_union_tool.c"), 561) - ptr->schedAnim = UNION_ROOM_SPAWN_IN; - ptr->gfxId = GetUnionRoomPlayerGraphicsId(gender, idMod256); - if (ptr->state == 0) - { - return TRUE; - } - else - { - return FALSE; - } -} - -static bool32 DespawnGroupLeader(u32 playerIdx) -{ - struct UnionRoomObject * ptr = &UnionObjWork[playerIdx]; - AGB_ASSERT_EX(UnionObjWork != NULL, ABSPATH("rfu_union_tool.c"), 577) - ptr->schedAnim = UNION_ROOM_SPAWN_OUT; - if (ptr->state == 1) - { - return TRUE; - } - else - { - return FALSE; - } -} - -static void AnimateUnionObj(u32 playerIdx, struct UnionRoomObject * ptr) -{ - switch (ptr->state) - { - case 0: - if (ptr->schedAnim == UNION_ROOM_SPAWN_IN) - { - ptr->state = 2; - ptr->animState = 0; - } - else - { - break; - } - // fallthrough - case 2: - if (!RfuUnionGroupMemberIsInvisible(playerIdx, 0) && ptr->schedAnim == 2) - { - ptr->state = 0; - ptr->animState = 0; - RemoveUnionRoomPlayerObjectEvent(playerIdx); - HideUnionRoomPlayer(playerIdx); - } - else if (AnimateUnionRoomPlayerSpawn(&ptr->animState, playerIdx, ptr) == TRUE) - { - ptr->state = 1; - } - break; - case 1: - if (ptr->schedAnim == UNION_ROOM_SPAWN_OUT) - { - ptr->state = 3; - ptr->animState = 0; - } - else - { - break; - } - // fallthrough - case 3: - if (AnimateUnionRoomPlayerDespawn(&ptr->animState, playerIdx, ptr) == TRUE) - { - ptr->state = 0; - } - break; - } - ptr->schedAnim = UNION_ROOM_SPAWN_NONE; -} - -static void Task_AnimateUnionObjs(u8 taskId) -{ - s32 i; - AGB_ASSERT_EX(UnionObjWork != NULL, ABSPATH("rfu_union_tool.c"), 643) - for (i = 0; i < 8; i++) - { - AnimateUnionObj(i, &UnionObjWork[i]); - } -} - -static u8 StartUnionObjAnimTask(void) -{ - if (FuncIsActiveTask(Task_AnimateUnionObjs) == TRUE) - { - AGB_ASSERT_EX(0, ABSPATH("rfu_union_tool.c"), 655) - return NUM_TASKS; - } - else - { - return CreateTask(Task_AnimateUnionObjs, 5); - } -} - -static void DestroyAnimateUnionObjsTask(void) -{ - u8 taskId = FindTaskIdByFunc(Task_AnimateUnionObjs); - if (taskId < NUM_TASKS) - { - DestroyTask(taskId); - } -} - -void DestroyUnionRoomPlayerObjects(void) -{ - s32 i; - for (i = 0; i < 8; i++) - { - if (!IsUnionRoomPlayerHidden(i)) - { - RemoveUnionRoomPlayerObjectEvent(i); - HideUnionRoomPlayer(i); - } - } - UnionObjWork = NULL; - DestroyAnimateUnionObjsTask(); -} - -void CreateGroupMemberObjectsInvisible(u8 * sprite_ids, s32 group) -{ - s32 i; - - for (i = 0; i < 5; i++) - { - s32 obj_id = 5 * group + i; - sprite_ids[obj_id] = CreateVirtualObject(OBJ_EVENT_GFX_MAN, obj_id - 0x38, sUnionPartnerCoords[group][0] + sFacingDirectionOffsets[i][0], sUnionPartnerCoords[group][1] + sFacingDirectionOffsets[i][1], 3, 1); - SetVirtualObjectInvisibility(obj_id - 0x38, TRUE); - } -} - -void DestroyGroupMemberObjects(u8 *spriteIds) -{ - s32 i; - for (i = 0; i < 40; i++) - { - DestroySprite(&gSprites[spriteIds[i]]); - } -} - -void MakeGroupAssemblyAreasPassable(void) -{ - s32 i, j, x, y; - for (i = 0; i < 8; i++) - { - for (j = 0; j < 5; j++) - { - GetUnionRoomPlayerFacingCoords(i, j, &x, &y); - MapGridSetMetatileImpassabilityAt(x, y, FALSE); - } - } -} - -static u8 UnionPartnerObjectGetFacing(u32 member, u32 group, struct RfuGameData * gname) -{ - if (member != 0) - { - return sUnionGroupMemberFacings[member]; - } - else if (gname->activity == 0x45) - { - return DIR_SOUTH; - } - else - { - return DIR_EAST; - } -} - -static u32 RfuUnionGroupMemberIsInvisible(u32 group, u32 member) -{ - return IsVirtualObjectInvisible(5 * group + member - 0x38); -} - -static void SpawnGroupMember(u32 groupNo, u32 memberNo, u8 direction, struct RfuGameData * gname) -{ - s32 x, y; - s32 objId = 5 * groupNo + memberNo; - if (RfuUnionGroupMemberIsInvisible(groupNo, memberNo) == TRUE) - { - SetVirtualObjectInvisibility(objId - 0x38, FALSE); - SetVirtualObjectSpriteAnim(objId - 0x38, UNION_ROOM_SPAWN_IN); - } - SetVirtualObjectGraphics(objId - 0x38, direction); - UnionPartnerObjectSetFacing(memberNo, groupNo, UnionPartnerObjectGetFacing(memberNo, groupNo, gname)); - GetUnionRoomPlayerFacingCoords(groupNo, memberNo, &x, &y); - MapGridSetMetatileImpassabilityAt(x, y, TRUE); -} - -static void DespawnGroupMember(u32 group, u32 member) -{ - s32 x, y; - SetVirtualObjectSpriteAnim(5 * group + member - 0x38, UNION_ROOM_SPAWN_OUT); - GetUnionRoomPlayerFacingCoords(group, member, &x, &y); - MapGridSetMetatileImpassabilityAt(x, y, FALSE); -} - -static void AssembleGroup(u32 group, struct RfuGameData * gname) -{ - s16 x, y, x2, y2; - s32 i; - - PlayerGetDestCoords(&x, &y); - player_get_pos_including_state_based_drift(&x2, &y2); - if (IsVirtualObjectInvisible(5 * group - 0x38) == TRUE) - { - if (IsUnionRoomPlayerFacingTileAt(group, 0, x, y) == TRUE || IsUnionRoomPlayerFacingTileAt(group, 0, x2, y2) == TRUE) - { - return; - } - SpawnGroupMember(group, 0, GetUnionRoomPlayerGraphicsId(gname->playerGender, gname->compatibility.playerTrainerId[0]), gname); - } - for (i = 1; i < 5; i++) - { - if (gname->partnerInfo[i - 1] == 0) - { - DespawnGroupMember(group, i); - } - else if (IsUnionRoomPlayerFacingTileAt(group, i, x, y) == FALSE && IsUnionRoomPlayerFacingTileAt(group, i, x2, y2) == FALSE) - { - SpawnGroupMember(group, i, GetUnionRoomPlayerGraphicsId((gname->partnerInfo[i - 1] >> 3) & 1, gname->partnerInfo[i - 1] & 7), gname); - } - } -} - -static void SpawnGroupLeaderAndMembers(u32 group, struct RfuGameData * gname) -{ - u32 i; - switch (gname->activity) - { - case 0x40: - case 0x54: - SpawnGroupLeader(group, gname->playerGender, gname->compatibility.playerTrainerId[0]); - for (i = 0; i < 5; i++) - { - DespawnGroupMember(group, i); - } - break; - case 0x41: - case 0x44: - case 0x45: - case 0x48: - case 0x51: - case 0x52: - case 0x53: - DespawnGroupLeader(group); - AssembleGroup(group, gname); - break; - default: - AGB_ASSERT_EX(0, ABSPATH("rfu_union_tool.c"), 979) - } -} - -static void DespawnGroupLeaderAndMembers(u32 group, struct RfuGameData * gname) -{ - s32 i; - DespawnGroupLeader(group); - for (i = 0; i < 5; i++) - { - DespawnGroupMember(group, i); - } -} - -static void UpdateUnionRoomPlayerSprites(struct WirelessLink_URoom * groups) -{ - s32 i; - struct RfuPlayer * x20_p; - sUnionObjRefreshTimer = 0; - for (i = 0, x20_p = groups->playerList->players; i < 8; i++) - { - if (x20_p[i].groupScheduledAnim == UNION_ROOM_SPAWN_IN) - { - SpawnGroupLeaderAndMembers(i, &x20_p[i].rfu.data); - } - else if (x20_p[i].groupScheduledAnim == UNION_ROOM_SPAWN_OUT) - { - DespawnGroupLeaderAndMembers(i, &x20_p[i].rfu.data); - } - } -} - -void ScheduleUnionRoomPlayerRefresh(struct WirelessLink_URoom *uroom_p) -{ - sUnionObjRefreshTimer = 300; -} - -void HandleUnionRoomPlayerRefresh(struct WirelessLink_URoom *uroom_p) -{ - if (++sUnionObjRefreshTimer > 300) - { - UpdateUnionRoomPlayerSprites(uroom_p); - } -} - -bool32 TryInteractWithUnionRoomMember(struct RfuPlayerList *main0_p, s16 *member_p, s16 *group_p, u8 *spriteIds) -{ - s16 x, y; - s32 i, j; - struct RfuPlayer * x20_p; - if (!is_walking_or_running()) - { - return FALSE; - } - GetXYCoordsOneStepInFrontOfPlayer(&x, &y); - for (i = 0, x20_p = main0_p->players; i < 8; i++) - { - for (j = 0; j < 5; j++) - { - s32 objId = 5 * i + j; - if (x != sUnionPartnerCoords[i][0] + sFacingDirectionOffsets[j][0] + 7) - { - continue; - } - if (y != sUnionPartnerCoords[i][1] + sFacingDirectionOffsets[j][1] + 7) - { - continue; - } - if (IsVirtualObjectInvisible(objId - 0x38) != FALSE) - { - continue; - } - if (IsVirtualObjectAnimating(objId - 0x38) != FALSE) - { - continue; - } - if (x20_p[i].groupScheduledAnim != UNION_ROOM_SPAWN_IN) - { - continue; - } - UnionPartnerObjectSetFacing(j, i, sOppositeFacingDirection[GetPlayerFacingDirection()]); - *member_p = j; - *group_p = i; - return TRUE; - } - } - return FALSE; -} - -static void UnionPartnerObjectSetFacing(s32 member, s32 group, u8 direction) -{ - TurnVirtualObject(5 * group - 0x38 + member, direction); -} - -void UpdateUnionGroupMemberFacing(u32 member, u32 group, struct RfuPlayerList *main0_p) -{ - return UnionPartnerObjectSetFacing(member, group, UnionPartnerObjectGetFacing(member, group, &main0_p->players[group].rfu.data)); -} diff --git a/src/union_room.c b/src/union_room.c index 2458e44ef..8b8410e3d 100644 --- a/src/union_room.c +++ b/src/union_room.c @@ -40,7 +40,7 @@ #include "union_room.h" #include "union_room_battle.h" #include "union_room_chat.h" -#include "rfu_union_tool.h" +#include "union_room_player_avatar.h" #include "union_room_message.h" #include "constants/songs.h" #include "constants/maps.h" @@ -2317,13 +2317,13 @@ static void Task_RunUnionRoom(u8 taskId) ClearRfuPlayerList(uroom->playerList->players, MAX_UNION_ROOM_LEADERS); sPlayerCurrActivity = IN_UNION_ROOM; uroom->searchTaskId = CreateTask_SearchForChildOrParent(uroom->incomingParentList, uroom->incomingChildList, LINK_GROUP_UNION_ROOM_RESUME); - ZeroUnionObjWork(uroom->objects); + InitUnionRoomPlayerObjects(uroom->objects); MakeGroupAssemblyAreasPassable(); uroom->state = UR_STATE_INIT_OBJECTS; break; case UR_STATE_INIT_OBJECTS: - CreateGroupMemberObjectsInvisible(uroom->spriteIds, taskData[0]); - if (++taskData[0] == 8) + CreateUnionRoomPlayerSprites(uroom->spriteIds, taskData[0]); + if (++taskData[0] == MAX_UNION_ROOM_LEADERS) uroom->state = UR_STATE_INIT_LINK; break; case UR_STATE_INIT_LINK: @@ -2515,7 +2515,7 @@ static void Task_RunUnionRoom(u8 taskId) if (!gReceivedRemoteLinkPlayers) { HandleCancelActivity(FALSE); - UpdateUnionGroupMemberFacing(taskData[0], taskData[1], uroom->playerList); + UpdateUnionRoomMemberFacing(taskData[0], taskData[1], uroom->playerList); uroom->state = UR_STATE_INIT_LINK; } break; @@ -2840,7 +2840,7 @@ static void Task_RunUnionRoom(u8 taskId) Free(uroom->incomingParentList); Free(uroom->incomingChildList); DestroyTask(uroom->searchTaskId); - DestroyGroupMemberObjects(uroom->spriteIds); + DestroyUnionRoomPlayerSprites(uroom->spriteIds); uroom->state = UR_STATE_START_ACTIVITY_FADE; break; case UR_STATE_START_ACTIVITY_FADE: @@ -3051,7 +3051,7 @@ static void Task_RunUnionRoom(u8 taskId) if (PrintOnTextbox(&uroom->textState, gStringVar4)) { HandleCancelActivity(TRUE); - UpdateUnionGroupMemberFacing(taskData[0], taskData[1], uroom->playerList); + UpdateUnionRoomMemberFacing(taskData[0], taskData[1], uroom->playerList); uroom->state = UR_STATE_MAIN; } break; diff --git a/src/union_room_player_avatar.c b/src/union_room_player_avatar.c new file mode 100644 index 000000000..2cfa38167 --- /dev/null +++ b/src/union_room_player_avatar.c @@ -0,0 +1,615 @@ +#include "global.h" +#include "event_data.h" +#include "event_object_movement.h" +#include "field_player_avatar.h" +#include "fieldmap.h" +#include "union_room_player_avatar.h" +#include "script.h" +#include "task.h" +#include "constants/event_object_movement.h" +#include "constants/union_room.h" +#include "constants/event_objects.h" + +#define UR_SPRITE_START_ID (MAX_SPRITES - MAX_UNION_ROOM_LEADERS) + +// Each parent player can lead a group of up to MAX_RFU_PLAYERS (including themselves). +// Multiply the leader's id by MAX_RFU_PLAYERS and add the member's id (0 if the leader) to +// get the sprite index of that player. +#define UR_PLAYER_SPRITE_ID(leaderId, memberId)(MAX_RFU_PLAYERS * leaderId + memberId) + +// Original symbol name from ASSERT statements +#define UnionObjWork sUnionObjWork + +static EWRAM_DATA struct UnionRoomObject * sUnionObjWork = NULL; +static EWRAM_DATA u32 sUnionObjRefreshTimer = 0; + +static u8 CreateTask_AnimateUnionRoomPlayers(void); +static u32 IsUnionRoomPlayerInvisible(u32 leaderId, u32 member); +static void SetUnionRoomObjectFacingDirection(s32 member, s32 leaderId, u8 direction); + +// + 2 is just to match, those elements are empty and never read +// Graphics ids should correspond with the classes in gUnionRoomFacilityClasses +static const u8 sUnionRoomObjGfxIds[GENDER_COUNT][NUM_UNION_ROOM_CLASSES + 2] = { + [MALE] = { + OBJ_EVENT_GFX_COOLTRAINER_M, + OBJ_EVENT_GFX_BLACKBELT, + OBJ_EVENT_GFX_CAMPER, + OBJ_EVENT_GFX_YOUNGSTER, + OBJ_EVENT_GFX_BOY, + OBJ_EVENT_GFX_BUG_CATCHER, + OBJ_EVENT_GFX_MAN, + OBJ_EVENT_GFX_ROCKER + }, + [FEMALE] = { + OBJ_EVENT_GFX_COOLTRAINER_F, + OBJ_EVENT_GFX_CHANNELER, + OBJ_EVENT_GFX_PICNICKER, + OBJ_EVENT_GFX_LASS, + OBJ_EVENT_GFX_WOMAN_1, + OBJ_EVENT_GFX_BATTLE_GIRL, + OBJ_EVENT_GFX_WOMAN_2, + OBJ_EVENT_GFX_BEAUTY + } +}; + +static const s16 sUnionRoomPlayerCoords[MAX_UNION_ROOM_LEADERS][2] = { + { 4, 6}, + {13, 8}, + {10, 6}, + { 1, 8}, + {13, 4}, + { 7, 4}, + { 1, 4}, + { 7, 8} +}; + +// If there's a group of players interacting in the Union Room, the group +// leader will be at one of the positions above and each member in the group +// will be at one of the offsets from that position below. The leader will +// be at the first offset (0,0), as they're at the center. +static const s8 sUnionRoomGroupOffsets[][2] = { + { 0, 0}, // Center + { 1, 0}, // Left + { 0, -1}, // Top + {-1, 0}, // Right + { 0, 1} // Bottom +}; + +static const u8 sOppositeFacingDirection[] = { + [DIR_NONE] = DIR_NONE, + [DIR_SOUTH] = DIR_NORTH, + [DIR_NORTH] = DIR_SOUTH, + [DIR_WEST] = DIR_EAST, + [DIR_EAST] = DIR_WEST +}; + +// Compare to sUnionRoomGroupOffsets, the direction each group member +// needs to be facing in order to face the group leader in the center. +static const u8 sMemberFacingDirections[] = { + DIR_SOUTH, // Leader, but never read + DIR_WEST, + DIR_SOUTH, + DIR_EAST, + DIR_NORTH +}; + +static const u8 sUnionRoomLocalIds[] = { + LOCALID_UNION_ROOM_PLAYER_1, + LOCALID_UNION_ROOM_PLAYER_2, + LOCALID_UNION_ROOM_PLAYER_3, + LOCALID_UNION_ROOM_PLAYER_4, + LOCALID_UNION_ROOM_PLAYER_5, + LOCALID_UNION_ROOM_PLAYER_6, + LOCALID_UNION_ROOM_PLAYER_7, + LOCALID_UNION_ROOM_PLAYER_8 +}; + +// Unused +static const u16 sHidePlayerFlags[] = { + FLAG_HIDE_UNION_ROOM_PLAYER_1, + FLAG_HIDE_UNION_ROOM_PLAYER_2, + FLAG_HIDE_UNION_ROOM_PLAYER_3, + FLAG_HIDE_UNION_ROOM_PLAYER_4, + FLAG_HIDE_UNION_ROOM_PLAYER_5, + FLAG_HIDE_UNION_ROOM_PLAYER_6, + FLAG_HIDE_UNION_ROOM_PLAYER_7, + FLAG_HIDE_UNION_ROOM_PLAYER_8 +}; + +static bool32 IsPlayerStandingStill(void) +{ + if (gPlayerAvatar.tileTransitionState == T_TILE_CENTER || gPlayerAvatar.tileTransitionState == T_NOT_MOVING) + return TRUE; + else + return FALSE; +} + +// Gender and trainer id are used to determine which sprite a player appears as +static u8 GetUnionRoomPlayerGraphicsId(u32 gender, u32 id) +{ + return sUnionRoomObjGfxIds[gender][id % NUM_UNION_ROOM_CLASSES]; +} + +static void GetUnionRoomPlayerCoords(u32 leaderId, u32 memberId, s32 * x, s32 * y) +{ + *x = sUnionRoomPlayerCoords[leaderId][0] + sUnionRoomGroupOffsets[memberId][0] + 7; + *y = sUnionRoomPlayerCoords[leaderId][1] + sUnionRoomGroupOffsets[memberId][1] + 7; +} + +static bool32 IsUnionRoomPlayerAt(u32 leaderId, u32 memberId, s32 x, s32 y) +{ + if ((sUnionRoomPlayerCoords[leaderId][0] + sUnionRoomGroupOffsets[memberId][0] + MAP_OFFSET == x) + && (sUnionRoomPlayerCoords[leaderId][1] + sUnionRoomGroupOffsets[memberId][1] + MAP_OFFSET == y)) + return TRUE; + else + return FALSE; +} + +static bool32 IsUnionRoomPlayerHidden(u32 leaderId) +{ + return FlagGet(FLAG_HIDE_UNION_ROOM_PLAYER_1 + leaderId); +} + +static void HideUnionRoomPlayer(u32 leaderId) +{ + FlagSet(FLAG_HIDE_UNION_ROOM_PLAYER_1 + leaderId); +} + +static void ShowUnionRoomPlayer(u32 leaderId) +{ + FlagClear(FLAG_HIDE_UNION_ROOM_PLAYER_1 + leaderId); +} + +static void SetUnionRoomPlayerGfx(u32 leaderId, u32 gfxId) +{ + VarSet(VAR_OBJ_GFX_ID_0 + leaderId, gfxId); +} + +static void CreateUnionRoomPlayerObjectEvent(u32 leaderId) +{ + TrySpawnObjectEvent(sUnionRoomLocalIds[leaderId], gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup); +} + +static void RemoveUnionRoomPlayerObjectEvent(u32 leaderId) +{ + RemoveObjectEventByLocalIdAndMap(sUnionRoomLocalIds[leaderId], gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup); +} + +static bool32 SetUnionRoomPlayerEnterExitMovement(u32 leaderId, const u8 * movement) +{ + u8 objectId; + struct ObjectEvent * object; + if (TryGetObjectEventIdByLocalIdAndMap(sUnionRoomLocalIds[leaderId], gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, &objectId)) + return FALSE; + object = &gObjectEvents[objectId]; + if (ObjectEventIsMovementOverridden(object)) + return FALSE; + if (ObjectEventSetHeldMovement(object, *movement)) + { + AGB_ASSERT_EX(0, ABSPATH("rfu_union_tool.c"), 387); + return FALSE; + } + return TRUE; +} + +static bool32 TryReleaseUnionRoomPlayerObjectEvent(u32 leaderId) +{ + u8 objectId; + struct ObjectEvent * object; + if (TryGetObjectEventIdByLocalIdAndMap(sUnionRoomLocalIds[leaderId], gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, &objectId)) + return TRUE; + + object = &gObjectEvents[objectId]; + if (!ObjectEventClearHeldMovementIfFinished(object)) + return FALSE; + + if (!ArePlayerFieldControlsLocked()) + UnfreezeObjectEvent(object); + else + FreezeObjectEvent(object); + return TRUE; +} + +u8 InitUnionRoomPlayerObjects(struct UnionRoomObject * players) +{ + s32 i; + + sUnionObjRefreshTimer = 0; + sUnionObjWork = players; + AGB_ASSERT_EX(UnionObjWork != NULL, ABSPATH("rfu_union_tool.c"), 442) + for (i = 0; i < MAX_UNION_ROOM_LEADERS; i++) + { + players[i].state = 0; + players[i].gfxId = 0; + players[i].animState = 0; + players[i].schedAnim = UNION_ROOM_SPAWN_NONE; + } + return CreateTask_AnimateUnionRoomPlayers(); +} + +static const u8 sMovement_UnionPlayerExit[2] = { + MOVEMENT_ACTION_FLY_UP, + MOVEMENT_ACTION_STEP_END +}; + +static bool32 AnimateUnionRoomPlayerDespawn(s8 * state, u32 leaderId, struct UnionRoomObject * object) +{ + switch (*state) + { + case 0: + if (SetUnionRoomPlayerEnterExitMovement(leaderId, sMovement_UnionPlayerExit) == TRUE) + { + HideUnionRoomPlayer(leaderId); + (*state)++; + } + break; + case 1: + if (TryReleaseUnionRoomPlayerObjectEvent(leaderId)) + { + RemoveUnionRoomPlayerObjectEvent(leaderId); + HideUnionRoomPlayer(leaderId); + *state = 0; + return TRUE; + } + break; + } + return FALSE; +} + +static const u8 sMovement_UnionPlayerEnter[2] = { + MOVEMENT_ACTION_FLY_DOWN, + MOVEMENT_ACTION_STEP_END +}; + +static bool32 AnimateUnionRoomPlayerSpawn(s8 * state, u32 leaderId, struct UnionRoomObject * object) +{ + s16 x, y; + + switch (*state) + { + case 0: + if (!IsPlayerStandingStill()) + break; + PlayerGetDestCoords(&x, &y); + if (IsUnionRoomPlayerAt(leaderId, 0, x, y) == TRUE) + break; + player_get_pos_including_state_based_drift(&x, &y); + if (IsUnionRoomPlayerAt(leaderId, 0, x, y) == TRUE) + break; + SetUnionRoomPlayerGfx(leaderId, object->gfxId); + CreateUnionRoomPlayerObjectEvent(leaderId); + ShowUnionRoomPlayer(leaderId); + (*state)++; + // fallthrough + case 3: // incorrect? + if (SetUnionRoomPlayerEnterExitMovement(leaderId, sMovement_UnionPlayerEnter) == 1) + (*state)++; + break; + case 2: + if (TryReleaseUnionRoomPlayerObjectEvent(leaderId)) + { + *state = 0; + return TRUE; + } + break; + } + return FALSE; +} + +static bool32 SpawnGroupLeader(u32 leaderId, u32 gender, u32 id) +{ + struct UnionRoomObject * object = &sUnionObjWork[leaderId]; + AGB_ASSERT_EX(UnionObjWork != NULL, ABSPATH("rfu_union_tool.c"), 561) + object->schedAnim = UNION_ROOM_SPAWN_IN; + object->gfxId = GetUnionRoomPlayerGraphicsId(gender, id); + + if (object->state == 0) + return TRUE; + else + return FALSE; +} + +static bool32 DespawnGroupLeader(u32 leaderId) +{ + struct UnionRoomObject * object = &sUnionObjWork[leaderId]; + AGB_ASSERT_EX(UnionObjWork != NULL, ABSPATH("rfu_union_tool.c"), 577) + object->schedAnim = UNION_ROOM_SPAWN_OUT; + + if (object->state == 1) + return TRUE; + else + return FALSE; +} + +static void AnimateUnionRoomPlayer(u32 leaderId, struct UnionRoomObject * object) +{ + switch (object->state) + { + case 0: + if (object->schedAnim == UNION_ROOM_SPAWN_IN) + { + object->state = 2; + object->animState = 0; + } + else + { + break; + } + // fallthrough + case 2: + if (!IsUnionRoomPlayerInvisible(leaderId, 0) && object->schedAnim == UNION_ROOM_SPAWN_OUT) + { + object->state = 0; + object->animState = 0; + RemoveUnionRoomPlayerObjectEvent(leaderId); + HideUnionRoomPlayer(leaderId); + } + else if (AnimateUnionRoomPlayerSpawn(&object->animState, leaderId, object) == TRUE) + { + object->state = 1; + } + break; + case 1: + if (object->schedAnim != UNION_ROOM_SPAWN_OUT) + break; + object->state = 3; + object->animState = 0; + // fallthrough + case 3: + if (AnimateUnionRoomPlayerDespawn(&object->animState, leaderId, object) == TRUE) + object->state = 0; + break; + } + object->schedAnim = UNION_ROOM_SPAWN_NONE; +} + +static void Task_AnimateUnionRoomPlayers(u8 taskId) +{ + s32 i; + AGB_ASSERT_EX(UnionObjWork != NULL, ABSPATH("rfu_union_tool.c"), 643) + for (i = 0; i < MAX_UNION_ROOM_LEADERS; i++) + AnimateUnionRoomPlayer(i, &sUnionObjWork[i]); +} + +static u8 CreateTask_AnimateUnionRoomPlayers(void) +{ + if (FuncIsActiveTask(Task_AnimateUnionRoomPlayers) == TRUE) + { + AGB_ASSERT_EX(0, ABSPATH("rfu_union_tool.c"), 655) + return NUM_TASKS; + } + else + { + return CreateTask(Task_AnimateUnionRoomPlayers, 5); + } +} + +static void DestroyTask_AnimateUnionRoomPlayers(void) +{ + u8 taskId = FindTaskIdByFunc(Task_AnimateUnionRoomPlayers); + if (taskId < NUM_TASKS) + DestroyTask(taskId); +} + +void DestroyUnionRoomPlayerObjects(void) +{ + s32 i; + for (i = 0; i < MAX_UNION_ROOM_LEADERS; i++) + { + if (!IsUnionRoomPlayerHidden(i)) + { + RemoveUnionRoomPlayerObjectEvent(i); + HideUnionRoomPlayer(i); + } + } + sUnionObjWork = NULL; + DestroyTask_AnimateUnionRoomPlayers(); +} + +void CreateUnionRoomPlayerSprites(u8 * spriteIds, s32 leaderId) +{ + s32 memberId; + + for (memberId = 0; memberId < MAX_RFU_PLAYERS; memberId++) + { + s32 id = UR_PLAYER_SPRITE_ID(leaderId, memberId); + spriteIds[id] = CreateVirtualObject(OBJ_EVENT_GFX_MAN, + id - UR_SPRITE_START_ID, + sUnionRoomPlayerCoords[leaderId][0] + sUnionRoomGroupOffsets[memberId][0], + sUnionRoomPlayerCoords[leaderId][1] + sUnionRoomGroupOffsets[memberId][1], + 3, 1); + SetVirtualObjectInvisibility(id - UR_SPRITE_START_ID, TRUE); + } +} + +void DestroyUnionRoomPlayerSprites(u8 *spriteIds) +{ + s32 i; + for (i = 0; i < NUM_UNION_ROOM_SPRITES; i++) + DestroySprite(&gSprites[spriteIds[i]]); +} + +// Clear the impassable metatiles around the group leaders that get set +// to prevent the player from walking through the group member sprites. +void MakeGroupAssemblyAreasPassable(void) +{ + s32 leaderId, memberId, x, y; + for (leaderId = 0; leaderId < MAX_UNION_ROOM_LEADERS; leaderId++) + { + for (memberId = 0; memberId < MAX_RFU_PLAYERS; memberId++) + { + GetUnionRoomPlayerCoords(leaderId, memberId, &x, &y); + MapGridSetMetatileImpassabilityAt(x, y, FALSE); + } + } +} + +static u8 GetNewFacingDirectionForUnionRoomPlayer(u32 memberId, u32 leaderId, struct RfuGameData * gameData) +{ + if (memberId != 0) // If not leader + return sMemberFacingDirections[memberId]; + else if (gameData->activity == (ACTIVITY_CHAT | IN_UNION_ROOM)) + return DIR_SOUTH; + else + return DIR_EAST; +} + +static u32 IsUnionRoomPlayerInvisible(u32 leaderId, u32 memberId) +{ + return IsVirtualObjectInvisible(UR_PLAYER_SPRITE_ID(leaderId, memberId) - UR_SPRITE_START_ID); +} + +static void SpawnGroupMember(u32 leaderId, u32 memberId, u8 graphicsId, struct RfuGameData * gameData) +{ + s32 x, y; + s32 id = UR_PLAYER_SPRITE_ID(leaderId, memberId); + if (IsUnionRoomPlayerInvisible(leaderId, memberId) == TRUE) + { + SetVirtualObjectInvisibility(id - UR_SPRITE_START_ID, FALSE); + SetVirtualObjectSpriteAnim(id - UR_SPRITE_START_ID, UNION_ROOM_SPAWN_IN); + } + SetVirtualObjectGraphics(id - UR_SPRITE_START_ID, graphicsId); + SetUnionRoomObjectFacingDirection(memberId, leaderId, GetNewFacingDirectionForUnionRoomPlayer(memberId, leaderId, gameData)); + GetUnionRoomPlayerCoords(leaderId, memberId, &x, &y); + MapGridSetMetatileImpassabilityAt(x, y, TRUE); +} + +static void DespawnGroupMember(u32 leaderId, u32 memberId) +{ + s32 x, y; + SetVirtualObjectSpriteAnim(UR_PLAYER_SPRITE_ID(leaderId, memberId) - UR_SPRITE_START_ID, UNION_ROOM_SPAWN_OUT); + GetUnionRoomPlayerCoords(leaderId, memberId, &x, &y); + MapGridSetMetatileImpassabilityAt(x, y, FALSE); +} + +static void AssembleGroup(u32 leaderId, struct RfuGameData * gameData) +{ + s16 x, y, x2, y2; + s32 i; + + PlayerGetDestCoords(&x, &y); + player_get_pos_including_state_based_drift(&x2, &y2); + if (IsVirtualObjectInvisible(UR_PLAYER_SPRITE_ID(leaderId, 0) - UR_SPRITE_START_ID) == TRUE) + { + if (IsUnionRoomPlayerAt(leaderId, 0, x, y) == TRUE || IsUnionRoomPlayerAt(leaderId, 0, x2, y2) == TRUE) + return; + SpawnGroupMember(leaderId, 0, GetUnionRoomPlayerGraphicsId(gameData->playerGender, gameData->compatibility.playerTrainerId[0]), gameData); + } + for (i = 1; i < MAX_RFU_PLAYERS; i++) + { + if (gameData->partnerInfo[i - 1] == 0) + DespawnGroupMember(leaderId, i); + else if (IsUnionRoomPlayerAt(leaderId, i, x, y) == FALSE && IsUnionRoomPlayerAt(leaderId, i, x2, y2) == FALSE) + SpawnGroupMember(leaderId, i, GetUnionRoomPlayerGraphicsId((gameData->partnerInfo[i - 1] >> PINFO_GENDER_SHIFT) & 1, + gameData->partnerInfo[i - 1] & PINFO_TID_MASK), + gameData); + } +} + +static void SpawnGroupLeaderAndMembers(u32 leaderId, struct RfuGameData * gameData) +{ + u32 i; + switch (gameData->activity) + { + case ACTIVITY_NONE | IN_UNION_ROOM: + case ACTIVITY_PLYRTALK | IN_UNION_ROOM: + SpawnGroupLeader(leaderId, gameData->playerGender, gameData->compatibility.playerTrainerId[0]); + for (i = 0; i < MAX_RFU_PLAYERS; i++) + DespawnGroupMember(leaderId, i); + break; + case ACTIVITY_BATTLE_SINGLE | IN_UNION_ROOM: + case ACTIVITY_TRADE | IN_UNION_ROOM: + case ACTIVITY_CHAT | IN_UNION_ROOM: + case ACTIVITY_CARD | IN_UNION_ROOM: + case ACTIVITY_ACCEPT | IN_UNION_ROOM: + case ACTIVITY_DECLINE | IN_UNION_ROOM: + case ACTIVITY_NPCTALK | IN_UNION_ROOM: + DespawnGroupLeader(leaderId); + AssembleGroup(leaderId, gameData); + break; + default: + AGB_ASSERT_EX(0, ABSPATH("rfu_union_tool.c"), 979) + } +} + +static void DespawnGroupLeaderAndMembers(u32 leaderId, struct RfuGameData * gameData) +{ + s32 i; + DespawnGroupLeader(leaderId); + for (i = 0; i < MAX_RFU_PLAYERS; i++) + DespawnGroupMember(leaderId, i); +} + +static void UpdateUnionRoomPlayerSprites(struct WirelessLink_URoom * uroom) +{ + s32 i; + struct RfuPlayer * leaders; + sUnionObjRefreshTimer = 0; + for (i = 0, leaders = uroom->playerList->players; i < MAX_UNION_ROOM_LEADERS; i++) + { + if (leaders[i].groupScheduledAnim == UNION_ROOM_SPAWN_IN) + SpawnGroupLeaderAndMembers(i, &leaders[i].rfu.data); + else if (leaders[i].groupScheduledAnim == UNION_ROOM_SPAWN_OUT) + DespawnGroupLeaderAndMembers(i, &leaders[i].rfu.data); + } +} + +void ScheduleUnionRoomPlayerRefresh(struct WirelessLink_URoom *uroom) +{ + sUnionObjRefreshTimer = 300; +} + +void HandleUnionRoomPlayerRefresh(struct WirelessLink_URoom *uroom) +{ + if (++sUnionObjRefreshTimer > 300) + UpdateUnionRoomPlayerSprites(uroom); +} + +bool32 TryInteractWithUnionRoomMember(struct RfuPlayerList *list, s16 *memberIdPtr, s16 *leaderIdPtr, u8 *spriteIds) +{ + s16 x, y; + s32 leaderId, memberId; + struct RfuPlayer * leaders; + if (!IsPlayerStandingStill()) + return FALSE; + + GetXYCoordsOneStepInFrontOfPlayer(&x, &y); + for (leaderId = 0, leaders = list->players; leaderId < MAX_UNION_ROOM_LEADERS; leaderId++) + { + for (memberId = 0; memberId < MAX_RFU_PLAYERS; memberId++) + { + s32 objId = UR_PLAYER_SPRITE_ID(leaderId, memberId); + + // Is the player in front of a group member position? + if (x != sUnionRoomPlayerCoords[leaderId][0] + sUnionRoomGroupOffsets[memberId][0] + 7) + continue; + if (y != sUnionRoomPlayerCoords[leaderId][1] + sUnionRoomGroupOffsets[memberId][1] + 7) + continue; + + // Has a group member spawned at this position? + if (IsVirtualObjectInvisible(objId - UR_SPRITE_START_ID) != FALSE) + continue; + if (IsVirtualObjectAnimating(objId - UR_SPRITE_START_ID) != FALSE) + continue; + if (leaders[leaderId].groupScheduledAnim != UNION_ROOM_SPAWN_IN) + continue; + + // Interaction attempt successful, face player + SetUnionRoomObjectFacingDirection(memberId, leaderId, sOppositeFacingDirection[GetPlayerFacingDirection()]); + *memberIdPtr = memberId; + *leaderIdPtr = leaderId; + return TRUE; + } + } + return FALSE; +} + +static void SetUnionRoomObjectFacingDirection(s32 memberId, s32 leaderId, u8 direction) +{ + TurnVirtualObject(MAX_RFU_PLAYERS * leaderId - UR_SPRITE_START_ID + memberId, direction); +} + +void UpdateUnionRoomMemberFacing(u32 memberId, u32 leaderId, struct RfuPlayerList *list) +{ + return SetUnionRoomObjectFacingDirection(memberId, leaderId, GetNewFacingDirectionForUnionRoomPlayer(memberId, leaderId, &list->players[leaderId].rfu.data)); +} diff --git a/sym_ewram.txt b/sym_ewram.txt index 0dc0544c1..f957d320b 100644 --- a/sym_ewram.txt +++ b/sym_ewram.txt @@ -102,7 +102,7 @@ .include "src/help_message.o" .include "src/quest_log_events.o" .include "src/union_room.o" - .include "src/rfu_union_tool.o" + .include "src/union_room_player_avatar.o" .include "src/union_room_battle.o" .include "src/pokemon_special_anim.o" .include "src/party_menu.o"