diff --git a/actors/common1.c b/actors/common1.c index 8773e2de7..1d811ca9f 100644 --- a/actors/common1.c +++ b/actors/common1.c @@ -54,6 +54,9 @@ UNUSED static const u64 binid_11 = 11; #include "mario_cap/model.inc.c" UNUSED static const u64 binid_12 = 12; +// luigi_cap +#include "luigi_cap/model.inc.c" + #include "power_meter/model.inc.c" UNUSED static const u64 binid_13 = 13; @@ -82,4 +85,4 @@ UNUSED static const u64 binid_20 = 20; UNUSED static const u64 binid_21 = 21; #include "tree/model.inc.c" -UNUSED static const u64 binid_22 = 22; +UNUSED static const u64 binid_22 = 22; \ No newline at end of file diff --git a/actors/common1.h b/actors/common1.h index 9a1b650e1..65c1127d6 100644 --- a/actors/common1.h +++ b/actors/common1.h @@ -172,6 +172,27 @@ extern const Gfx mario_cap_seg3_dl_03023108[]; extern const Gfx mario_cap_seg3_dl_03023160[]; extern const Gfx mario_cap_seg3_dl_03023298[]; +// luigi_cap + +extern const GeoLayout luigis_cap_geo[]; +//extern const GeoLayout luigis_metal_cap_geo[]; +//extern const GeoLayout luigis_wing_cap_geo[]; +//extern const GeoLayout luigis_winged_metal_cap_geo[]; +extern const Gfx luigi_cap_seg3_dl_03022B30[]; +extern const Gfx luigi_cap_seg3_dl_03022B68[]; +extern const Gfx luigi_cap_seg3_dl_03022CC8[]; +extern const Gfx luigi_cap_seg3_dl_03022D10[]; +extern const Gfx luigi_cap_seg3_dl_03022E78[]; +extern const Gfx luigi_cap_seg3_dl_03022EA8[]; +extern const Gfx luigi_cap_seg3_dl_03022ED8[]; +extern const Gfx luigi_cap_seg3_dl_03022F20[]; +extern const Gfx luigi_cap_seg3_dl_03022F48[]; +extern const Gfx luigi_cap_seg3_dl_03022FF8[]; +extern const Gfx luigi_cap_seg3_dl_030230B0[]; +extern const Gfx luigi_cap_seg3_dl_03023108[]; +extern const Gfx luigi_cap_seg3_dl_03023160[]; +extern const Gfx luigi_cap_seg3_dl_03023298[]; + // mist extern const GeoLayout mist_geo[]; extern const GeoLayout white_puff_geo[]; diff --git a/actors/common1_geo.c b/actors/common1_geo.c index 7f75637ae..e64f7bbe8 100644 --- a/actors/common1_geo.c +++ b/actors/common1_geo.c @@ -17,6 +17,7 @@ #include "blue_fish/geo.inc.c" #include "leaves/geo.inc.c" #include "mario_cap/geo.inc.c" +#include "luigi_cap/geo.inc.c" // custom luigi_cap #include "number/geo.inc.c" #include "mushroom_1up/geo.inc.c" #include "star/geo.inc.c" diff --git a/actors/klepto/geo.inc.c b/actors/klepto/geo.inc.c index 0d0bbe304..668725ec1 100644 --- a/actors/klepto/geo.inc.c +++ b/actors/klepto/geo.inc.c @@ -24,7 +24,7 @@ const GeoLayout klepto_geo[] = { GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, NULL), GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, NULL), GEO_OPEN_NODE(), - GEO_SWITCH_CASE(4, geo_switch_anim_state), + GEO_SWITCH_CASE(5, geo_switch_anim_state), GEO_OPEN_NODE(), GEO_NODE_START(), GEO_NODE_START(), @@ -53,6 +53,14 @@ const GeoLayout klepto_geo[] = { GEO_TRANSLATE_ROTATE_WITH_DL(LAYER_OPAQUE, 0, 100, 0, 180, 270, 0, transparent_star_seg3_dl_0302C620), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), + GEO_NODE_START(), + GEO_OPEN_NODE(), + GEO_SCALE(0x00, 16384), + GEO_OPEN_NODE(), + GEO_ASM(0, geo_offset_klepto_held_object), + GEO_TRANSLATE_ROTATE_WITH_DL(LAYER_OPAQUE, 0, 100, 0, 180, 270, 0, luigi_cap_seg3_dl_03022F48), + GEO_CLOSE_NODE(), + GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), diff --git a/actors/ukiki/geo.inc.c b/actors/ukiki/geo.inc.c index 72d864c9a..c28ad0f0a 100644 --- a/actors/ukiki/geo.inc.c +++ b/actors/ukiki/geo.inc.c @@ -8,7 +8,7 @@ const GeoLayout ukiki_geo[] = { GEO_OPEN_NODE(), GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 99, -11, NULL), GEO_OPEN_NODE(), - GEO_SWITCH_CASE(4, geo_switch_anim_state), + GEO_SWITCH_CASE(5, geo_switch_anim_state), GEO_OPEN_NODE(), GEO_NODE_START(), GEO_OPEN_NODE(), @@ -32,6 +32,13 @@ const GeoLayout ukiki_geo[] = { GEO_TRANSLATE_ROTATE_WITH_DL(LAYER_OPAQUE, 100, 0, 0, -90, -90, 0, mario_cap_seg3_dl_03022F48), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), + GEO_NODE_START(), + GEO_OPEN_NODE(), + GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, ukiki_seg5_dl_0500B2E8), + GEO_OPEN_NODE(), + GEO_TRANSLATE_ROTATE_WITH_DL(LAYER_OPAQUE, 100, 0, 0, -90, -90, 0, luigi_cap_seg3_dl_03022F48), + GEO_CLOSE_NODE(), + GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_ANIMATED_PART(LAYER_OPAQUE, 71, 69, -9, NULL), diff --git a/include/model_ids.h b/include/model_ids.h index 44b935952..57f381450 100644 --- a/include/model_ids.h +++ b/include/model_ids.h @@ -25,7 +25,11 @@ #define MODEL_MARIO 0x01 // mario_geo #define MODEL_LUIGI 0xE2 // luigi_geo -#define MODEL_BUBBLE_PLAYER 0xE4 // water_bomb_geo +#define MODEL_BUBBLE_PLAYER 0xE3 // water_bomb_geo + +/* Additional custom models */ + +#define MODEL_LUIGIS_CAP 0xE4 // luigis_cap_geo /* Various static level geometry, the geo layout differs but terrain object presets treat them the same.*/ diff --git a/include/object_constants.h b/include/object_constants.h index 2916a7d9d..8c546977e 100644 --- a/include/object_constants.h +++ b/include/object_constants.h @@ -660,9 +660,11 @@ #define UKIKI_ANIM_HELD 12 /* oAnimState */ - #define UKIKI_ANIM_STATE_DEFAULT 0 - #define UKIKI_ANIM_STATE_EYE_CLOSED 1 - #define UKIKI_ANIM_STATE_HAT_ON 2 + #define UKIKI_ANIM_STATE_DEFAULT 0 + #define UKIKI_ANIM_STATE_EYE_CLOSED 1 // unused + #define UKIKI_ANIM_STATE_HAT_ON 2 + #define UKIKI_ANIM_STATE_UNUSED 3 // unused, HAT_ON+EYE_CLOSED + #define UKIKI_ANIM_STATE_HAT_ON_LUIGI 4 /* oUkikiHasHat */ #define UKIKI_HAT_ON 1 @@ -883,6 +885,7 @@ #define KLEPTO_ANIM_STATE_HOLDING_NOTHING 0 #define KLEPTO_ANIM_STATE_HOLDING_CAP 1 #define KLEPTO_ANIM_STATE_HOLDING_STAR 2 + #define KLEPTO_ANIM_STATE_HOLDING_CAP_LUIGI 4 /* Bird */ /* oAction */ diff --git a/levels/scripts.c b/levels/scripts.c index 5d80bd34e..29043ff59 100644 --- a/levels/scripts.c +++ b/levels/scripts.c @@ -66,7 +66,7 @@ const LevelScript level_main_scripts_entry[] = { LOAD_RAW( /*seg*/ 0x13, _behaviorSegmentRomStart, _behaviorSegmentRomEnd), ALLOC_LEVEL_POOL(), LOAD_MODEL_FROM_GEO(MODEL_MARIO, mario_geo), - LOAD_MODEL_FROM_GEO(MODEL_LUIGI, luigi_geo), + LOAD_MODEL_FROM_GEO(MODEL_LUIGI, luigi_geo), // custom luigi LOAD_MODEL_FROM_GEO(MODEL_BUBBLE_PLAYER, water_bomb_geo), LOAD_MODEL_FROM_GEO(MODEL_SMOKE, smoke_geo), LOAD_MODEL_FROM_GEO(MODEL_SPARKLES, sparkles_geo), @@ -104,6 +104,7 @@ const LevelScript level_main_scripts_entry[] = { LOAD_MODEL_FROM_GEO(MODEL_MARIOS_WING_CAP, marios_wing_cap_geo), LOAD_MODEL_FROM_GEO(MODEL_MARIOS_CAP, marios_cap_geo), LOAD_MODEL_FROM_GEO(MODEL_MARIOS_CAP, marios_cap_geo), // repeated + LOAD_MODEL_FROM_GEO(MODEL_LUIGIS_CAP, luigis_cap_geo), // custom luigi_cap LOAD_MODEL_FROM_GEO(MODEL_BOWSER_KEY_CUTSCENE, bowser_key_cutscene_geo), LOAD_MODEL_FROM_GEO(MODEL_BOWSER_KEY, bowser_key_geo), LOAD_MODEL_FROM_GEO(MODEL_RED_FLAME_SHADOW, red_flame_shadow_geo), diff --git a/src/game/behaviors/klepto.inc.c b/src/game/behaviors/klepto.inc.c index b2dad85d4..81ea76820 100644 --- a/src/game/behaviors/klepto.inc.c +++ b/src/game/behaviors/klepto.inc.c @@ -96,11 +96,12 @@ void bhv_klepto_init(void) { o->oKleptoStartPosY = o->oPosY; o->oKleptoStartPosZ = o->oPosZ; - if (save_file_get_flags() & SAVE_FLAG_CAP_ON_KLEPTO) { - o->oAnimState = KLEPTO_ANIM_STATE_HOLDING_CAP; - } else { + // skip hat save flags + //if (save_file_get_flags() & SAVE_FLAG_CAP_ON_KLEPTO) { + // o->oAnimState = KLEPTO_ANIM_STATE_HOLDING_CAP; + //} else { o->oAction = KLEPTO_ACT_WAIT_FOR_MARIO; - } + //} } struct SyncObject* so = network_init_object(o, 4000.0f); @@ -290,7 +291,12 @@ static void klepto_act_dive_at_mario(void) { && !(marioState->action & (ACT_FLAG_SHORT_HITBOX | ACT_FLAG_BUTT_OR_STOMACH_SLIDE)) && distanceToPlayer < 200.0f && dy > 50.0f && dy < 90.0f) { if (network_owns_object(o) && mario_lose_cap_to_enemy(marioState, 1)) { - o->oAnimState = KLEPTO_ANIM_STATE_HOLDING_CAP; + u8 isLuigi = (gNetworkType == NT_SERVER) ? (marioState->playerIndex != 0) : (marioState->playerIndex == 0); + if (isLuigi) { + o->oAnimState = KLEPTO_ANIM_STATE_HOLDING_CAP_LUIGI; + } else { + o->oAnimState = KLEPTO_ANIM_STATE_HOLDING_CAP; + } network_send_object(o); } } @@ -413,12 +419,14 @@ void bhv_klepto_update(void) { if (obj_handle_attacks(&sKleptoHitbox, o->oAction, sKleptoAttackHandlers)) { cur_obj_play_sound_2(SOUND_OBJ_KLEPTO2); - if (network_owns_object(o) && o->oAnimState == KLEPTO_ANIM_STATE_HOLDING_CAP) { + if (network_owns_object(o) && (o->oAnimState == KLEPTO_ANIM_STATE_HOLDING_CAP || o->oAnimState == KLEPTO_ANIM_STATE_HOLDING_CAP_LUIGI)) { save_file_clear_flags(SAVE_FLAG_CAP_ON_KLEPTO); - struct Object* cap = spawn_object(o, MODEL_MARIOS_CAP, bhvNormalCap); + + u8 capModel = (o->oAnimState == KLEPTO_ANIM_STATE_HOLDING_CAP) ? MODEL_MARIOS_CAP : MODEL_LUIGIS_CAP; + struct Object* cap = spawn_object(o, capModel, bhvNormalCap); struct Object* spawn_objects[] = { cap }; - u32 models[] = { MODEL_MARIOS_CAP }; + u32 models[] = { capModel }; network_send_spawn_objects(spawn_objects, models, 1); } else if (o->oAnimState == KLEPTO_ANIM_STATE_HOLDING_STAR) { diff --git a/src/game/behaviors/ukiki.inc.c b/src/game/behaviors/ukiki.inc.c index 45a382b5c..83a963d0a 100644 --- a/src/game/behaviors/ukiki.inc.c +++ b/src/game/behaviors/ukiki.inc.c @@ -638,12 +638,13 @@ void hat_ukiki_held_loop(void) { * Initializatation for ukiki, determines if it has Mario's hat. */ void bhv_ukiki_init(void) { - if (o->oBehParams2ndByte == UKIKI_HAT) { - if (save_file_get_flags() & SAVE_FLAG_CAP_ON_UKIKI) { - o->oUkikiTextState = UKIKI_TEXT_HAS_HAT; - o->oUkikiHasHat |= UKIKI_HAT_ON; - } - } + // skip hat save flags + //if (o->oBehParams2ndByte == UKIKI_HAT) { + // if (save_file_get_flags() & SAVE_FLAG_CAP_ON_UKIKI) { + // o->oUkikiTextState = UKIKI_TEXT_HAS_HAT; + // o->oUkikiHasHat |= UKIKI_HAT_ON; + // } + //} network_init_object(o, 4000.0f); network_init_object_field(o, &o->oUkikiTauntCounter); @@ -684,7 +685,18 @@ void bhv_ukiki_loop(void) { } if (o->oUkikiHasHat & UKIKI_HAT_ON) { - o->oAnimState = UKIKI_ANIM_STATE_HAT_ON; + for (int i = 0; i < MAX_PLAYERS; i++) { + if (!is_player_active(&gMarioStates[i])) { continue; } + if (!does_mario_have_hat(&gMarioStates[i])) { + u8 isLuigi = (gNetworkType == NT_SERVER) ? (gMarioStates[i].playerIndex != 0) : (gMarioStates[i].playerIndex == 0); + if(isLuigi) { + o->oAnimState = UKIKI_ANIM_STATE_HAT_ON_LUIGI; + } else { + o->oAnimState = UKIKI_ANIM_STATE_HAT_ON; + } + break; + } + } } else { o->oAnimState = UKIKI_ANIM_STATE_DEFAULT; } diff --git a/src/game/interaction.c b/src/game/interaction.c index 7ee96fdb6..9cc933336 100644 --- a/src/game/interaction.c +++ b/src/game/interaction.c @@ -387,7 +387,8 @@ void mario_blow_off_cap(struct MarioState *m, f32 capSpeed) { m->flags &= ~(MARIO_NORMAL_CAP | MARIO_CAP_ON_HEAD); - capObject = spawn_object(m->marioObj, MODEL_MARIOS_CAP, bhvNormalCap); + u8 isLuigi = (gNetworkType == NT_SERVER) ? (m->playerIndex != 0) : (m->playerIndex == 0); + capObject = spawn_object(m->marioObj, isLuigi ? MODEL_LUIGIS_CAP : MODEL_MARIOS_CAP, bhvNormalCap); capObject->oPosY += (m->action & ACT_FLAG_SHORT_HITBOX) ? 120.0f : 180.0f; capObject->oForwardVel = capSpeed;