Merge branch 'unstable' of github.com:sm64ex-coop-dev/sm64ex-coop into unstable

This commit is contained in:
MysterD 2022-03-22 20:26:58 -07:00
commit 473c318f71
28 changed files with 486 additions and 295 deletions

3
.gitignore vendored
View file

@ -42,6 +42,9 @@
# Stackdumps
*.stackdump
# Backup files
*.bak
# datadump
/tools/ddump/*

View file

@ -1218,10 +1218,11 @@
--- @field public oToadMessageRecentlyTalked integer
--- @field public oToadMessageState integer
--- @field public oToxBoxMovementStep integer
--- @field public oTreasureChestCurrentAnswer integer
--- @field public oTreasureChestIsAboveWater integer
--- @field public oTreasureChestIsLastInteractionIncorrect integer
--- @field public oTreasureChestLastNetworkPlayerIndex integer
--- @field public oTreasureChestSound integer
--- @field public oTreasureChestUnkF4 integer
--- @field public oTreasureChestUnkF8 integer
--- @field public oTreasureChestUnkFC integer
--- @field public oTreeSnowOrLeafUnkF4 integer
--- @field public oTreeSnowOrLeafUnkF8 integer
--- @field public oTreeSnowOrLeafUnkFC integer

View file

@ -1526,10 +1526,11 @@
| oTTCSpinnerDir | `integer` | |
| oTTCChangeDirTimer | `integer` | |
| oBetaTrampolineMarioOnTrampoline | `integer` | |
| oTreasureChestUnkF4 | `integer` | |
| oTreasureChestUnkF8 | `integer` | |
| oTreasureChestUnkFC | `integer` | |
| oTreasureChestCurrentAnswer | `integer` | |
| oTreasureChestIsLastInteractionIncorrect | `integer` | |
| oTreasureChestIsAboveWater | `integer` | |
| oTreasureChestSound | `integer` | |
| oTreasureChestLastNetworkPlayerIndex | `integer` | |
| oTreeSnowOrLeafUnkF4 | `integer` | |
| oTreeSnowOrLeafUnkF8 | `integer` | |
| oTreeSnowOrLeafUnkFC | `integer` | |

View file

@ -929,6 +929,7 @@
/* Hidden Star */
// Secrets/Red Coins
#define /*0x0F4*/ oHiddenStarTriggerCounter OBJECT_FIELD_S32(0x1B)
#define /*0x0F8*/ oHiddenStarLastInteractedObject OBJECT_FIELD_VPTR(0x1D)
// Overall very difficult to determine usage, mostly stubbed code.
/* Sparkle Spawn Star */
@ -1037,10 +1038,11 @@
#define /*0x110*/ oBetaTrampolineMarioOnTrampoline OBJECT_FIELD_S32(0x22)
/* Treasure Chest */
#define /*0x0F4*/ oTreasureChestUnkF4 OBJECT_FIELD_S32(0x1B)
#define /*0x0F8*/ oTreasureChestUnkF8 OBJECT_FIELD_S32(0x1C)
#define /*0x0FC*/ oTreasureChestUnkFC OBJECT_FIELD_S32(0x1D)
#define /*0x0F4*/ oTreasureChestCurrentAnswer OBJECT_FIELD_S32(0x1B)
#define /*0x0F8*/ oTreasureChestIsLastInteractionIncorrect OBJECT_FIELD_S32(0x1C)
#define /*0x0FC*/ oTreasureChestIsAboveWater OBJECT_FIELD_S32(0x1D)
#define /*0x100*/ oTreasureChestSound OBJECT_FIELD_S32(0x1E)
#define /*0x104*/ oTreasureChestLastNetworkPlayerIndex OBJECT_FIELD_S16(0x21, 0)
/* Tree Snow Or Leaf */
#define /*0x0F4*/ oTreeSnowOrLeafUnkF4 OBJECT_FIELD_S32(0x1B)

View file

@ -1,5 +1,5 @@
-- name: Mario RUN!
-- description: Mario Is contantly runing
-- description: Mario is constantly running.
Threshold = 50 --set Threshold to 50

View file

@ -97,7 +97,7 @@ static void homing_amp_appear_loop(void) {
*/
static void homing_amp_chase_loop(void) {
struct Object* player = nearest_player_to_object(o);
int angleToPlayer = obj_angle_to_object(o, player);
s32 angleToPlayer = obj_angle_to_object(o, player);
// Lock on to Mario if he ever goes within 11.25 degrees of the amp's line of sight
if ((angleToPlayer - 0x400 < o->oMoveAngleYaw)
@ -199,7 +199,8 @@ static void amp_attack_cooldown_loop(void) {
*/
void bhv_homing_amp_loop(void) {
if (!network_sync_object_initialized(o)) {
network_init_object(o, 4000.0f);
struct SyncObject *so = network_init_object(o, 4000.0f);
if (so) {
network_init_object_field(o, &o->oAmpYPhase);
network_init_object_field(o, &o->oAnimState);
network_init_object_field(o, &o->oFaceAnglePitch);
@ -209,6 +210,7 @@ void bhv_homing_amp_loop(void) {
network_init_object_field(o, &o->oHomingAmpAvgY);
network_init_object_field(o, &o->oHomingAmpLockedOn);
}
}
switch (o->oAction) {
case HOMING_AMP_ACT_INACTIVE:
@ -342,7 +344,8 @@ static void circling_amp_idle_loop(void) {
*/
void bhv_circling_amp_loop(void) {
if (!network_sync_object_initialized(o)) {
network_init_object(o, 4000.0f);
struct SyncObject *so = network_init_object(o, 4000.0f);
if (so) {
network_init_object_field(o, &o->oAmpYPhase);
network_init_object_field(o, &o->oAnimState);
network_init_object_field(o, &o->oFaceAnglePitch);
@ -350,6 +353,7 @@ void bhv_circling_amp_loop(void) {
network_init_object_field(o, &o->oForwardVel);
network_init_object_field(o, &o->oFriction);
}
}
switch (o->oAction) {
case AMP_ACT_IDLE:

View file

@ -60,11 +60,13 @@ static s8 arrow_lift_move_back(void) {
*/
void bhv_arrow_lift_loop(void) {
if (!network_sync_object_initialized(o)) {
network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS);
struct SyncObject *so = network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS);
if (so) {
network_init_object_field(o, &o->oTimer);
network_init_object_field(o, &o->oPrevAction);
network_init_object_field(o, &o->oAction);
}
}
switch (o->oAction) {
case ARROW_LIFT_ACT_IDLE:

View file

@ -21,14 +21,13 @@ static void handle_merry_go_round_music(void) {
}
} else {
// Get Mario's floor and floor surface type
struct Surface *marioFloor;
u16 marioFloorType;
struct Surface *marioFloor = NULL;
struct Object *marioObject = gMarioObjects[0];
u16 marioFloorType = 0;
find_floor(gMarioObject->oPosX, gMarioObject->oPosY, gMarioObject->oPosZ, &marioFloor);
find_floor(marioObject->oPosX, marioObject->oPosY, marioObject->oPosZ, &marioFloor);
if (marioFloor == NULL) {
marioFloorType = 0;
} else {
if (marioFloor != NULL) {
marioFloorType = marioFloor->type;
}

View file

@ -24,7 +24,7 @@ static u8 boo_ignore_update(void) {
}
struct SyncObject* boo_network_init_object(void) {
struct SyncObject* so = network_init_object(o, 4000.0f);
struct SyncObject *so = network_init_object(o, 4000.0f);
if (so == NULL) { return NULL; }
so->ignore_if_true = boo_ignore_update;
network_init_object_field(o, &o->oBooBaseScale);

View file

@ -48,8 +48,8 @@ void bub_act_0(void) {
void bub_act_1(void) {
struct Object* player = nearest_player_to_object(o);
int distanceToPlayer = dist_between_objects(o, player);
int angleToPlayer = obj_angle_to_object(o, player);
s32 distanceToPlayer = dist_between_objects(o, player);
s32 angleToPlayer = obj_angle_to_object(o, player);
f32 dy;
if (o->oTimer == 0) {
o->oForwardVel = random_float() * 2 + 2;
@ -80,8 +80,8 @@ void bub_act_1(void) {
void bub_act_2(void) {
struct Object* player = nearest_player_to_object(o);
int distanceToPlayer = dist_between_objects(o, player);
int angleToPlayer = obj_angle_to_object(o, player);
s32 distanceToPlayer = dist_between_objects(o, player);
s32 angleToPlayer = obj_angle_to_object(o, player);
f32 dy;
if (o->oTimer < 20) {
if (o->oInteractStatus & INT_STATUS_INTERACTED)
@ -116,13 +116,15 @@ void (*sCheepCheepActions[])(void) = { bub_act_0, bub_act_1, bub_act_2 };
void bhv_bub_loop(void) {
if (!network_sync_object_initialized(o)) {
network_init_object(o, 4000.0f);
struct SyncObject *so = network_init_object(o, 4000.0f);
if (so) {
network_init_object_field(o, &o->oCheepCheepUnkF4);
network_init_object_field(o, &o->oCheepCheepUnkF8);
network_init_object_field(o, &o->oCheepCheepUnkFC);
network_init_object_field(o, &o->oCheepCheepUnk104);
network_init_object_field(o, &o->oCheepCheepUnk108);
}
}
struct Object* player = nearest_player_to_object(o);

View file

@ -39,7 +39,8 @@ void bhv_camera_lakitu_init(void) {
}
lakituTargetLocalIndex = UNKNOWN_LOCAL_INDEX;
struct SyncObject* so = network_init_object(o, 4000.0f);
if (!network_sync_object_initialized(o)) {
struct SyncObject *so = network_init_object(o, 4000.0f);
if (so) {
so->ignore_if_true = bhv_camera_lakitu_ignore_if_true;
so->override_ownership = bhv_camera_lakitu_override_ownership;
@ -53,6 +54,7 @@ void bhv_camera_lakitu_init(void) {
network_init_object_field(o, &o->oCameraLakituUnk104);
network_init_object_field(o, &o->oCameraLakituPitchVel);
}
}
}
static u8 camera_lakitu_intro_act_trigger_cutscene_continue_dialog(void) {
@ -112,8 +114,8 @@ static void camera_lakitu_intro_act_show_dialog(void) {
marioState = &gMarioStates[lakituTargetLocalIndex];
}
struct Object* player = marioState->marioObj;
int distanceToPlayer = dist_between_objects(o, player);
int angleToPlayer = obj_angle_to_object(o, player);
s32 distanceToPlayer = dist_between_objects(o, player);
s32 angleToPlayer = obj_angle_to_object(o, player);
s16 targetMovePitch = 0;
s16 targetMoveYaw = 0;

View file

@ -19,7 +19,7 @@ void opened_cannon_act_0(void) {
cur_obj_enable_rendering();
struct Object* player = nearest_player_to_object(o);
int distanceToPlayer = dist_between_objects(o, player);
s32 distanceToPlayer = dist_between_objects(o, player);
if (distanceToPlayer < 500.0f) {
//cur_obj_become_tangible();

View file

@ -28,8 +28,13 @@ static struct ObjectHitbox sChainChompHitbox = {
* Update function for chain chomp part / pivot.
*/
void bhv_chain_chomp_chain_part_update(void) {
if (o->parentObj->behavior != (BehaviorScript*)&bhvChainChomp || o->parentObj->oAction == CHAIN_CHOMP_ACT_UNLOAD_CHAIN) {
if (!network_sync_object_initialized(o)) {
network_init_object(o, SYNC_DISTANCE_ONLY_DEATH);
}
if (o->parentObj->behavior != (BehaviorScript *)&bhvChainChomp || o->parentObj->oAction == CHAIN_CHOMP_ACT_UNLOAD_CHAIN) {
obj_mark_for_deletion(o);
network_send_object(o);
} else if (o->oBehParams2ndByte != CHAIN_CHOMP_CHAIN_PART_BP_PIVOT) {
struct ChainSegment *segment = &o->parentObj->oChainChompSegments[o->oBehParams2ndByte];
@ -47,17 +52,14 @@ void bhv_chain_chomp_chain_part_update(void) {
* When mario gets close enough, allocate chain segments and spawn their objects.
*/
static void chain_chomp_act_uninitialized(void) {
struct ChainSegment *segments;
s32 i;
segments = mem_pool_alloc(gObjectMemoryPool, 5 * sizeof(struct ChainSegment));
struct ChainSegment *segments = mem_pool_alloc(gObjectMemoryPool, 5 * sizeof(struct ChainSegment));
if (segments != NULL) {
// Each segment represents the offset of a chain part to the pivot.
// Segment 0 connects the pivot to the chain chomp itself. Segment
// 1 connects the pivot to the chain part next to the chain chomp
// (chain part 1), etc.
o->oChainChompSegments = segments;
for (i = 0; i <= 4; i++) {
for (s32 i = 0; i <= 4; i++) {
chain_segment_init(&segments[i]);
}
@ -69,7 +71,7 @@ static void chain_chomp_act_uninitialized(void) {
!= NULL) {
// Spawn the non-pivot chain parts, starting from the chain
// chomp and moving toward the pivot
for (i = 1; i <= 4; i++) {
for (s32 i = 1; i <= 4; i++) {
spawn_object_relative(i, 0, 0, 0, o, MODEL_METALLIC_BALL, bhvChainChompChainPart);
}
@ -84,15 +86,7 @@ static void chain_chomp_act_uninitialized(void) {
* part as well as from the pivot.
*/
static void chain_chomp_update_chain_segments(void) {
struct ChainSegment *prevSegment;
struct ChainSegment *segment;
f32 offsetX;
f32 offsetY;
f32 offsetZ;
f32 offset;
f32 segmentVelY;
f32 maxTotalOffset;
s32 i;
if (o->oVelY < 0.0f) {
segmentVelY = o->oVelY;
@ -103,9 +97,9 @@ static void chain_chomp_update_chain_segments(void) {
// Segment 0 connects the pivot to the chain chomp itself, and segment i>0
// connects the pivot to chain part i (1 is closest to the chain chomp).
for (i = 1; i <= 4; i++) {
prevSegment = &o->oChainChompSegments[i - 1];
segment = &o->oChainChompSegments[i];
for (s32 i = 1; i <= 4; i++) {
struct ChainSegment *prevSegment = &o->oChainChompSegments[i - 1];
struct ChainSegment *segment = &o->oChainChompSegments[i];
// Apply gravity
@ -116,10 +110,10 @@ static void chain_chomp_update_chain_segments(void) {
// Cap distance to previous chain part (so that the tail follows the
// chomp)
offsetX = segment->posX - prevSegment->posX;
offsetY = segment->posY - prevSegment->posY;
offsetZ = segment->posZ - prevSegment->posZ;
offset = sqrtf(offsetX * offsetX + offsetY * offsetY + offsetZ * offsetZ);
f32 offsetX = segment->posX - prevSegment->posX;
f32 offsetY = segment->posY - prevSegment->posY;
f32 offsetZ = segment->posZ - prevSegment->posZ;
f32 offset = sqrtf(offsetX * offsetX + offsetY * offsetY + offsetZ * offsetZ);
if (offset > o->oChainChompMaxDistBetweenChainParts) {
offset = o->oChainChompMaxDistBetweenChainParts / offset;
@ -136,7 +130,7 @@ static void chain_chomp_update_chain_segments(void) {
offsetZ += prevSegment->posZ;
offset = sqrtf(offsetX * offsetX + offsetY * offsetY + offsetZ * offsetZ);
maxTotalOffset = o->oChainChompMaxDistFromPivotPerChainPart * (5 - i);
f32 maxTotalOffset = o->oChainChompMaxDistFromPivotPerChainPart * (5 - i);
if (offset > maxTotalOffset) {
offset = maxTotalOffset / offset;
offsetX *= offset;
@ -168,9 +162,9 @@ static void chain_chomp_sub_act_turn(void) {
chain_chomp_restore_normal_chain_lengths();
obj_move_pitch_approach(0, 0x100);
struct Object* player = nearest_player_to_object(o);
int distanceToPlayer = dist_between_objects(o, player);
int angleToPlayer = obj_angle_to_object(o, player);
struct Object *player = nearest_player_to_object(o);
s32 distanceToPlayer = dist_between_objects(o, player);
s32 angleToPlayer = obj_angle_to_object(o, player);
if (o->oMoveFlags & OBJ_MOVE_MASK_ON_GROUND) {
cur_obj_rotate_yaw_toward(angleToPlayer, 0x400);
@ -343,8 +337,6 @@ static void chain_chomp_released_end_cutscene(void) {
* released.
*/
static void chain_chomp_act_move(void) {
f32 maxDistToPivot;
// Unload chain if mario is far enough
cur_obj_update_floor_and_walls();
@ -389,7 +381,7 @@ static void chain_chomp_act_move(void) {
+ o->oChainChompSegments[0].posZ * o->oChainChompSegments[0].posZ);
// If the chain is fully stretched
maxDistToPivot = o->oChainChompMaxDistFromPivotPerChainPart * 5;
f32 maxDistToPivot = o->oChainChompMaxDistFromPivotPerChainPart * 5;
if (o->oChainChompDistToPivot > maxDistToPivot) {
f32 ratio = maxDistToPivot / o->oChainChompDistToPivot;
o->oChainChompDistToPivot = maxDistToPivot;
@ -524,9 +516,9 @@ void bhv_wooden_post_update(void) {
if (o->oWoodenPostOffsetY != 0.0f) {
o->oPosY = o->oHomeY + o->oWoodenPostOffsetY;
} else if (!(o->oBehParams & WOODEN_POST_BP_NO_COINS_MASK)) {
struct Object* player = nearest_player_to_object(o);
int distanceToPlayer = dist_between_objects(o, player);
int angleToPlayer = obj_angle_to_object(o, player);
struct Object *player = nearest_player_to_object(o);
s32 distanceToPlayer = dist_between_objects(o, player);
s32 angleToPlayer = obj_angle_to_object(o, player);
// Reset the timer once mario is far enough
if (distanceToPlayer > 400.0f) {
@ -536,9 +528,9 @@ void bhv_wooden_post_update(void) {
// coins
o->oWoodenPostTotalMarioAngle += (s16)(angleToPlayer - o->oWoodenPostPrevAngleToMario);
if (absi(o->oWoodenPostTotalMarioAngle) > 0x30000 && o->oTimer < 200) {
network_send_object(o);
obj_spawn_loot_yellow_coins(o, 5, 20.0f);
set_object_respawn_info_bits(o, 1);
network_send_object(o);
}
}

View file

@ -1,31 +1,55 @@
// hidden_star.c.inc
void bhv_hidden_star_init(void) {
s16 sp36;
struct Object *sp30;
sp36 = count_objects_with_behavior(bhvHiddenStarTrigger);
if (sp36 == 0) {
sp30 =
spawn_object_abs_with_rot(o, 0, MODEL_STAR, bhvStar, o->oPosX, o->oPosY, o->oPosZ, 0, 0, 0);
if (sp30 != NULL) { sp30->oBehParams = o->oBehParams; }
s16 count = count_objects_with_behavior(bhvHiddenStarTrigger);
if (count == 0) {
struct Object *obj = spawn_object_abs_with_rot(o, 0, MODEL_STAR, bhvStar, o->oPosX, o->oPosY, o->oPosZ, 0, 0, 0);
if (obj != NULL) { obj->oBehParams = o->oBehParams; }
o->activeFlags = ACTIVE_FLAG_DEACTIVATED;
}
o->oHiddenStarTriggerCounter = 5 - sp36;
o->oHiddenStarTriggerCounter = 5 - count;
// We haven't interacted with a player yet.
// We also don't sync this as not only is it not required
// but it also is only set for an interaction.
// Therefore this object must already be loaded for it to be set
// and if it wasn't. You couldn't of possibly been the one
// who last interacted to begin with.
o->oHiddenStarLastInteractedObject = NULL;
if (!network_sync_object_initialized(o)) {
struct SyncObject *so = network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS);
if (so) {
network_init_object_field(o, &o->oAction);
network_init_object_field(o, &o->oHiddenStarTriggerCounter);
network_init_object_field(o, &o->oPosX);
network_init_object_field(o, &o->oPosY);
network_init_object_field(o, &o->oPosZ);
network_init_object_field(o, &o->oTimer);
}
}
}
void bhv_hidden_star_loop(void) {
switch (o->oAction) {
case 0:
if (o->oHiddenStarTriggerCounter == 5)
if (o->oHiddenStarTriggerCounter == 5) {
o->oAction = 1;
}
break;
case 1:
if (o->oTimer > 2) {
spawn_red_coin_cutscene_star(o->oPosX, o->oPosY, o->oPosZ);
struct Object *obj = spawn_red_coin_cutscene_star(o->oPosX, o->oPosY, o->oPosZ);
if (obj != NULL) {
if (o->oHiddenStarLastInteractedObject == &gMarioStates[0]) {
obj->oStarSpawnExtCutsceneFlags = 1;
} else {
obj->oStarSpawnExtCutsceneFlags = 0;
}
spawn_mist_particles();
}
o->activeFlags = ACTIVE_FLAG_DEACTIVATED;
}
break;
@ -34,15 +58,21 @@ void bhv_hidden_star_loop(void) {
/* TODO: this is likely not a checkpoint but a Secret */
void bhv_hidden_star_trigger_loop(void) {
struct Object *hiddenStar;
if ((o->oInteractStatus & INT_STATUS_INTERACTED) || obj_check_if_collided_with_object(o, gMarioObject) == 1) {
hiddenStar = cur_obj_nearest_object_with_behavior(bhvHiddenStar);
if ((o->oInteractStatus & INT_STATUS_INTERACTED) || obj_check_if_collided_with_object(o, gMarioObjects[0]) == 1) {
struct Object *hiddenStar = cur_obj_nearest_object_with_behavior(bhvHiddenStar);
if (hiddenStar != NULL) {
hiddenStar->oHiddenStarTriggerCounter++;
if (hiddenStar->oHiddenStarTriggerCounter != 5) {
spawn_orange_number(hiddenStar->oHiddenStarTriggerCounter, 0, 0, 0);
}
// Set the last person who interacted with a secret to the
// parent so only they get the star cutscene.
struct MarioState *player = nearest_mario_state_to_object(o);
if (player) {
hiddenStar->oHiddenStarLastInteractedObject = player;
}
#ifdef VERSION_JP
play_sound(SOUND_MENU_STAR_SOUND, gGlobalSoundSource);
#else
@ -63,14 +93,22 @@ void bhv_bowser_course_red_coin_star_loop(void) {
gRedCoinsCollected = o->oHiddenStarTriggerCounter;
switch (o->oAction) {
case 0:
if (o->oHiddenStarTriggerCounter == 8)
if (o->oHiddenStarTriggerCounter == 8) {
o->oAction = 1;
}
break;
case 1:
if (o->oTimer > 2) {
spawn_no_exit_star(o->oPosX, o->oPosY, o->oPosZ);
struct Object *obj = spawn_no_exit_star(o->oPosX, o->oPosY, o->oPosZ);
if (obj != NULL) {
if (o->oHiddenStarLastInteractedObject == &gMarioStates[0]) {
obj->oStarSpawnExtCutsceneFlags = 1;
} else {
obj->oStarSpawnExtCutsceneFlags = 0;
}
spawn_mist_particles();
}
o->activeFlags = ACTIVE_FLAG_DEACTIVATED;
}
break;

View file

@ -23,24 +23,19 @@ static struct ObjectHitbox sRedCoinHitbox = {
* Red coin initialization function. Sets the coin's hitbox and parent object.
*/
void bhv_red_coin_init(void) {
// This floor and floor height are unused. Perhaps for orange number spawns originally?
struct Surface *dummyFloor;
UNUSED f32 floorHeight = find_floor(o->oPosX, o->oPosY, o->oPosZ, &dummyFloor);
struct Object *hiddenRedCoinStar;
// Set the red coins to have a parent of the closest red coin star.
hiddenRedCoinStar = cur_obj_nearest_object_with_behavior(bhvHiddenRedCoinStar);
if (hiddenRedCoinStar != NULL)
o->parentObj = hiddenRedCoinStar;
else {
struct Object *hiddenRedCoinStar = cur_obj_nearest_object_with_behavior(bhvHiddenRedCoinStar);
// If it's not a typical red coin star, it's a Bowser one.
if (hiddenRedCoinStar == NULL) {
hiddenRedCoinStar = cur_obj_nearest_object_with_behavior(bhvBowserCourseRedCoinStar);
}
// If we found a red coin star, It's our parent.
if (hiddenRedCoinStar != NULL) {
o->parentObj = hiddenRedCoinStar;
} else {
o->parentObj = NULL;
}
}
obj_set_hitbox(o, &sRedCoinHitbox);
}
@ -57,6 +52,13 @@ void bhv_red_coin_loop(void) {
// ...increment the star's counter.
o->parentObj->oHiddenStarTriggerCounter++;
// Set the last person who interacted with a red coin to the
// parent so only they get the star cutscene.
struct MarioState *player = nearest_mario_state_to_object(o);
if (player) {
o->parentObj->oHiddenStarLastInteractedObject = player;
}
// For JP version, play an identical sound for all coins.
#ifdef VERSION_JP
create_sound_spawner(SOUND_GENERAL_RED_COIN);

View file

@ -7,7 +7,9 @@
// a rolling log of another variation.
static void bhv_rolling_log_network_init(void) {
network_init_object(o, 4000.0f);
if (!network_sync_object_initialized(o)) {
struct SyncObject *so = network_init_object(o, 4000.0f);
if (so) {
network_init_object_field(o, &o->oAngleVelPitch);
network_init_object_field(o, &o->oFaceAnglePitch);
network_init_object_field(o, &o->oMoveAnglePitch);
@ -15,6 +17,8 @@ static void bhv_rolling_log_network_init(void) {
network_init_object_field(o, &o->oPitouneUnkF8);
network_init_object_field(o, &o->oPitouneUnkFC);
network_init_object_field(o, &o->oForwardVel);
}
}
}
void bhv_ttm_rolling_log_init(void) {
@ -143,11 +147,13 @@ void volcano_act_3(void) {
void bhv_volcano_trap_loop(void) {
if (!network_sync_object_initialized(o)) {
network_init_object(o, 2000.0f);
struct SyncObject *so = network_init_object(o, 2000.0f);
if (so) {
network_init_object_field(o, &o->oRollingLogUnkF4);
network_init_object_field(o, &o->oAngleVelPitch);
network_init_object_field(o, &o->oFaceAnglePitch);
}
}
switch (o->oAction) {
case 0:

View file

@ -25,7 +25,8 @@ s32 update_angle_from_move_flags(s32 *angle) {
void bhv_scuttlebug_loop(void) {
if (!network_sync_object_initialized(o)) {
network_init_object(o, 4000.0f);
struct SyncObject *so = network_init_object(o, 4000.0f);
if (so) {
network_init_object_field(o, &o->oFlags);
network_init_object_field(o, &o->oForwardVel);
network_init_object_field(o, &o->oHomeX);
@ -34,12 +35,11 @@ void bhv_scuttlebug_loop(void) {
network_init_object_field(o, &o->oInteractStatus);
network_init_object_field(o, &o->oScuttlebugUnkF4);
}
}
struct Object* player = nearest_player_to_object(o);
int angleToPlayer = obj_angle_to_object(o, player);
struct Object *player = nearest_player_to_object(o);
s32 angleToPlayer = obj_angle_to_object(o, player);
UNUSED s32 unused;
f32 sp18;
cur_obj_update_floor_and_walls();
if (o->oSubAction != 0
&& cur_obj_set_hitbox_and_die_if_attacked(&sScuttlebugHitbox, SOUND_OBJ_DYING_ENEMY1,
@ -114,13 +114,16 @@ void bhv_scuttlebug_loop(void) {
o->oSubAction = 0;
break;
}
if (o->oForwardVel < 10.0f)
f32 sp18;
if (o->oForwardVel < 10.0f) {
sp18 = 1.0f;
else
} else {
sp18 = 3.0f;
}
cur_obj_init_animation_with_accel_and_sound(0, sp18);
if (o->oMoveFlags & OBJ_MOVE_MASK_ON_GROUND)
if (o->oMoveFlags & OBJ_MOVE_MASK_ON_GROUND) {
set_obj_anim_with_accel_and_sound(1, 23, SOUND_OBJ2_SCUTTLEBUG_WALK);
}
if (o->parentObj != o) {
if (obj_is_hidden(o))
obj_mark_for_deletion(o);
@ -134,31 +137,32 @@ void bhv_scuttlebug_loop(void) {
void bhv_scuttlebug_spawn_loop(void) {
if (!network_sync_object_initialized(o)) {
network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS);
struct SyncObject *so = network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS);
if (so) {
network_init_object_field(o, &o->oAction);
network_init_object_field(o, &o->oTimer);
network_init_object_field(o, &o->oScuttlebugSpawnerUnkF4);
network_init_object_field(o, &o->oScuttlebugSpawnerUnk88);
}
}
struct MarioState* marioState = nearest_mario_state_to_object(o);
if (marioState->playerIndex != 0) { return; }
struct Object* player = marioState->marioObj;
int distanceToPlayer = dist_between_objects(o, player);
s32 distanceToPlayer = dist_between_objects(o, player);
struct Object *scuttlebug;
if (o->oAction == 0) {
if (o->oTimer > 30 && 500.0f < distanceToPlayer && distanceToPlayer < 1500.0f) {
cur_obj_play_sound_2(SOUND_OBJ2_SCUTTLEBUG_ALERT);
scuttlebug = spawn_object(o, MODEL_SCUTTLEBUG, bhvScuttlebug);
struct Object *scuttlebug = spawn_object(o, MODEL_SCUTTLEBUG, bhvScuttlebug);
if (scuttlebug != NULL) {
scuttlebug->oScuttlebugUnkF4 = o->oScuttlebugSpawnerUnkF4;
scuttlebug->oForwardVel = 30.0f;
scuttlebug->oVelY = 80.0f;
network_set_sync_id(scuttlebug);
struct Object* spawn_objects[] = { scuttlebug };
struct Object *spawn_objects[] = { scuttlebug };
u32 models[] = { MODEL_SCUTTLEBUG };
network_send_spawn_objects(spawn_objects, models, 1);
}

View file

@ -24,16 +24,19 @@ void bhv_seesaw_platform_init(void) {
o->oCollisionDistance = 2000.0f;
}
network_init_object(o, 1000.0f);
if (!network_sync_object_initialized(o)) {
struct SyncObject *so = network_init_object(o, 1000.0f);
if (so) {
network_init_object_field(o, &o->oSeesawPlatformPitchVel);
network_init_object_field(o, &o->oFaceAnglePitch);
}
}
}
/**
* Update function for bhvSeesawPlatform.
*/
void bhv_seesaw_platform_update(void) {
UNUSED s32 startPitch = o->oFaceAnglePitch;
o->oFaceAnglePitch += (s32) o->oSeesawPlatformPitchVel;
if (absf(o->oSeesawPlatformPitchVel) > 10.0f) {
@ -44,7 +47,7 @@ void bhv_seesaw_platform_update(void) {
f32 y = 0;
f32 z = 0;
u8 playersTouched = 0;
for (int i = 0; i < MAX_PLAYERS; i++) {
for (s32 i = 0; i < MAX_PLAYERS; i++) {
if (!is_player_active(&gMarioStates[i])) { continue; }
if (gMarioStates[i].marioObj->platform == o) {
x += gMarioStates[i].marioObj->oPosX;
@ -59,12 +62,11 @@ void bhv_seesaw_platform_update(void) {
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, z);
s32 distanceToPlayer = dist_between_object_and_point(o, x, y, z);
s32 angleToPlayer = obj_angle_to_point(o, x, z);
// Rotate toward mario
f32 rotation = distanceToPlayer * coss(angleToPlayer - o->oMoveAngleYaw);
UNUSED s32 unused;
// Deceleration is faster than acceleration
if (o->oSeesawPlatformPitchVel * rotation < 0) {

View file

@ -4,18 +4,19 @@ u8 bhv_sl_snowman_wind_loop_continue_dialog(void) { return o->oSubAction == SL_S
void bhv_sl_snowman_wind_loop(void) {
if (!network_sync_object_initialized(o)) {
network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS);
struct SyncObject *so = network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS);
if (so) {
network_init_object_field(o, &o->oAction);
network_init_object_field(o, &o->oPrevAction);
network_init_object_field(o, &o->oTimer);
network_init_object_field(o, &o->oSubAction);
}
}
struct Object* player = nearest_player_to_object(o);
int distanceToPlayer = dist_between_objects(o, player);
int angleToPlayer = obj_angle_to_object(o, player);
struct Object *player = nearest_player_to_object(o);
s32 distanceToPlayer = dist_between_objects(o, player);
s32 angleToPlayer = obj_angle_to_object(o, player);
UNUSED s32 unusedVar = 0;
s16 marioAngleFromWindSource;
Vec3f tempPos;

View file

@ -38,7 +38,8 @@ void bhv_sl_walking_penguin_loop(void) {
f32 perpendicularOffset = 100.0f;
if (!network_sync_object_initialized(o)) {
network_init_object(o, 4000.0f);
struct SyncObject *so = network_init_object(o, 4000.0f);
if (so) {
network_init_object_field(o, &o->oTimer);
network_init_object_field(o, &o->oAction);
network_init_object_field(o, &o->oPrevAction);
@ -47,6 +48,7 @@ void bhv_sl_walking_penguin_loop(void) {
network_init_object_field(o, &o->oSLWalkingPenguinWindCollisionXPos);
network_init_object_field(o, &o->oSLWalkingPenguinWindCollisionZPos);
}
}
o->oAngleVelYaw = 0;
cur_obj_update_floor_and_walls();

View file

@ -36,7 +36,6 @@ void bhv_sliding_plat_2_init(void) {
void bhv_sliding_plat_2_loop(void) {
if (!network_sync_object_initialized(o)) {
struct SyncObject* so = network_init_object(o, 4000.0f);
if (so) {
so->minUpdateRate = 5.0f;
network_init_object_field(o, &o->oBackAndForthPlatformDirection);

View file

@ -140,7 +140,7 @@ static u8 spawn_star_deduplication(u32* array, u8* count, u32 behParams) {
return TRUE;
}
struct Object* spawn_default_star(f32 x, f32 y, f32 z) {
struct Object *spawn_default_star(f32 x, f32 y, f32 z) {
if (sCurrPlayMode != PLAY_MODE_NORMAL && sCurrPlayMode != PLAY_MODE_PAUSED) { return NULL; }
if (o == NULL) { return NULL; }
u32 behParams = o->oBehParams;
@ -154,12 +154,12 @@ struct Object* spawn_default_star(f32 x, f32 y, f32 z) {
star = spawn_star(star, x, y, z);
if (star != NULL) {
star->oBehParams2ndByte = 0;
network_send_spawn_star(star, 0, x, y, z, behParams);
network_send_spawn_star(star, 0, x, y, z, behParams, UNKNOWN_GLOBAL_INDEX);
}
return star;
}
struct Object* spawn_red_coin_cutscene_star(f32 x, f32 y, f32 z) {
struct Object *spawn_red_coin_cutscene_star(f32 x, f32 y, f32 z) {
u32 behParams = o->oBehParams;
// de-duplication checking
@ -171,12 +171,12 @@ struct Object* spawn_red_coin_cutscene_star(f32 x, f32 y, f32 z) {
star = spawn_star(star, x, y, z);
if (star != NULL) {
star->oBehParams2ndByte = 1;
network_send_spawn_star(star, 1, x, y, z, behParams);
network_send_spawn_star(star, 1, x, y, z, behParams, UNKNOWN_GLOBAL_INDEX);
}
return star;
}
struct Object* spawn_no_exit_star(f32 x, f32 y, f32 z) {
struct Object *spawn_no_exit_star(f32 x, f32 y, f32 z) {
u32 behParams = o->oBehParams;
// de-duplication checking
@ -189,14 +189,45 @@ struct Object* spawn_no_exit_star(f32 x, f32 y, f32 z) {
if (star != NULL) {
star->oBehParams2ndByte = 1;
star->oInteractionSubtype |= INT_SUBTYPE_NO_EXIT;
network_send_spawn_star(star, 2, x, y, z, behParams);
network_send_spawn_star(star, 2, x, y, z, behParams, UNKNOWN_GLOBAL_INDEX);
}
return star;
}
/**
* A special star spawning routine just for a networked stars.
* These stars require the global index for a network player for proper
* cutscene functionality.
*/
struct Object *spawn_networked_default_star(f32 x, f32 y, f32 z, u8 networkPlayerIndex) {
if (sCurrPlayMode != PLAY_MODE_NORMAL && sCurrPlayMode != PLAY_MODE_PAUSED) { return NULL; }
if (o == NULL) { return NULL; }
u32 behParams = o->oBehParams;
// de-duplication checking
if (spawn_star_deduplication(gSpawnedStarDefault, &gSpawnedStarDefaultCount, behParams)) {
return NULL;
}
struct Object *star = NULL;
star = spawn_star(star, x, y, z);
if (star != NULL) {
star->oBehParams2ndByte = 0;
//printf("spawn_networked_default_star: Network Player Index is %i, Our Global Index is %i.\n", networkPlayerIndex, gNetworkPlayers[0].globalIndex);
if (networkPlayerIndex == gNetworkPlayers[0].globalIndex) {
star->oStarSpawnExtCutsceneFlags = 1;
} else {
star->oStarSpawnExtCutsceneFlags = 0;
}
network_send_spawn_star(star, 0, x, y, z, behParams, networkPlayerIndex);
}
return star;
}
void bhv_hidden_red_coin_star_init(void) {
if (gCurrCourseNum != COURSE_JRB)
if (gCurrCourseNum != COURSE_JRB) {
spawn_object(o, MODEL_TRANSPARENT_STAR, bhvRedCoinStarMarker);
}
s16 redCoins = count_objects_with_behavior(bhvRedCoin);
if (redCoins == 0) {
@ -206,20 +237,48 @@ void bhv_hidden_red_coin_star_init(void) {
}
o->oHiddenStarTriggerCounter = 8 - redCoins;
// We haven't interacted with a player yet.
// We also don't sync this as not only is it not required
// but it also is only set for an interaction.
// Therefore this object must already be loaded for it to be set
// and if it wasn't. You couldn't of possibly been the one
// who last interacted to begin with.
o->oHiddenStarLastInteractedObject = NULL;
if (!network_sync_object_initialized(o)) {
struct SyncObject *so = network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS);
if (so) {
network_init_object_field(o, &o->oAction);
network_init_object_field(o, &o->oHiddenStarTriggerCounter);
network_init_object_field(o, &o->oPosX);
network_init_object_field(o, &o->oPosY);
network_init_object_field(o, &o->oPosZ);
network_init_object_field(o, &o->oTimer);
}
}
}
void bhv_hidden_red_coin_star_loop(void) {
gRedCoinsCollected = o->oHiddenStarTriggerCounter;
switch (o->oAction) {
case 0:
if (o->oHiddenStarTriggerCounter == 8)
if (o->oHiddenStarTriggerCounter == 8) {
o->oAction = 1;
}
break;
case 1:
if (o->oTimer > 2) {
spawn_red_coin_cutscene_star(o->oPosX, o->oPosY, o->oPosZ);
struct Object *obj = spawn_red_coin_cutscene_star(o->oPosX, o->oPosY, o->oPosZ);
if (obj != NULL) {
if (o->oHiddenStarLastInteractedObject == &gMarioStates[0]) {
obj->oStarSpawnExtCutsceneFlags = 1;
} else {
obj->oStarSpawnExtCutsceneFlags = 0;
}
spawn_mist_particles();
}
o->activeFlags = ACTIVE_FLAG_DEACTIVATED;
}
break;

View file

@ -1,5 +1,7 @@
// treasure_chest.c.inc
#include "pc/network/network_player.h"
/**
* Hitbox for treasure chest bottom.
*/
@ -15,8 +17,9 @@ static struct ObjectHitbox sTreasureChestBottomHitbox = {
/* hurtboxHeight: */ 310,
};
void bhv_treasure_chest_top_loop(void) {
struct Object* sp34 = o->parentObj->parentObj;
struct Object *rootParent = o->parentObj->parentObj;
switch (o->oAction) {
case 0:
@ -27,7 +30,7 @@ void bhv_treasure_chest_top_loop(void) {
case 1:
if (o->oTimer == 0) {
if (sp34->oTreasureChestUnkFC == 0) {
if (rootParent->oTreasureChestIsAboveWater == 0) {
spawn_object_relative(0, 0, -80, 120, o, MODEL_BUBBLE, bhvWaterAirBubble);
play_sound(SOUND_GENERAL_CLAM_SHELL1, o->header.gfx.cameraToObject);
} else {
@ -39,9 +42,10 @@ void bhv_treasure_chest_top_loop(void) {
if (o->oFaceAnglePitch < -0x4000) {
o->oFaceAnglePitch = -0x4000;
o->oAction++;
if (o->parentObj->oBehParams2ndByte != 4)
if (o->parentObj->oBehParams2ndByte != 4) {
spawn_orange_number(o->parentObj->oBehParams2ndByte, 0, -40, 0);
}
}
break;
case 2:
@ -74,36 +78,35 @@ void bhv_treasure_chest_bottom_loop(void) {
}
o->parentObj->oTreasureChestSound = 0;
}
struct Object* player = nearest_player_to_object(o);
struct MarioState *player = nearest_mario_state_to_object(o);
switch (o->oAction) {
case 0:
if (network_owns_object(o->parentObj) && obj_check_if_facing_toward_angle(o->oMoveAngleYaw, player->header.gfx.angle[1] + 0x8000, 0x3000)) {
if (player && network_owns_object(o->parentObj) && obj_check_if_facing_toward_angle(o->oMoveAngleYaw, player->marioObj->header.gfx.angle[1] + 0x8000, 0x3000)) {
if (is_point_within_radius_of_mario(o->oPosX, o->oPosY, o->oPosZ, 150)) {
if (!o->parentObj->oTreasureChestUnkF8) {
if (o->parentObj->oTreasureChestUnkF4 == o->oBehParams2ndByte) {
if (!o->parentObj->oTreasureChestIsLastInteractionIncorrect) {
if (o->parentObj->oTreasureChestCurrentAnswer == o->oBehParams2ndByte) {
play_sound(SOUND_GENERAL2_RIGHT_ANSWER, gGlobalSoundSource);
o->parentObj->oTreasureChestUnkF4++;
o->parentObj->oTreasureChestCurrentAnswer++;
o->oAction = 1;
o->parentObj->oTreasureChestSound = 1;
network_send_object(o->parentObj);
o->parentObj->oTreasureChestSound = 0;
} else {
o->parentObj->oTreasureChestUnkF4 = 1;
o->parentObj->oTreasureChestUnkF8 = 1;
o->parentObj->oTreasureChestCurrentAnswer = 1;
o->parentObj->oTreasureChestIsLastInteractionIncorrect = 1;
o->oAction = 2;
cur_obj_become_tangible();
play_sound(SOUND_MENU_CAMERA_BUZZ, gGlobalSoundSource);
o->parentObj->oTreasureChestSound = 2;
}
o->parentObj->oTreasureChestLastNetworkPlayerIndex = gNetworkPlayers[player->playerIndex].globalIndex;
network_send_object(o->parentObj);
o->parentObj->oTreasureChestSound = 0;
}
}
}
}
break;
case 1:
if (o->parentObj->oTreasureChestUnkF8 == 1) {
if (o->parentObj->oTreasureChestIsLastInteractionIncorrect == 1) {
o->oAction = 0;
}
break;
@ -111,7 +114,7 @@ void bhv_treasure_chest_bottom_loop(void) {
case 2:
cur_obj_become_intangible();
if (!is_point_within_radius_of_mario(o->oPosX, o->oPosY, o->oPosZ, 500)) {
o->parentObj->oTreasureChestUnkF8 = 0;
o->parentObj->oTreasureChestIsLastInteractionIncorrect = 0;
o->oAction = 0;
}
}
@ -120,44 +123,56 @@ void bhv_treasure_chest_bottom_loop(void) {
o->oInteractStatus = 0;
}
struct Object* spawn_treasure_chest(s8 sp3B, s32 sp3C, s32 sp40, s32 sp44, s16 sp4A) {
struct Object* sp34;
sp34 = spawn_object_abs_with_rot(o, 0, MODEL_TREASURE_CHEST_BASE, bhvTreasureChestBottom, sp3C,
sp40, sp44, 0, sp4A, 0);
if (sp34 != NULL) { sp34->oBehParams2ndByte = sp3B; }
return sp34;
struct Object* spawn_treasure_chest(s8 index, s32 x, s32 y, s32 z, s16 r) {
struct Object *obj = spawn_object_abs_with_rot(o, 0, MODEL_TREASURE_CHEST_BASE, bhvTreasureChestBottom, x, y, z, 0, r, 0);
if (obj != NULL) { obj->oBehParams2ndByte = index; }
return obj;
}
void bhv_treasure_chest_ship_init(void) {
struct Object* chests[4] = { 0 };
struct Object *chests[4] = { 0 };
chests[0] = spawn_treasure_chest(1, 400, -350, -2700, 0);
chests[1] = spawn_treasure_chest(2, 650, -350, -940, -0x6001);
chests[2] = spawn_treasure_chest(3, -550, -350, -770, 0x5FFF);
chests[3] = spawn_treasure_chest(4, 100, -350, -1700, 0);
o->oTreasureChestUnkF4 = 1;
o->oTreasureChestUnkFC = 0;
network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS);
o->oTreasureChestCurrentAnswer = 1;
o->oTreasureChestIsAboveWater = 0;
// We haven't interacted with a player yet.
// We also don't sync this as not only is it not required
// but it also is only set for an interaction.
// Therefore this object must already be loaded for it to be set
// and if it wasn't. You couldn't of possibly been the one
// who last interacted to begin with.
o->oTreasureChestLastNetworkPlayerIndex = UNKNOWN_GLOBAL_INDEX;
if (!network_sync_object_initialized(o)) {
struct SyncObject *so = network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS);
if (so) {
network_init_object_field(o, &o->oAction);
network_init_object_field(o, &o->oPrevAction);
network_init_object_field(o, &o->oTimer);
network_init_object_field(o, &o->oTreasureChestUnkF4);
network_init_object_field(o, &o->oTreasureChestUnkF8);
network_init_object_field(o, &o->oTreasureChestUnkFC);
network_init_object_field(o, &o->oTreasureChestCurrentAnswer);
network_init_object_field(o, &o->oTreasureChestIsLastInteractionIncorrect);
network_init_object_field(o, &o->oTreasureChestIsAboveWater);
network_init_object_field(o, &o->oTreasureChestSound);
for (int i = 0; i < 4; i++) {
struct Object* chest = chests[i];
network_init_object_field(o, &o->oTreasureChestLastNetworkPlayerIndex);
for (s32 i = 0; i < 4; i++) {
struct Object *chest = chests[i];
network_init_object_field(o, &chest->oAction);
network_init_object_field(o, &chest->oPrevAction);
network_init_object_field(o, &chest->oTimer);
network_init_object_field(o, &chest->oIntangibleTimer);
}
}
}
}
void bhv_treasure_chest_ship_loop(void) {
switch (o->oAction) {
case 0:
if (network_owns_object(o) && o->oTreasureChestUnkF4 == 5) {
if (network_owns_object(o) && o->oTreasureChestCurrentAnswer == 5) {
play_puzzle_jingle();
fade_volume_scale(0, 127, 1000);
o->oAction = 1;
@ -185,35 +200,49 @@ void bhv_treasure_chest_ship_loop(void) {
}
void bhv_treasure_chest_jrb_init(void) {
struct Object* chests[4] = { 0 };
struct Object *chests[4] = { 0 };
chests[0] = spawn_treasure_chest(1, -1700, -2812, -1150, 0x7FFF);
chests[1] = spawn_treasure_chest(2, -1150, -2812, -1550, 0x7FFF);
chests[2] = spawn_treasure_chest(3, -2400, -2812, -1800, 0x7FFF);
chests[3] = spawn_treasure_chest(4, -1800, -2812, -2100, 0x7FFF);
o->oTreasureChestUnkF4 = 1;
o->oTreasureChestUnkFC = 1;
network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS);
o->oTreasureChestCurrentAnswer = 1;
o->oTreasureChestIsAboveWater = 1;
// We haven't interacted with a player yet.
// We also don't sync this as not only is it not required
// but it also is only set for an interaction.
// Therefore this object must already be loaded for it to be set
// and if it wasn't. You couldn't of possibly been the one
// who last interacted to begin with.
o->oTreasureChestLastNetworkPlayerIndex = UNKNOWN_GLOBAL_INDEX;
if (!network_sync_object_initialized(o)) {
struct SyncObject *so = network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS);
if (so) {
network_init_object_field(o, &o->oAction);
network_init_object_field(o, &o->oPrevAction);
network_init_object_field(o, &o->oTimer);
network_init_object_field(o, &o->oTreasureChestUnkF4);
network_init_object_field(o, &o->oTreasureChestUnkF8);
network_init_object_field(o, &o->oTreasureChestUnkFC);
network_init_object_field(o, &o->oTreasureChestCurrentAnswer);
network_init_object_field(o, &o->oTreasureChestIsLastInteractionIncorrect);
network_init_object_field(o, &o->oTreasureChestIsAboveWater);
network_init_object_field(o, &o->oTreasureChestSound);
for (int i = 0; i < 4; i++) {
struct Object* chest = chests[i];
network_init_object_field(o, &o->oTreasureChestLastNetworkPlayerIndex);
for (s32 i = 0; i < 4; i++) {
struct Object *chest = chests[i];
network_init_object_field(o, &chest->oAction);
network_init_object_field(o, &chest->oPrevAction);
network_init_object_field(o, &chest->oTimer);
network_init_object_field(o, &chest->oIntangibleTimer);
}
}
}
}
void bhv_treasure_chest_jrb_loop(void) {
switch (o->oAction) {
case 0:
if (network_owns_object(o) && o->oTreasureChestUnkF4 == 5) {
if (network_owns_object(o) && o->oTreasureChestCurrentAnswer == 5) {
play_puzzle_jingle();
o->oAction = 1;
o->oTreasureChestSound = 4;
@ -225,7 +254,7 @@ void bhv_treasure_chest_jrb_loop(void) {
case 1:
if (o->oTimer == 60) {
spawn_mist_particles();
spawn_default_star(-1800.0f, -2500.0f, -1700.0f);
spawn_networked_default_star(-1800.0f, -2500.0f, -1700.0f, o->oTreasureChestLastNetworkPlayerIndex);
o->oAction = 2;
}
break;
@ -236,36 +265,49 @@ void bhv_treasure_chest_jrb_loop(void) {
}
void bhv_treasure_chest_init(void) {
struct Object* chests[4] = { 0 };
struct Object *chests[4] = { 0 };
chests[0] = spawn_treasure_chest(1, -4500, -5119, 1300, -0x6001);
chests[1] = spawn_treasure_chest(2, -1800, -5119, 1050, 0x1FFF);
chests[2] = spawn_treasure_chest(3, -4500, -5119, -1100, 9102);
chests[3] = spawn_treasure_chest(4, -2400, -4607, 125, 16019);
o->oTreasureChestUnkF4 = 1;
o->oTreasureChestUnkFC = 0;
o->oTreasureChestCurrentAnswer = 1;
o->oTreasureChestIsAboveWater = 0;
network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS);
// We haven't interacted with a player yet.
// We also don't sync this as not only is it not required
// but it also is only set for an interaction.
// Therefore this object must already be loaded for it to be set
// and if it wasn't. You couldn't of possibly been the one
// who last interacted to begin with.
o->oTreasureChestLastNetworkPlayerIndex = UNKNOWN_GLOBAL_INDEX;
if (!network_sync_object_initialized(o)) {
struct SyncObject *so = network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS);
if (so) {
network_init_object_field(o, &o->oAction);
network_init_object_field(o, &o->oPrevAction);
network_init_object_field(o, &o->oTimer);
network_init_object_field(o, &o->oTreasureChestUnkF4);
network_init_object_field(o, &o->oTreasureChestUnkF8);
network_init_object_field(o, &o->oTreasureChestUnkFC);
network_init_object_field(o, &o->oTreasureChestCurrentAnswer);
network_init_object_field(o, &o->oTreasureChestIsLastInteractionIncorrect);
network_init_object_field(o, &o->oTreasureChestIsAboveWater);
network_init_object_field(o, &o->oTreasureChestSound);
for (int i = 0; i < 4; i++) {
struct Object* chest = chests[i];
network_init_object_field(o, &o->oTreasureChestLastNetworkPlayerIndex);
for (s32 i = 0; i < 4; i++) {
struct Object *chest = chests[i];
network_init_object_field(o, &chest->oAction);
network_init_object_field(o, &chest->oPrevAction);
network_init_object_field(o, &chest->oTimer);
network_init_object_field(o, &chest->oIntangibleTimer);
}
}
}
}
void bhv_treasure_chest_loop(void) {
switch (o->oAction) {
case 0:
if (network_owns_object(o) && o->oTreasureChestUnkF4 == 5) {
if (network_owns_object(o) && o->oTreasureChestCurrentAnswer == 5) {
play_puzzle_jingle();
o->oAction = 1;
o->oTreasureChestSound = 4;
@ -277,7 +319,7 @@ void bhv_treasure_chest_loop(void) {
case 1:
if (o->oTimer == 60) {
spawn_mist_particles();
spawn_default_star(-1900.0f, -4000.0f, -1400.0f);
spawn_networked_default_star(-1900.0f, -4000.0f, -1400.0f, o->oTreasureChestLastNetworkPlayerIndex);
o->oAction = 2;
}
break;

View file

@ -1369,10 +1369,16 @@ u32 interact_player(struct MarioState* m, UNUSED u32 interactType, struct Object
Vec3f velDiff;
vec3f_dif(velDiff, m->vel, m2->vel);
if (vec3f_length(velDiff) < 40) {
if (m->action == ACT_SLIDE_KICK_SLIDE || m->action == ACT_SLIDE_KICK) {
if (vec3f_length(m->vel) < 15) {
return FALSE;
}
} else {
if (vec3f_length(m->vel) < 40) {
// the difference vectors are not different enough, do not attack
return FALSE;
}
}
if (vec3f_length(m2->vel) > vec3f_length(m->vel)) {
// the one being attacked is going faster, do not attack
return FALSE;

View file

@ -380,6 +380,11 @@ static bool smlua_is_valid_object_field(struct Object* obj, struct LuaObjectFiel
case id_bhvHauntedChair:
if (!smlua_field_valid(data, LOT_NONE, offsetof(struct Object, oHauntedChairUnk100))) { return false; }
break;
case id_bhvHiddenStar:
case id_bhvHiddenRedCoinStar:
case id_bhvBowserCourseRedCoinStar:
if (!smlua_field_valid(data, LOT_NONE, offsetof(struct Object, oHiddenStarLastInteractedObject ))) { return false; }
break;
case id_bhvBreakableBox:
case id_bhvHiddenObject:
if (!smlua_field_valid(data, LOT_OBJECT, offsetof(struct Object, oHiddenObjectUnkF4))) { return false; }

View file

@ -678,7 +678,7 @@ static struct LuaObjectField sNetworkPlayerFields[LUA_NETWORK_PLAYER_FIELD_COUNT
{ "type", LVT_U8, offsetof(struct NetworkPlayer, type), true, LOT_NONE },
};
#define LUA_OBJECT_FIELD_COUNT 750
#define LUA_OBJECT_FIELD_COUNT 751
static struct LuaObjectField sObjectFields[LUA_OBJECT_FIELD_COUNT] = {
{ "activeFlags", LVT_S16, offsetof(struct Object, activeFlags), false, LOT_NONE },
{ "areaTimer", LVT_U32, offsetof(struct Object, areaTimer), false, LOT_NONE },
@ -999,6 +999,7 @@ static struct LuaObjectField sObjectFields[LUA_OBJECT_FIELD_COUNT] = {
{ "oHeldState", LVT_U32, offsetof(struct Object, oHeldState), false, LOT_NONE },
{ "oHiddenBlueCoinSwitch", LVT_COBJECT_P, offsetof(struct Object, oHiddenBlueCoinSwitch), false, LOT_OBJECT },
{ "oHiddenObjectUnkF4", LVT_COBJECT_P, offsetof(struct Object, oHiddenObjectUnkF4), false, LOT_OBJECT },
// { "oHiddenStarLastInteractedObject", LVT_???, offsetof(struct Object, oHiddenStarLastInteractedObject), false, LOT_??? }, <--- UNIMPLEMENTED
{ "oHiddenStarTriggerCounter", LVT_S32, offsetof(struct Object, oHiddenStarTriggerCounter), false, LOT_NONE },
{ "oHomeX", LVT_F32, offsetof(struct Object, oHomeX), false, LOT_NONE },
{ "oHomeY", LVT_F32, offsetof(struct Object, oHomeY), false, LOT_NONE },
@ -1332,10 +1333,11 @@ static struct LuaObjectField sObjectFields[LUA_OBJECT_FIELD_COUNT] = {
{ "oToadMessageState", LVT_S32, offsetof(struct Object, oToadMessageState), false, LOT_NONE },
// { "oToxBoxMovementPattern", LVT_???, offsetof(struct Object, oToxBoxMovementPattern), false, LOT_??? }, <--- UNIMPLEMENTED
{ "oToxBoxMovementStep", LVT_S32, offsetof(struct Object, oToxBoxMovementStep), false, LOT_NONE },
{ "oTreasureChestCurrentAnswer", LVT_S32, offsetof(struct Object, oTreasureChestCurrentAnswer), false, LOT_NONE },
{ "oTreasureChestIsAboveWater", LVT_S32, offsetof(struct Object, oTreasureChestIsAboveWater), false, LOT_NONE },
{ "oTreasureChestIsLastInteractionIncorrect", LVT_S32, offsetof(struct Object, oTreasureChestIsLastInteractionIncorrect), false, LOT_NONE },
{ "oTreasureChestLastNetworkPlayerIndex", LVT_S16, offsetof(struct Object, oTreasureChestLastNetworkPlayerIndex), false, LOT_NONE },
{ "oTreasureChestSound", LVT_S32, offsetof(struct Object, oTreasureChestSound), false, LOT_NONE },
{ "oTreasureChestUnkF4", LVT_S32, offsetof(struct Object, oTreasureChestUnkF4), false, LOT_NONE },
{ "oTreasureChestUnkF8", LVT_S32, offsetof(struct Object, oTreasureChestUnkF8), false, LOT_NONE },
{ "oTreasureChestUnkFC", LVT_S32, offsetof(struct Object, oTreasureChestUnkFC), false, LOT_NONE },
{ "oTreeSnowOrLeafUnkF4", LVT_S32, offsetof(struct Object, oTreeSnowOrLeafUnkF4), false, LOT_NONE },
{ "oTreeSnowOrLeafUnkF8", LVT_S32, offsetof(struct Object, oTreeSnowOrLeafUnkF8), false, LOT_NONE },
{ "oTreeSnowOrLeafUnkFC", LVT_S32, offsetof(struct Object, oTreeSnowOrLeafUnkFC), false, LOT_NONE },

View file

@ -187,7 +187,7 @@ void network_send_spawn_objects_to(u8 sendToLocalIndex, struct Object* objects[]
void network_receive_spawn_objects(struct Packet* p);
// packet_spawn_star.c
void network_send_spawn_star(struct Object* o, u8 starType, f32 x, f32 y, f32 z, u32 behParams);
void network_send_spawn_star(struct Object* o, u8 starType, f32 x, f32 y, f32 z, u32 behParams, u8 networkPlayerIndex);
void network_receive_spawn_star(struct Packet* p);
void network_send_spawn_star_nle(struct Object* o, u32 params);
void network_receive_spawn_star_nle(struct Packet* p);

View file

@ -7,7 +7,7 @@
extern struct Object* gCurrentObject;
void network_send_spawn_star(struct Object* o, u8 starType, f32 x, f32 y, f32 z, u32 behParams) {
void network_send_spawn_star(struct Object* o, u8 starType, f32 x, f32 y, f32 z, u32 behParams, u8 networkPlayerIndex) {
struct Packet p = { 0 };
packet_init(&p, PACKET_SPAWN_STAR, true, PLMT_AREA);
packet_write(&p, &starType, sizeof(u8));
@ -15,6 +15,7 @@ void network_send_spawn_star(struct Object* o, u8 starType, f32 x, f32 y, f32 z,
packet_write(&p, &y, sizeof(f32));
packet_write(&p, &z, sizeof(f32));
packet_write(&p, &behParams, sizeof(u32));
packet_write(&p, &networkPlayerIndex, sizeof(u8));
packet_write(&p, &o->oPosX, sizeof(u32) * 3);
packet_write(&p, &o->oHomeX, sizeof(u32) * 3);
@ -26,12 +27,14 @@ void network_receive_spawn_star(struct Packet* p) {
u8 starType;
f32 x, y, z;
u32 behParams;
u8 networkPlayerIndex = UNKNOWN_GLOBAL_INDEX;
packet_read(p, &starType, sizeof(u8));
packet_read(p, &x, sizeof(f32));
packet_read(p, &y, sizeof(f32));
packet_read(p, &z, sizeof(f32));
packet_read(p, &behParams, sizeof(u32));
packet_read(p, &networkPlayerIndex, sizeof(u8));
u32 oldBehParams = gCurrentObject->oBehParams;
gCurrentObject->oBehParams = behParams;
@ -47,8 +50,20 @@ void network_receive_spawn_star(struct Packet* p) {
if (o != NULL) {
packet_read(p, &o->oPosX, sizeof(u32) * 3);
packet_read(p, &o->oHomeX, sizeof(u32) * 3);
// Here we check if we're supposed to play the cutscene or not depending on if
// the global player index sent matches us.
// If the network player index is -1, Then the cutscene will always be skipped.
// This check is vital for objects which are network owned specfically.
// Leaving this the only way to properly set the cutscene flags
// for those who don't own the object.
//printf("network_receive_spawn_star: Network Player Index is %i, Our Global Index is %i.\n", networkPlayerIndex, gNetworkPlayers[0].globalIndex);
if (networkPlayerIndex == gNetworkPlayers[0].globalIndex) {
o->oStarSpawnExtCutsceneFlags = 1;
} else {
o->oStarSpawnExtCutsceneFlags = 0;
}
}
}
void network_send_spawn_star_nle(struct Object* o, u32 params) {