diff --git a/include/types.h b/include/types.h index 66f02a1d4..87f43fc8b 100644 --- a/include/types.h +++ b/include/types.h @@ -372,4 +372,9 @@ struct MarioState #define PLAY_MODE_FRAME_ADVANCE 5 #define PLAY_MODE_SYNC_LEVEL 6 +// NOTE: this defines the maximum number of players... +// HOWEVER, simply increasing this to 3 will not magically work +// many things will have to be overhauled! +#define MAX_PLAYERS 2 + #endif // _SM64_TYPES_H_ diff --git a/src/engine/level_script.c b/src/engine/level_script.c index a6e12dddc..0d519cf67 100644 --- a/src/engine/level_script.c +++ b/src/engine/level_script.c @@ -666,7 +666,7 @@ static void level_cmd_unload_area(void) { } static void level_cmd_set_mario_start_pos(void) { - for (int i = 0; i < 2; i++) { + for (int i = 0; i < MAX_PLAYERS; i++) { gPlayerSpawnInfos[i].areaIndex = CMD_GET(u8, 2); #if IS_64_BIT diff --git a/src/game/area.c b/src/game/area.c index 44d539114..eb96a5c6b 100644 --- a/src/game/area.c +++ b/src/game/area.c @@ -24,7 +24,7 @@ #include "gfx_dimensions.h" -struct SpawnInfo gPlayerSpawnInfos[2]; +struct SpawnInfo gPlayerSpawnInfos[MAX_PLAYERS]; struct GraphNode *D_8033A160[0x100]; struct Area gAreaData[8]; diff --git a/src/game/behaviors/bowser.inc.c b/src/game/behaviors/bowser.inc.c index ebc6bf475..582383b70 100644 --- a/src/game/behaviors/bowser.inc.c +++ b/src/game/behaviors/bowser.inc.c @@ -1033,7 +1033,7 @@ void bowser_free_update(void) { struct Object *platform; UNUSED f32 floorHeight; if ((platform = o->platform) != NULL) - apply_platform_displacement(0, platform); + apply_platform_displacement((u32)-1, platform); o->oBowserUnk10E = 0; cur_obj_update_floor_and_walls(); cur_obj_call_action_function(sBowserActions); diff --git a/src/game/behaviors/seesaw_platform.inc.c b/src/game/behaviors/seesaw_platform.inc.c index 81a47e761..f28930fc3 100644 --- a/src/game/behaviors/seesaw_platform.inc.c +++ b/src/game/behaviors/seesaw_platform.inc.c @@ -23,6 +23,10 @@ void bhv_seesaw_platform_init(void) { if (o->oBehParams2ndByte == 2) { o->oCollisionDistance = 2000.0f; } + + network_init_object(o, 1000.0f); + network_init_object_field(o, &o->oSeesawPlatformPitchVel); + network_init_object_field(o, &o->oFaceAnglePitch); } /** @@ -36,9 +40,29 @@ void bhv_seesaw_platform_update(void) { cur_obj_play_sound_1(SOUND_ENV_BOAT_ROCKING1); } - if (gMarioObject->platform == o) { + f32 x = 0; + f32 y = 0; + f32 z = 0; + u8 playersTouched = 0; + for (int i = 0; i < MAX_PLAYERS; i++) { + if (gMarioStates[i].marioObj->platform == o) { + x += gMarioStates[i].marioObj->oPosX; + y += gMarioStates[i].marioObj->oPosY; + z += gMarioStates[i].marioObj->oPosZ; + playersTouched++; + } + } + + if (playersTouched > 0) { + x /= (f32)playersTouched; + y /= (f32)playersTouched; + z /= (f32)playersTouched; + + int distanceToPlayer = dist_between_object_and_point(o, x, y, z); + int angleToPlayer = obj_angle_to_point(o, x, y, z); + // Rotate toward mario - f32 rotation = o->oDistanceToMario * coss(o->oAngleToMario - o->oMoveAngleYaw); + f32 rotation = distanceToPlayer * coss(angleToPlayer - o->oMoveAngleYaw); UNUSED s32 unused; // Deceleration is faster than acceleration diff --git a/src/game/camera.c b/src/game/camera.c index d3c822a54..23c40a7b4 100644 --- a/src/game/camera.c +++ b/src/game/camera.c @@ -89,7 +89,7 @@ Vec3f sOldFocus; * Global array of PlayerCameraState. * L is real. */ -struct PlayerCameraState gPlayerCameraState[2]; +struct PlayerCameraState gPlayerCameraState[MAX_PLAYERS]; /** * Direction controlled by player 2, moves the focus during the credits. */ diff --git a/src/game/camera.h b/src/game/camera.h index b1abdc4f9..95017afb1 100644 --- a/src/game/camera.h +++ b/src/game/camera.h @@ -667,7 +667,7 @@ struct LakituState extern s16 sSelectionFlags; extern s16 sCameraSoundFlags; extern u16 sCButtonsPressed; -extern struct PlayerCameraState gPlayerCameraState[2]; +extern struct PlayerCameraState gPlayerCameraState[MAX_PLAYERS]; extern struct LakituState gLakituState; extern s16 gCameraMovementFlags; extern s32 gObjCutsceneDone; diff --git a/src/game/game_init.c b/src/game/game_init.c index da7d11a0f..f683782ab 100644 --- a/src/game/game_init.c +++ b/src/game/game_init.c @@ -43,9 +43,9 @@ OSMesg D_80339CD4; struct VblankHandler gGameVblankHandler; uintptr_t gPhysicalFrameBuffers[3]; uintptr_t gPhysicalZBuffer; -void *D_80339CF0[2]; +void *D_80339CF0[MAX_PLAYERS]; void *D_80339CF4; -struct MarioAnimation D_80339D10[2]; +struct MarioAnimation D_80339D10[MAX_PLAYERS]; struct MarioAnimation gDemo; UNUSED u8 filler80339D30[0x90]; @@ -547,7 +547,7 @@ void setup_game_memory(void) { gPhysicalFrameBuffers[0] = VIRTUAL_TO_PHYSICAL(gFrameBuffer0); gPhysicalFrameBuffers[1] = VIRTUAL_TO_PHYSICAL(gFrameBuffer1); gPhysicalFrameBuffers[2] = VIRTUAL_TO_PHYSICAL(gFrameBuffer2); - for (int i = 0; i < 2; i++) { + for (int i = 0; i < MAX_PLAYERS; i++) { D_80339CF0[i] = main_pool_alloc(0x4000, MEMORY_POOL_LEFT); set_segment_base_addr(17, (void *)D_80339CF0[i]); func_80278A78(&D_80339D10[i], gMarioAnims, D_80339CF0[i]); diff --git a/src/game/interaction.c b/src/game/interaction.c index c6607594d..7465f7e3b 100644 --- a/src/game/interaction.c +++ b/src/game/interaction.c @@ -820,7 +820,7 @@ u32 interact_star_or_key(struct MarioState *m, UNUSED u32 interactType, struct O save_file_collect_star_or_key(m->numCoins, starIndex); s32 numStars = save_file_get_total_star_count(gCurrSaveFileNum - 1, COURSE_MIN - 1, COURSE_MAX - 1); - for (int i = 0; i < 2; i++) { + for (int i = 0; i < MAX_PLAYERS; i++) { gMarioStates[i].numStars = numStars; } diff --git a/src/game/level_update.c b/src/game/level_update.c index 0c8ab70a2..cd15fee68 100644 --- a/src/game/level_update.c +++ b/src/game/level_update.c @@ -150,7 +150,7 @@ struct CreditsEntry sCreditsSequence[] = { { LEVEL_NONE, 0, 1, 0, { 0, 0, 0 }, NULL }, }; -struct MarioState gMarioStates[2]; +struct MarioState gMarioStates[MAX_PLAYERS]; struct HudDisplay gHudDisplay; s16 sCurrPlayMode; u16 D_80339ECA; @@ -371,7 +371,7 @@ void init_mario_after_warp(void) { u32 marioSpawnType = get_mario_spawn_type(spawnNode->object); if (gMarioState->action != ACT_UNINITIALIZED) { - for (int i = 0; i < 2; i++) { + for (int i = 0; i < MAX_PLAYERS; i++) { gPlayerSpawnInfos[i].startPos[0] = (s16) spawnNode->object->oPosX; gPlayerSpawnInfos[i].startPos[1] = (s16) spawnNode->object->oPosY; gPlayerSpawnInfos[i].startPos[2] = (s16) spawnNode->object->oPosZ; @@ -506,7 +506,7 @@ void warp_credits(void) { load_area(sWarpDest.areaIdx); - for (int i = 0; i < 2; i++) { + for (int i = 0; i < MAX_PLAYERS; i++) { vec3s_set(gPlayerSpawnInfos[i].startPos, gCurrCreditsEntry->marioPos[0], gCurrCreditsEntry->marioPos[1], gCurrCreditsEntry->marioPos[2]); diff --git a/src/game/mario_misc.c b/src/game/mario_misc.c index 375127d83..5d12f6dab 100644 --- a/src/game/mario_misc.c +++ b/src/game/mario_misc.c @@ -69,7 +69,7 @@ static s8 gMarioAttackScaleAnimation[3 * 6] = { 10, 12, 16, 24, 10, 10, 10, 14, 20, 30, 10, 10, 10, 16, 20, 26, 26, 20, }; -struct MarioBodyState gBodyStates[2]; // 2nd is never accessed in practice, most likely Luigi related +struct MarioBodyState gBodyStates[MAX_PLAYERS]; // 2nd is never accessed in practice, most likely Luigi related struct GraphNodeObject gMirrorMario; // copy of Mario's geo node for drawing mirror Mario // This whole file is weirdly organized. It has to be the same file due diff --git a/src/game/mario_misc.h b/src/game/mario_misc.h index 25c0cabaf..7c8fdaf8d 100644 --- a/src/game/mario_misc.h +++ b/src/game/mario_misc.h @@ -7,7 +7,7 @@ #include "types.h" extern struct GraphNodeObject gMirrorMario; -extern struct MarioBodyState gBodyStates[2]; +extern struct MarioBodyState gBodyStates[MAX_PLAYERS]; Gfx *geo_draw_mario_head_goddard(s32 callContext, struct GraphNode *node, Mat4 *c); void bhv_toad_message_loop(void); diff --git a/src/game/object_helpers.c b/src/game/object_helpers.c index fbfa1d351..99d0702f7 100644 --- a/src/game/object_helpers.c +++ b/src/game/object_helpers.c @@ -301,6 +301,14 @@ f32 dist_between_objects(struct Object *obj1, struct Object *obj2) { return sqrtf(dx * dx + dy * dy + dz * dz); } +f32 dist_between_object_and_point(struct Object *obj, f32 pointX, f32 pointY, f32 pointZ) { + f32 dx = (f32)obj->oPosX - pointX; + f32 dy = (f32)obj->oPosY - pointY; + f32 dz = (f32)obj->oPosZ - pointZ; + + return sqrtf(dx * dx + dy * dy + dz * dz); +} + void cur_obj_forward_vel_approach_upward(f32 target, f32 increment) { if (o->oForwardVel >= target) { o->oForwardVel = target; @@ -393,6 +401,17 @@ s16 obj_angle_to_object(struct Object *obj1, struct Object *obj2) { return angle; } +s16 obj_angle_to_point(struct Object *obj, f32 pointX, f32 pointY, f32 pointZ) { + f32 z1, x1, z2, x2; + s16 angle; + + z1 = obj->oPosZ; z2 = pointZ; //ordering of instructions.. + x1 = obj->oPosX; x2 = pointX; + + angle = atan2s(z2 - z1, x2 - x1); + return angle; +} + s16 obj_turn_toward_object(struct Object *obj, struct Object *target, s16 angleIndex, s16 turnAmount) { f32 a, b, c, d; UNUSED s32 unused; diff --git a/src/game/object_helpers.h b/src/game/object_helpers.h index 092a07208..b959d362d 100644 --- a/src/game/object_helpers.h +++ b/src/game/object_helpers.h @@ -82,12 +82,14 @@ void create_transformation_from_matrices(Mat4 a0, Mat4 a1, Mat4 a2); void obj_set_held_state(struct Object *obj, const BehaviorScript *heldBehavior); f32 lateral_dist_between_objects(struct Object *obj1, struct Object *obj2); f32 dist_between_objects(struct Object *obj1, struct Object *obj2); +f32 dist_between_object_and_point(struct Object *obj, f32 pointX, f32 pointY, f32 pointZ); void cur_obj_forward_vel_approach_upward(f32 target, f32 increment); s32 approach_f32_signed(f32 *value, f32 target, f32 increment); f32 approach_f32_symmetric(f32 value, f32 target, f32 increment); s16 approach_s16_symmetric(s16 value, s16 target, s16 increment); s32 cur_obj_rotate_yaw_toward(s16 target, s16 increment); s16 obj_angle_to_object(struct Object *obj1, struct Object *obj2); +s16 obj_angle_to_point(struct Object *obj, f32 pointX, f32 pointY, f32 pointZ); s16 obj_turn_toward_object(struct Object *obj, struct Object *target, s16 angleIndex, s16 turnAmount); void obj_set_parent_relative_pos(struct Object *obj, s16 relX, s16 relY, s16 relZ); void obj_set_pos(struct Object *obj, s16 x, s16 y, s16 z); diff --git a/src/game/platform_displacement.c b/src/game/platform_displacement.c index 29a741c23..f220312a4 100644 --- a/src/game/platform_displacement.c +++ b/src/game/platform_displacement.c @@ -20,49 +20,53 @@ struct Object *gMarioPlatform = NULL; * within 4 units of the floor. Set his referenced platform object accordingly. */ void update_mario_platform(void) { - struct Surface *floor; - UNUSED u32 unused; - f32 marioX; - f32 marioY; - f32 marioZ; - f32 floorHeight; - u32 awayFromFloor; + for (int i = 0; i < MAX_PLAYERS; i++) { + struct Surface *floor; + UNUSED u32 unused; + f32 marioX; + f32 marioY; + f32 marioZ; + f32 floorHeight; + u32 awayFromFloor; - if (gMarioObject == NULL) { - return; - } + struct Object* player = gMarioStates[i].marioObj; - //! If Mario moves onto a rotating platform in a PU, the find_floor call - // will detect the platform and he will end up receiving a large amount - // of displacement since he is considered to be far from the platform's - // axis of rotation. + if (player == NULL) { + return; + } - marioX = gMarioObject->oPosX; - marioY = gMarioObject->oPosY; - marioZ = gMarioObject->oPosZ; - floorHeight = find_floor(marioX, marioY, marioZ, &floor); + //! If Mario moves onto a rotating platform in a PU, the find_floor call + // will detect the platform and he will end up receiving a large amount + // of displacement since he is considered to be far from the platform's + // axis of rotation. - if (absf(marioY - floorHeight) < 4.0f) { - awayFromFloor = 0; - } else { - awayFromFloor = 1; - } + marioX = player->oPosX; + marioY = player->oPosY; + marioZ = player->oPosZ; + floorHeight = find_floor(marioX, marioY, marioZ, &floor); - switch (awayFromFloor) { - case 1: - gMarioPlatform = NULL; - gMarioObject->platform = NULL; - break; + if (absf(marioY - floorHeight) < 4.0f) { + awayFromFloor = 0; + } else { + awayFromFloor = 1; + } - case 0: - if (floor != NULL && floor->object != NULL) { - gMarioPlatform = floor->object; - gMarioObject->platform = floor->object; - } else { + switch (awayFromFloor) { + case 1: gMarioPlatform = NULL; - gMarioObject->platform = NULL; - } - break; + player->platform = NULL; + break; + + case 0: + if (floor != NULL && floor->object != NULL) { + gMarioPlatform = floor->object; + player->platform = floor->object; + } else { + gMarioPlatform = NULL; + player->platform = NULL; + } + break; + } } } @@ -88,7 +92,7 @@ void set_mario_pos(f32 x, f32 y, f32 z) { * Apply one frame of platform rotation to Mario or an object using the given * platform. If isMario is 0, use gCurrentObject. */ -void apply_platform_displacement(u32 isMario, struct Object *platform) { +void apply_platform_displacement(u32 playerIndex, struct Object *platform) { f32 x; f32 y; f32 z; @@ -108,9 +112,11 @@ void apply_platform_displacement(u32 isMario, struct Object *platform) { rotation[1] = platform->oAngleVelYaw; rotation[2] = platform->oAngleVelRoll; - if (isMario) { + if (playerIndex != (u32)-1) { D_8032FEC0 = 0; - get_mario_pos(&x, &y, &z); + x = gMarioStates[playerIndex].pos[0]; + y = gMarioStates[playerIndex].pos[1]; + z = gMarioStates[playerIndex].pos[2]; } else { x = gCurrentObject->oPosX; y = gCurrentObject->oPosY; @@ -125,8 +131,8 @@ void apply_platform_displacement(u32 isMario, struct Object *platform) { unused2 = rotation[2]; unused3 = platform->oFaceAngleYaw; - if (isMario) { - gMarioStates[0].faceAngle[1] += rotation[1]; + if (playerIndex != (u32)-1) { + gMarioStates[playerIndex].faceAngle[1] += rotation[1]; } platformPosX = platform->oPosX; @@ -156,8 +162,10 @@ void apply_platform_displacement(u32 isMario, struct Object *platform) { z = platformPosZ + newObjectOffset[2]; } - if (isMario) { - set_mario_pos(x, y, z); + if (playerIndex != (u32)-1) { + gMarioStates[playerIndex].pos[0] = x; + gMarioStates[playerIndex].pos[1] = y; + gMarioStates[playerIndex].pos[2] = z; } else { gCurrentObject->oPosX = x; gCurrentObject->oPosY = y; @@ -169,11 +177,14 @@ void apply_platform_displacement(u32 isMario, struct Object *platform) { * If Mario's platform is not null, apply platform displacement. */ void apply_mario_platform_displacement(void) { - struct Object *platform; + for (int i = 0; i < MAX_PLAYERS; i++) { + struct Object* player = gMarioStates[i].marioObj; + if (player == NULL) { continue; } - platform = gMarioPlatform; - if (!(gTimeStopState & TIME_STOP_ACTIVE) && gMarioObject != NULL && platform != NULL) { - apply_platform_displacement(1, platform); + struct Object *platform = player->platform; + if (!(gTimeStopState & TIME_STOP_ACTIVE) && player != NULL && platform != NULL) { + apply_platform_displacement(i, platform); + } } } diff --git a/src/game/platform_displacement.h b/src/game/platform_displacement.h index 556192b50..bcde439f6 100644 --- a/src/game/platform_displacement.h +++ b/src/game/platform_displacement.h @@ -8,7 +8,7 @@ void update_mario_platform(void); void get_mario_pos(f32 *x, f32 *y, f32 *z); void set_mario_pos(f32 x, f32 y, f32 z); -void apply_platform_displacement(u32 isMario, struct Object *platform); +void apply_platform_displacement(u32 playerIndex, struct Object *platform); void apply_mario_platform_displacement(void); #ifndef VERSION_JP void clear_mario_platform(void); diff --git a/src/pc/network/packets/packet_collect_star.c b/src/pc/network/packets/packet_collect_star.c index b78419b9f..84a9c6a5d 100644 --- a/src/pc/network/packets/packet_collect_star.c +++ b/src/pc/network/packets/packet_collect_star.c @@ -30,7 +30,7 @@ void network_receive_collect_star(struct Packet* p) { save_file_collect_star_or_key(coinScore, starIndex); s32 numStars = save_file_get_total_star_count(gCurrSaveFileNum - 1, COURSE_MIN - 1, COURSE_MAX - 1); - for (int i = 0; i < 2; i++) { + for (int i = 0; i < MAX_PLAYERS; i++) { gMarioStates[i].numStars = numStars; }