From 6b3ab5f115986908a958f8c836bbae05d8752923 Mon Sep 17 00:00:00 2001 From: MysterD Date: Wed, 29 Jul 2020 21:08:38 -0700 Subject: [PATCH] Started adding player 2 / Luigi --- data/behavior_data.c | 11 +++++++++ include/behavior_data.h | 1 + include/level_commands.h | 5 +++++ levels/castle_grounds/script.c | 1 + levels/castle_inside/script.c | 1 + src/engine/level_script.c | 33 ++++++++++++++++++++------- src/game/area.c | 5 +++-- src/game/level_update.c | 38 ++++++++++++++++++-------------- src/game/mario.c | 25 ++++++++++++++++++--- src/game/object_list_processor.c | 12 ++++++++++ src/game/object_list_processor.h | 1 + src/pc/pc_main.c | 1 + 12 files changed, 104 insertions(+), 30 deletions(-) diff --git a/data/behavior_data.c b/data/behavior_data.c index d27cf09fe..30e1f3d0e 100644 --- a/data/behavior_data.c +++ b/data/behavior_data.c @@ -3522,6 +3522,17 @@ const BehaviorScript bhvMario[] = { END_LOOP(), }; +const BehaviorScript bhvLuigi[] = { + BEGIN(OBJ_LIST_PLAYER), + SET_INT(oIntangibleTimer, 0), + OR_INT(oFlags, OBJ_FLAG_0100), + OR_INT(oUnk94, 0x0001), + SET_HITBOX(/*Radius*/ 37, /*Height*/ 160), + BEGIN_LOOP(), + CALL_NATIVE(bhv_luigi_update), + END_LOOP(), +}; + const BehaviorScript bhvToadMessage[] = { BEGIN(OBJ_LIST_GENACTOR), OR_INT(oFlags, (OBJ_FLAG_PERSISTENT_RESPAWN | OBJ_FLAG_COMPUTE_DIST_TO_MARIO | OBJ_FLAG_SET_FACE_YAW_TO_MOVE_YAW | OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE)), diff --git a/include/behavior_data.h b/include/behavior_data.h index 6a92882e9..1a00c3941 100644 --- a/include/behavior_data.h +++ b/include/behavior_data.h @@ -300,6 +300,7 @@ extern const BehaviorScript bhvSLSnowmanWind[]; extern const BehaviorScript bhvSLWalkingPenguin[]; extern const BehaviorScript bhvYellowBall[]; extern const BehaviorScript bhvMario[]; +extern const BehaviorScript bhvLuigi[]; extern const BehaviorScript bhvToadMessage[]; extern const BehaviorScript bhvUnlockDoorStar[]; extern const BehaviorScript bhvInstantActiveWarp[]; diff --git a/include/level_commands.h b/include/level_commands.h index 513ff6f09..7f1550ad5 100644 --- a/include/level_commands.h +++ b/include/level_commands.h @@ -188,6 +188,11 @@ CMD_W(behArg), \ CMD_PTR(beh) +#define LUIGI(unk3, behArg, beh) \ + CMD_BBBB(0x3F, 0x0C, 0x00, unk3), \ + CMD_W(behArg), \ + CMD_PTR(beh) + #define WARP_NODE(id, destLevel, destArea, destNode, flags) \ CMD_BBBB(0x26, 0x08, id, destLevel), \ CMD_BBBB(destArea, destNode, flags, 0x00) diff --git a/levels/castle_grounds/script.c b/levels/castle_grounds/script.c index 8d197f931..550651540 100644 --- a/levels/castle_grounds/script.c +++ b/levels/castle_grounds/script.c @@ -105,6 +105,7 @@ const LevelScript level_castle_grounds_entry[] = { LOAD_RAW( /*seg*/ 0x0F, _common0_geoSegmentRomStart, _common0_geoSegmentRomEnd), ALLOC_LEVEL_POOL(), MARIO(/*model*/ MODEL_MARIO, /*behParam*/ 0x00000001, /*beh*/ bhvMario), + LUIGI(/*model*/ MODEL_MARIO, /*behParam*/ 0x00000002, /*beh*/ bhvLuigi), JUMP_LINK(script_func_global_1), JUMP_LINK(script_func_global_11), JUMP_LINK(script_func_global_16), diff --git a/levels/castle_inside/script.c b/levels/castle_inside/script.c index 5d9ae4fb5..a56652c38 100644 --- a/levels/castle_inside/script.c +++ b/levels/castle_inside/script.c @@ -227,6 +227,7 @@ const LevelScript level_castle_inside_entry[] = { LOAD_RAW( /*seg*/ 0x0D, _group15_geoSegmentRomStart, _group15_geoSegmentRomEnd), ALLOC_LEVEL_POOL(), MARIO(/*model*/ MODEL_MARIO, /*behParam*/ 0x00000001, /*beh*/ bhvMario), + LUIGI(/*model*/ MODEL_MARIO, /*behParam*/ 0x00000002, /*beh*/ bhvLuigi), JUMP_LINK(script_func_global_16), LOAD_MODEL_FROM_GEO(MODEL_CASTLE_BOWSER_TRAP, castle_geo_000F18), LOAD_MODEL_FROM_GEO(MODEL_CASTLE_WATER_LEVEL_PILLAR, castle_geo_001940), diff --git a/src/engine/level_script.c b/src/engine/level_script.c index b623c7f16..a6e12dddc 100644 --- a/src/engine/level_script.c +++ b/src/engine/level_script.c @@ -438,6 +438,21 @@ static void level_cmd_init_mario(void) { sCurrentCmd = CMD_NEXT; } +static void level_cmd_init_luigi(void) { + vec3s_set(gPlayerSpawnInfos[1].startPos, 0, 0, 0); + vec3s_set(gPlayerSpawnInfos[1].startAngle, 0, 0, 0); + + gPlayerSpawnInfos[1].activeAreaIndex = -1; + gPlayerSpawnInfos[1].areaIndex = 0; + gPlayerSpawnInfos[1].behaviorArg = CMD_GET(u32, 4); + gPlayerSpawnInfos[1].behaviorScript = CMD_GET(void *, 8); + gPlayerSpawnInfos[1].unk18 = gLoadedGraphNodes[CMD_GET(u8, 3)]; + gPlayerSpawnInfos[1].next = NULL; + gMarioSpawnInfo->next = &gPlayerSpawnInfos[1]; + + sCurrentCmd = CMD_NEXT; +} + static void level_cmd_place_object(void) { u8 val7 = 1 << (gCurrActNum - 1); u16 model; @@ -651,15 +666,16 @@ static void level_cmd_unload_area(void) { } static void level_cmd_set_mario_start_pos(void) { - gMarioSpawnInfo->areaIndex = CMD_GET(u8, 2); - -#if IS_64_BIT - vec3s_set(gMarioSpawnInfo->startPos, CMD_GET(s16, 6), CMD_GET(s16, 8), CMD_GET(s16, 10)); -#else - vec3s_copy(gMarioSpawnInfo->startPos, CMD_GET(Vec3s, 6)); -#endif - vec3s_set(gMarioSpawnInfo->startAngle, 0, CMD_GET(s16, 4) * 0x8000 / 180, 0); + for (int i = 0; i < 2; i++) { + gPlayerSpawnInfos[i].areaIndex = CMD_GET(u8, 2); + #if IS_64_BIT + vec3s_set(gPlayerSpawnInfos[i].startPos, CMD_GET(s16, 6), CMD_GET(s16, 8), CMD_GET(s16, 10)); + #else + vec3s_copy(gPlayerSpawnInfos[i].startPos, CMD_GET(Vec3s, 6)); + #endif + vec3s_set(gPlayerSpawnInfos[i].startAngle, 0, CMD_GET(s16, 4) * 0x8000 / 180, 0); + } sCurrentCmd = CMD_NEXT; } @@ -858,6 +874,7 @@ static void (*LevelScriptJumpTable[])(void) = { /*3C*/ level_cmd_get_or_set_var, /*3D*/ level_cmd_advdemo, /*3E*/ level_cmd_cleardemoptr, + /*3F*/ level_cmd_init_luigi, }; struct LevelCommand *level_script_execute(struct LevelCommand *cmd) { diff --git a/src/game/area.c b/src/game/area.c index ba7768a4b..44d539114 100644 --- a/src/game/area.c +++ b/src/game/area.c @@ -24,7 +24,7 @@ #include "gfx_dimensions.h" -struct SpawnInfo gPlayerSpawnInfos[1]; +struct SpawnInfo gPlayerSpawnInfos[2]; struct GraphNode *D_8033A160[0x100]; struct Area gAreaData[8]; @@ -187,7 +187,8 @@ void clear_areas(void) { gCurrentArea = NULL; gWarpTransition.isActive = FALSE; gWarpTransition.pauseRendering = FALSE; - gMarioSpawnInfo->areaIndex = -1; + gPlayerSpawnInfos[0].areaIndex = -1; + gPlayerSpawnInfos[1].areaIndex = -1; for (i = 0; i < 8; i++) { gAreaData[i].index = i; diff --git a/src/game/level_update.c b/src/game/level_update.c index 72a6a6073..a041df47e 100644 --- a/src/game/level_update.c +++ b/src/game/level_update.c @@ -155,7 +155,7 @@ struct CreditsEntry sCreditsSequence[] = { { LEVEL_NONE, 0, 1, 0, { 0, 0, 0 }, NULL }, }; -struct MarioState gMarioStates[1]; +struct MarioState gMarioStates[2]; struct HudDisplay gHudDisplay; s16 sCurrPlayMode; u16 D_80339ECA; @@ -371,21 +371,23 @@ void init_mario_after_warp(void) { u32 marioSpawnType = get_mario_spawn_type(spawnNode->object); if (gMarioState->action != ACT_UNINITIALIZED) { - gPlayerSpawnInfos[0].startPos[0] = (s16) spawnNode->object->oPosX; - gPlayerSpawnInfos[0].startPos[1] = (s16) spawnNode->object->oPosY; - gPlayerSpawnInfos[0].startPos[2] = (s16) spawnNode->object->oPosZ; + for (int i = 0; i < 2; 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; - gPlayerSpawnInfos[0].startAngle[0] = 0; - gPlayerSpawnInfos[0].startAngle[1] = spawnNode->object->oMoveAngleYaw; - gPlayerSpawnInfos[0].startAngle[2] = 0; + gPlayerSpawnInfos[i].startAngle[0] = 0; + gPlayerSpawnInfos[i].startAngle[1] = spawnNode->object->oMoveAngleYaw; + gPlayerSpawnInfos[i].startAngle[2] = 0; - if (marioSpawnType == MARIO_SPAWN_DOOR_WARP) { - init_door_warp(&gPlayerSpawnInfos[0], sWarpDest.arg); - } + if (marioSpawnType == MARIO_SPAWN_DOOR_WARP) { + init_door_warp(&gPlayerSpawnInfos[i], sWarpDest.arg); + } - if (sWarpDest.type == WARP_TYPE_CHANGE_LEVEL || sWarpDest.type == WARP_TYPE_CHANGE_AREA) { - gPlayerSpawnInfos[0].areaIndex = sWarpDest.areaIdx; - load_mario_area(); + if (sWarpDest.type == WARP_TYPE_CHANGE_LEVEL || sWarpDest.type == WARP_TYPE_CHANGE_AREA) { + gPlayerSpawnInfos[i].areaIndex = sWarpDest.areaIdx; + if (i == 0) { load_mario_area(); } + } } init_mario(); @@ -504,12 +506,14 @@ void warp_credits(void) { load_area(sWarpDest.areaIdx); - vec3s_set(gPlayerSpawnInfos[0].startPos, gCurrCreditsEntry->marioPos[0], - gCurrCreditsEntry->marioPos[1], gCurrCreditsEntry->marioPos[2]); + for (int i = 0; i < 2; i++) { + vec3s_set(gPlayerSpawnInfos[i].startPos, gCurrCreditsEntry->marioPos[0], + gCurrCreditsEntry->marioPos[1], gCurrCreditsEntry->marioPos[2]); - vec3s_set(gPlayerSpawnInfos[0].startAngle, 0, 0x100 * gCurrCreditsEntry->marioAngle, 0); + vec3s_set(gPlayerSpawnInfos[i].startAngle, 0, 0x100 * gCurrCreditsEntry->marioAngle, 0); - gPlayerSpawnInfos[0].areaIndex = sWarpDest.areaIdx; + gPlayerSpawnInfos[i].areaIndex = sWarpDest.areaIdx; + } load_mario_area(); init_mario(); diff --git a/src/game/mario.c b/src/game/mario.c index 5f8e5114e..e42a75623 100644 --- a/src/game/mario.c +++ b/src/game/mario.c @@ -1839,6 +1839,10 @@ s32 execute_mario_action(UNUSED struct Object *o) { **************************************************/ void init_mario(void) { + bool isMario = (gMarioState == &gMarioStates[0]); + if (isMario && gMarioObject == NULL) { goto skippy; } + if (!isMario && gLuigiObject == NULL) { goto skippy; } + Vec3s capPos; struct Object *capObject; @@ -1875,12 +1879,13 @@ void init_mario(void) { find_water_level(gMarioSpawnInfo->startPos[0], gMarioSpawnInfo->startPos[2]); gMarioState->area = gCurrentArea; - gMarioState->marioObj = gMarioObject; + gMarioState->marioObj = isMario ? gMarioObject : gLuigiObject; gMarioState->marioObj->header.gfx.unk38.animID = -1; vec3s_copy(gMarioState->faceAngle, gMarioSpawnInfo->startAngle); vec3s_set(gMarioState->angleVel, 0, 0, 0); vec3s_to_vec3f(gMarioState->pos, gMarioSpawnInfo->startPos); vec3f_set(gMarioState->vel, 0, 0, 0); + if (!isMario) { gMarioState->pos[0] -= 50; } gMarioState->floorHeight = find_floor(gMarioState->pos[0], gMarioState->pos[1], gMarioState->pos[2], &gMarioState->floor); @@ -1919,15 +1924,23 @@ void init_mario(void) { capObject->oMoveAngleYaw = 0; } + +skippy: + if (isMario) { + gMarioState = &gMarioStates[1]; + init_mario(); + gMarioState = &gMarioStates[0]; + } } void init_mario_from_save_file(void) { gMarioState->unk00 = 0; gMarioState->flags = 0; gMarioState->action = 0; - gMarioState->spawnInfo = &gPlayerSpawnInfos[0]; + int i = (gMarioState == &gMarioStates[0]) ? 0 : 1; + gMarioState->spawnInfo = &gPlayerSpawnInfos[i]; gMarioState->statusForCamera = &gPlayerCameraState[0]; - gMarioState->marioBodyState = &gBodyStates[0]; + gMarioState->marioBodyState = &gBodyStates[i]; gMarioState->controller = &gControllers[0]; gMarioState->animation = &D_80339D10; @@ -1944,4 +1957,10 @@ void init_mario_from_save_file(void) { gHudDisplay.coins = 0; gHudDisplay.wedges = 8; + + if (gMarioState == &gMarioStates[0]) { + gMarioState = &gMarioStates[1]; + init_mario_from_save_file(); + gMarioState = &gMarioStates[0]; + } } diff --git a/src/game/object_list_processor.c b/src/game/object_list_processor.c index 7113e7c81..d3265c714 100644 --- a/src/game/object_list_processor.c +++ b/src/game/object_list_processor.c @@ -286,6 +286,12 @@ void bhv_mario_update(void) { } } +void bhv_luigi_update(void) { + gMarioState = &gMarioStates[1]; + bhv_mario_update(); + gMarioState = &gMarioStates[0]; +} + /** * Update every object that occurs after firstObj in the given object list, * including firstObj itself. Return the number of objects that were updated. @@ -500,6 +506,11 @@ void spawn_objects_from_info(UNUSED s32 unused, struct SpawnInfo *spawnInfo) { geo_make_first_child(&object->header.gfx.node); } + if (spawnInfo->behaviorArg & 0x02) { + gLuigiObject = object; + geo_make_first_child(&object->header.gfx.node); + } + geo_obj_init_spawninfo(&object->header.gfx, spawnInfo); object->oPosX = spawnInfo->startPos[0]; @@ -531,6 +542,7 @@ void clear_objects(void) { gTHIWaterDrained = 0; gTimeStopState = 0; gMarioObject = NULL; + gLuigiObject = NULL; gMarioCurrentRoom = 0; for (i = 0; i < 60; i++) { diff --git a/src/game/object_list_processor.h b/src/game/object_list_processor.h index 205ec3f14..55c07e904 100644 --- a/src/game/object_list_processor.h +++ b/src/game/object_list_processor.h @@ -122,6 +122,7 @@ extern s16 gMarioOnMerryGoRound; void bhv_mario_update(void); +void bhv_luigi_update(void); void set_object_respawn_info_bits(struct Object *obj, u8 bits); void unload_objects_from_area(UNUSED s32 unused, s32 areaIndex); void spawn_objects_from_info(UNUSED s32 unused, struct SpawnInfo *spawnInfo); diff --git a/src/pc/pc_main.c b/src/pc/pc_main.c index 63679ade6..47c461b39 100644 --- a/src/pc/pc_main.c +++ b/src/pc/pc_main.c @@ -282,6 +282,7 @@ void main_func(void) { #ifdef DISCORDRPC discord_update_rich_presence(); #endif + fflush(stdout); } #endif }