From 520b3d58e33b2a4efbe36f00efb5e53f3b75c49d Mon Sep 17 00:00:00 2001 From: Ryan Myers Date: Tue, 3 Jun 2025 14:47:46 -0400 Subject: [PATCH] Add a few NON_EQUIVALENT functions from scratches to keep them up to date (#602) * WIP func_800101AC * WIP func_800452A0 * cleanup * Formatter and func_8004CC20 near match * func_8004CC20 better score and documentation * func_80049794 WIP and compilable * Major cleanup of func_80049794 * Formatter * Update scratch * Add func_80019808 from scratch * Cleanup func_80019808 * func_80019808 score improvment * Improve func_80049794 score (Thanks Dominik!) * func_8001C6C4 WIP * func_8001E93C WIP * small documenting * Eliminate a lot of Obj64 casts. --- include/level_object_entries.h | 7 + include/structs.h | 22 +- src/camera.c | 3 +- src/game_ui.c | 35 +- src/menu.c | 20 +- src/menu.h | 3 +- src/object_functions.c | 238 ++--- src/object_functions.h | 2 - src/objects.c | 910 +++++++++++++++++++- src/objects.h | 2 + src/racer.c | 1482 +++++++++++++++++++++++++++++++- src/racer.h | 2 +- src/tracks.c | 2 +- src/vehicle_bluey.c | 2 +- src/vehicle_bubbler.c | 2 +- src/vehicle_rocket.c | 4 +- src/vehicle_smokey.c | 2 +- src/vehicle_tricky.c | 2 +- src/vehicle_wizpig.c | 2 +- src/weather.h | 1 + 20 files changed, 2519 insertions(+), 224 deletions(-) diff --git a/include/level_object_entries.h b/include/level_object_entries.h index adaf7f60..fae45372 100644 --- a/include/level_object_entries.h +++ b/include/level_object_entries.h @@ -885,6 +885,12 @@ typedef struct LevelObjectEntry_Hud { s32 offsetY; } LevelObjectEntry_Hud; +typedef struct LevelObjectEntry_BHV_UNK_5C { + LevelObjectEntryCommon common; + s8 unk8; + s8 unk9; +} LevelObjectEntry_BHV_UNK_5C; + typedef struct LevelObjectEntry { union { LevelObjectEntry_Racer racer; @@ -978,6 +984,7 @@ typedef struct LevelObjectEntry { LevelObjectEntry_WavePower wavePower; LevelObjectEntry_CharacterSelect characterSelect; LevelObjectEntry_Hud hud; + LevelObjectEntry_BHV_UNK_5C bhv_unk_5C; }; } LevelObjectEntry; diff --git a/include/structs.h b/include/structs.h index 00b16029..20a05b76 100644 --- a/include/structs.h +++ b/include/structs.h @@ -1537,12 +1537,17 @@ typedef struct Object_FogChanger { typedef struct Object_NPC { /* 0x00 */ f32 unk0; /* 0x04 */ f32 animFrameF; - /* 0x08 */ s32 unk8; - /* 0x0C */ s8 nodeBack1; // One node backwards - /* 0x0D */ u8 nodeCurrent; // Intended target node - /* 0x0E */ u8 nodeBack2; // Two nodes backward - /* 0x0F */ u8 nodeForward1; // One node forward - /* 0x10 */ u8 nodeForward2; // Two nodes forward + /* 0x08 */ f32 unk8; + union { + /* 0x0C */ u8 nodeData[5]; + struct { + /* 0x0C */ s8 nodeBack1; // One node backwards + /* 0x0D */ u8 nodeCurrent; // Intended target node + /* 0x0E */ u8 nodeBack2; // Two nodes backward + /* 0x0F */ u8 nodeForward1; // One node forward + /* 0x10 */ u8 nodeForward2; // Two nodes forward + }; + }; /* 0x11 */ u8 fogR; /* 0x12 */ u8 fogG; /* 0x13 */ u8 fogB; @@ -1596,7 +1601,7 @@ typedef struct Object_Log { typedef struct Object_Fireball_Octoweapon { u8 pad0[0x1C]; - SoundHandle soundMask; + struct AudioPoint *soundMask; } Object_Fireball_Octoweapon; typedef struct Object_AnimatedObject { @@ -1722,6 +1727,7 @@ typedef struct Object_68_38 { typedef struct Object_68 { /* 0x00 */ union { ObjectModel *objModel; + Sprite *sprite; TextureHeader *texHeader; }; /* 0x04 */ Vertex *vertices[3]; @@ -1845,7 +1851,7 @@ typedef struct Object { /* 0x0064 */ Object_64 *unk64; //player + 0x98 /* 0x0068 */ Object_68 **unk68; //player + 0x80 /* 0x006C */ struct ParticleEmitter *particleEmitter; //player + 0x370 - /* 0x0070 */ Object_LightData **lightData; + /* 0x0070 */ struct ObjectLight **lightData; /* 0x0074 */ u32 particleEmittersEnabled; /* 0x0078 */ ObjProperties properties; /* 0x0080 */ void *unk80; diff --git a/src/camera.c b/src/camera.c index e45322a6..16b7a1f2 100644 --- a/src/camera.c +++ b/src/camera.c @@ -106,10 +106,11 @@ MtxF gCurrentModelMatrixS; /******************************/ +extern s32 D_B0000578; // Used as a symbol for anti-piracy checks in the game. + /** * Official Name: camInit */ -extern s32 D_B0000578; void cam_init(void) { s32 i; s32 j; diff --git a/src/game_ui.c b/src/game_ui.c index f54dadb5..3bd3d684 100644 --- a/src/game_ui.c +++ b/src/game_ui.c @@ -704,7 +704,7 @@ void hud_render_player(Gfx **dList, Mtx **mtx, Vertex **vertexList, Object *obj, } } if (gShowHUD == FALSE) { - racer = (Object_Racer *) obj->unk64; + racer = &obj->unk64->racer; if (D_8012718A) { gHudController = 1 - racer->playerIndex; } else { @@ -1251,7 +1251,7 @@ void hud_main_battle(s32 countdown, Object *obj, s32 updateRate) { s32 racersFinished; s32 i; - racer = (Object_Racer *) obj->unk64; + racer = &obj->unk64->racer; if (gNumActivePlayers != 1 || racer->raceFinished == FALSE) { sprite_anim_off(TRUE); hud_race_start(countdown, updateRate); @@ -1395,7 +1395,7 @@ void hud_lives_render(Object_Racer *racer, UNUSED s32 updateRate) { */ void hud_main_boss(s32 countdown, Object *obj, s32 updateRate) { LevelHeader *level; - Object_Racer *racer = (Object_Racer *) obj->unk64; + Object_Racer *racer = &obj->unk64->racer; sprite_anim_off(TRUE); hud_wrong_way(racer, updateRate); @@ -1417,7 +1417,7 @@ void hud_main_boss(s32 countdown, Object *obj, s32 updateRate) { * When racing Taj in the overworld, render most of the basic race hud. */ void hud_main_taj(s32 countdown, Object *obj, s32 updateRate) { - Object_Racer *racer = (Object_Racer *) obj->unk64; + Object_Racer *racer = &obj->unk64->racer; sprite_anim_off(TRUE); hud_wrong_way(racer, updateRate); @@ -1438,7 +1438,7 @@ void hud_main_hub(Object *obj, s32 updateRate) { HudElement *portrait; if (cam_get_viewport_layout() == PLAYER_ONE) { - racer = (Object_Racer *) obj->unk64; + racer = &obj->unk64->racer; sprite_anim_off(TRUE); hud_balloons(racer); hud_speedometre(obj, updateRate); @@ -1820,7 +1820,7 @@ void hud_speedometre(Object *obj, UNUSED s32 updateRate) { if (gNumActivePlayers == 1) { if (!check_if_showing_cutscene_camera()) { - racer = (Object_Racer *) obj->unk64; + racer = &obj->unk64->racer; if (racer->raceFinished == FALSE) { if (racer->vehicleID == VEHICLE_PLANE) { vel = sqrtf((obj->segment.x_velocity * obj->segment.x_velocity) + @@ -3031,7 +3031,7 @@ void hud_weapon(Object *obj, s32 updateRate) { Object_Racer *racer; s32 temp_a0; - racer = (Object_Racer *) obj->unk64; + racer = &obj->unk64->racer; if (racer->raceFinished == FALSE) { enable_pal_viewport_height_adjust(TRUE); temp_a0 = (racer->balloon_type * 3) + (racer->balloon_level); @@ -3526,7 +3526,7 @@ void hud_render_general(Gfx **dList, Mtx **mtx, Vertex **vtx, s32 updateRate) { spBC = gCurrentHud->entry[HUD_TREASURE_METRE].pos.y; racerGroup = get_racer_objects(&racerCount); for (sp144 = 0; sp144 < racerCount; sp144++) { - someRacer = (Object_Racer *) racerGroup[sp144]->unk64; + someRacer = &racerGroup[sp144]->unk64->racer; hud_treasure(someRacer); if (osTvType == OS_TV_TYPE_PAL) { gCurrentHud->entry[HUD_CHALLENGE_PORTRAIT].pos.y += 66.0; @@ -3586,7 +3586,7 @@ void hud_render_general(Gfx **dList, Mtx **mtx, Vertex **vtx, s32 updateRate) { sp113 = TRUE; for (i = 0; i < objectCount; i++) { - someRacer = (Object_Racer *) objectGroup[i]->unk64; + someRacer = &objectGroup[i]->unk64->racer; if (someRacer != NULL && someRacer->playerIndex != PLAYER_COMPUTER && someRacer->raceFinished == FALSE) { sp113 = FALSE; } @@ -3708,7 +3708,7 @@ void hud_render_general(Gfx **dList, Mtx **mtx, Vertex **vtx, s32 updateRate) { // Non AI players get an arrow instead of a blob that rotates. for (i = objectCount - 1; i >= 0; i--) { temp_v0_8 = objectGroup[i]; - someRacer = (Object_Racer *) objectGroup[i]->unk64; + someRacer = &objectGroup[i]->unk64->racer; if (someRacer != NULL) { minimap_marker_pos(objectGroup[i]->segment.trans.x_position, objectGroup[i]->segment.trans.z_position, sp114, sp118, sp11C); @@ -3811,7 +3811,7 @@ void minimap_marker_pos(f32 x, f32 z, f32 angleSin, f32 angleCos, f32 modelAspec * deciding to draw a texture rectangle, ortho tris, or a 3D model entirely. */ void hud_element_render(Gfx **dList, Mtx **mtx, Vertex **vtxList, HudElement *hud) { - TextureHeader **textureHeader3; + ObjectModel **objModels; TextureHeader *textureHeader2; TextureHeader *textureHeader; Camera *camera; @@ -3949,7 +3949,7 @@ void hud_element_render(Gfx **dList, Mtx **mtx, Vertex **vtxList, HudElement *hu sp48.drawTexture.yOffset = 0; sp48.unk8 = 0; texrect_draw_scaled(&gHudDL, &sp48.drawTexture, hud->pos.x, hud->pos.y, hud->scale, hud->scale, gHudColour, - 1); + TEXRECT_POINT); rendermode_reset(&gHudDL); } } else if (gAssetHudElementIds[spriteID] & ASSET_MASK_SPRITE) { @@ -3973,14 +3973,15 @@ void hud_element_render(Gfx **dList, Mtx **mtx, Vertex **vtxList, HudElement *hu } else { mtx_cam_push(&gHudDL, &gHudMtx, (ObjectTransform *) hud, 1.0f, 0.0f); if (0) {} - textureHeader3 = gAssetHudElements->entry[hud->spriteID]; - hud_draw_model((ObjectModel *) *textureHeader3); + objModels = gAssetHudElements->entry[hud->spriteID]; + hud_draw_model(*objModels); mtx_pop(&gHudDL); } spriteID = hud->spriteID; - if (spriteID != 0x28) { - if ((spriteID != 0xE) && (spriteID != 0x1B) && ((spriteID < 0x2F) || (spriteID >= 0x36)) && - (spriteID != 0x2E) && (gMinimapXlu & 1)) { + if (spriteID != HUD_SPRITE_PRO_AM) { + if (spriteID != HUD_SPRITE_MAP_DOT && spriteID != HUD_SPRITE_MAP_ARROW && + (spriteID < HUD_ASSET_47 || spriteID >= HUD_ASSET_54) && spriteID != HUD_SPRITE_SPEEDOMETRE_ARROW && + gMinimapXlu & 1) { hud->pos.y -= objEntry.offsetY; } hud->pos.x -= gHudOffsetX + gHudBounceX; diff --git a/src/menu.c b/src/menu.c index c1796ef1..9d835275 100644 --- a/src/menu.c +++ b/src/menu.c @@ -2152,17 +2152,18 @@ void func_8007FFEC(s32 numberOfPanels) { vertexSize = sizeof(Vertex) * (20 * numberOfPanels); triangleCount = sizeof(Triangle) * (10 * numberOfPanels); - gWoodPanelTriangles[0] = (Triangle *)mempool_alloc_safe(((vertexSize + triangleCount) * 2) + menuGeometrySize, COLOUR_TAG_WHITE); - gWoodPanelTriangles[1] = (Triangle *)((u32)gWoodPanelTriangles[0] + triangleCount); + gWoodPanelTriangles[0] = + (Triangle *) mempool_alloc_safe(((vertexSize + triangleCount) * 2) + menuGeometrySize, COLOUR_TAG_WHITE); + gWoodPanelTriangles[1] = (Triangle *) ((u32) gWoodPanelTriangles[0] + triangleCount); - gMenuGeometry = (unk80080BC8 *)((u32)gWoodPanelTriangles[1] + triangleCount); + gMenuGeometry = (unk80080BC8 *) ((u32) gWoodPanelTriangles[1] + triangleCount); - gWoodPanelVertices[0] = (Vertex *)((u32)gMenuGeometry + menuGeometrySize); - gWoodPanelVertices[1] = (Vertex *)((u32)gWoodPanelVertices[0] + vertexSize); + gWoodPanelVertices[0] = (Vertex *) ((u32) gMenuGeometry + menuGeometrySize); + gWoodPanelVertices[1] = (Vertex *) ((u32) gWoodPanelVertices[0] + vertexSize); panelIndex = 0; triangleCount = 0; - for(i = 0; i < numberOfPanels; i++) { + for (i = 0; i < numberOfPanels; i++) { gMenuGeometry[i].vertices[0] = &gWoodPanelVertices[0][panelIndex]; gMenuGeometry[i].vertices[1] = &gWoodPanelVertices[1][panelIndex]; gMenuGeometry[i].triangles[0] = &gWoodPanelTriangles[0][triangleCount]; @@ -2176,10 +2177,10 @@ void func_8007FFEC(s32 numberOfPanels) { } triItemIndex = 0; - for(i = 0; i < numberOfPanels; i++) { + for (i = 0; i < numberOfPanels; i++) { panelIndex = 0; - for(IndicesIndex = 0; IndicesIndex < 10; triItemIndex++, panelIndex += 3, IndicesIndex++) { - for(triListIndex = 0; triListIndex < 2; triListIndex++) { + for (IndicesIndex = 0; IndicesIndex < 10; triItemIndex++, panelIndex += 3, IndicesIndex++) { + for (triListIndex = 0; triListIndex < 2; triListIndex++) { gWoodPanelTriangles[triListIndex][triItemIndex].verticesArray[0] = BACKFACE_DRAW; gWoodPanelTriangles[triListIndex][triItemIndex].verticesArray[1] = gWoodPanelsIndices[panelIndex]; gWoodPanelTriangles[triListIndex][triItemIndex].verticesArray[2] = gWoodPanelsIndices[panelIndex + 1]; @@ -2198,7 +2199,6 @@ void func_8007FFEC(s32 numberOfPanels) { gWoodPanelAllocCount = numberOfPanels; } - /** * Resize the UV's of the menu panels. */ diff --git a/src/menu.h b/src/menu.h index 404bec8d..d619e248 100644 --- a/src/menu.h +++ b/src/menu.h @@ -662,6 +662,7 @@ void rankings_render_order(s32 updateRate); void results_render(UNUSED s32 updateRate, f32 opacity); void func_80092188(s32 updateRate); SIDeviceStatus func_80087F14(s32 *controllerIndex, s32 xAxisDirection); +void postrace_start(s32 finishState, s32 worldID); // Non Matching functions below here void load_menu_text(s32 language); // Non Matching @@ -678,7 +679,7 @@ void dialogue_tt_gamestatus(void); s32 menu_title_screen_loop(s32 updateRate); s32 menu_magic_codes_loop(s32 updateRate); s32 menu_credits_loop(s32 updateRate); -void func_8007FFEC(s32 arg0); +void func_8007FFEC(s32 numberOfPanels); void set_gIntDisFlag(u8 setting); void init_save_data(void); void func_80080580(Gfx **dList, s32 startX, s32 startY, s32 width, s32 height, s32 borderWidth, s32 borderHeight, diff --git a/src/object_functions.c b/src/object_functions.c index 55511e79..90ec4e2f 100644 --- a/src/object_functions.c +++ b/src/object_functions.c @@ -250,13 +250,13 @@ void obj_loop_fireball_octoweapon(Object *obj, s32 updateRate) { } } obj->segment.animFrame += updateRate * 10; - weapon = (Object_Fireball_Octoweapon *) obj->unk64; + weapon = &obj->unk64->fireball_octoweapon; interactObj = obj->interactObj; if ((interactObj->obj)) { if ((interactObj->distance < 60)) { someObj = interactObj->obj; if (someObj->segment.header->behaviorId == BHV_RACER) { - racer = (Object_Racer *) someObj->unk64; + racer = &someObj->unk64->racer; if (racer->playerIndex != PLAYER_COMPUTER) { if (obj->behaviorId == BHV_FIREBALL_OCTOWEAPON) { racer->attackType = ATTACK_EXPLOSION; @@ -352,7 +352,7 @@ void obj_loop_lasergun(Object *obj, s32 updateRate) { ObjectInteraction *interactObj; LevelObjectEntryCommon spawnObj; - lasergun = (Object_LaserGun *) obj->unk64; + lasergun = &obj->unk64->lasergun; if (lasergun->fireTimer > 0) { lasergun->fireTimer -= updateRate; } else { @@ -604,7 +604,7 @@ void obj_loop_trophycab(Object *obj, s32 updateRate) { settings = get_settings(); header = get_current_level_header(); - gfxData = (Object_TrophyCabinet *) obj->unk64; + gfxData = &obj->unk64->trophy_cabinet; if (obj->properties.trophyCabinet.trophy == FALSE) { if (header->race_type != RACETYPE_CUTSCENE_2 && header->race_type != RACETYPE_CUTSCENE_1) { obj->properties.trophyCabinet.trophy = TRUE; @@ -720,7 +720,7 @@ void obj_loop_collectegg(Object *obj, s32 updateRate) { s32 hasCollision; s8 surface; - egg = (Object_CollectEgg *) obj->unk64; + egg = &obj->unk64->egg; updateRateF = updateRate; if (osTvType == OS_TV_TYPE_PAL) { updateRateF *= 1.2; @@ -767,7 +767,7 @@ void obj_loop_collectegg(Object *obj, s32 updateRate) { egg->status = EGG_IN_BASE; racerObj = get_racer_object(egg->racerID); if (racerObj != NULL) { - racer = (Object_Racer *) racerObj->unk64; + racer = &racerObj->unk64->racer; racer->eggHudCounter += 1; } egg->hatchTimer = 600; @@ -779,7 +779,7 @@ void obj_loop_collectegg(Object *obj, s32 updateRate) { egg->hatchTimer -= updateRate; racerObj = get_racer_object(egg->racerID); if (racerObj != NULL) { - racer = (Object_Racer *) racerObj->unk64; + racer = &racerObj->unk64->racer; } if (egg->hatchTimer <= 0) { if (racerObj != NULL) { @@ -798,7 +798,7 @@ void obj_loop_collectegg(Object *obj, s32 updateRate) { case EGG_HATCHED: racerObj = get_racer_object(egg->racerID); if (racerObj != NULL) { - racer = (Object_Racer *) racerObj->unk64; + racer = &racerObj->unk64->racer; if (racer->lap >= 3) { racer->raceFinished = TRUE; } @@ -1142,7 +1142,7 @@ void obj_loop_characterflag(Object *obj, UNUSED s32 updateRate) { * if the player is not already carrying an egg. */ void try_to_collect_egg(Object *obj, Object_CollectEgg *egg) { - Object_64 *racer; + Object_Racer *racer; Object *interactedObj; MtxF mat; ObjectTransform transF; @@ -1150,11 +1150,11 @@ void try_to_collect_egg(Object *obj, Object_CollectEgg *egg) { if (obj->interactObj->distance < 40) { interactedObj = obj->interactObj->obj; if (interactedObj->segment.header->behaviorId == BHV_RACER) { - racer = interactedObj->unk64; - if (racer->racer.held_obj == NULL) { + racer = &interactedObj->unk64->racer; + if (racer->held_obj == NULL) { egg->status = EGG_COLLECTED; obj->segment.trans.flags |= OBJ_FLAGS_INVISIBLE; - racer->racer.held_obj = obj; + racer->held_obj = obj; transF.rotation.y_rotation = -interactedObj->segment.trans.rotation.y_rotation; transF.rotation.x_rotation = -interactedObj->segment.trans.rotation.x_rotation; transF.rotation.z_rotation = -interactedObj->segment.trans.rotation.z_rotation; @@ -1216,7 +1216,7 @@ void obj_loop_stopwatchman(Object *obj, s32 updateRate) { if (osTvType == OS_TV_TYPE_PAL) { updateRateF *= 1.2; } - tt = (Object_NPC *) obj->unk64; + tt = &obj->unk64->npc; if (obj->segment.animFrame == 0) { if (tt->animFrameF > 1.0) { tt->animFrameF = 0.0f; @@ -1228,7 +1228,7 @@ void obj_loop_stopwatchman(Object *obj, s32 updateRate) { obj->segment.z_velocity = 0.0f; racerObj = get_racer_object(PLAYER_ONE); if (racerObj != NULL) { - racer = (Object_Racer *) racerObj->unk64; + racer = &racerObj->unk64->racer; diffX = ((racerObj->segment.trans.x_position - (racer->ox1 * 50.0f)) - (racer->ox3 * 5.0f)) - obj->segment.trans.x_position; diffZ = ((racerObj->segment.trans.z_position - (racer->oz1 * 50.0f)) - (racer->oz3 * 5.0f)) - @@ -1380,7 +1380,7 @@ void obj_loop_stopwatchman(Object *obj, s32 updateRate) { tt->nodeBack1 = tt->nodeCurrent; } } else { - diffZ = func_8001C6C4((Object_64 *) tt, obj, updateRateF, 1.0f, 0); + diffZ = func_8001C6C4(tt, obj, updateRateF, 1.0f, 0); tt->animFrameF += diffZ * 1.5; } break; @@ -1696,7 +1696,7 @@ void obj_init_animator(Object *obj, LevelObjectEntry_Animator *entry, s32 param) void obj_loop_animator(Object *obj, s32 updateRate) { s32 pad[2]; - Object_64 *obj64; + Object_Animator *animator; LevelModel *levelModel; s32 trisStart; s32 trisEnd; @@ -1711,10 +1711,10 @@ void obj_loop_animator(Object *obj, s32 updateRate) { s32 shift2; TextureHeader *tex; - obj64 = obj->unk64; + animator = &obj->unk64->animator; - t0 = obj64->animator.speedFactorX; - t1 = obj64->animator.speedFactorY; + t0 = animator->speedFactorX; + t1 = animator->speedFactorY; t0 *= updateRate; t1 *= updateRate; @@ -1722,27 +1722,27 @@ void obj_loop_animator(Object *obj, s32 updateRate) { t0 <<= 4; t1 <<= 4; - obj64->animator.xSpeed += t0; - obj64->animator.ySpeed += t1; + animator->xSpeed += t0; + animator->ySpeed += t1; - trisStart = obj64->animator.xSpeed; + trisStart = animator->xSpeed; t0 = trisStart; - trisEnd = obj64->animator.ySpeed; + trisEnd = animator->ySpeed; t1 = trisEnd; - obj64->animator.xSpeed &= 0xF; - obj64->animator.ySpeed &= 0xF; + animator->xSpeed &= 0xF; + animator->ySpeed &= 0xF; t0 >>= 4; t1 >>= 4; - if (obj64->animator.segmentId == -1) { + if (animator->segmentId == -1) { return; } levelModel = get_current_level_model(); - curBlock = &levelModel->segments[obj64->animator.segmentId]; - curBatch = &curBlock->batches[obj64->animator.batchId]; + curBlock = &levelModel->segments[animator->segmentId]; + curBatch = &curBlock->batches[animator->batchId]; textureIndex = curBatch->textureIndex; trisStart = curBatch->facesOffset; trisEnd = (curBatch + 1)->facesOffset; @@ -2572,7 +2572,7 @@ void obj_loop_parkwarden(Object *obj, s32 updateRate) { if (osTvType == OS_TV_TYPE_PAL) { updateRateF *= 1.2; } - taj = (Object_NPC *) obj->unk64; + taj = &obj->unk64->npc; levelHeader = get_current_level_header(); obj->particleEmittersEnabled = OBJ_EMIT_NONE; if (obj->segment.animFrame == 0 && taj->animFrameF > 1.0) { @@ -2583,7 +2583,7 @@ void obj_loop_parkwarden(Object *obj, s32 updateRate) { obj->segment.z_velocity = 0.0f; racerObj = get_racer_object(PLAYER_ONE); if (racerObj != NULL) { - racer = (Object_Racer *) racerObj->unk64; + racer = &racerObj->unk64->racer; xPosDiff = (racerObj->segment.trans.x_position - (racer->ox1 * 50.0f)) - obj->segment.trans.x_position; zPosDiff = (racerObj->segment.trans.z_position - (racer->oz1 * 50.0f)) - obj->segment.trans.z_position; distance = sqrtf((xPosDiff * xPosDiff) + (zPosDiff * zPosDiff)); @@ -3019,7 +3019,7 @@ void obj_loop_parkwarden(Object *obj, s32 updateRate) { taj->unk1C = 0; } if (taj->unk1C < 120) { - taj->animFrameF += func_8001C6C4((Object_64 *) taj, obj, updateRateF, 1.0f, 0); + taj->animFrameF += func_8001C6C4(taj, obj, updateRateF, 1.0f, 0); } else { var_a2 = taj->unk1E - (obj->segment.trans.rotation.y_rotation & 0xFFFF); if (var_a2 > 0x8000) { @@ -3224,7 +3224,7 @@ void obj_loop_modechange(Object *obj, UNUSED s32 updateRate) { Object **racerObjects; s32 numRacers; Object_Racer *racer; - Object_Trigger *modeChange; + Object_Trigger *trigger; f32 diffX; f32 diffY; f32 diffZ; @@ -3233,29 +3233,29 @@ void obj_loop_modechange(Object *obj, UNUSED s32 updateRate) { f32 radiusF; f32 dist; - modeChange = (Object_Trigger *) obj->unk64; - if (obj->interactObj->distance < modeChange->radius) { - radiusF = modeChange->radius; + trigger = &obj->unk64->trigger; + if (obj->interactObj->distance < trigger->radius) { + radiusF = trigger->radius; racerObjects = get_racer_objects(&numRacers); for (i = 0; i < numRacers; i++) { racerObj = racerObjects[i]; - racer = (Object_Racer *) racerObj->unk64; - if (racer->vehicleID != modeChange->vehicleID) { + racer = &racerObj->unk64->racer; + if (racer->vehicleID != trigger->vehicleID) { diffX = racerObj->segment.trans.x_position - obj->segment.trans.x_position; diffY = racerObj->segment.trans.y_position - obj->segment.trans.y_position; diffZ = racerObj->segment.trans.z_position - obj->segment.trans.z_position; dist = sqrtf((diffX * diffX) + (diffY * diffY) + (diffZ * diffZ)); if (dist < radiusF) { - dist = ((modeChange->directionX * racerObj->segment.trans.x_position) + - (modeChange->directionZ * racerObj->segment.trans.z_position) + modeChange->rotationDiff); + dist = ((trigger->directionX * racerObj->segment.trans.x_position) + + (trigger->directionZ * racerObj->segment.trans.z_position) + trigger->rotationDiff); if (dist < 0.0f) { racer->trickType = 0; - if (modeChange->vehicleID == VEHICLE_CAR) { + if (trigger->vehicleID == VEHICLE_CAR) { racer->vehicleID = racer->vehicleIDPrev; } else { - racer->vehicleID = modeChange->vehicleID; + racer->vehicleID = trigger->vehicleID; } - if (modeChange->vehicleID == VEHICLE_LOOPDELOOP) { + if (trigger->vehicleID == VEHICLE_LOOPDELOOP) { if (racer->raceFinished == FALSE) { rumble_set(racer->playerIndex, RUMBLE_TYPE_8); } @@ -3396,7 +3396,7 @@ void obj_loop_goldenballoon(Object *obj, s32 updateRate) { LevelObjectEntry *levelEntry; ObjectInteraction *interactObj; Object_Racer *racer; - Object_NPC *obj64; + Object_NPC *npc; Settings *settings; s32 flag; s32 doubleSpeed; @@ -3439,7 +3439,7 @@ void obj_loop_goldenballoon(Object *obj, s32 updateRate) { obj->segment.object.opacity = 255; } interactObj = obj->interactObj; - if ((interactObj->distance < 45) && (isPirated == FALSE)) { + if (interactObj->distance < 45 && isPirated == FALSE) { racerObj = interactObj->obj; if ((racerObj && (racerObj->segment.header->behaviorId == 1))) { racer = &racerObj->unk64->racer; @@ -3460,21 +3460,21 @@ void obj_loop_goldenballoon(Object *obj, s32 updateRate) { } } } - obj64 = &obj->unk64->npc; + npc = &obj->unk64->npc; obj->segment.object.animationID = 0; - obj64->forwardVel = 0.0f; + npc->forwardVel = 0.0f; speedf = (obj->segment.object.opacity < 255) ? 0 : 1; - if (obj64->nodeCurrent == 255) { - obj64->nodeCurrent = ainode_find_nearest(obj->segment.trans.x_position, obj->segment.trans.y_position, - obj->segment.trans.z_position, FALSE); - if (obj64->nodeCurrent != 255) { - obj64->nodeBack2 = ainode_find_next(obj64->nodeCurrent, -1, 0); - obj64->nodeForward1 = ainode_find_next(obj64->nodeBack2, obj64->nodeCurrent, 0); - obj64->nodeForward2 = ainode_find_next(obj64->nodeForward1, obj64->nodeBack2, 0); - obj64->nodeBack1 = obj64->nodeCurrent; + if (npc->nodeCurrent == 255) { + npc->nodeCurrent = ainode_find_nearest(obj->segment.trans.x_position, obj->segment.trans.y_position, + obj->segment.trans.z_position, FALSE); + if (npc->nodeCurrent != 255) { + npc->nodeBack2 = ainode_find_next(npc->nodeCurrent, -1, 0); + npc->nodeForward1 = ainode_find_next(npc->nodeBack2, npc->nodeCurrent, 0); + npc->nodeForward2 = ainode_find_next(npc->nodeForward1, npc->nodeBack2, 0); + npc->nodeBack1 = npc->nodeCurrent; } } else { - func_8001C6C4((Object_64 *) obj64, obj, updateRateF, speedf, 0); + func_8001C6C4(npc, obj, updateRateF, speedf, 0); } } } @@ -3782,7 +3782,7 @@ void obj_loop_ttdoor(Object *obj, s32 updateRate) { s16 angle; s32 openDoor; - ttDoor = (Object_Door *) obj->unk64; + ttDoor = &obj->unk64->door; settings = get_settings(); if (ttDoor->doorType == 0) { obj->segment.object.modelIndex = D_800DCA94[settings->ttAmulet]; @@ -3792,7 +3792,7 @@ void obj_loop_ttdoor(Object *obj, s32 updateRate) { if (obj->interactObj->distance < ttDoor->radius && (settings->ttAmulet < 4 || *settings->balloonsPtr < 47)) { racerObj = obj->interactObj->obj; if (racerObj != NULL && racerObj->segment.header->behaviorId == BHV_RACER) { - racer = (Object_Racer *) racerObj->unk64; + racer = &racerObj->unk64->racer; if (racer->playerIndex != PLAYER_COMPUTER && racerObj == obj->unk5C->unk100) { if (ttDoor->textID != -1 && textbox_visible() == 0 && ttDoor->jingleCooldown == 0) { music_fade(-8); @@ -3906,8 +3906,8 @@ void obj_loop_trigger(Object *obj, UNUSED s32 updateRate) { f32 distance; s32 courseFlags; - triggerEntry = (LevelObjectEntry_Trigger *) obj->segment.level_entry; - trigger = (Object_Trigger *) obj->unk64; + triggerEntry = &obj->segment.level_entry->trigger; + trigger = &obj->unk64->trigger; settings = get_settings(); courseFlags = settings->courseFlagsPtr[settings->courseId]; curRaceType = get_current_level_race_type(); @@ -3919,7 +3919,7 @@ void obj_loop_trigger(Object *obj, UNUSED s32 updateRate) { racers = get_racer_objects(&numRacers); for (i = 0; i < numRacers; i++) { racerObj = racers[i]; - racer = (Object_Racer *) racerObj->unk64; + racer = &racerObj->unk64->racer; if ((!(trigger->unk14 & 1) && racer->playerIndex == PLAYER_COMPUTER) || (!(trigger->unk14 & 2) && racer->playerIndex != PLAYER_COMPUTER)) { diffX = racerObj->segment.trans.x_position - obj->segment.trans.x_position; @@ -3988,8 +3988,8 @@ void obj_loop_bridge_whaleramp(Object *obj, s32 updateRate) { f32 bellZ2; Object_Racer *racer; - whaleRamp = (Object_Bridge_WhaleRamp *) obj->unk64; - entry = (LevelObjectEntry_Bridge_WhaleRamp *) obj->segment.level_entry; + whaleRamp = &obj->unk64->bridge_whale_ramp; + entry = &obj->segment.level_entry->bridge_whaleRamp; updateRateF = updateRate; if (osTvType == OS_TV_TYPE_PAL) { @@ -4018,8 +4018,8 @@ void obj_loop_bridge_whaleramp(Object *obj, s32 updateRate) { } } } else if (obj->properties.common.unk0 != 0) { - if (obj->segment.trans.rotation.x_rotation >= -0x12FF) { - obj->segment.trans.rotation.x_rotation -= updateRate * 0x2D; + if (obj->segment.trans.rotation.x_rotation > -0x1300) { + obj->segment.trans.rotation.x_rotation -= updateRate * 45; } if (whaleRamp->soundMask == NULL) { obj_bridge_pos(entry->unkA, &bellX1, &bellY1, &bellZ1); @@ -4027,7 +4027,7 @@ void obj_loop_bridge_whaleramp(Object *obj, s32 updateRate) { } } else { if (obj->segment.trans.rotation.x_rotation < 0) { - obj->segment.trans.rotation.x_rotation += updateRate * 0x28; + obj->segment.trans.rotation.x_rotation += updateRate * 40; if (whaleRamp->soundMask == NULL) { obj_bridge_pos(entry->unkA, &bellX2, &bellY2, &bellZ2); audspat_play_sound_at_position(SOUND_DRAWBRIDGE_BELL, bellX2, bellY2, bellZ2, 1, &whaleRamp->soundMask); @@ -4051,7 +4051,7 @@ void obj_loop_bridge_whaleramp(Object *obj, s32 updateRate) { obj->properties.common.unk0 = 1; racerObj = get_racer_object(PLAYER_ONE); if (racerObj != NULL) { - racer = (Object_Racer *) racerObj->unk64; + racer = &racerObj->unk64->racer; switch (racer->vehicleID) { default: vehicleID = VEHICLE_HOVERCRAFT; @@ -4182,7 +4182,7 @@ void obj_loop_treasuresucker(Object *obj, s32 updateRate) { racerObj = get_racer_object(obj->properties.treasureSucker.playerID); if (racerObj != NULL) { - racer = (Object_Racer *) racerObj->unk64; + racer = &racerObj->unk64->racer; doSpawnObj = FALSE; if (racer->bananas != 0 && obj->properties.treasureSucker.spawnTimer == 0) { diffX = obj->segment.trans.x_position - racerObj->segment.trans.x_position; @@ -4349,9 +4349,9 @@ void obj_loop_banana(Object *obj, s32 updateRate) { if (osTvType == OS_TV_TYPE_PAL) { updateRateF *= 1.2; } - banana = (Object_Banana *) obj->unk64; + banana = &obj->unk64->banana; obj->segment.animFrame += updateRate * 8; - properties = (ObjPropertyBanana *) &obj->properties.banana; + properties = &obj->properties.banana; if (properties->status == BANANA_COLLECTED) { obj->segment.trans.flags |= OBJ_FLAGS_INVISIBLE; properties->destroyTimer -= updateRate; @@ -4422,7 +4422,7 @@ void obj_loop_banana(Object *obj, s32 updateRate) { if (get_current_level_race_type() == RACETYPE_CHALLENGE_BANANAS) { racerObj = obj->interactObj->obj; if (racerObj != NULL && racerObj->segment.header->behaviorId == BHV_RACER) { - racer = (Object_Racer *) racerObj->unk64; + racer = &racerObj->unk64->racer; if (racer->playerIndex == PLAYER_COMPUTER) { hitDist += 30; // AI players are offered extra courtesy. } @@ -4432,7 +4432,7 @@ void obj_loop_banana(Object *obj, s32 updateRate) { if (obj->interactObj->distance < hitDist && properties->intangibleTimer == 0) { racerObj = obj->interactObj->obj; if (racerObj != NULL && racerObj->segment.header->behaviorId == BHV_RACER) { - racer = (Object_Racer *) racerObj->unk64; + racer = &racerObj->unk64->racer; if (get_current_level_race_type() != RACETYPE_CHALLENGE_BANANAS || racer->bananas < 2) { prevSoundMask = racer->bananaSoundMask; audspat_play_sound_at_position(SOUND_SELECT, racerObj->segment.trans.x_position, @@ -4531,7 +4531,7 @@ void obj_loop_silvercoin(Object *obj, s32 updateRate) { if (interactObj->distance < 80) { racerObj = interactObj->obj; if (racerObj != NULL && racerObj->segment.header->behaviorId == BHV_RACER) { - racer = (Object_Racer *) racerObj->unk64; + racer = &racerObj->unk64->racer; if (racer->playerIndex != PLAYER_COMPUTER) { if (racer->raceFinished == FALSE && !(obj->properties.npc.action & (SILVER_COIN_COLLECTED << racer->playerIndex))) { @@ -4679,7 +4679,7 @@ void obj_loop_weaponballoon(Object *weaponBalloonObj, s32 updateRate) { ObjectInteraction *interactObj; s32 prevBalloonType; - weaponBalloon = (Object_WeaponBalloon *) weaponBalloonObj->unk64; + weaponBalloon = &weaponBalloonObj->unk64->weapon_balloon; weaponBalloonObj->segment.trans.scale = weaponBalloon->scale * (1.0 - (weaponBalloon->respawnTime / 90.0f)); if (weaponBalloonObj->segment.trans.scale < 0.001) { weaponBalloonObj->segment.trans.scale = 0.001f; @@ -4857,7 +4857,7 @@ void weapon_projectile(Object *obj, s32 updateRate) { ObjectTransform trans; obj->interactObj->flags |= INTERACT_FLAGS_UNK_0100; - weapon = (Object_Weapon *) obj->unk64; + weapon = &obj->unk64->weapon; posX = obj->segment.trans.x_position; posY = obj->segment.trans.y_position; posZ = obj->segment.trans.z_position; @@ -4941,9 +4941,9 @@ void weapon_projectile(Object *obj, s32 updateRate) { } if (obj->interactObj->distance < size) { if (interactObj->segment.header->behaviorId == BHV_RACER) { - racer = (Object_Racer *) interactObj->unk64; + racer = &interactObj->unk64->racer; racer->attackType = ATTACK_EXPLOSION; - weaponOwner = (Object_Racer *) weapon->owner->unk64; + weaponOwner = &weapon->owner->unk64->racer; if (racer->playerIndex != PLAYER_COMPUTER || weaponOwner->playerIndex != PLAYER_COMPUTER) { weaponOwner->boost_sound |= BOOST_SOUND_UNK2; } @@ -4960,7 +4960,7 @@ void weapon_projectile(Object *obj, s32 updateRate) { block_37: obj->properties.projectile.unk4 += updateRate; if (obj->unk60 != NULL) { - temp_s1_2 = (Object *) obj->unk60->unk4[0]; + temp_s1_2 = obj->unk60->unk4[0]; if (obj->properties.projectile.unk4 < 8) { temp_s1_2->segment.trans.scale = obj->properties.projectile.unk4 * 0.5f; } else if (obj->properties.projectile.unk4 < 16) { @@ -5010,7 +5010,7 @@ void rocket_prevent_overshoot(Object *obj, UNUSED s32 updateRate, Object_Weapon angleDiff = angle - (obj->segment.trans.rotation.y_rotation & 0xFFFF); WRAP(angleDiff, -0x8000, 0x8000); if (angleDiff > 0x6000 || angleDiff < -0x6000) { - obj->interactObj->obj = (Object *) interactedObj; + obj->interactObj->obj = interactedObj; obj->interactObj->distance = 1; } obj->segment.trans.rotation.x_rotation = arctan2_f(diffY, dist); @@ -5027,7 +5027,7 @@ void rocket_prevent_overshoot(Object *obj, UNUSED s32 updateRate, Object_Weapon */ void homing_rocket_prevent_overshoot(Object *obj, s32 updateRate, Object_Weapon *rocket) { Object *targetObj; - Object_64 *racer; + Object_Racer *racer; f32 dist; f32 diffX; f32 diffY; @@ -5041,9 +5041,9 @@ void homing_rocket_prevent_overshoot(Object *obj, s32 updateRate, Object_Weapon if (rocket->target != NULL) { targetObj = rocket->target; - racer = targetObj->unk64; - rocket->unk14 = racer->racer.unk1BA >> 1; - rocket->unk16 = racer->racer.unk1BC >> 1; + racer = &targetObj->unk64->racer; + rocket->unk14 = racer->unk1BA >> 1; + rocket->unk16 = racer->unk1BC >> 1; diffX = targetObj->segment.trans.x_position - obj->segment.trans.x_position; diffY = targetObj->segment.trans.y_position - obj->segment.trans.y_position; diffZ = targetObj->segment.trans.z_position - obj->segment.trans.z_position; @@ -5055,7 +5055,7 @@ void homing_rocket_prevent_overshoot(Object *obj, s32 updateRate, Object_Weapon } dist = sqrtf(dist + distY); if (dist > 300.0f && rocket->checkpoint != -1 && rocket->hitObj == NULL) { - sp58 = func_8001955C(obj, rocket->checkpoint, racer->racer.unk1C8, rocket->unk14, rocket->unk16, + sp58 = func_8001955C(obj, rocket->checkpoint, racer->unk1C8, rocket->unk14, rocket->unk16, rocket->checkpointDist, &diffX, &diffY, &diffZ); sineY = arctan2_f(diffY, 500.0f) & 0xFFFF; shift = 3; @@ -5476,7 +5476,7 @@ void obj_loop_texscroll(Object *obj, s32 updateRate) { s32 pad[2]; LevelModel *levelModel; LevelModelSegment *curBlock; - Object_64 *obj64; + Object_TexScroll *texScroll; Triangle *curTriangle; TriangleBatchInfo *curBatch; s32 prevUnk8; @@ -5497,13 +5497,13 @@ void obj_loop_texscroll(Object *obj, s32 updateRate) { s32 i; s32 j; - obj64 = obj->unk64; + texScroll = &obj->unk64->tex_scroll; levelModel = get_current_level_model(); - t0 = obj64->tex_scroll.unk4; - t1 = obj64->tex_scroll.unk6; + t0 = texScroll->unk4; + t1 = texScroll->unk6; - tex = levelModel->textures[obj64->tex_scroll.textureIndex].texture; + tex = levelModel->textures[texScroll->textureIndex].texture; uShift = tex->width; vShift = tex->height; @@ -5513,14 +5513,14 @@ void obj_loop_texscroll(Object *obj, s32 updateRate) { t0 *= updateRate; t1 *= updateRate; - obj64->tex_scroll.unk8 += t0; - obj64->tex_scroll.unkA += t1; + texScroll->unk8 += t0; + texScroll->unkA += t1; - t0 = obj64->tex_scroll.unk8; - t1 = obj64->tex_scroll.unkA; + t0 = texScroll->unk8; + t1 = texScroll->unkA; - obj64->tex_scroll.unk8 &= 3; - obj64->tex_scroll.unkA &= 3; + texScroll->unk8 &= 3; + texScroll->unkA &= 3; t0 = t0 >> 2; t1 = ((t1 >> 2) & 0xFFFFFFFFFFFFFFFF); // fake @@ -5529,7 +5529,7 @@ void obj_loop_texscroll(Object *obj, s32 updateRate) { for (i = 0; i < levelModel->numberOfSegments; i++) { curBatch = curBlock[i].batches; for (j = 0; j < curBlock[i].numberOfBatches; j++) { - if (curBatch[j].textureIndex == obj64->tex_scroll.textureIndex) { + if (curBatch[j].textureIndex == texScroll->textureIndex) { for (tri = curBatch[j].facesOffset; tri < curBatch[j + 1].facesOffset; tri++) { curTriangle = &curBlock[i].triangles[tri]; if (!(curTriangle->flags & 0x80)) { @@ -5631,7 +5631,7 @@ void obj_loop_log(Object *obj, s32 updateRate) { f32 diffZ; f32 diffX; - log = (Object_Log *) obj->unk64; + log = &obj->unk64->log; if (log != NULL) { obj->segment.trans.y_position = obj_wave_height(log, updateRate); } else { @@ -5639,9 +5639,9 @@ void obj_loop_log(Object *obj, s32 updateRate) { } if (obj->unk5C->unk100 != NULL) { obj->properties.log.velocityY++; - racerObj = (Object *) obj->unk5C->unk100; + racerObj = obj->unk5C->unk100; if (racerObj->behaviorId == BHV_RACER) { - racer = (Object_Racer *) racerObj->unk64; + racer = &racerObj->unk64->racer; if (racer->velocity < -4.0 && racer->raceFinished == FALSE) { rumble_set(racer->playerIndex, RUMBLE_TYPE_18); } @@ -5700,7 +5700,7 @@ void obj_init_weather(Object *obj, LevelObjectEntry_Weather *entry) { void obj_loop_weather(Object *obj, UNUSED s32 updateRate) { s32 currViewport; s32 numberOfObjects; - Object_Racer *curObj64; + Object_Racer *racer; Object **objects; Object *curObj; LevelObjectEntry_Weather *entry; @@ -5717,8 +5717,8 @@ void obj_loop_weather(Object *obj, UNUSED s32 updateRate) { last = numberOfObjects - 1; do { curObj = objects[cur + 1]; - curObj64 = (Object_Racer *) curObj->unk64; - } while (++cur < last && currViewport != curObj64->playerIndex); + racer = &curObj->unk64->racer; + } while (++cur < last && currViewport != racer->playerIndex); diffX = obj->segment.trans.x_position - curObj->segment.trans.x_position; diffZ = obj->segment.trans.z_position - curObj->segment.trans.z_position; @@ -6129,7 +6129,7 @@ void obj_loop_butterfly(Object *butterflyObj, s32 updateRate) { } void obj_init_midifade(Object *obj, LevelObjectEntry_MidiFade *entry) { - Object_64 *obj64; + Object_MidiFade *midiFade; Object_68 *obj68; ObjectTransform transform; f32 ox; @@ -6153,7 +6153,7 @@ void obj_init_midifade(Object *obj, LevelObjectEntry_MidiFade *entry) { s32 i; obj->segment.trans.rotation.y_rotation = entry->angleY << 8 << 2; // Two shifts needed to skip a register. - obj64 = obj->unk64; + midiFade = &obj->unk64->midi_fade; scaleF = (f32) (((s32) entry->scale) & 0xFFFF); if (scaleF < 1.0f) { scaleF = 1.0f; @@ -6169,16 +6169,16 @@ void obj_init_midifade(Object *obj, LevelObjectEntry_MidiFade *entry) { transform.z_position = 0.0f; mtxf_from_transform(&mtx, &transform); mtxf_transform_point(&mtx, 0.0f, 0.0f, 1.0f, &ox, &oy, &oz); - obj64->midi_fade.unk8 = ox; - obj64->midi_fade.unkC = oy; - obj64->midi_fade.unk10 = oz; - obj64->midi_fade.unk14 = -((obj->segment.trans.x_position * ox) + (obj->segment.trans.y_position * oy) + + midiFade->unk8 = ox; + midiFade->unkC = oy; + midiFade->unk10 = oz; + midiFade->unk14 = -((obj->segment.trans.x_position * ox) + (obj->segment.trans.y_position * oy) + (obj->segment.trans.z_position * oz)); - obj64->midi_fade.unk2 = entry->unk1A; - obj64->midi_fade.unk40 = entry->unk1B; + midiFade->unk2 = entry->unk1A; + midiFade->unk40 = entry->unk1B; - for (i = 0; i < 15; i++) { - obj64->midi_fade.unk2F[i] = entry->unkA[i]; + for (i = 0; i < ARRAY_COUNT(midiFade->unk2F) - 1; i++) { + midiFade->unk2F[i] = entry->unkA[i]; } obj68 = *obj->unk68; @@ -6229,13 +6229,13 @@ void obj_init_midifade(Object *obj, LevelObjectEntry_MidiFade *entry) { maxZ = minZ; minZ = tempF2; } - obj64->midi_fade.unk18 = (obj->segment.trans.scale * minX) + obj->segment.trans.x_position; - obj64->midi_fade.unk1C = (obj->segment.trans.scale * minY) + obj->segment.trans.y_position; - obj64->midi_fade.unk20 = (obj->segment.trans.scale * minZ) + obj->segment.trans.z_position; - obj64->midi_fade.unk24 = (obj->segment.trans.scale * maxX) + obj->segment.trans.x_position; - obj64->midi_fade.unk28 = (obj->segment.trans.scale * maxY) + obj->segment.trans.y_position; - obj64->midi_fade.unk2C = (obj->segment.trans.scale * maxZ) + obj->segment.trans.z_position; - obj64->midi_fade.unk1 = 0; + midiFade->unk18 = (obj->segment.trans.scale * minX) + obj->segment.trans.x_position; + midiFade->unk1C = (obj->segment.trans.scale * minY) + obj->segment.trans.y_position; + midiFade->unk20 = (obj->segment.trans.scale * minZ) + obj->segment.trans.z_position; + midiFade->unk24 = (obj->segment.trans.scale * maxX) + obj->segment.trans.x_position; + midiFade->unk28 = (obj->segment.trans.scale * maxY) + obj->segment.trans.y_position; + midiFade->unk2C = (obj->segment.trans.scale * maxZ) + obj->segment.trans.z_position; + midiFade->unk1 = 0; } void obj_init_midifadepoint(Object *obj, LevelObjectEntry_MidiFadePoint *entry) { @@ -6404,7 +6404,7 @@ void obj_loop_frog(Object *obj, s32 updateRate) { if (osTvType == OS_TV_TYPE_PAL) { updateRateF *= 1.2; } - frog = (Object_Frog *) obj->unk64; + frog = &obj->unk64->frog; switch (frog->action) { case FROG_IDLE: diff --git a/src/object_functions.h b/src/object_functions.h index 5abdb6ae..0aa9e924 100644 --- a/src/object_functions.h +++ b/src/object_functions.h @@ -443,8 +443,6 @@ void obj_init_fish(Object *fishObj, LevelObjectEntry_Fish *fishEntry, s32 param) void obj_init_midifade(Object *obj, LevelObjectEntry_MidiFade *entry); void obj_loop_butterfly(Object *butterflyObj, s32 updateRate); s32 ainode_find_nearest(f32 diffX, f32 diffY, f32 diffZ, s32 useElevation); -s32 ainode_find_next(s32, s32, s32); -f32 func_8001C6C4(Object_64 *, Object *, f32, f32, s32); void func_8000CBF0(Object*, s32); void try_to_collect_egg(Object *, Object_CollectEgg*); diff --git a/src/objects.c b/src/objects.c index db264f0d..09cc8aa6 100644 --- a/src/objects.c +++ b/src/objects.c @@ -29,6 +29,8 @@ #include "vehicle_misc.h" #include "PRinternal/viint.h" #include "printf.h" +#include "weather.h" +#include "PRinternal/piint.h" #define MAX_CHECKPOINTS 60 #define OBJECT_POOL_SIZE 0x15800 @@ -843,14 +845,14 @@ void clear_object_pointers(void) { D_8011AE88 = 0; D_8011ADD4 = 0; gCutsceneID = 0; - D_8011AE7E = 1; + D_8011AE7E = TRUE; gFirstActiveObjectId = 0; gTransformTimer = 0; gIsTajChallenge = FALSE; gTajRaceInit = 0; D_8011AF60[0] = 0; D_8011AE00 = 0; - D_8011AE01 = 1; + D_8011AE01 = TRUE; D_8011AD53 = 0; gOverrideDoors = FALSE; } @@ -1406,7 +1408,7 @@ void func_8000CC7C(Vehicle vehicle, u32 arg1, s32 arg2) { newRacerObj->segment.level_entry = NULL; newRacerObj->behaviorId = BHV_TIMETRIAL_GHOST; newRacerObj->shadow->scale = 0.01f; - newRacerObj->interactObj->flags = 0; + newRacerObj->interactObj->flags = INTERACT_FLAGS_NONE; gGhostObjPlayer = newRacerObj; newRacerObj->unk64->racer.transparency = 0x60; } @@ -1422,7 +1424,7 @@ void func_8000CC7C(Vehicle vehicle, u32 arg1, s32 arg2) { newRacerObj->segment.level_entry = NULL; newRacerObj->behaviorId = BHV_TIMETRIAL_GHOST; newRacerObj->shadow->scale = 0.01f; - newRacerObj->interactObj->flags = 0; + newRacerObj->interactObj->flags = INTERACT_FLAGS_NONE; gGhostObjStaff = newRacerObj; newRacerObj->unk64->racer.transparency = 0x60; } @@ -1737,9 +1739,10 @@ UNUSED s32 func_8000E558(Object *arg0) { return TRUE; } -// https://decomp.me/scratch/QHVHG +// https://decomp.me/scratch/QHVHG - 43.07% #pragma GLOBAL_ASM("asm/nonmatchings/objects/func_8000E5EC.s") -// https://decomp.me/scratch/btRnW + +// https://decomp.me/scratch/btRnW - 95.87% #pragma GLOBAL_ASM("asm/nonmatchings/objects/func_8000E79C.s") UNUSED u8 *func_8000E898(u8 *arg0, s32 arg1) { @@ -2013,7 +2016,7 @@ Object *spawn_object(LevelObjectEntryCommon *entry, s32 arg1) { } sizeOfobj = (uintptr_t) address - (uintptr_t) curObj; if (curObj->segment.header->numLightSources > 0) { - curObj->lightData = (Object_LightData **) address; + curObj->lightData = (ObjectLight **) address; sizeOfobj = (s32) ((uintptr_t) address + (curObj->segment.header->numLightSources * 4)) - (uintptr_t) curObj; } newObj = mempool_alloc_pool((MemoryPoolSlot *) gObjectMemoryPool, sizeOfobj); @@ -2074,7 +2077,7 @@ Object *spawn_object(LevelObjectEntryCommon *entry, s32 arg1) { } if (newObj->segment.header->numLightSources > 0) { newObj->lightData = - (Object_LightData **) (((uintptr_t) newObj + (uintptr_t) newObj->lightData) - (uintptr_t) gSpawnObjectHeap); + (ObjectLight **) (((uintptr_t) newObj + (uintptr_t) newObj->lightData) - (uintptr_t) gSpawnObjectHeap); } newObj->unk68 = (Object_68 **) ((uintptr_t) newObj + (uintptr_t) 0x80); if (arg1 & 1) { @@ -2145,7 +2148,7 @@ void objFreeAssets(Object *obj, s32 count, s32 objType) { void light_setup_light_sources(Object *obj) { s32 i; for (i = 0; i < obj->segment.header->numLightSources; i++) { - obj->lightData[i] = (Object_LightData *) add_object_light(obj, &obj->segment.header->unk24[i]); + obj->lightData[i] = add_object_light(obj, &obj->segment.header->unk24[i]); } } @@ -2427,8 +2430,224 @@ void gParticlePtrList_flush(void) { gFreeListCount = 0; } -// https://decomp.me/scratch/bJM0P +#ifdef NON_EQUIVALENT +void func_800101AC(Object *obj, s32 arg1) { + Object *tempObj; + Object_Weapon *weapon; + Object_Racer *racer; + Object_Racer *snowball; + Object_Fireball_Octoweapon *fireball; + Object_Log *log; + Object_Butterfly *butterfly; + SoundHandle soundMask; + s32 numberOfModelIds; + s32 i; + s32 j; + + if (obj->segment.trans.flags & OBJ_FLAGS_PARTICLE) { + particle_deallocate((Particle *) obj); + gParticleCount--; + return; + } + if (obj->unk60 != NULL) { + for (i = 0; i < obj->unk60->unk0; i++) { + tempObj = obj->unk60->unk4[i]; + numberOfModelIds = tempObj->segment.header->numberOfModelIds; + if (tempObj->segment.header->modelType == OBJECT_MODEL_TYPE_3D_MODEL) { + if (!gObjPtrList) {} // fake + for (j = 0; j < numberOfModelIds; j++) { + free_3d_model(&tempObj->unk68[j]->objModel); + } + } else { + for (j = 0; j < numberOfModelIds; j++) { + sprite_free(&tempObj->unk68[j]->sprite); + } + } + try_free_object_header(tempObj->segment.object.unk2C); + mempool_free(tempObj); + } + } + if (obj->lightData != NULL) { + for (i = 0; i < obj->segment.header->numLightSources; i++) { + func_80032BAC(obj->lightData[i]); + } + } + switch (obj->behaviorId) { + case BHV_RACER: + case BHV_ANIMATED_OBJECT_3: + for (i = 0; i < gObjectCount; i++) { + if (gObjPtrList[i]->behaviorId == BHV_BUTTERFLY) { + butterfly = &gObjPtrList[i]->unk64->butterfly; + if (obj == butterfly->unk100) { + butterfly->unk100 = 0; + butterfly->unkFD = 1; + } + } + } + break; + case BHV_WEAPON: + case BHV_WEAPON_2: + weapon = &obj->unk64->weapon; + if (weapon->soundMask != NULL) { + audspat_point_stop(weapon->soundMask); + weapon->soundMask = NULL; + if (obj->behaviorId == BHV_WEAPON_2) { + decrease_rocket_sound_timer(); + } + } + break; + case BHV_FIREBALL_OCTOWEAPON_2: + fireball = &obj->unk64->fireball_octoweapon; + if (fireball->soundMask != NULL) { + audspat_point_stop(fireball->soundMask); + } + break; + case BHV_SNOWBALL: + case BHV_SNOWBALL_2: + case BHV_SNOWBALL_3: + case BHV_SNOWBALL_4: + // TODO: Get a Snowball struct? + snowball = &obj->unk64->racer; + if (snowball->unk20 != NULL) { + audspat_point_stop(snowball->unk20); + } + break; + case BHV_WAVE_GENERATOR: + wavegen_destroy(obj); + break; + case BHV_LIGHT_RGBA: + func_80032BAC((ObjectLight *) obj->unk64); + break; + case BHV_ANIMATION: + if (obj->unk64 != NULL && arg1 == 0) { + free_object(&obj->unk64->obj); + } + break; + case BHV_OVERRIDE_POS: + for (i = 0; i < D_8011AE00 && obj != D_8011ADD8[i]; i++) {} + if (i < D_8011AE00) { + D_8011AE00--; + for (; i < D_8011AE00; i++) { + D_8011ADD8[i] = D_8011ADD8[i + 1]; + } + } + break; + case BHV_BUOY_PIRATE_SHIP: + case BHV_LOG: + log = &obj->unk64->log; + if (log != NULL) { + mempool_free(log); + } + break; + case BHV_LENS_FLARE: + lensflare_remove(obj); + break; + case BHV_LENS_FLARE_SWITCH: + lensflare_override_remove(obj); + break; + } + switch (obj->behaviorId) { + case BHV_DINO_WHALE: + case BHV_ANIMATED_OBJECT: + case BHV_CAMERA_ANIMATION: + case BHV_CAR_ANIMATION: + case BHV_CHARACTER_SELECT: + case BHV_VEHICLE_ANIMATION: + case BHV_HIT_TESTER: + case BHV_HIT_TESTER_2: + case BHV_PARK_WARDEN_2: + case BHV_ANIMATED_OBJECT_2: + case BHV_WIZPIG_SHIP: + case BHV_ANIMATED_OBJECT_3: + case BHV_ANIMATED_OBJECT_4: + case BHV_SNOWBALL: + case BHV_SNOWBALL_2: + case BHV_SNOWBALL_3: + case BHV_SNOWBALL_4: + case BHV_HIT_TESTER_3: + case BHV_HIT_TESTER_4: + case BHV_DOOR_OPENER: + case BHV_PIG_ROCKETEER: + case BHV_WIZPIG_GHOSTS: + // Not sure if this is an animation yet... + soundMask = obj->unk64->animation.unk18; + if (soundMask != NULL) { + sndp_stop(soundMask); + } + break; + } + if (obj->behaviorId == BHV_RACER) { + racer = &obj->unk64->racer; + if (racer->unk18 != NULL) { + sndp_stop((SoundHandle) (s32) racer->unk18); // type cast required to match + } + if (racer->unk10 != NULL) { + sndp_stop((SoundHandle) (s32) racer->unk10); // type cast required to match + } + if (racer->unk14 != NULL) { + sndp_stop((SoundHandle) (s32) racer->unk14); // type cast required to match + } + if (racer->unk1C != NULL) { + sndp_stop((SoundHandle) (s32) racer->unk1C); // type cast required to match + } + if (racer->unk20 != NULL) { + sndp_stop((SoundHandle) (s32) racer->unk20); // type cast required to match + } + if (racer->soundMask != NULL) { + audspat_point_stop(racer->soundMask); + } + if (racer->shieldSoundMask != NULL) { + audspat_point_stop(racer->shieldSoundMask); + } + if (racer->magnetSoundMask != NULL) { + sndp_stop(racer->magnetSoundMask); + } + racer_sound_free(obj); + for (i = 0; i < gObjectCount; i++) { + if ((gObjPtrList[i]->segment.trans.flags & OBJ_FLAGS_PARTICLE) && + (gObjPtrList[i]->segment.level_entry == obj->segment.level_entry)) { + gObjPtrList[i]->segment.level_entry = NULL; + } + if (gObjPtrList[i]->behaviorId == BHV_WEAPON_2 || gObjPtrList[i]->behaviorId == BHV_FLY_COIN || + gObjPtrList[i]->behaviorId == BHV_WEAPON) { + free_object(gObjPtrList[i]); + } + } + } + if (obj->shadow != NULL && obj->shadow->texture != NULL) { + tex_free(obj->shadow->texture); + } + if (obj->waterEffect != NULL && obj->waterEffect->texture != NULL) { + tex_free(obj->waterEffect->texture); + } + numberOfModelIds = obj->segment.header->numberOfModelIds; + if (obj->segment.header->modelType == OBJECT_MODEL_TYPE_3D_MODEL) { + for (i = 0; i < numberOfModelIds; i++) { + if (obj->unk68[i] != NULL) { + free_3d_model(&obj->unk68[i]->objModel); + } + } + } else if (obj->segment.header->modelType == OBJECT_MODEL_TYPE_MISC) { + for (i = 0; i < numberOfModelIds; i++) { + tex_free(&obj->unk68[i]->texHeader); + } + } else { + for (i = 0; i < numberOfModelIds; i++) { + sprite_free(&obj->unk68[i]->sprite); + } + } + if (obj->segment.header->particleCount > 0) { + for (i = 0; i < obj->segment.header->particleCount; i++) { + emitter_cleanup(&obj->particleEmitter[i]); + } + } + try_free_object_header(obj->segment.object.unk2C); + mempool_free(obj); +} +#else +// https://decomp.me/scratch/DW6EX #pragma GLOBAL_ASM("asm/nonmatchings/objects/func_800101AC.s") +#endif void obj_update(s32 updateRate) { s32 i; @@ -2615,7 +2834,7 @@ void obj_tex_animate(Object *obj, s32 updateRate) { * Sets the texture offset on the door number based on the balloon requirement. */ void obj_door_number(ObjectModel *model, Object *obj) { - Object_64 *obj64; + Object_Door *door; s32 current; s32 remaining; s32 i; @@ -2625,8 +2844,8 @@ void obj_door_number(ObjectModel *model, Object *obj) { return; } - obj64 = obj->unk64; - remaining = obj64->door.balloonCount; + door = &obj->unk64->door; + remaining = door->balloonCount; current = ((remaining / 10) - 1) << 2; remaining = (remaining % 10) << 2; i = 0; @@ -3367,7 +3586,7 @@ void func_80012F94(Object *obj) { ret2 = 1.0f; if (!(obj->segment.trans.flags & OBJ_FLAGS_PARTICLE)) { if (obj->segment.header->behaviorId == BHV_RACER) { - objRacer = (Object_Racer *) obj->unk64; + objRacer = &obj->unk64->racer; objRacer->unk201 = 30; if (objRacer->unk206 > 0) { ret2 = 1.0f - (objRacer->unk206 * 0.05f); @@ -4802,8 +5021,400 @@ s32 func_8001955C(Object *obj, s32 checkpoint, u8 arg2, s32 arg3, s32 arg4, f32 return TRUE; } +#ifdef NON_EQUIVALENT +extern s32 D_B0000574; + +// D_8011ADC0 = gNextRacerPlaceNumber? + +// This function seems to be part of the main gameplay loop that tracks the win conditions for each race mode. +void func_80019808(s32 updateRate) { + u32 new_var; + s16 numHumanRacers; + s16 numHumanRacersFinished; + Object_Racer *curRacer; + LevelHeader *currentLevelHeader; + Object_Racer *racer[4]; // sp6C + s8 sp5C[4]; + s32 i; + s32 j; + Object_Racer *curRacer2; + Settings *settings; + s32 prevUnk1AA; + s16 racerIndex; + s32 newUnk1AA; + s16 numFinishedRacers; + s16 foundIndex; + s32 battleMusic; + s32 playerButtonPresses; + s8 raceType; + s8 someBool; + s32 newStartingPosition; + s32 shouldAwardBalloon; + s8 someBool2; + +#ifdef ANTI_TAMPER + s32 antiPiracySkipTajBalloonCutscene; + u32 stat; +#endif + + currentLevelHeader = get_current_level_header(); + settings = get_settings(); + numHumanRacersFinished = 0; + numHumanRacers = 0; + raceType = currentLevelHeader->race_type; + numFinishedRacers = 0; + if (raceType != RACETYPE_DEFAULT && raceType != RACETYPE_HORSESHOE_GULCH && raceType != RACETYPE_BOSS) { + if (raceType & RACETYPE_CHALLENGE) { + if (raceType == RACETYPE_CHALLENGE_EGGS) { + func_80045128(*gRacers); + } + if (D_8011ADB4 == 0) { + for (i = 0; i < gNumRacers; i++) { + racer[i] = &(*gRacers)[i]->unk64->racer; + if (currentLevelHeader->race_type == RACETYPE_CHALLENGE_BATTLE && racer[i]->bananas <= 0 && + !racer[i]->raceFinished) { + racer[i]->raceFinished = TRUE; + racer[i]->balloon_quantity = 0; + racer_sound_free((*gRacers)[i]); + (*gRacers)[i]->segment.trans.flags |= OBJ_FLAGS_INVISIBLE; + (*gRacers)[i]->interactObj->flags = INTERACT_FLAGS_NONE; + racer[i]->finishPosition = 5 - D_8011ADC0; + D_8011ADC0++; + } + if (racer[i]->playerIndex != PLAYER_COMPUTER) { + if (racer[i]->raceFinished) { + numHumanRacersFinished++; + } + numHumanRacers++; + } + if (racer[i]->raceFinished) { + numFinishedRacers++; + if (racer[i]->finishPosition == 0) { + racer[i]->finishPosition = D_8011ADC0; + D_8011ADC0++; + } + } + } + + if (currentLevelHeader->race_type == RACETYPE_CHALLENGE_BATTLE || numFinishedRacers > 0 || + (!(((numHumanRacers == 1 && numHumanRacersFinished == 1) || + (numHumanRacers >= 2 && numHumanRacersFinished >= numHumanRacers)) || + numFinishedRacers < 3))) { + for (i = 0; i < gNumRacers; i++) { + if (currentLevelHeader->race_type == RACETYPE_CHALLENGE_BATTLE) { + sp5C[i] = 10 - racer[i]->bananas; + } else { + sp5C[i] = racer[i]->lap; + if (currentLevelHeader->race_type == RACETYPE_CHALLENGE_EGGS) { + sp5C[i] *= 3; + if (racer[i]->eggHudCounter != 0) { + sp5C[i] += 2; + } else if (racer[i]->held_obj != NULL) { + sp5C[i] += 1; + } + } + } + if (sp5C[i] > 10) { + sp5C[i] = 10; + } + if (sp5C[i] < 0) { + sp5C[i] = 0; + } + } + + do { + racerIndex = -1; + foundIndex = -1; + for (i = 0; i < gNumRacers; i++) { + if (!racer[i]->raceFinished && sp5C[i] >= foundIndex) { + foundIndex = sp5C[i]; + racerIndex = i; + } + } + + if (racerIndex != -1) { + if (currentLevelHeader->race_type == RACETYPE_CHALLENGE_BATTLE) { + racer[racerIndex]->finishPosition = 5 - D_8011ADC0; + } else { + racer[racerIndex]->finishPosition = D_8011ADC0; + } + D_8011ADC0++; + racer[racerIndex]->raceFinished = TRUE; + } + } while (racerIndex != -1); + + gSwapLeadPlayer = FALSE; + + if ((!is_in_tracks_mode() && racer[0]->finishPosition == 1) || + (is_in_two_player_adventure() && racer[1]->finishPosition == 1)) { + if (!(settings->courseFlagsPtr[settings->courseId] & RACE_CLEARED)) { + settings->courseFlagsPtr[settings->courseId] |= RACE_CLEARED; + i = settings->ttAmulet + 1; + if (i > 4) { + i = 4; + } + settings->ttAmulet = i; + } + } + for (i = 0; i < 8; i++) { + settings->racers[i].starting_position = -1; + } + + battleMusic = SEQUENCE_BATTLE_LOSE; + for (i = 0; i < gNumRacers; i++) { + if (racer[i]->playerIndex != PLAYER_COMPUTER && racer[i]->finishPosition == 1) { + battleMusic = SEQUENCE_BATTLE_VICTORY; + } + settings->racers[i].starting_position = racer[i]->finishPosition - 1; + } + + music_play(battleMusic); + newStartingPosition = 4; + for (i = 0; i < 8; i++) { + if (settings->racers[i].starting_position == -1) { + settings->racers[i].starting_position = newStartingPosition; + newStartingPosition++; + } + } + + gSwapLeadPlayer = 0; + if (is_in_two_player_adventure() && settings->racers[PLAYER_TWO].starting_position < + settings->racers[PLAYER_ONE].starting_position) { + gSwapLeadPlayer = 1; + } + if (i == 0) { + if (is_in_two_player_adventure()) { + if (gSwapLeadPlayer) { + gSwapLeadPlayer = 0; + swap_lead_player(); + if (D_800DC73C != 0) { + D_800DC748 = TRUE; + } + } else if (D_800DC73C != 0) { + D_800DC748 = TRUE; + } + } + postrace_start(0, 30); + } else { + push_level_property_stack(SPECIAL_MAP_ID_NO_LEVEL, 0, VEHICLE_CAR, CUTSCENE_ID_NONE); + push_level_property_stack(ASSET_LEVEL_TTAMULETSEQUENCE, 0, VEHICLE_NO_OVERRIDE, + settings->ttAmulet - 1); + race_finish_adventure(1); + } + D_8011ADB4 = 1; + } + } + } + return; + } + for (i = 0; i < gNumRacers; i++) { + new_var = i; + newUnk1AA = 1; + curRacer = &(*gRacers)[i]->unk64->racer; + prevUnk1AA = curRacer->unk1AA; + for (j = 0; j < gNumRacers; j++) { + if (j != i) { + curRacer2 = &(*gRacers)[new_var]->unk64->racer; + if (curRacer->raceFinished == FALSE && curRacer2->raceFinished != FALSE) { + newUnk1AA++; + } else if (curRacer->courseCheckpoint < curRacer2->courseCheckpoint) { + newUnk1AA++; + } else if (curRacer2->courseCheckpoint == curRacer->courseCheckpoint) { + if (curRacer2->unk1A8 < curRacer->unk1A8) { + newUnk1AA++; + } + if (curRacer2->unk1A8 == curRacer->unk1A8 && i < j) { + newUnk1AA++; + } + } + } + } + + curRacer->unk1AA = newUnk1AA; + if (curRacer->lap < currentLevelHeader->laps) { + if (prevUnk1AA == curRacer->unk1AA) { + if (curRacer->unk1B0 < 2) { + if (curRacer->vehicleID != VEHICLE_LOOPDELOOP) { + curRacer->unk1B0++; + } + } else if (curRacer->racePosition != curRacer->unk1AA) { + curRacer->unk1B2 = 10; + curRacer->racePosition = curRacer->unk1AA; + } + } else { + curRacer->unk1B0 = 0; + } + } + } + + for (i = 0; i < gNumRacers; i++) { + curRacer = &(*gRacers)[i]->unk64->racer; + if (curRacer->lap >= currentLevelHeader->laps && curRacer->raceFinished == FALSE) { + if (get_game_mode() != GAMEMODE_UNUSED_4) { + curRacer->raceFinished = TRUE; + curRacer->finishPosition = D_8011ADC0; + if (D_8011ADC0 == 1 && curRacer->playerIndex == PLAYER_COMPUTER) { + sound_play(SOUND_WHOOSH5, NULL); + } + D_8011ADC0++; + } + } + if (curRacer->playerIndex != PLAYER_COMPUTER) { + numHumanRacers++; + if (curRacer->raceFinished) { + numHumanRacersFinished++; + numFinishedRacers++; + } + } else if (curRacer->raceFinished) { + numFinishedRacers++; + } + } + + for (i = 0; i < gNumRacers; i++) { + gRacersByPosition[i] = 0; + } + + for (i = 0; i < gNumRacers; i++) { + curRacer = &(*gRacers)[i]->unk64->racer; + if (curRacer->raceFinished) { + j = curRacer->finishPosition; + } else { + j = curRacer->unk1AA; + } + gRacersByPosition[j - 1] = (Object *) curRacer; // TODO: This should be a pointer to Object, not Object_Racer + } + + for (i = 0; i < gNumRacers; i++) { + someBool = FALSE; + for (j = 0; j < gNumRacers; j++) { + if (gRacersByPosition[j] == (*gRacers)[i]) { + someBool = TRUE; + j = gNumRacers + 1; + } + } + + if (!someBool) { + for (j = 0; j < gNumRacers; j++) { + if (gRacersByPosition[j] == 0) { + gRacersByPosition[j] = (*gRacers)[i]; + j = gNumRacers + 1; + } + } + } + } + + playerButtonPresses = 0; + for (i = 0; i < MAXCONTROLLERS; i++) { + playerButtonPresses |= input_pressed(i); + } + + if (gIsTajChallenge && numHumanRacersFinished != 0) { + mode_end_taj_race(CHALLENGE_END_FINISH); + } else if (D_8011AD3C != 0 && numFinishedRacers != 0) { + curRacer2 = &(*gRacers)[0]->unk64->racer; + if (!curRacer2->raceFinished) { + curRacer2->raceFinished = TRUE; + curRacer2->finishPosition = D_8011ADC0; + D_8011ADC0 += 1; + } + } else if (D_8011ADB4 == 0) { + someBool2 = FALSE; + if (is_in_two_player_adventure() && numHumanRacersFinished > 0 && get_trophy_race_world_id() == 0 && + set_course_finish_flags(settings) != 0) { + someBool2 = TRUE; + } + if ((numHumanRacersFinished == numHumanRacers || + (numHumanRacers >= 2 && numFinishedRacers >= (gNumRacers - 1))) || + someBool2) { + if (numHumanRacersFinished != numHumanRacers) { + for (i = 0; i < gNumRacers; i++) { + curRacer2 = &gRacersByPosition[i]->unk64->racer; + if (curRacer2->raceFinished == FALSE) { + if (curRacer2->playerIndex >= 0) { + set_active_camera(curRacer2->playerIndex); + cam_get_active_camera_no_cutscenes()->mode = CAMERA_FINISH_CHALLENGE; + } + curRacer2->raceFinished = TRUE; + curRacer2->finishPosition = D_8011ADC0; + D_8011ADC0++; + } + } + } + +#ifdef ANTI_TAMPER + antiPiracySkipTajBalloonCutscene = FALSE; + // Anti-Piracy check + WAIT_ON_IOBUSY(stat); + // D_B0000574 is a direct read from the ROM as opposed to RAM + if (((D_B0000574 & 0xFFFF) & 0xFFFF) != 0x6C07) { + antiPiracySkipTajBalloonCutscene = TRUE; + } +#endif + + if (!gIsTimeTrial) { + for (i = 0; i < gNumRacers; i++) { + curRacer = &gRacersByPosition[i]->unk64->racer; + settings->racers[curRacer->characterId].starting_position = i; + } + } + gSwapLeadPlayer = FALSE; + if (is_in_two_player_adventure() && + (settings->racers[PLAYER_TWO].starting_position < settings->racers[PLAYER_ONE].starting_position)) { + gSwapLeadPlayer = TRUE; + } + curRacer2 = &(*gRacersByPosition)->unk64->racer; + gFirstTimeFinish = FALSE; + if ((settings->gNumRacers == 1 || is_in_two_player_adventure()) && + curRacer2->playerIndex != PLAYER_COMPUTER && !is_in_tracks_mode() && get_trophy_race_world_id() == 0) { + gFirstTimeFinish = TRUE; + } + shouldAwardBalloon = FALSE; + if (gFirstTimeFinish && !someBool2) { + shouldAwardBalloon = set_course_finish_flags(settings); + } + if (someBool2) { + gFirstTimeFinish = TRUE; + shouldAwardBalloon = TRUE; + } + +#ifdef ANTI_TAMPER + if (antiPiracySkipTajBalloonCutscene) { + shouldAwardBalloon = FALSE; + gFirstTimeFinish = FALSE; + } +#endif + + if (!shouldAwardBalloon) { + if (is_in_two_player_adventure()) { + if (gSwapLeadPlayer) { + gSwapLeadPlayer = FALSE; + swap_lead_player(); + if (D_800DC73C) { + D_800DC748 = TRUE; + } + } else if (D_800DC73C) { + D_800DC748 = TRUE; + } + } + postrace_start(gFirstTimeFinish, 30); + } else { + settings->balloonsPtr[settings->worldId]++; + if (settings->worldId != 0) { + settings->balloonsPtr[0]++; + } + race_finish_adventure(1); + } + D_8011ADB4 = -1; + if (get_number_of_active_players() == 1) { + race_finish_time_trial(); + } + } + } +} +#else // https://decomp.me/scratch/QupaR #pragma GLOBAL_ASM("asm/nonmatchings/objects/func_80019808.s") +#endif /** * Mark the course as finished for the appropriate mode. @@ -5754,10 +6365,142 @@ s32 ainode_find_nearest(f32 diffX, f32 diffY, f32 diffZ, s32 useElevation) { return result; } +#ifdef NON_EQUIVALENT +f32 func_8001C6C4(Object_NPC *npc, Object *npcParentObj, f32 updateRateF, f32 speedF, s32 direction) { + Object *aiNode; + f32 var_f20_2; + f32 xPosData[5]; + f32 yPosData[5]; + f32 zPosData[5]; + f32 xDiff2; + f32 yDiff2; + f32 zDiff2; + f32 xDiff; + f32 yDiff; + f32 zDiff; + f32 dist; + f32 dist2; + f32 mag; + s32 i; + s32 var_s0; + s32 var_s1; + u8 nodeForward1; + u8 nodeForward2; + + if (osTvType == OS_TV_TYPE_PAL) { + updateRateF *= 1.2; + } + i = 0; + while (1) { + if (npc->nodeData[i] == 0xFF) { + return 0.0f; + } + aiNode = ainode_get(npc->nodeData[i]); + if (aiNode == NULL) { + return 0.0f; + } + xPosData[i] = aiNode->segment.trans.x_position; + yPosData[i] = aiNode->segment.trans.y_position; + zPosData[i] = aiNode->segment.trans.z_position; + i++; + if (i != 5) { + continue; + } + // This puts xPosData into yDiff2, and yPosData into xDiff2. Bug? + yDiff2 = catmull_rom_interpolation(xPosData, 0, npc->unk0); + xDiff2 = catmull_rom_interpolation(yPosData, 0, npc->unk0); + zDiff2 = catmull_rom_interpolation(zPosData, 0, npc->unk0); + if (npc->unk8 == 0.0f) { + npc->unk8 = 0.01f; + } + + var_s1 = 0; + for (var_s0 = 0; var_s0 != 2; var_s0++) { + var_f20_2 = npc->unk0 + (npc->unk8 * updateRateF); + if (var_f20_2 >= 1.0) { + var_f20_2 -= 1.0; + var_s1 = 1; + } + xDiff = catmull_rom_interpolation(xPosData, var_s1, var_f20_2); + yDiff = catmull_rom_interpolation(yPosData, var_s1, var_f20_2); + zDiff = catmull_rom_interpolation(zPosData, var_s1, var_f20_2); + + // This puts mixes up y and x diffs like above. + xDiff -= yDiff2; + yDiff -= xDiff2; + zDiff -= zDiff2; + if (var_s0 == 0) { + var_s1 = 0; + dist = sqrtf((xDiff * xDiff) + (yDiff * yDiff) + (zDiff * zDiff)) / updateRateF; + if (dist != 0.0f) { + npc->unk8 *= (speedF / dist); + } + } + } + npc->unk0 = var_f20_2; + xDiff2 += xDiff; + yDiff2 += yDiff; + zDiff2 += zDiff; + xDiff = xDiff2 - npcParentObj->segment.trans.x_position; + yDiff = yDiff2 - npcParentObj->segment.trans.y_position; + if (0) {} + zDiff = zDiff2 - npcParentObj->segment.trans.z_position; + xDiff2 = xDiff; + yDiff2 = yDiff; + zDiff2 = zDiff; + dist = sqrtf((xDiff * xDiff) + (yDiff * yDiff) + (zDiff * zDiff)); + if (dist != 0.0f) { + mag = 255.0 / dist; + xDiff *= mag; + yDiff *= mag; + zDiff *= mag; + } + dist2 = sqrtf((xDiff2 * xDiff2) + (yDiff2 * yDiff2) + (zDiff2 * zDiff2)) / 16; + if (speedF < dist2) { + dist2 = speedF; + } + if (dist2 >= 1.0) { + var_s0 = (arctan2_f(xDiff, zDiff) - (npcParentObj->segment.trans.rotation.y_rotation & 0xFFFF)) - 0x8000; + if (var_s0 > 0x8000) { + var_s0 -= 0xFFFF; + } + if (var_s0 < -0x8000) { + var_s0 += 0xFFFF; + } + npcParentObj->segment.trans.rotation.y_rotation += (var_s0 * (s32) updateRateF) >> 4; + var_s0 = arctan2_f(yDiff, 255.0f) - (npcParentObj->segment.trans.rotation.x_rotation & 0xFFFF); + if (var_s0 > 0x8000) { + var_s0 -= 0xFFFF; + } + if (var_s0 < -0x8000) { + var_s0 += 0xFFFF; + } + npcParentObj->segment.trans.rotation.x_rotation += ((var_s0 * (s32) updateRateF) >> 4); + } + npcParentObj->segment.trans.rotation.z_rotation = 0; + xDiff = sins_f(npcParentObj->segment.trans.rotation.y_rotation + 0x8000) * dist2; + move_object(npcParentObj, xDiff * updateRateF, 0.0f, + coss_f(npcParentObj->segment.trans.rotation.y_rotation + 0x8000) * dist2 * updateRateF); + npcParentObj->segment.trans.y_position = yDiff2; + dist2 = dist2 * updateRateF * 2; + if (var_s1 != 0) { + nodeForward1 = npc->nodeData[3]; + nodeForward2 = npc->nodeData[4]; + npc->nodeData[0] = npc->nodeData[1]; + npc->nodeData[1] = npc->nodeData[2]; + npc->nodeData[2] = npc->nodeData[3]; + npc->nodeData[3] = npc->nodeData[4]; + npc->nodeData[4] = ainode_find_next(nodeForward2 & 0xFF, nodeForward1 & 0xFF, direction); + } + return dist2; + } +} +#else // https://decomp.me/scratch/cfVAM #pragma GLOBAL_ASM("asm/nonmatchings/objects/func_8001C6C4.s") +#endif -s32 ainode_find_next(s32 nodeId, s32 arg1, s32 direction) { +s32 ainode_find_next(s32 nodeId, s32 nextNodeId, s32 direction) { Object *aiNodeObj; LevelObjectEntry_AiNode *entry; Object_AiNode *aiNode; @@ -5780,7 +6523,7 @@ s32 ainode_find_next(s32 nodeId, s32 arg1, s32 direction) { nextIndex = (aiNode->directions[direction] + 1) & 3; for (i = 0; i < 4; i++) { - if (entry->adjacent[nextIndex] != NODE_NONE && arg1 != entry->adjacent[nextIndex]) { + if (entry->adjacent[nextIndex] != NODE_NONE && entry->adjacent[nextIndex] != nextNodeId) { aiNode->directions[direction] = nextIndex; i = 4; // break someCount++; @@ -6374,7 +7117,7 @@ void func_8001E45C(s32 cutsceneID) { if (cutsceneID != gCutsceneID) { gCutsceneID = cutsceneID; gPathUpdateOff = FALSE; - D_8011AE7E = 1; + D_8011AE7E = TRUE; if (get_game_mode() == GAMEMODE_MENU) { set_frame_blackout_timer(); } @@ -6484,8 +7227,8 @@ void func_8001E89C(void) { Object_8001E89C_64 *obj64; // some flag, flips to 1 when loading a new zone - if (D_8011AE01 != 0) { - D_8011AE01 = 0; + if (D_8011AE01 != FALSE) { + D_8011AE01 = FALSE; return; } @@ -6502,8 +7245,130 @@ void func_8001E89C(void) { } } -// https://decomp.me/scratch/G2ZOW +#ifdef NON_EQUIVALENT +void func_8001E93C(void) { + s32 pad[3]; + LevelObjectEntry_OverridePos *overridePos; + Object *obj; + s32 numOfObjs; + s32 pad2; + s32 i; + s32 stopLooping; + s32 sp28; + s16 animActorIndex1; + s16 animActorIndex2; + s32 var_a0; + Object *animObj1; + Object *animObj2; + LevelObjectEntry_Animation *animation1; // Not 100% positive this is an animation yet. + LevelObjectEntry_Animation *animation2; // Not 100% positive this is an animation yet. + + if (D_8011AE7E) { + for (numOfObjs = 0; numOfObjs < D_8011AE78; numOfObjs++) { + obj = D_8011AE74[numOfObjs]; + animation1 = &obj->segment.level_entry->animation; + if (obj->unk64 != NULL && animation1->channel != 20) { + animObj1 = (Object *) obj->unk64; + free_object(animObj1); + obj->unk64 = NULL; + } + } + } + if (D_8011AD3E > 20) { + D_8011AD3E = 0; + } + func_8001E4C4(); + numOfObjs = 0; + for (i = 0; i < gObjectCount; i++) { + if (gObjPtrList[i] != NULL) { + if (!(gObjPtrList[i]->segment.trans.flags & OBJ_FLAGS_PARTICLE)) { + if (gObjPtrList[i]->behaviorId == BHV_OVERRIDE_POS) { + overridePos = &gObjPtrList[i]->segment.level_entry->overridePos; + if (overridePos->cutsceneId == gCutsceneID || + overridePos->cutsceneId == (CUTSCENE_SHERBET_ISLAND_BOSS | CUTSCENE_ADVENTURE_TWO)) { + D_8011ADD8[numOfObjs] = gObjPtrList[i]; + numOfObjs++; + } + } + } + } + } + D_8011AE00 = numOfObjs; + D_8011AE01 = TRUE; + + D_8011AE78 = 0; + numOfObjs = 0; + for (i = gObjectListStart; i < gObjectCount; i++) { + if (gObjPtrList[i] != NULL) { + if (!(gObjPtrList[i]->segment.trans.flags & OBJ_FLAGS_PARTICLE)) { + if (gObjPtrList[i]->behaviorId == BHV_ANIMATION) { + D_8011AE74[numOfObjs] = gObjPtrList[i]; + numOfObjs++; + } + } + } + } + + do { + stopLooping = TRUE; + for (i = 0; i < numOfObjs - 1; i++) { + animObj1 = D_8011AE74[i + 0]; + animObj2 = D_8011AE74[i + 1]; + animation1 = &animObj1->segment.level_entry->animation; + animation2 = &animObj2->segment.level_entry->animation; + animActorIndex1 = animation1->actorIndex; + animActorIndex2 = animation2->actorIndex; + + if (animation1->channel == 20) { + animActorIndex1 -= 400; + } + if (animation2->channel == 20) { + animActorIndex2 -= 400; + } + + if (!gCutsceneID && !gCutsceneID) {} // fake + + if (animActorIndex2 < animActorIndex1) { + D_8011AE74[i] = animObj2; + D_8011AE74[i + 1] = animObj1; + stopLooping = FALSE; + } else if (animActorIndex1 == animActorIndex2) { + if (animation2->order < animation1->order) { + D_8011AE74[i] = animObj2; + D_8011AE74[i + 1] = animObj1; + stopLooping = FALSE; + } else if (animation1->order == animation2->order && (animObj2->properties.animatedObj.action == 1 || + animObj1->properties.animatedObj.action == 2)) { + D_8011AE74[i] = animObj2; + D_8011AE74[i + 1] = animObj1; + stopLooping = FALSE; + } + } + } + } while (stopLooping == FALSE); + + var_a0 = -101; + for (i = 0; i < numOfObjs; i++) { + animation1 = &D_8011AE74[i]->segment.level_entry->animation; + if (animation1->actorIndex != var_a0) { + var_a0 = animation1->actorIndex; + sp28 = 0; + } + animation1->order = sp28++; // It is possible that sp28 could not be initalized? + D_8011AE74[i]->properties.animatedObj.action = 0; + if (!i) {} // fake + } + + D_8011AE78 = numOfObjs; + if (D_8011AE7E) { + func_8001EE74(); + } + D_8011AE7E = FALSE; +} +#else +// https://decomp.me/scratch/OKbBN #pragma GLOBAL_ASM("asm/nonmatchings/objects/func_8001E93C.s") +#endif void func_8001EE74(void) { LevelObjectEntry_Animation *animation; @@ -6612,9 +7477,8 @@ void func_8001F23C(Object *obj, LevelObjectEntry_Animation *animEntry) { obj->unk64 = NULL; newObj = NULL; } - camera = (Object_AnimCamera *) newObj; - if (camera != NULL) { - camera->unk3C = 0; + if (newObj != NULL) { + newObj->segment.level_entry = NULL; obj_init_animcamera(obj, newObj); if (newObj->segment.header->behaviorId == BHV_CAMERA_ANIMATION) { camera = &newObj->unk64->anim_camera; diff --git a/src/objects.h b/src/objects.h index 672aeed5..b265f515 100644 --- a/src/objects.h +++ b/src/objects.h @@ -501,6 +501,7 @@ void race_transition_adventure(s32 updateRate); void func_8001E4C4(void); void racerfx_alloc(s32 numberOfVertices, s32 numberOfTriangles); s32 func_80014B50(s32 arg0, s32 arg1, f32 arg2, u32 arg3); +s32 ainode_find_next(s32 nodeId, s32 nextNodeId, s32 direction); /** * Faster variant of the shading function for objects. @@ -542,5 +543,6 @@ void obj_update(s32 updateRate); void func_800159C8(Object *, Object *); void obj_door_number(ObjectModel *, Object *); s16 func_8001CD28(s32 arg0, s32 arg1, s32 arg2, s32 arg3); // NON MATCHING +f32 func_8001C6C4(Object_NPC *, Object *, f32, f32, s32); #endif diff --git a/src/racer.c b/src/racer.c index f086b27b..cd94b2d7 100644 --- a/src/racer.c +++ b/src/racer.c @@ -1028,23 +1028,327 @@ void func_8004447C(Object *aiRacerObj, Object_Racer *aiRacer, s32 updateRate) { #endif void func_80045128(Object **racerObjs) { - Object_Racer *obj; + Object_Racer *racer; s32 i; for (i = 0; i < 4; i++) { - obj = (Object_Racer *) racerObjs[i]->unk64; - gEggChallengeFlags[i] = obj->lap; - if (obj->eggHudCounter) { + racer = &racerObjs[i]->unk64->racer; + gEggChallengeFlags[i] = racer->lap; + if (racer->eggHudCounter != 0) { gEggChallengeFlags[i] |= 0x40; } - if (obj->held_obj != 0) { + if (racer->held_obj != NULL) { gEggChallengeFlags[i] |= 0x80; } } } -// https://decomp.me/scratch/HSAE4 +#ifdef NON_EQUIVALENT +void func_800452A0(Object *obj, Object_Racer *racer, s32 updateRate) { + Object *curObj; + s32 var_s2_2; + Object_CollectEgg *egg; + s32 someBehaviour0; + Object **objList; + f32 distance; + f32 bestDist; + s32 targetBehaviourID; + s32 racerCount; + s32 someBehaviour1; + s32 objStart; + s32 objCount; + f32 diffX; + f32 diffY; + f32 diffZ; + Object *targetObj; + s32 angleDiffX; + s32 angleDiffY; + s8 *header; + s8 tickCount; + s8 flags; + s8 racerID; + s8 bestTick; + s32 i; + + gCurrentButtonsPressed = 0; + gCurrentButtonsReleased = 0; + gCurrentRacerInput = A_BUTTON; + gCurrentStickX = 0; + gCurrentStickY = 0; + get_racer_objects(&racerCount); + if (racerCount == 4) { + header = get_current_level_header()->unk2A; + if (racer->groundedWheels) { + racer->unk1C6 += updateRate; + if (racer->unk1C6 > 60) { + racer->unk1C6 = 0; + racer->unk1CD = 0; + racer->unk1CE = 3; + } + } else { + racer->unk1C6 = 0; + } + while (racer->unk1CD == 0) { + racerID = PLAYER_COMPUTER; + targetBehaviourID = BHV_NONE; + flags = 0; + bestTick = 0; + for (i = 3; i >= 0; i--) { + flags = gEggChallengeFlags[i]; + tickCount = (flags & 0xF) * 3; + if (flags & 0x40) { + tickCount += 2; + } else if (flags & 0x80) { + tickCount += 1; + } + if (bestTick < tickCount) { + bestTick = tickCount; + flags = i; + } + } + if (racer->unk1CE & 0x40) { + racerID = racer->unk1CE & 0xF; + racer->unk1CD = 8; + racer->unk1CE = 0; + } + if (racer->unk1CE & 0x80) { + if (roll_percent_chance(header[6])) { + var_s2_2 = 2; + } else { + var_s2_2 = 1; + if (roll_percent_chance(header[2]) && cam_get_viewport_layout() == 0) { + flags = 0; + } + } + if (var_s2_2 == 2) { + for (i = 0; i < 4; i++) { + if (racer->racerIndex != i && gEggChallengeFlags[i] & 0x40) { + racerID = i; + } + } + if (racerID == PLAYER_COMPUTER) { + var_s2_2 = 1; + } else { + racer->unk1CD = 7; + } + } + if (var_s2_2 == 1) { + if (racer->balloon_quantity != 0) { + racer->unk1CD = 6; + if (flags != racer->racerIndex) { + racerID = flags; + } else { + racerID = (racer->racerIndex + 1) & 3; + } + } else { + racer->unk1CD = 5; + } + } + racer->unk1CE = 0; + } + if (racer->held_obj != NULL) { + racer->unk1CD = 2; + } + if (racer->unk1CE != 0) { + racer->unk1CD = racer->unk1CE; + } + racer->unk1CE = 0; + if (racer->unk1CD == 0) { + switch (obj->interactObj->pushForce) { + case 1: + racer->unk1CD = 1; + break; + case 2: + racer->unk1CD = 1; + break; + case 3: + racer->unk1CD = 1; + break; + } + } + someBehaviour0 = 0; + if (racer->raceFinished) { + racer->unk1CD = 3; + } + switch (racer->unk1CD) { + case 1: + targetBehaviourID = BHV_COLLECT_EGG; + break; + case 2: + targetBehaviourID = BHV_UNK_5C; + break; + case 3: /* fall through */ + case 7: + targetBehaviourID = BHV_UNK_5C; + someBehaviour0 = 2; + break; + case 4: + racerID = racer->racerIndex; + targetBehaviourID = BHV_UNK_5C; + someBehaviour0 = 2; + break; + case 5: + targetBehaviourID = BHV_WEAPON_BALLOON; + break; + case 6: + targetBehaviourID = BHV_RACER; + break; + case 8: + targetBehaviourID = BHV_COLLECT_EGG; + someBehaviour0 = 1; + break; + } + if (targetBehaviourID != BHV_NONE && targetBehaviourID != BHV_RACER) { + bestDist = 1000000.0f; + objList = objGetObjList(&objStart, &objCount); + targetObj = NULL; + for (objStart = 0; objStart < objCount; objStart++) { + someBehaviour1 = FALSE; + curObj = objList[objStart]; + if (!(curObj->segment.trans.flags & OBJ_FLAGS_PARTICLE) && + targetBehaviourID == curObj->behaviorId) { + switch (targetBehaviourID) { + case BHV_UNK_5C: + if ((someBehaviour0 == curObj->segment.level_entry->bhv_unk_5C.unk8 && + racerID == PLAYER_COMPUTER) || + (racerID == curObj->segment.level_entry->bhv_unk_5C.unk9)) { + someBehaviour1 = TRUE; + } + break; + case BHV_COLLECT_EGG: + egg = &curObj->unk64->egg; + if (someBehaviour0 == 0) { + if (egg->status == EGG_SPAWNED) { + someBehaviour1 = TRUE; + } + } else if (egg->status == EGG_IN_BASE && racerID == egg->racerID) { + someBehaviour1 = TRUE; + } + break; + default: + someBehaviour1 = TRUE; + break; + } + } + if (someBehaviour1) { + diffX = curObj->segment.trans.x_position - obj->segment.trans.x_position; + diffY = curObj->segment.trans.y_position - obj->segment.trans.y_position; + diffZ = curObj->segment.trans.z_position - obj->segment.trans.z_position; + distance = sqrtf((diffX * diffX) + (diffY * diffY) + (diffZ * diffZ)); + if (distance < bestDist) { + bestDist = distance; + targetObj = curObj; + } + } + } + } + if (targetBehaviourID == BHV_RACER && racerID != PLAYER_COMPUTER) { + targetObj = get_racer_object(racerID); + } + racer->unk154 = targetObj; + if (targetObj == NULL) { + racer->unk1CE = 0x80; + racer->unk1CD = 0; + } + } + curObj = racer->unk154; + distance = 0.0f; + if (curObj != NULL) { + if (curObj->behaviorId == BHV_COLLECT_EGG) { + egg = &curObj->unk64->egg; + var_s2_2 = racer->unk1CD; + if (racer->unk1CD == 1 && egg->status != EGG_SPAWNED) { + racer->unk154 = NULL; + } + if (var_s2_2 == 8 && egg->status != EGG_IN_BASE) { + racer->unk154 = NULL; + } + } + diffX = curObj->segment.trans.x_position - obj->segment.trans.x_position; + diffY = curObj->segment.trans.z_position - obj->segment.trans.z_position; + diffZ = curObj->segment.trans.y_position - obj->segment.trans.y_position; + distance = sqrtf((diffX * diffX) + (diffZ * diffZ) + (diffY * diffY)); + if (distance > 0.0) { + angleDiffX = (arctan2_f(diffX, diffY) - 0x8000) & 0xFFFF; + racerCount = angleDiffX; // Fakematch? + angleDiffX -= racer->steerVisualRotation & 0xFFFF; + if (angleDiffX > 0x8000) { + angleDiffX -= 0xFFFF; + } + if (angleDiffX < -0x8000) { + angleDiffX += 0xFFFF; + } + gCurrentStickX = -angleDiffX >> 5; + angleDiffY = (u16) arctan2_f(diffZ, sqrtf((diffX * diffX) + (diffY * diffY))); + if (angleDiffY > 0x8000) { + angleDiffY -= 0xFFFF; + } + if (angleDiffY < -0x8000) { + angleDiffY += 0xFFFF; + } + gCurrentStickY = -angleDiffY >> 7; + } + if (racer->aiSkill < 0) { + gCurrentStickX = 0; + gCurrentStickY = -35; + racer->aiSkill++; + } else if (gCurrentStickX > 60 || gCurrentStickX < -60) { + racer->aiSkill++; + if (racer->aiSkill > 110) { + racer->aiSkill = -40; + } + } else { + racer->aiSkill = 0; + } + } else { + racer->unk1CD = 0; + } + switch (racer->unk1CD) { + case 1: /* fall through */ + case 8: + if (racer->held_obj != NULL) { + racer->unk1CD = 0; + racer->unk1CE = 4; + } + break; + case 2: + if (distance < 100.0) { + racer->unk1CD = 0; + gCurrentButtonsPressed |= Z_TRIG; + } + break; + case 3: /* fall through */ + case 4: + if (distance < 200.0) { + racer->unk1CD = 0; + } + break; + case 5: + if (racer->balloon_quantity != 0) { + racer->unk1CD = 0; + } + break; + case 6: + if (racer->balloon_quantity == 0) { + racer->unk1CD = 0; + } + if (distance < 500.0) { + gCurrentButtonsReleased |= Z_TRIG; + racer->unk1CD = 0; + } + break; + case 7: + if (distance < 200.0 && curObj != NULL) { + racer->unk1CD = 0; + racer->unk1CE = (curObj->segment.level_entry->bhv_unk_5C.unk9 & 3) | 0x40; + } + break; + } + } +} +#else #pragma GLOBAL_ASM("asm/nonmatchings/racer/func_800452A0.s") +#endif #ifdef NON_EQUIVALENT void func_80045C48(Object *obj, Object_Racer *racer, s32 updateRate) { @@ -2227,8 +2531,866 @@ f32 rotate_racer_in_water(Object *obj, Object_Racer *racer, Vec3f *pos, s8 arg3, return velocity; } -// https://decomp.me/scratch/ZIUaE +#ifdef NON_EQUIVALENT +// Plane physics, largest function in DKR. +void func_80049794(s32 updateRate, f32 updateRateF, Object *obj, Object_Racer *racer) { + s32 pad5; + s32 pad7; + f32 spEC; + f32 spE8; + f32 spE4; + f32 spE0; + f32 var_f20; + f32 spD8; + f32 spD4; + f32 spD0; + f32 spCC; + f32 racerThrottle; + f32 racerBrake; + s32 racerMiscAssetIdx; + s32 racerSteerAngle; + s32 var_t0; + s32 var_v0; + s32 var_v1; + s32 var_a0; + f32 var_f0; + s32 temp_t7; + s8 spA3; + s8 spA2; + s8 spA1; + s8 newSpinoutTimer; + f32 segmentZVelocity; + s32 pad2; + f32 var_f2; + s32 xRotationOffset; + s32 zRotationOffset; + s32 i; + f32 racerVelocity; + s32 var_t9; + Object *temp_v0_obj; + f32 var_f6; + s32 racerTrickType; + f32 segmentXVelocity; + f32 sp60[4]; // Should be MtxF, but produces a worse score. + s8 playerObjectMoved; + f32 var_f14; + s32 steerVisualRotationOffset; + Object_Boost *boostObj; + s32 pad3; + s32 pad4; + + if (func_8000E138()) { + updateRateF *= 1.09; + } + playerObjectMoved = FALSE; + if (racer->groundedWheels > 0) { + racer->unk84 = 0.0f; + racer->unk88 = 0.0f; + } + if (racer->unk1FE == 4 && racer->spinout_timer == 0) { + sound_play(SOUND_ZAP4, NULL); + racer->spinout_timer = 20; + } + + spA2 = FALSE; + if (gCurrentPlayerIndex != PLAYER_COMPUTER && racer->vehicleIDPrev != VEHICLE_WIZPIG && gRacerWaveCount != 0) { + // UNMATCHED + for (var_a0 = gRacerWaveCount - 1; + var_a0 >= 0 && gRacerCurrentWave[var_a0]->waveHeight < obj->segment.trans.y_position + 5; var_a0--) {} + + if (var_a0 == gRacerWaveCount - 1) { + var_a0--; + } + + var_f2 = gRacerCurrentWave[var_a0 + 1]->waveHeight; + var_f2 = (obj->segment.trans.y_position - var_f2) - 10; + if (var_f2 > 100.0f) { + racer->drift_direction = 0; + } + // previously var_f0 + racerVelocity = -racer->velocity; + if (racerVelocity < 0.0f) { + racerVelocity = 0.0f; + } + if (var_f2 < 35 && racerVelocity < 8.0) { + spA2 = TRUE; + } + if (racer->drift_direction == 0 && var_f2 < 38 && racerVelocity >= 8.0) { + if ((!racerSteerAngle)) {} + racer->drift_direction = 1; + } + if (racer->trickType == 1 || racer->trickType == -1 || gRacerCurrentWave[var_a0 + 1]->rot.y < 0.4) { + racer->drift_direction = 0; + spA2 = FALSE; + } + if (racer->drift_direction != 0) { + if (racerVelocity < 8.0 || gCurrentStickY < -10) { + racer->drift_direction = 0.0f; + } + racerVelocity -= 8; + if (racerVelocity > 4.0) { + racerVelocity = 4; + } + racerVelocity /= 4; + obj->segment.trans.y_position += ((38 - var_f2) * updateRateF * racerVelocity) / 8; + if (gCurrentStickY > 0) { + gCurrentStickY >>= 1; + } + } + } + D_8011D550 = 0; + +#ifdef FAKEMATCH + // fake match for $f registers + gCurrentCarSteerVel = (var_f0 > 0.0f) * 0; +#else + gCurrentCarSteerVel = 0; +#endif + + D_8011D558 = 0; + spE8 = obj->segment.trans.x_position; + spE4 = obj->segment.trans.y_position; + spE0 = obj->segment.trans.z_position; + if (racer->trickType != 0) { + var_f2 = 4.0; + } else { + var_f2 = 8.0; + } + + var_v0 = gCurrentStickX - racer->steerAngle; + var_v1 = var_v0 * updateRateF / var_f2; + if (var_v0 != 0 && var_v1 == 0) { + if (var_v0 > 0) { + var_v1 = 1; + } + if (var_v0 < 0) { + var_v1 = -1; + } + } + racer->steerAngle += var_v1; + + var_v0 = gCurrentStickY - racer->unk1E8; + var_v1 = var_v0 * updateRateF * 0.0625; + if (var_v0 != 0 && var_v1 == 0) { + if (var_v0 > 0) { + var_v1 = 1; + } + if (var_v0 < 0) { + var_v1 = -1; + } + } + + racer->unk1E8 += var_v1; + handle_racer_items(obj, racer, updateRate); + func_800535C4(obj, racer); + racer_attack_handler_plane(obj, racer); + if (gCurrentPlayerIndex != PLAYER_COMPUTER) { + handle_racer_head_turning(obj, racer, updateRate); + } else { + slowly_reset_head_angle(racer); + } + + if (gCurrentRacerInput & A_BUTTON) { + racer->throttle += updateRateF * 0.01; + if (racer->throttle > 1.0) { + racer->throttle = 1; + } + } else { + racer->throttle -= updateRateF * 0.01; + if (racer->throttle < 0) { + racer->throttle = 0.0f; + } + } + + if (racer->exitObj) { + racer->throttle = 0.5; + } + + racerThrottle = racer->throttle; + if (gCurrentRacerInput & B_BUTTON && (gCurrentStickY < -40 || racer->velocity < 0.0f)) { + racer->brake += updateRateF * 0.016; + if (racer->brake > 1.2) { + racer->brake = 1.2f; + } + if (racer->velocity < -2.0 && racer->groundedWheels >= 2) { + rumble_set(racer->playerIndex, RUMBLE_TYPE_3); + } + } else { + racer->brake -= updateRateF * 0.016; + if (racer->brake < 0.0f) { + racer->brake = 0.0f; + } + } + racerBrake = racer->brake; + gCurrentRacerTransform.rotation.y_rotation = obj->segment.trans.rotation.y_rotation; + gCurrentRacerTransform.rotation.x_rotation = obj->segment.trans.rotation.x_rotation; + gCurrentRacerTransform.rotation.z_rotation = 0; + gCurrentRacerTransform.x_position = 0.0f; + gCurrentRacerTransform.y_position = 0.0f; + gCurrentRacerTransform.z_position = 0.0f; + gCurrentRacerTransform.scale = 1.0f; + mtxf_from_transform((MtxF *) &sp60, &gCurrentRacerTransform); + mtxf_transform_point((MtxF *) &sp60, 0.0f, 0.0f, 1.0f, &racer->ox1, &racer->oy1, &racer->oz1); + mtxf_transform_point((MtxF *) &sp60, 1.0f, 0.0f, 0.0f, &racer->ox3, &racer->oy3, &racer->oz3); + mtxf_transform_point((MtxF *) &sp60, 0.0f, 1.0f, 0.0f, &racer->ox2, &racer->oy2, &racer->oz2); + if (racer->approachTarget == NULL) { + apply_plane_tilt_anim(updateRate, obj, racer); + } + var_v0 = racer->playerIndex; + if (var_v0 == PLAYER_COMPUTER && gCurrentPlayerIndex != PLAYER_COMPUTER) { + gCurrentRacerHandlingStat = 1.4f; + } + var_f20 = sqrtf((obj->segment.x_velocity * obj->segment.x_velocity) + + (obj->segment.z_velocity * obj->segment.z_velocity) + + (obj->segment.y_velocity * obj->segment.y_velocity)) - + 2.0; + if (racer->vehicleID >= VEHICLE_BOSSES) { + var_f20 = ((var_f20 - 2.0) / 2.0); + } + if (var_f20 < 0) { + var_f20 = 0; + } + if (var_f20 > 4.0) { + var_f20 = 4; + } + spA3 = FALSE; + // This line (or somewhere here about) seems to be culprit as it incorrectly uses $f12 instead of $f2 + // This may or may not cause $20 to be swapped with $f2 + var_f20 = 1.0 - (var_f20 / 4.0); + var_f2 = (gCurrentCourseHeight - 50.0) - obj->segment.trans.y_position; + if (racer->trickType < 2 && racer->trickType >= -1 && var_f2 < 0) { + var_f20 += -var_f2 / 25.0; + if (gCurrentStickY < -20) { + gCurrentStickY = -20; + } + if (var_f20 > 2.5) { + var_f20 = 2.5; + } + spA3 = TRUE; + } + var_f14 = racer->velocity; + if (var_f14 < 0) { + var_f14 = -var_f14; + } + + var_f0 = racer->velocity; + if (var_f0 < 0.0f) { + var_f0 = -var_f0; + } + if (var_f14 > (var_f0 + 4)) { + var_f14 = var_f0 + 3; + } + if (var_f14 > 12.0f) { + var_f14 = 12.0f; + } + racerMiscAssetIdx = var_f14; // racerMiscAssetIdx = Integer part of var_f14 + var_f0 = var_f14 - (s32) var_f14; // var_f0 = fractional part of var_f14 + // UNMATCHED + segmentZVelocity = (gCurrentRacerMiscAssetPtr[racerMiscAssetIdx + 1] * var_f0) + + (gCurrentRacerMiscAssetPtr[racerMiscAssetIdx] * (1.0 - var_f0)); + var_f14 = segmentZVelocity; + spD4 = 0.01; + spD0 = 0.02; + spD8 = 0.004; + if (racer->groundedWheels != 0) { + spD4 = 0.02; + spD0 = 0.01f; + i = SURFACE_DEFAULT; + for (var_t0 = 0; var_t0 < 4; var_t0++) { + if (racer->wheel_surfaces[var_t0] != SURFACE_NONE && i < racer->wheel_surfaces[var_t0]) { + i = racer->wheel_surfaces[var_t0]; + } + } + if (i == SURFACE_STONE) { + racer->magnetTimer = 0; + } + if (racer->playerIndex == PLAYER_ONE && i == SURFACE_TAJ_PAD && gCurrentButtonsPressed & Z_TRIG) { + gTajInteractStatus = TAJ_TELEPORT; + } + if (gCurrentRacerInput & B_BUTTON && gCurrentStickY >= -40 && racer->velocity >= -0.5) { + spD8 *= 8; + } + if (racer->boostTimer == 0 && i == SURFACE_ZIP_PAD) { + racer->boostTimer = normalise_time(45); + racer->boostType = BOOST_LARGE; + if (racer->throttleReleased != 0) { + racer->boostType |= EMPOWER_BOOST; + } + racer_play_sound(obj, SOUND_ZIP_PAD_BOOST); + play_random_character_voice(obj, SOUND_VOICE_CHARACTER_POSITIVE, SOUND_NUMBER_OF_RACERS, 0x80 | 0x2); + rumble_set(racer->playerIndex, RUMBLE_TYPE_8); + } + if (racer->vehicleID >= VEHICLE_BOSSES && racer->velocity > -6.0) { + racerThrottle *= 0.6; + racerBrake *= 0.3; + } + racer->trickType = 0; + if (gCurrentRacerInput & B_BUTTON && gNumViewports < 3) { + obj->particleEmittersEnabled = OBJ_EMIT_1 | OBJ_EMIT_2; + } + gCurrentStickY = (1.0 - var_f20) * ((f32) gCurrentStickY); + if (gCurrentStickY > 0) { + gCurrentStickY = 0; + } + } + var_t0 = 0; + if (spA3 == FALSE) { + var_t0 = (var_f20 * 4608); + } + if (racer->vehicleID > VEHICLE_BOSSES) { + var_t0 = 0; + } + if (racer->vehicleID == VEHICLE_CARPET) { + var_f20 = 0.0; + var_t0 = 0; + } + apply_vehicle_rotation_offset(racer, updateRate, 0, var_t0, 0); + if (racer->unk1FE == 0) { + var_f20 = 5.5; + obj->particleEmittersEnabled |= OBJ_EMIT_9; + } + if (racer->unk1FE == 1) { + var_f20 = 2; + } + if (racer->buoyancy != 0.0) { + gCurrentStickY = -60; + var_f2 = racer->buoyancy - 20.0f; + if (var_f2 < 0.0) { + var_f2 = 0; + } + var_f20 = -1 - (var_f2 / 10); + if (var_f20 < -4.0) { + var_f20 = -4; + } + } + if (gRaceStartTimer != 0) { + var_f20 = 1; + } + if (racer->vehicleIDPrev == VEHICLE_WIZPIG) { + if (obj->segment.object.animationID < 3) { + var_f20 = 4.0f; + } else { + var_f20 = 0.0f; + } + } + var_f20 *= gCurrentRacerWeightStat; + obj->segment.y_velocity -= var_f20; + if (racer->zipperDirCorrection != 0 && racer->spinout_timer == 0) { + racer->magnetTimer = 0; + racer->spinout_timer = 0; + racer->trickType = 0; + steerVisualRotationOffset = + racer->zipperObj->segment.trans.rotation.y_rotation - (racer->steerVisualRotation & 0xFFFF); + if (steerVisualRotationOffset > 0x8000) { + steerVisualRotationOffset -= 0xFFFF; + } + if (steerVisualRotationOffset < -0x8000) { + steerVisualRotationOffset += 0xFFFF; + } + racer->steerVisualRotation += (steerVisualRotationOffset * updateRate) >> 3; + if (((steerVisualRotationOffset < 0x400) && (steerVisualRotationOffset > -0x400)) || + (racer->playerIndex == PLAYER_COMPUTER)) { + if (racer->playerIndex != PLAYER_COMPUTER) { + sound_play_spatial(SOUND_ZIP_PAD_BOOST, obj->segment.trans.x_position, obj->segment.trans.y_position, + obj->segment.trans.z_position, NULL); + play_random_character_voice(obj, SOUND_VOICE_CHARACTER_POSITIVE, SOUND_NUMBER_OF_RACERS, 0x80 | 0x2); + } + racer->boostTimer = normalise_time(45); + racer->boostType = BOOST_LARGE; + if (racer->throttleReleased != 0) { + racer->boostType |= EMPOWER_BOOST; + } + rumble_set(racer->playerIndex, 8); + racer->zipperDirCorrection = 0; + } else { + obj->segment.x_velocity *= 0.75; + obj->segment.y_velocity *= 0.75; + obj->segment.z_velocity *= 0.75; + } + } + if (racer->spinout_timer != 0) { + xRotationOffset = racer->x_rotation_offset; + if (racer->unk1F1 == 0) { + racer->unk1F1 = 1; + } + if (racer->groundedWheels != 0 || racer->unk1F1 == 2) { + racer->unk1F1 = 2; + // s0.162 = x_rot_offset + // s0.164 = z_rot_offset + temp_t7 = updateRate << 11; + racer->x_rotation_offset -= temp_t7; + var_t0 = racer->z_rotation_offset; + if ((temp_t7 + var_t0) > 0 && var_t0 <= 0) { + racer->z_rotation_offset = 0; + } else { + racer->z_rotation_offset += temp_t7; + } + if (racer->velocity > -2.0 && racer->groundedWheels >= 3) { + racer->spinout_timer = 0; + } + } else { + racer->z_rotation_offset += updateRate << 11; + } + if (racer->groundedWheels != 0 && ((xRotationOffset > 0x6000 && racer->x_rotation_offset <= 0x6000) || + (xRotationOffset > -0x6000 && racer->x_rotation_offset <= -0x6000) || + (xRotationOffset > 0 && racer->x_rotation_offset <= 0))) { + racer_play_sound(obj, SOUND_CRASH); + if (racer->playerIndex != PLAYER_COMPUTER) { + gCameraObject->shakeMagnitude = 6.0f; + } + } + gCurrentRacerInput &= ~(A_BUTTON | Z_TRIG); + racer->spinout_timer -= updateRate; + racer->boostTimer = 0; + racer->brake = 1; + if (racer->spinout_timer <= 0) { + racer->spinout_timer = 0; + racer->unk1F1 = 0; + } + xRotationOffset = 0xD800 - (obj->segment.trans.rotation.x_rotation & 0xFFFF); + if (xRotationOffset > 0x8000) { + xRotationOffset -= 0xFFFF; + } + if (xRotationOffset < -0x8000) { + xRotationOffset += 0xFFFF; + } + obj->segment.trans.rotation.x_rotation += (xRotationOffset * updateRate) >> 4; + } else { + if (racer->trickType == 1 || racer->trickType == -1) { + var_v1 = racer->x_rotation_vel; + racer->x_rotation_vel = (0, var_v1) + ((racer->trickType * 0x600) * updateRate); + racerThrottle = 1.2f; + if (racer->trickType == 1) { + if (var_v1 > 0) { + racer->unk1D4 = 1; + } + if ((var_v1 < 0) && (racer->x_rotation_vel >= 0) && (racer->unk1D4 != 0)) { + racer->trickType = 0; + racer->x_rotation_vel = 0; + } + } else { + if (var_v1 < 0) { + racer->unk1D4 = 1; + } + if ((var_v1 > 0) && (racer->x_rotation_vel <= 0) && (racer->unk1D4 != 0)) { + racer->trickType = 0; + racer->x_rotation_vel = 0; + } + } + } else if (racer->trickType == 2 || racer->trickType == -2) { + var_v1 = obj->segment.trans.rotation.x_rotation; + var_t0 = var_v1; + if (racer->unk1D5 == 0) { + obj->segment.trans.rotation.x_rotation = + var_v1 + ((racer->trickType * (((0x180 & 0xFFFFFFFF) & 0xFFFFFFFF) & 0xFFFFFFFF)) * updateRate); + } + if (!(gCurrentRacerInput & R_TRIG)) { + racer->unk1D5 = 0; + } + if (racer->unk1D5 > 0) { + racer->unk1D5 -= updateRate; + } else { + racer->unk1D5 = 0; + } + var_v1 = racer->x_rotation_vel; + racer->x_rotation_vel = var_v1 - ((var_v1 * updateRate) >> 4); + obj->segment.x_velocity = racer->velocity * racer->ox1; + obj->segment.y_velocity = racer->oy1 * racer->velocity; + obj->segment.z_velocity = racer->velocity * racer->oz1; + if (racer->trickType == 2) { + if (var_t0 > 0) { + racer->unk1D4 = 1; + } + if (var_t0 < 0) { + if (obj->segment.trans.rotation.x_rotation >= 0) { + if (racer->unk1D4 != 0) { + racer->trickType = 0; + obj->segment.trans.rotation.x_rotation = 0; + racer->boostTimer = normalise_time(0xA); + racer->boostType = BOOST_NONE; + if (racer->throttleReleased != 0) { + racer->boostType |= EMPOWER_BOOST; + } + } + } + } + if (var_t0 > 0x4000 && obj->segment.trans.rotation.x_rotation < -0x4000 && + (gCurrentRacerInput & R_TRIG)) { + racer->unk1D5 = 60; + } + } else { + if (var_t0 < 0) { + racer->unk1D4 = 1; + } + if (var_t0 > 0) { + if (obj->segment.trans.rotation.x_rotation <= 0) { + if (racer->unk1D4 != 0) { + racer->trickType = 0; + obj->segment.trans.rotation.x_rotation = 0; + racer->boostTimer = normalise_time(10); + racer->boostType = BOOST_NONE; + if (racer->throttleReleased != 0) { + racer->boostType |= EMPOWER_BOOST; + } + } + } + } + if (var_t0 < -0x4000 && obj->segment.trans.rotation.x_rotation > 0x4000 && + (gCurrentRacerInput & R_TRIG)) { + racer->unk1D5 = 60; + } + } + } else { + racerSteerAngle = racer->steerAngle; + spA1 = FALSE; + if (racer->groundedWheels != 0) { + if (gCurrentRacerInput & R_TRIG) { + spA1 = TRUE; + } + gCurrentRacerInput &= ~R_TRIG; + } + if (racer->groundedWheels < 2) { + var_v1 = obj->segment.trans.rotation.x_rotation; + xRotationOffset = 0; + var_t0 = racerSteerAngle; + if (obj->segment.trans.rotation.x_rotation > 0x3000) { + xRotationOffset = var_v1 - 0x3000; + if (xRotationOffset > 0x1000) { + xRotationOffset = 0x1000; + } + } else if (var_v1 < -0x3000) { + xRotationOffset = var_v1 + 0x3000; + if (xRotationOffset < -0x1000) { + xRotationOffset = -0x1000; + } + xRotationOffset = -xRotationOffset; + } + var_t0 *= (f32) (1.0 - ((f32) xRotationOffset / 4096)); + if (gCurrentRacerInput & R_TRIG) { + obj->particleEmittersEnabled |= OBJ_EMIT_7 | OBJ_EMIT_8; + racer->x_rotation_vel -= (var_t0 * 16 * updateRate) >> 1; + } + racer->x_rotation_vel -= (var_t0 * updateRate * 20) >> 1; + racer->x_rotation_vel -= (racer->x_rotation_vel * updateRate) >> 4; + if (racer->zipperDirCorrection == 0) { + if (gCurrentPlayerIndex != PLAYER_COMPUTER && racer->raceFinished == FALSE) { + var_t0 = -racer->x_rotation_vel >> 6; + if ((gCurrentRacerInput & R_TRIG) && (gCurrentRacerInput & B_BUTTON)) { + var_t0 *= 2; + } + var_t0 *= gCurrentRacerHandlingStat; + var_v0 = var_t0 * updateRate; + racer->steerVisualRotation -= var_v0 & 0xFFFF; + } else { + var_t0 = gCurrentStickX * 4; + var_v0 = var_t0 * updateRate; + racer->steerVisualRotation -= var_v0 & 0xFFFF; + } + } + } else { + var_v0 = -(racer->x_rotation_vel & 0xFFFF); + if (var_v0 > 0x8000) { + var_v0 -= 0xFFFF; + } + if (var_v0 < -0x8000) { + var_v0 += 0xFFFF; + } + racer->x_rotation_vel += (var_v0 * updateRate) >> 4; + if (gCurrentRacerInput & R_TRIG) { + var_t0 = racerSteerAngle * 6; + } else { + var_t0 = racerSteerAngle * 4; + } + racer->steerVisualRotation -= (var_t0 * updateRate) & 0xFFFF; + } + if (!(gCurrentRacerInput & R_TRIG) || racer->groundedWheels == 0 || racer->zipperDirCorrection != 0) { + var_f20 = racer->velocity * var_t0 * 0.00015; + obj->segment.x_velocity -= racer->ox3 * var_f20; + obj->segment.y_velocity -= racer->oy3 * var_f20; + obj->segment.z_velocity -= racer->oz3 * var_f20; + } + + var_t0 = gCurrentStickY; + if (gCurrentPlayerIndex != PLAYER_COMPUTER && racer->raceFinished == FALSE) { + var_t0 = racer->unk1E8; + } + + var_f2 = -racer->velocity; + if (var_f2 < 4.0) { + var_f2 = 4.0f; + } + if (var_f2 > 14.0) { + var_f2 = 14.0f; + } + var_f2 /= 7.0; + var_t0 *= var_f2; + + // Note: The following if/else has messed up t registers + if (!(gCurrentRacerInput & R_TRIG)) { + obj->segment.trans.rotation.x_rotation -= (obj->segment.trans.rotation.x_rotation * updateRate) >> 4; + obj->segment.trans.rotation.x_rotation -= ((var_t0 >> 1) * 19 * updateRate) >> 1; + } else { + obj->segment.trans.rotation.x_rotation -= (obj->segment.trans.rotation.x_rotation * updateRate) >> 4; + obj->segment.trans.rotation.x_rotation -= ((var_t0 >> 1) * 30 * updateRate) >> 1; + } + + if (racer->tappedR) { + racer->tappedR = FALSE; + if (racer->groundedWheels == 0 && racer->velocity < -6.5 && racer->waterTimer == 0) { + if (gCurrentStickX > 40) { + racer->trickType = -1; + } + if (gCurrentStickX < -40) { + racer->trickType = 1; + } + if (gCurrentStickY > 40) { + racer->trickType = -2; + } else if (racer->trickType == 0) { + racer->trickType = 2; + } + racer->unk1D4 = 0; + racer->unk1D5 = 0; + } + } + } + } + if (gCurrentPlayerIndex != PLAYER_COMPUTER && racer->velocity < -4.0f) { + if ((obj->particleEmittersEnabled & (OBJ_EMIT_7 | OBJ_EMIT_8)) != (OBJ_EMIT_7 | OBJ_EMIT_8)) { + obj->particleEmittersEnabled |= OBJ_EMIT_3 | OBJ_EMIT_4; + } + } + // This line looks unmatched + var_f14 = (var_f14 * handle_racer_top_speed(obj, racer)) * 1.8; + if (racer->boostTimer > 0) { + if (gRaceStartTimer == 0) { + racer->throttle = 1; + var_f14 = 2.0f; + racer->boostTimer -= updateRate; + obj->particleEmittersEnabled |= OBJ_EMIT_7 | OBJ_EMIT_8; + } + } else { + racer->boostTimer = 0; + } + if (racer->zipperDirCorrection == 0 && gRaceStartTimer == 0) { + if (racer->groundedWheels == 0 && racerThrottle < 0.4 && racer->vehicleID != VEHICLE_CARPET) { + racerThrottle = 0.4f; + } + var_f0 = racerThrottle * var_f14; + obj->segment.x_velocity -= racer->ox1 * var_f0; + obj->segment.y_velocity -= racer->oy1 * var_f0; + obj->segment.z_velocity -= racer->oz1 * var_f0; + if (racer->groundedWheels >= 3 || racer->velocity < 1.0 || racer->vehicleID == VEHICLE_CARPET) { + if (racer->groundedWheels == 0) { + racerBrake /= 2; + } + racerBrake *= var_f14 / 2; + obj->segment.x_velocity += racer->ox1 * racerBrake; + obj->segment.y_velocity += racer->oy1 * racerBrake; + obj->segment.z_velocity += racer->oz1 * racerBrake; + } + spEC = racer->velocity * racer->velocity; + if (racer->velocity < 0.0f) { + spEC = -spEC; + } + if (spEC < 1.0f && !(gCurrentRacerInput & A_BUTTON)) { + var_f20 = racer->velocity * spD8 * 8.0f; + } else { + var_f20 = spEC * spD8; + } + obj->segment.x_velocity -= racer->ox1 * var_f20; + obj->segment.y_velocity -= racer->oy1 * var_f20; + obj->segment.z_velocity -= racer->oz1 * var_f20; + var_f20 = racer->lateral_velocity * racer->lateral_velocity * spD4; + if (racer->lateral_velocity < 0) { + var_f20 = -var_f20; + } + var_f20 += (racer->lateral_velocity * spD4 * 4.0f); + obj->segment.x_velocity -= racer->ox3 * var_f20; + obj->segment.y_velocity -= racer->oy3 * var_f20; + obj->segment.z_velocity -= racer->oz3 * var_f20; + if (racer->trickType == 1 || racer->trickType == -1) { + spEC = racer->velocity * 0.0588235 * 1.5; + var_f20 = coss_f(racer->x_rotation_vel) * spEC * racer->trickType; + if (racer->x_rotation_vel > 0x4000 || racer->x_rotation_vel < -0x4000) { + var_f20 *= 2; + } + obj->segment.x_velocity -= racer->ox3 * var_f20; + obj->segment.y_velocity -= racer->oy3 * var_f20; + obj->segment.z_velocity -= racer->oz3 * var_f20; + + var_f20 = sins_f(racer->x_rotation_vel) * spEC * racer->trickType * 1.5; + obj->segment.x_velocity -= racer->ox2 * var_f20; + obj->segment.y_velocity -= racer->oy2 * var_f20; + obj->segment.z_velocity -= racer->oz2 * var_f20; + } + var_f20 = racer->unk34 * racer->unk34 * spD0; + if (racer->unk34 < 0.0f) { + var_f20 = -var_f20; + } + var_f20 += 4.0f * (racer->unk34 * spD0); + obj->segment.x_velocity -= racer->ox2 * var_f20; + obj->segment.y_velocity -= racer->oy2 * var_f20; + obj->segment.z_velocity -= racer->oz2 * var_f20; + + racer->forwardVel -= (racer->forwardVel + (racer->velocity * 0.05)) * 0.125; + } + racer->unk10C = 0; + racer->y_rotation_vel += (gCurrentCarSteerVel - racer->y_rotation_vel) >> 3; + obj->segment.trans.rotation.y_rotation = racer->steerVisualRotation + racer->y_rotation_vel; + racer->z_rotation_vel += (D_8011D558 - racer->z_rotation_vel) >> 3; + obj->segment.trans.rotation.z_rotation = racer->x_rotation_vel + racer->z_rotation_vel; + if (racer->magnetTimer != 0) { + obj->segment.x_velocity = gRacerMagnetVelX; + obj->segment.z_velocity = gRacerMagnetVelZ; + } + if (racer->approachTarget == NULL) { + var_f20 = obj->segment.x_velocity; + spEC = obj->segment.z_velocity; + if (racer->unk1D2 != 0) { + var_f20 += racer->unk11C * 0.5; + spEC += racer->unk120 * 0.5; + } + if (gRacerInputBlocked) { + if (var_f20 > 0.5 || var_f20 < -0.5) { + var_f20 *= 0.65; + } else { + var_f20 = 0.0f; + } + if (spEC > 0.5 || spEC < -0.5) { + spEC *= 0.65; + } else { + spEC = 0.0f; + } + } else { + var_f20 += racer->unk84; + spEC += racer->unk88; + } + if (move_object(obj, var_f20 * updateRateF, obj->segment.y_velocity * updateRateF, spEC * updateRateF) && + gCurrentPlayerIndex != PLAYER_COMPUTER) { + playerObjectMoved = TRUE; + } + } else { + racer_approach_object(obj, racer, updateRateF); + } + var_t0 = racer->groundedWheels; + if (gCurrentPlayerIndex == PLAYER_COMPUTER) { + if (racer->vehicleIDPrev != VEHICLE_ROCKET || gRaceStartTimer != 0) { + onscreen_ai_racer_physics(obj, racer, updateRate); + } else { + racer->groundedWheels = 0; + racer->unk1E3 = 0; + } + } else { + func_80054FD0(obj, racer, updateRate); + } + if (var_t0 == 0 && racer->groundedWheels != 0 && racer->spinout_timer != 0) { + racer_play_sound(obj, SOUND_CRASH); + if (racer->playerIndex != PLAYER_COMPUTER) { + gCameraObject->shakeMagnitude = 6.0f; + } + } + if (racer->unk1D2 != 0) { + racer->unk1D2 -= updateRate; + if (racer->unk1D2 < 0) { + racer->unk1D2 = 0; + } + } else { + var_f0 = 1.0f / updateRateF; + var_f20 = (obj->segment.trans.x_position - spE8 - D_8011D548) * var_f0; + obj->segment.y_velocity = (obj->segment.trans.y_position - spE4) * var_f0; + spEC = (obj->segment.trans.z_position - spE0 - D_8011D54C) * var_f0; + } + if (gRaceStartTimer == 100) { + obj->segment.y_velocity = -5.0f; + } + obj->segment.x_velocity = var_f20; + obj->segment.z_velocity = spEC; + gCurrentRacerTransform.rotation.y_rotation = -obj->segment.trans.rotation.y_rotation; + gCurrentRacerTransform.rotation.x_rotation = -obj->segment.trans.rotation.x_rotation; + gCurrentRacerTransform.rotation.z_rotation = 0; + gCurrentRacerTransform.x_position = 0.0f; + gCurrentRacerTransform.y_position = 0.0f; + gCurrentRacerTransform.z_position = 0.0f; + gCurrentRacerTransform.scale = 1.0f; + mtxf_from_inverse_transform((MtxF *) &sp60, &gCurrentRacerTransform); + mtxf_transform_point((MtxF *) &sp60, obj->segment.x_velocity, obj->segment.y_velocity, obj->segment.z_velocity, + &racer->lateral_velocity, &racer->unk34, &racer->velocity); + if (obj->unk60 != NULL && obj->unk60->unk0 >= 3) { + temp_v0_obj = obj->unk60->unk4[2]; + temp_v0_obj->segment.trans.rotation.y_rotation = 0x4000; + temp_v0_obj->segment.object.modelIndex += 1; + if (temp_v0_obj->segment.object.modelIndex == temp_v0_obj->segment.header->numberOfModelIds) { + temp_v0_obj->segment.object.modelIndex = 0; + } + } + if (obj->unk60 != NULL && obj->unk60->unk0 >= 3) { + if (racer->groundedWheels != 0 || spA2 != FALSE) { + temp_v0_obj = obj->unk60->unk4[0]; + if (temp_v0_obj->segment.trans.y_position > 0.0f) { + temp_v0_obj->segment.trans.y_position = temp_v0_obj->segment.trans.y_position - 2.0; + } else { + temp_v0_obj->segment.trans.y_position = 0.0f; + } + temp_v0_obj->segment.trans.flags &= ~OBJ_FLAGS_INVISIBLE; + temp_v0_obj = obj->unk60->unk4[1]; + if (temp_v0_obj->segment.trans.y_position > 0.0f) { + temp_v0_obj->segment.trans.y_position = temp_v0_obj->segment.trans.y_position - 2.0; + } else { + temp_v0_obj->segment.trans.y_position = 0.0f; + } + temp_v0_obj->segment.trans.flags &= ~OBJ_FLAGS_INVISIBLE; + } else { + temp_v0_obj = obj->unk60->unk4[0]; + if (temp_v0_obj->segment.trans.y_position < 20.0f) { + temp_v0_obj->segment.trans.y_position = temp_v0_obj->segment.trans.y_position + 1.0f; + } else { + temp_v0_obj->segment.trans.flags |= OBJ_FLAGS_INVISIBLE; + } + temp_v0_obj = obj->unk60->unk4[1]; + if (temp_v0_obj->segment.trans.y_position < 20.0f) { + temp_v0_obj->segment.trans.y_position = temp_v0_obj->segment.trans.y_position + 1.0f; + } else { + temp_v0_obj->segment.trans.flags |= OBJ_FLAGS_INVISIBLE; + } + } + } + if (gCurrentPlayerIndex != PLAYER_COMPUTER && racer->boostTimer == 0 && gNumViewports < 2) { + boostObj = (Object_Boost *) get_misc_asset(ASSET_MISC_20); + boostObj = &boostObj[racer->racerIndex]; + var_t0 = ((racer->boostType & EMPOWER_BOOST) >> 2) + 9; + if (var_t0 >= 10) { + if (boostObj->unk70 > 0 || boostObj->unk74 > 0.0) { + obj->particleEmittersEnabled |= 1 << var_t0; + } + } else { + if (boostObj->unk70 == 2 && boostObj->unk74 < 0.5) { + obj->particleEmittersEnabled |= 1 << var_t0; + } else if (boostObj->unk70 < 2 && boostObj->unk74 > 0.0f) { + obj->particleEmittersEnabled |= 1 << var_t0; + } + } + } + if (gCurrentPlayerIndex == PLAYER_COMPUTER) { + obj->particleEmittersEnabled = OBJ_EMIT_NONE; + } + if (racer->unk201 == 0) { + obj->particleEmittersEnabled = OBJ_EMIT_NONE; + } + if (racer->vehicleIDPrev < VEHICLE_BOSSES) { + update_vehicle_particles(obj, updateRate); + } + if (spA1 != FALSE) { + gCurrentRacerInput |= R_TRIG; + } + second_racer_camera_update(obj, racer, 1, updateRateF); + if (playerObjectMoved != FALSE) { + func_800230D0(obj, racer); + } +} +#else +// https://decomp.me/scratch/SlvtN #pragma GLOBAL_ASM("asm/nonmatchings/racer/func_80049794.s") +#endif /** * When turning left and right in a plane, apply the tilting animation to the character. @@ -2529,8 +3691,260 @@ void update_camera_plane(f32 updateRate, Object *obj, Object_Racer *racer) { #pragma GLOBAL_ASM("asm/nonmatchings/racer/update_camera_plane.s") #endif -// https://decomp.me/scratch/yfGqf +#ifdef NON_EQUIVALENT +// Handles loop de loops +void func_8004CC20(s32 updateRate, f32 updateRateF, Object *racerObj, Object_Racer *racer) { + s32 animFrame; + s32 moveObjResult; + f32 curYPos; + Object *new_var; + Object *obj; + Object **nodes; + s32 var_a2; + f32 prevXPos; + f32 prevYPos; + f32 prevZPos; + s32 steerAngle; // sp90 + f32 xDiff; + f32 zDiff; + f32 yDiff; + s32 var_v0; + s32 var_v1; + f32 temp; + f32 temp2; + f32 temp3; + f32 temp4; + MtxF mtx; // sp48 + f32 var_f0; + f32 var_f2; + s8 objectMoved; + + objectMoved = FALSE; + racer->shieldTimer = 0; + racer->shieldType = 0; + if (racer->shieldSoundMask != NULL) { + audspat_point_stop(racer->shieldSoundMask); + racer->shieldSoundMask = NULL; + } + if (racer->boostTimer == 0) { + racer->boostTimer = 8; + racer_play_sound(racerObj, SOUND_ZIP_PAD_BOOST); + } + if (racer->boostTimer < 4) { + racer->boostTimer = 4; + } + racer->boostType = BOOST_NONE; + func_8002ACC8(2); + D_8011D550 = 0; + gCurrentCarSteerVel = 0; + D_8011D558 = 0; + prevXPos = racerObj->segment.trans.x_position; + prevYPos = racerObj->segment.trans.y_position; + prevZPos = racerObj->segment.trans.z_position; + var_v1 = gCurrentStickX - racer->steerAngle; + var_a2 = (var_v1 * updateRate) >> 4; + if (var_v1 != 0 && var_a2 == 0) { + if (var_v1 > 0) { + var_a2 = 1; + } + if (var_v1 < 0) { + var_a2 = -1; + } + } + racer->steerAngle += var_a2; + var_v1 = gCurrentStickY - racer->unk1E8; + var_a2 = (var_v1 * updateRate) >> 4; + if (var_v1 != 0 && var_a2 == 0) { + if (var_v1 > 0) { + var_a2 = 1; + } + if (var_v1 < 0) { + var_a2 = -1; + } + } + racer->unk1E8 += var_a2; + racer->y_rotation_offset = 0; + racer->x_rotation_offset = 0; + racer->z_rotation_offset = 0; + func_800575EC(racerObj, racer); + gCurrentRacerTransform.rotation.y_rotation = racerObj->segment.trans.rotation.y_rotation; + gCurrentRacerTransform.rotation.x_rotation = racerObj->segment.trans.rotation.x_rotation; + gCurrentRacerTransform.rotation.z_rotation = racerObj->segment.trans.rotation.z_rotation; + gCurrentRacerTransform.x_position = 0.0f; + gCurrentRacerTransform.y_position = 0.0f; + gCurrentRacerTransform.z_position = 0.0f; + gCurrentRacerTransform.scale = 1.0f; + mtxf_from_transform(&mtx, &gCurrentRacerTransform); + mtxf_transform_point(&mtx, 0.0f, 1.0f, 0.0f, &racer->ox2, &racer->oy2, &racer->oz2); + gCurrentRacerInput = A_BUTTON; + func_800535C4(racerObj, racer); + handle_car_velocity_control(racer); + func_80053750(racerObj, racer, updateRateF); + racerObj->segment.object.animationID = 0; + animFrame = racer->steerAngle >> 1; + animFrame = 40 - animFrame; + if (animFrame < 0) { + animFrame = 0; + } + if (animFrame > 73) { + animFrame = 73; + } + racerObj->segment.animFrame = animFrame; + steerAngle = 10; + if (racer->playerIndex != PLAYER_COMPUTER) { + steerAngle = racer->steerAngle; + } else { + obj = racer->nodeCurrent; + if (obj != NULL) { + xDiff = obj->segment.trans.x_position - racerObj->segment.trans.x_position; + yDiff = obj->segment.trans.y_position - racerObj->segment.trans.y_position; + zDiff = obj->segment.trans.z_position - racerObj->segment.trans.z_position; + if (sqrtf((xDiff * xDiff) + (yDiff * yDiff) + (zDiff * zDiff)) < 200.0) { + nodes = obj->unk64->ai_node.nodeObj; + for (var_v0 = 0; var_v0 < ARRAY_COUNT(obj->unk64->ai_node.nodeObj); var_v0++) { + if (nodes[var_v0] != NULL && racer->challengeMarker != nodes[var_v0]) { + racer->challengeMarker = obj; + racer->nodeCurrent = nodes[var_v0]; + var_v0 = ARRAY_COUNT(obj->unk64->ai_node.nodeObj); + } + } + if (var_v0 != (ARRAY_COUNT(obj->unk64->ai_node.nodeObj) + 1)) { + racer->nodeCurrent = NULL; + } + } else { + temp = -((racer->ox3 * racerObj->segment.trans.x_position) + + (racer->oz3 * racerObj->segment.trans.z_position)); + steerAngle = + ((racer->ox3 * obj->segment.trans.x_position) + (racer->oz3 * obj->segment.trans.z_position)) + + temp; + steerAngle /= 5; + } + } + } + racer->attackType = ATTACK_NONE; + racer->spinout_timer = 0; + var_f0 = racer->velocity; + var_f0 = (steerAngle * var_f0) / 360; + racerObj->segment.x_velocity -= racer->ox3 * var_f0; + racerObj->segment.y_velocity -= racer->oy3 * var_f0; + racerObj->segment.z_velocity -= racer->oz3 * var_f0; + var_f2 = 1.0f; + if (gCurrentPlayerIndex == PLAYER_COMPUTER) { + var_f2 = 1.3f; + } + racer->unk19A += updateRate; + if (racer->unk19A > 600) { + racer->vehicleID = racer->vehicleIDPrev; + racerObj->segment.trans.rotation.x_rotation = 0; + racer->trickType = 0; + if (racer->playerIndex >= 0) { + objectMoved = 1; + } + } + if (racer->groundedWheels == 0) { + var_f2 = 0.1f; + racer->trickType += updateRate; + if (racer->trickType > 60) { + racer->vehicleID = racer->vehicleIDPrev; + racerObj->segment.trans.rotation.x_rotation = 0; + racer->trickType = 0; + } + } else { + racer->trickType = 0; + } + var_v0 = racer->unk198 - (racer->steerVisualRotation & 0xFFFF); + if (var_v0 > 0x8000) { + var_v0 -= 0xFFFF; + } + if (var_v0 < -0x8000) { + var_v0 += 0xFFFF; + } + if (var_v0 > 0x1000 || var_v0 < -0x1000) { + var_f2 = 0.0f; + } + racer->steerVisualRotation += (var_v0 >> 3); + racer->x_rotation_vel = 0; + + racerObj->segment.x_velocity -= racer->ox1 * var_f2; + racerObj->segment.y_velocity -= racer->oy1 * var_f2; + racerObj->segment.z_velocity -= racer->oz1 * var_f2; + racerObj->segment.x_velocity -= racer->ox2 * 1.5; + racerObj->segment.y_velocity -= racer->oy2 * 1.5; + racerObj->segment.z_velocity -= racer->oz2 * 1.5; + + var_f0 = racer->velocity * racer->velocity * 0.002f; + if (racer->velocity < 0.0f) { + var_f0 = -var_f0; + } + racerObj->segment.x_velocity -= racer->ox1 * var_f0; + racerObj->segment.y_velocity -= racer->oy1 * var_f0; + racerObj->segment.z_velocity -= racer->oz1 * var_f0; + + var_f0 = racer->lateral_velocity * racer->lateral_velocity * 0.01f; + if (racer->lateral_velocity < 0.0f) { + var_f0 = -var_f0; + } + racerObj->segment.x_velocity -= racer->ox3 * var_f0; + racerObj->segment.y_velocity -= racer->oy3 * var_f0; + racerObj->segment.z_velocity -= racer->oz3 * var_f0; + var_f0 = racer->unk34 * racer->unk34 * 0.01f; + if (racer->unk34 < 0.0f) { + var_f0 = -var_f0; + } + racerObj->segment.x_velocity -= racer->ox2 * var_f0; + racerObj->segment.y_velocity -= racer->oy2 * var_f0; + racerObj->segment.z_velocity -= racer->oz2 * var_f0; + + racer->unk10C = 0; + racer->y_rotation_vel += ((gCurrentCarSteerVel - racer->y_rotation_vel) >> 3); + racerObj->segment.trans.rotation.y_rotation = racer->steerVisualRotation + racer->y_rotation_vel; + racer->z_rotation_vel += ((D_8011D558 - racer->z_rotation_vel) >> 3); + racerObj->segment.trans.rotation.z_rotation = racer->x_rotation_vel + racer->z_rotation_vel; + temp2 = racerObj->segment.x_velocity; + racer->unk1D2 = 0; + moveObjResult = move_object(racerObj, temp2 * updateRateF, racerObj->segment.y_velocity * updateRateF, + racerObj->segment.z_velocity * updateRateF); + if (moveObjResult && gCurrentPlayerIndex != PLAYER_COMPUTER) { + objectMoved = TRUE; + } + if (gCurrentPlayerIndex == PLAYER_COMPUTER) { + onscreen_ai_racer_physics(racerObj, racer, updateRate); + } else { + func_80054FD0(racerObj, racer, updateRate); + } + // Not sure what to do here. + var_f0 = (racerObj->segment.trans.x_position - prevXPos) * (1 / updateRateF); + temp = (racerObj->segment.trans.y_position - prevYPos) * (1 / updateRateF); + racerObj->segment.x_velocity = var_f0; + racerObj->segment.y_velocity = temp; + var_f0 = (racerObj->segment.trans.z_position - prevZPos) * (1 / updateRateF); + racerObj->segment.z_velocity = var_f0; + gCurrentRacerTransform.rotation.y_rotation = -racerObj->segment.trans.rotation.y_rotation; + gCurrentRacerTransform.rotation.x_rotation = -racerObj->segment.trans.rotation.x_rotation; + gCurrentRacerTransform.rotation.z_rotation = 0; + gCurrentRacerTransform.x_position = 0.0f; + gCurrentRacerTransform.y_position = 0.0f; + gCurrentRacerTransform.z_position = 0.0f; + gCurrentRacerTransform.scale = 1.0f; + mtxf_from_inverse_transform(&mtx, &gCurrentRacerTransform); + mtxf_transform_point(&mtx, racerObj->segment.x_velocity, racerObj->segment.y_velocity, racerObj->segment.z_velocity, + &racer->lateral_velocity, &racer->unk34, &racer->velocity); + second_racer_camera_update(racerObj, racer, CAMERA_LOOP, updateRateF); + if (racerObj->unk60 != NULL && racer->vehicleIDPrev == VEHICLE_CAR && racerObj->unk60->unk0 >= 4) { + obj = racerObj->unk60->unk4[2]; + obj->segment.trans.rotation.y_rotation = 0; + obj = racerObj->unk60->unk4[3]; + obj->segment.trans.rotation.y_rotation = 0; + } + if (objectMoved) { + racer->vehicleID = racer->vehicleIDPrev; + func_800230D0(racerObj, racer); + } +} +#else +// https://decomp.me/scratch/yfGqf - 97.27% #pragma GLOBAL_ASM("asm/nonmatchings/racer/func_8004CC20.s") +#endif /** * Handles the camera movement when the player is on a loop-the-loop. @@ -2649,7 +4063,7 @@ void obj_init_racer(Object *obj, LevelObjectEntry_Racer *racer) { s32 i; unused_8011D53C = 0; - tempRacer = (struct Object_Racer *) obj->unk64; + tempRacer = &obj->unk64->racer; obj->segment.trans.rotation.y_rotation = racer->angleY; obj->segment.trans.rotation.x_rotation = racer->angleX; obj->segment.trans.rotation.z_rotation = racer->angleZ; @@ -2775,7 +4189,7 @@ void update_player_racer(Object *obj, s32 updateRate) { gCurrentSurfaceType = SURFACE_DEFAULT; gRaceStartTimer = get_race_countdown(); updateRateF = updateRate; - tempRacer = (Object_Racer *) obj->unk64; + tempRacer = &obj->unk64->racer; // Cap all of the velocities on the different axes. // Unfortunately, Rareware didn't appear to use a clamp macro here, which would've saved a lot of real estate. if (obj->segment.x_velocity > 50.0) { @@ -4288,10 +5702,10 @@ s32 turn_head_towards_object(Object *obj, Object_Racer *racer, Object *targetObj WRAP(intendedAngle, -0x8000, 0x8000); CLAMP(intendedAngle, -0x3000, 0x3000); racer->headAngleTarget = intendedAngle; - if ((racer->miscAnimCounter & 0x3F) < 0x1F) { + if ((racer->miscAnimCounter & 0x3F) <= 30) { racer->headAngleTarget = 0; } - racer = (struct Object_Racer *) targetObj->unk64; + racer = &targetObj->unk64->racer; intendedAngle = arctan2_f(diffX, diffZ) - (obj->segment.trans.rotation.y_rotation & 0xFFFF); WRAP(intendedAngle, -0x8000, 0x8000); CLAMP(intendedAngle, -0x3000, 0x3000); @@ -5567,10 +6981,10 @@ void handle_racer_items(Object *obj, Object_Racer *racer, UNUSED s32 updateRate) s32 objID; Object *heldObj; Object *intendedTarget; - Object_64 *magnetTarget; + Object_Racer *magnetTarget; f32 objDist; ObjectModel *model; - Object_64 *objData; + Object_Weapon *weapon; f32 velocity; f32 distance; f32 scaleY; @@ -5668,7 +7082,7 @@ void handle_racer_items(Object *obj, Object_Racer *racer, UNUSED s32 updateRate) } if (objDist < distance) { if (weaponID == WEAPON_MAGNET_LEVEL_3 && intendedTarget != NULL) { - magnetTarget = intendedTarget->unk64; + magnetTarget = &intendedTarget->unk64->racer; } racer->magnetTargetObj = intendedTarget; } else { @@ -5768,10 +7182,10 @@ void handle_racer_items(Object *obj, Object_Racer *racer, UNUSED s32 updateRate) racer->magnetTargetObj = NULL; if (racer->playerIndex != PLAYER_COMPUTER) { if (magnetTarget != NULL) { - magnetTarget->racer.magnetLevel3 = TRUE; - magnetTarget->racer.magnetTimer = 120; - magnetTarget->racer.magnetTargetObj = obj; - magnetTarget->racer.magnetModelID = MAGNET_LEVEL3; + magnetTarget->magnetLevel3 = TRUE; + magnetTarget->magnetTimer = 120; + magnetTarget->magnetTargetObj = obj; + magnetTarget->magnetModelID = MAGNET_LEVEL3; } if (racer->raceFinished == FALSE) { rumble_set(racer->playerIndex, RUMBLE_TYPE_15); @@ -5817,13 +7231,13 @@ void handle_racer_items(Object *obj, Object_Racer *racer, UNUSED s32 updateRate) spawnedObj->segment.trans.rotation.x_rotation = 0; } } - objData = spawnedObj->unk64; - objData->weapon.owner = obj; - objData->weapon.target = intendedTarget; - objData->weapon.checkpoint = racer->checkpoint; - objData->weapon.forwardVel = (racer->velocity - velocity); - objData->weapon.weaponID = weaponID; - switch (objData->weapon.weaponID) { + weapon = &spawnedObj->unk64->weapon; + weapon->owner = obj; + weapon->target = intendedTarget; + weapon->checkpoint = racer->checkpoint; + weapon->forwardVel = (racer->velocity - velocity); + weapon->weaponID = weaponID; + switch (weapon->weaponID) { case WEAPON_ROCKET_HOMING: soundID = SOUND_NYOOM2; break; @@ -5967,7 +7381,7 @@ void racer_activate_magnet(Object *obj, Object_Racer *racer, s32 updateRate) { f32 diffX; f32 diffZ; f32 vel; - Object_64 *magnetTarget; + Object_Racer *magnetTarget; racer->magnetTimer -= updateRate; if (racer->magnetTimer < 0) { @@ -5998,8 +7412,8 @@ void racer_activate_magnet(Object *obj, Object_Racer *racer, s32 updateRate) { } diffX /= vel; diffZ /= vel; - magnetTarget = racer->magnetTargetObj->unk64; - vel = -magnetTarget->racer.velocity; + magnetTarget = &racer->magnetTargetObj->unk64->racer; + vel = -magnetTarget->velocity; if (vel < 8.0 && racer->magnetLevel3 == FALSE) { vel = 8.0f; } @@ -6008,7 +7422,7 @@ void racer_activate_magnet(Object *obj, Object_Racer *racer, s32 updateRate) { } gRacerMagnetVelX = (vel + 5.0f) * diffX; gRacerMagnetVelZ = (vel + 5.0f) * diffZ; - if (magnetTarget->racer.shieldTimer && racer->magnetLevel3 == FALSE) { + if (magnetTarget->shieldTimer && racer->magnetLevel3 == FALSE) { racer->magnetTimer = 0; } } @@ -6045,7 +7459,7 @@ void play_random_character_voice(Object *obj, s32 soundID, s32 range, s32 flags) s32 soundIndex; Object_Racer *tempRacer; - tempRacer = (Object_Racer *) obj->unk64; + tempRacer = &obj->unk64->racer; if (tempRacer->exitObj == 0 && (!(flags & 0x80) || gCurrentPlayerIndex != PLAYER_COMPUTER)) { if (flags == 2) { if (tempRacer->soundMask != NULL && soundID != tempRacer->unk2A) { @@ -6239,7 +7653,7 @@ void drop_bananas(Object *obj, Object_Racer *racer, s32 number) { bananaObj = spawn_object(&newObject, 1); if (bananaObj != NULL) { bananaObj->segment.level_entry = NULL; - banana = (Object_Banana *) bananaObj->unk64; + banana = &bananaObj->unk64->banana; banana->droppedVehicleID = racer->vehicleID; bananaObj->segment.x_velocity = racer->ox1 * 2; bananaObj->segment.y_velocity = (0.0f - racer->oy1) + 5.0; @@ -7243,11 +8657,11 @@ void drm_checksum_balloon(void) { * After a timer hits 0, execute the transition. */ void racer_enter_door(Object_Racer *racer, s32 updateRate) { - struct Object_Exit *exit; + Object_Exit *exit; f32 updateRateF; s32 angle; - exit = (struct Object_Exit *) racer->exitObj->unk64; + exit = &racer->exitObj->unk64->exit; racer->playerIndex = PLAYER_COMPUTER; angle = (u16) arctan2_f(exit->directionX, exit->directionZ) - (racer->steerVisualRotation & 0xFFFF); WRAP(angle, -0x8000, 0x8000); diff --git a/src/racer.h b/src/racer.h index 77591de0..f7838c9f 100644 --- a/src/racer.h +++ b/src/racer.h @@ -227,7 +227,7 @@ void update_car_velocity_offground(Object *obj, Object_Racer *racer, s32, f32); s32 func_80017248(void*, s32, s32*, Vec3f*, f32*, f32*, s8* surface); void func_80059208(Object* obj, Object_Racer* racer, s32 updateRate); /* extern */ void func_80049794(s32 updateRate, f32 updateRateF, Object* obj, Object_Racer* racer); /* extern */ -void func_8004CC20(s32 updateRate, f32 updateRateF, Object* obj, Object_Racer* racer); /* extern */ +void func_8004CC20(s32 updateRate, f32 updateRateF, Object *racerObj, Object_Racer *racer); /* extern */ void func_8004447C(Object *aiRacerObj, Object_Racer *aiRacer, s32 updateRate); void func_800452A0(Object *obj, Object_Racer *racer, s32 updateRate); void func_80045C48(Object *obj, Object_Racer *racer, s32 updateRate); diff --git a/src/tracks.c b/src/tracks.c index e4ad8d7a..11fa605e 100644 --- a/src/tracks.c +++ b/src/tracks.c @@ -2369,7 +2369,7 @@ s32 check_if_in_draw_range(Object *obj) { case BHV_HIT_TESTER_2: // animated objects? case BHV_ANIMATED_OBJECT_2: // space ships obj64 = obj->unk64; - obj->segment.object.opacity = obj64->wizpig2.pad0[0x42]; + obj->segment.object.opacity = obj64->animation.unk42; break; case BHV_PARK_WARDEN: case BHV_GOLDEN_BALLOON: diff --git a/src/vehicle_bluey.c b/src/vehicle_bluey.c index 700d8274..a9ee8cf4 100644 --- a/src/vehicle_bluey.c +++ b/src/vehicle_bluey.c @@ -191,7 +191,7 @@ void update_bluey(s32 updateRate, f32 updateRateF, Object *obj, Object_Racer *ra if (obj->segment.object.animationID == ANIM_BLUEY_TURN) { racer->headAngleTarget = 0; } - racer = (Object_Racer *) firstRacerObj->unk64; + racer = &firstRacerObj->unk64->racer; if (obj == firstRacerObj->interactObj->obj && firstRacerObj->interactObj->flags & INTERACT_FLAGS_PUSHING && obj->segment.object.animationID == ANIM_BLUEY_WALK) { racer->attackType = ATTACK_SQUISHED; diff --git a/src/vehicle_bubbler.c b/src/vehicle_bubbler.c index c9417202..3b381e26 100644 --- a/src/vehicle_bubbler.c +++ b/src/vehicle_bubbler.c @@ -167,7 +167,7 @@ void update_bubbler(s32 updateRate, f32 updateRateF, Object *obj, Object_Racer * racer->headAngleTarget >>= 1; } } - racer = (Object_Racer *) firstRacerObj->unk64; + racer = &firstRacerObj->unk64->racer; if (obj == firstRacerObj->interactObj->obj && firstRacerObj->interactObj->flags & INTERACT_FLAGS_PUSHING && obj->segment.object.animationID == ANIM_BUBBLER_MOVE) { racer->attackType = ATTACK_SQUISHED; diff --git a/src/vehicle_rocket.c b/src/vehicle_rocket.c index 5f82936b..5cd7cc92 100644 --- a/src/vehicle_rocket.c +++ b/src/vehicle_rocket.c @@ -134,7 +134,7 @@ void update_rocket(s32 updateRate, f32 updateRateF, Object *obj, Object_Racer *r if (*startTimer != 100) { someObj = racerfx_get_boost(BOOST_DEFAULT); if (someObj != NULL) { - rocket = (Object_WizpigRocket *) someObj->unk64; + rocket = &someObj->unk64->wizpigRocket; someObj->properties.racer.unk0 = 0; if (rocket != NULL) { rocket->unk72 += updateRate; @@ -145,7 +145,7 @@ void update_rocket(s32 updateRate, f32 updateRateF, Object *obj, Object_Racer *r } } firstRacerObj = get_racer_object(PLAYER_ONE); - racer = (Object_Racer *) firstRacerObj->unk64; + racer = &firstRacerObj->unk64->racer; if (obj == firstRacerObj->interactObj->obj && firstRacerObj->interactObj->flags & INTERACT_FLAGS_PUSHING && obj->segment.object.animationID == ANIM_ROCKET_DAMAGE) { racer->attackType = ATTACK_SQUISHED; diff --git a/src/vehicle_smokey.c b/src/vehicle_smokey.c index 8d594f06..c333ed97 100644 --- a/src/vehicle_smokey.c +++ b/src/vehicle_smokey.c @@ -260,7 +260,7 @@ void update_smokey(s32 updateRate, f32 updateRateF, Object *obj, Object_Racer *r racer->headAngleTarget >>= 1; } } - racer = (Object_Racer *) firstRacerObj->unk64; + racer = &firstRacerObj->unk64->racer; if (obj == firstRacerObj->interactObj->obj && firstRacerObj->interactObj->flags & INTERACT_FLAGS_PUSHING && obj->segment.object.animationID == ANIM_SMOKEY_RUN) { racer->attackType = ATTACK_SQUISHED; diff --git a/src/vehicle_tricky.c b/src/vehicle_tricky.c index c5c58206..03df38e4 100644 --- a/src/vehicle_tricky.c +++ b/src/vehicle_tricky.c @@ -193,7 +193,7 @@ void update_tricky(s32 updateRate, f32 updateRateF, Object *obj, Object_Racer *r } } // Record the players height record. Falling 400 units below that will trigger a warp. - racer = (Object_Racer *) firstRacerObj->unk64; + racer = &firstRacerObj->unk64->racer; if (gTrickyRacerPeakHeight < firstRacerObj->segment.trans.y_position) { gTrickyRacerPeakHeight = firstRacerObj->segment.trans.y_position; } diff --git a/src/vehicle_wizpig.c b/src/vehicle_wizpig.c index de395ae6..cdfd84bd 100644 --- a/src/vehicle_wizpig.c +++ b/src/vehicle_wizpig.c @@ -232,7 +232,7 @@ void update_wizpig(s32 updateRate, f32 updateRateF, Object *obj, Object_Racer *r obj_spawn_particle(obj, updateRate); fade_when_near_camera(obj, racer, 40); firstRacerObj = get_racer_object(PLAYER_ONE); - racer = (Object_Racer *) firstRacerObj->unk64; + racer = &firstRacerObj->unk64->racer; if (obj == firstRacerObj->interactObj->obj && firstRacerObj->interactObj->flags & INTERACT_FLAGS_PUSHING && obj->segment.object.animationID == ANIM_WIZPIG_WALK) { racer->attackType = ATTACK_SQUISHED; diff --git a/src/weather.h b/src/weather.h index 170c000c..a42f5a74 100644 --- a/src/weather.h +++ b/src/weather.h @@ -124,6 +124,7 @@ void weather_init(void); void snow_vertices(void); void lensflare_init(Object *); void lensflare_render(Gfx**, Mtx**, Vertex**, Camera*); +void lensflare_override_remove(Object *obj); void weather_reset(s32 weatherType, s32 density, s32 velX, s32 velY, s32 velZ, s32 intensity, s32 opacity); #endif