diff --git a/data/behavior_table.c b/data/behavior_table.c index fbe918cd..2b1311f5 100644 --- a/data/behavior_table.c +++ b/data/behavior_table.c @@ -529,3 +529,20 @@ const BehaviorScript* get_behavior_from_id(enum BehaviorId id) { } return gBehaviorTable[id]; } + +u8 is_behavior_a_coin(const BehaviorScript* behavior) { + return behavior == bhvCoinFormationSpawn + || behavior == bhvCoinFormation + || behavior == bhvOneCoin + || behavior == bhvYellowCoin + || behavior == bhvTemporaryYellowCoin + || behavior == bhvThreeCoinsSpawn + || behavior == bhvTenCoinsSpawn + || behavior == bhvHiddenBlueCoin + || behavior == bhvMovingYellowCoin + || behavior == bhvMovingBlueCoin + || behavior == bhvBlueCoinSliding + || behavior == bhvBlueCoinJumping + || behavior == bhvRedCoin + || behavior == bhvBowserCourseRedCoinStar; +} diff --git a/include/behavior_table.h b/include/behavior_table.h index 142df2f9..0dc8fe7d 100644 --- a/include/behavior_table.h +++ b/include/behavior_table.h @@ -526,5 +526,6 @@ enum BehaviorId { enum BehaviorId get_id_from_behavior(const BehaviorScript* behavior); const BehaviorScript* get_behavior_from_id(enum BehaviorId id); +u8 is_behavior_a_coin(const BehaviorScript* behavior); #endif diff --git a/include/object_fields.h b/include/object_fields.h index a6d771ce..3b507da0 100644 --- a/include/object_fields.h +++ b/include/object_fields.h @@ -406,6 +406,7 @@ #ifndef VERSION_JP #define /*0x1B0*/ oCoinUnk1B0 OBJECT_FIELD_S32(0x4A) #endif +#define /*0x110*/ oCoinID OBJECT_FIELD_S16(0x49, 0) /* Collision Particle */ #define /*0x0F4*/ oCollisionParticleUnkF4 OBJECT_FIELD_F32(0x1B) diff --git a/src/game/interaction.c b/src/game/interaction.c index 5390638e..985bb8cb 100644 --- a/src/game/interaction.c +++ b/src/game/interaction.c @@ -838,6 +838,9 @@ u32 interact_coin(struct MarioState *m, UNUSED u32 interactType, struct Object * } network_send_collect_coin(o); + if (o->oCoinID > 0) { + coin_collection_remember(o->oCoinID); + } return FALSE; } diff --git a/src/pc/network/network.c b/src/pc/network/network.c index 66d048f2..ae8d3542 100644 --- a/src/pc/network/network.c +++ b/src/pc/network/network.c @@ -2,6 +2,8 @@ #include "network.h" #include "object_fields.h" #include "object_constants.h" +#include "game/object_list_processor.h" +#include "behavior_table.h" #include "socket/socket.h" #ifdef DISCORD_SDK #include "discord/discord.h" @@ -98,6 +100,15 @@ void network_on_loaded_level(void) { gSyncObjects[i].staticLevelSpawn = true; } + // give all coins an ID + u8 coinId = 0; + for (int i = 0; i < OBJECT_POOL_CAPACITY; i++) { + struct Object* o = &gObjectPool[i]; + if (o->activeFlags & ACTIVE_FLAG_DEACTIVATED) { continue; } + if (!is_behavior_a_coin(o->behavior)) { continue; } + o->oCoinID = ++coinId; + } + // check for level change struct NetworkPlayer* np = gNetworkPlayerLocal; if (np != NULL) { diff --git a/src/pc/network/packets/packet.h b/src/pc/network/packets/packet.h index be73f111..75d6727e 100644 --- a/src/pc/network/packets/packet.h +++ b/src/pc/network/packets/packet.h @@ -173,6 +173,8 @@ void network_send_level_area_valid(u8 toGlobalIndex); void network_receive_level_area_valid(struct Packet* p); // packet_location_request.c +void coin_collection_remember(u8 coinId); +void coin_collection_clear(void); void static_spawn_removal_remember(u8 syncId); void static_spawn_removal_clear(void); void network_send_location_request(void); diff --git a/src/pc/network/packets/packet_level_area.c b/src/pc/network/packets/packet_level_area.c index 5d94637c..a63d9a30 100644 --- a/src/pc/network/packets/packet_level_area.c +++ b/src/pc/network/packets/packet_level_area.c @@ -34,7 +34,7 @@ void network_send_level_area(void) { np->currAreaIndex = gCurrAreaIndex; np->currAreaSyncValid = false; - LOG_INFO("set currAreaSyncValid to false"); + //LOG_INFO("set currAreaSyncValid to false"); } //LOG_INFO("tx location: [%d, %d, %d, %d]", gCurrCourseNum, gCurrActNum, gCurrLevelNum, gCurrAreaIndex); @@ -118,7 +118,7 @@ static void network_receive_level_area_valid_server(struct Packet* p) { return; } np->currAreaSyncValid = true; - LOG_INFO("set global %d's currAreaSyncValid to true", np->globalIndex); + //LOG_INFO("set global %d's currAreaSyncValid to true", np->globalIndex); } static void network_receive_level_area_valid_client(struct Packet* p) { @@ -135,7 +135,7 @@ static void network_receive_level_area_valid_client(struct Packet* p) { gNetworkPlayerLocal->currAreaSyncValid = true; network_send_level_area_valid_client(); - LOG_INFO("set currAreaSyncValid to true (3)"); + //LOG_INFO("set currAreaSyncValid to true (3)"); } void network_receive_level_area_valid(struct Packet* p) { diff --git a/src/pc/network/packets/packet_location_request.c b/src/pc/network/packets/packet_location_request.c index a17d6abe..80408f19 100644 --- a/src/pc/network/packets/packet_location_request.c +++ b/src/pc/network/packets/packet_location_request.c @@ -1,6 +1,10 @@ #include #include "../network.h" #include "menu/custom_menu_system.h" +#include "game/interaction.h" +#include "game/object_list_processor.h" +#include "object_constants.h" +#include "object_fields.h" //#define DISABLE_MODULE_LOG 1 #include "pc/debuglog.h" @@ -10,6 +14,19 @@ extern s16 gCurrCourseNum, gCurrActNum, gCurrLevelNum, gCurrAreaIndex; u8 sStaticSpawnRemoval[MAX_STATIC_SPAWN_REMOVAL] = { 0 }; u8 sStaticSpawnRemovalIndex = 0; +#define MAX_COIN_COLLECTION 128 +u8 sCoinCollection[MAX_STATIC_SPAWN_REMOVAL] = { 0 }; +u8 sCoinCollectionIndex = 0; + +void coin_collection_remember(u8 coinId) { + sCoinCollection[sCoinCollectionIndex++] = coinId; + if (sStaticSpawnRemovalIndex >= MAX_COIN_COLLECTION) { sStaticSpawnRemovalIndex = MAX_COIN_COLLECTION - 1; } +} + +void coin_collection_clear(void) { + sCoinCollectionIndex = 0; +} + void static_spawn_removal_remember(u8 syncId) { sStaticSpawnRemoval[sStaticSpawnRemovalIndex++] = syncId; if (sStaticSpawnRemovalIndex == 0) { sStaticSpawnRemovalIndex = MAX_STATIC_SPAWN_REMOVAL - 1; } @@ -40,7 +57,7 @@ void network_send_location_request(void) { struct NetworkPlayer* np = get_network_player_from_valid_location(gCurrCourseNum, gCurrActNum, gCurrLevelNum, gCurrAreaIndex); if (np == NULL) { gNetworkPlayerLocal->currAreaSyncValid = true; - LOG_INFO("set currAreaSyncValid to true (1)"); + //LOG_INFO("set currAreaSyncValid to true (1)"); return; } //LOG_INFO("network_send_location_request()"); @@ -81,7 +98,7 @@ void network_receive_location_request(struct Packet* p) { np->currLevelNum = levelNum; np->currAreaIndex = areaIndex; np->currAreaSyncValid = false; - LOG_INFO("set global %d's currAreaSyncValid to false", np->globalIndex); + //LOG_INFO("set global %d's currAreaSyncValid to false", np->globalIndex); //LOG_INFO("network_receive_location_request() { %d, %d, %d, %d }", courseNum, actNum, levelNum, areaIndex); @@ -180,6 +197,11 @@ void network_send_location_response(u8 destGlobalIndex) { packet_write(&p, &sStaticSpawnRemoval[i], sizeof(u8)); } + packet_write(&p, &sCoinCollectionIndex, sizeof(u8)); + for (int i = 0; i < sCoinCollectionIndex; i++) { + packet_write(&p, &sCoinCollection[i], sizeof(u8)); + } + //LOG_INFO("network_send_location_response() { %d, %d, %d, %d, %d } to: %d", destGlobalIndex, gCurrCourseNum, gCurrActNum, gCurrLevelNum, gCurrAreaIndex, (gNetworkType == NT_SERVER) ? destNp->localIndex : 0); network_send_to(destNp->localIndex, &p); @@ -202,20 +224,17 @@ void network_receive_location_response(struct Packet* p) { packet_read(p, &levelNum, sizeof(s16)); packet_read(p, &areaIndex, sizeof(s16)); - // TODO: read entities here! - //LOG_INFO("network_receive_location_response() { %d, %d, %d, %d, %d }", destGlobalIndex, courseNum, actNum, levelNum, areaIndex); if (courseNum != gCurrCourseNum || actNum != gCurrActNum || levelNum != gCurrLevelNum || areaIndex != gCurrAreaIndex) { LOG_ERROR("Receiving 'location response' with the wrong location!"); return; } - // TODO: apply entities! - if (gNetworkType == NT_SERVER) { + /*if (gNetworkType == NT_SERVER) { struct NetworkPlayer* srcNp = &gNetworkPlayers[p->localIndex]; LOG_INFO("sending location response from global %d to global %d", srcNp->globalIndex, gNetworkPlayerLocal->globalIndex); - } + }*/ if (gNetworkPlayerLocal->currAreaSyncValid) { LOG_ERROR("Receiving 'location response' when our location is already valid!"); @@ -228,6 +247,7 @@ void network_receive_location_response(struct Packet* p) { u8 staticSpawnRemovals; static_spawn_removal_clear(); + // read static spawn removals packet_read(p, &staticSpawnRemovals, sizeof(u8)); for (int i = 0; i < staticSpawnRemovals; i++) { u8 syncId; @@ -236,15 +256,33 @@ void network_receive_location_response(struct Packet* p) { if (so != NULL) { if (so->o != NULL) { obj_mark_for_deletion(so->o); - LOG_INFO("marking for deletion: %d", syncId); } network_forget_sync_object(so); } } + // read coin collections + packet_read(p, &sCoinCollectionIndex, sizeof(u8)); + for (int i = 0; i < sCoinCollectionIndex; i++) { + packet_read(p, &sCoinCollection[i], sizeof(u8)); + } + + // collect the coins + for (int i = 0; i < OBJECT_POOL_CAPACITY; i++) { + struct Object* o = &gObjectPool[i]; + if (o->activeFlags & ACTIVE_FLAG_DEACTIVATED) { continue; } + if (!is_behavior_a_coin(o->behavior)) { continue; } + for (int j = 0; j < sCoinCollectionIndex; j++) { + if (o->oCoinID == sCoinCollection[j]) { + o->oInteractStatus = INT_STATUS_INTERACTED; + } + } + } + + gMarioStates[0].numCoins = numCoins; gNetworkPlayerLocal->currAreaSyncValid = true; - LOG_INFO("set currAreaSyncValid to true (2)"); + //LOG_INFO("set currAreaSyncValid to true (2)"); if (gNetworkType != NT_SERVER) { network_send_level_area_valid(0); } diff --git a/src/pc/network/packets/packet_object.c b/src/pc/network/packets/packet_object.c index 1ce29dc0..2c6682d2 100644 --- a/src/pc/network/packets/packet_object.c +++ b/src/pc/network/packets/packet_object.c @@ -138,6 +138,7 @@ void network_clear_sync_objects(void) { } nextSyncID = 1; static_spawn_removal_clear(); + coin_collection_clear(); } void network_set_sync_id(struct Object* o) {