diff --git a/README.md b/README.md index 17972070..a0f11636 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,9 @@ This repo contains a work-in-progress decompilation of Diddy Kong Racing for the All versions are supported, and the US 1.0 version (SHA1 = 0cb115d8716dbbc2922fda38e533b9fe63bb9670) of the game is the default if not specified. -As of June 17, 2025, this is our current score: +As of June 18, 2025, this is our current score: -    Decomp progress: 92.78% +    Decomp progress: 92.93%     Documentation progress: 59.95% @@ -43,11 +43,11 @@ As of June 17, 2025, this is our current score: To build other versions of the ROM, just specifcy the region and version in the make command. All examples are below: Baserom|REGION|VERSION|Command ---|--|---|- -US 1.0 | US | v77 | `make REGION=US VERSION=v77` -PAL 1.0 | PAL | v77 | `make REGION=PAL VERSION=v77` -JPN 1.0 | JPN | v79 | `make REGION=JPN VERSION=v79` -US 1.1 | US | v80 | `make REGION=US VERSION=v80` -PAL 1.1 | PAL | v80 | `make REGION=PAL VERSION=v80` +US 1.0 | US | v77 | `make REGION=us VERSION=v77` +PAL 1.0 | PAL | v77 | `make REGION=pal VERSION=v77` +JPN 1.0 | JPN | v79 | `make REGION=jpn VERSION=v79` +US 1.1 | US | v80 | `make REGION=us VERSION=v80` +PAL 1.1 | PAL | v80 | `make REGION=pal VERSION=v80` ## Modding If you are modifying the code in the repo, then you should add `NON_MATCHING=1` to the make command. @@ -117,20 +117,20 @@ s32 is_drumstick_unlocked(void) { ``` -As of June 17, 2025, this is our current score: +As of June 18, 2025, this is our current score: ``` ====================================================================== ADVENTURE ONE (ASM -> C Decompilation) - --------------- 92.78% Complete (93.55% NON_MATCHING) ---------------- - # Decompiled functions: 1925 - # GLOBAL_ASM remaining: 25 + --------------- 92.93% Complete (93.71% NON_MATCHING) ---------------- + # Decompiled functions: 1926 + # GLOBAL_ASM remaining: 24 # NON_MATCHING functions: 4 - # NON_EQUIVALENT WIP functions: 21 + # NON_EQUIVALENT WIP functions: 20 ---------------------------- Game Status ----------------------------- Balloons: 44/47, Keys: 4/4, Trophies: 4/5 T.T. Amulets: 4/4, Wizpig Amulets: 4/4 ---------------------------------------------------------------------- - We are collecting silver coins in Darkmoon Caverns. (2/8 silver coins) + We are collecting silver coins in Darkmoon Caverns. (3/8 silver coins) ====================================================================== ADVENTURE TWO (Cleanup & Documentation) -------------------------- 59.95% Complete --------------------------- diff --git a/src/object_functions.c b/src/object_functions.c index e64d4e68..e5637e33 100644 --- a/src/object_functions.c +++ b/src/object_functions.c @@ -1064,7 +1064,7 @@ void obj_loop_timetrialghost(Object *obj, s32 updateRate) { if (get_race_countdown() == 0) { obj->properties.timeTrial.timestamp += updateRate; } - set_ghost_position_and_rotation(obj); + timetrial_ghost_read(obj); obj_spawn_particle(obj, updateRate); someOtherObj = get_racer_object(PLAYER_ONE); someOtherObj64 = &someOtherObj->unk64->unkid58; diff --git a/src/racer.c b/src/racer.c index 2a6a37a1..4b2c690b 100644 --- a/src/racer.c +++ b/src/racer.c @@ -8455,25 +8455,22 @@ s16 timetrial_ghost_full(void) { return gGhostNodeFull[gCurrentGhostIndex]; } -// https://decomp.me/scratch/yMObT -#ifdef NON_EQUIVALENT -// timetrial_ghost_read -s32 set_ghost_position_and_rotation(Object *obj) { - f32 vectorX[4]; - f32 vectorY[4]; - f32 vectorZ[4]; - GhostNode *nextGhostNode; - GhostNode *ghostData; - GhostNode *curGhostNode; - Object_Racer *racer; +s32 timetrial_ghost_read(Object *obj) { f32 catmullX; - f32 commonUnk0f32; - s32 commonUnk0s32; - s32 ghostNodeCount; - s32 ghostDataIndex; - s32 nodeIndex; + s32 temp; + f32 vectorX[3]; s32 rotDiff; - s16 rot; + f32 vectorY[3]; + Object_Racer *racer; + f32 vectorZ[3]; + s32 commonUnk0s32; + s32 ghostDataIndex; + s32 pad_sp58; + s32 nodeIndex; + GhostNode *nextGhostNode; + s32 ghostNodeCount; + GhostNode *curGhostNode; + Object_64 *obj64; s32 i; ghostDataIndex = (gCurrentGhostIndex + 1) & 1; @@ -8481,94 +8478,89 @@ s32 set_ghost_position_and_rotation(Object *obj) { ghostDataIndex = 2; } - commonUnk0f32 = (f32) obj->properties.common.unk0 / 30.0f; + catmullX = (f32) obj->properties.common.unk0 / 30.0f; if (osTvType == OS_TV_TYPE_PAL && ghostDataIndex == 2) { - commonUnk0f32 = ((f32) obj->properties.common.unk0 * 1.2) / 30.0f; + catmullX = ((f32) obj->properties.common.unk0 * 1.2) / 30.0f; } - commonUnk0s32 = commonUnk0f32; // Truncate the float to an integer? + commonUnk0s32 = catmullX; // Truncate the float to an integer? ghostNodeCount = gGhostNodeCount[ghostDataIndex]; if (commonUnk0s32 >= (ghostNodeCount - 2)) { +#if VERSION >= VERSION_79 + obj64 = obj->unk64; + if (obj64->racer.transparency > 0) { + obj64->racer.transparency -= 1; + } +#endif return FALSE; } if (ghostDataIndex != 2 && get_current_map_id() != gGhostMapID) { return FALSE; } - ghostData = gGhostData[ghostDataIndex]; nodeIndex = commonUnk0s32 - 1; - curGhostNode = &ghostData[nodeIndex]; -#define DOUBLE(x) ((x) + (x)) - // This whole loop is a bit of a mystery still... The i < 4 is a complete guess... - for (i = 0; i < 4; i++) { + for (i = 0; i <= ARRAY_COUNT(vectorY); i++) { + curGhostNode = &gGhostData[ghostDataIndex][nodeIndex]; if (nodeIndex == -1) { - vectorX[i] = DOUBLE(ghostData[nodeIndex + 1].x) - ghostData[nodeIndex + 2].x; - vectorY[i] = DOUBLE(ghostData[nodeIndex + 1].y) - ghostData[nodeIndex + 2].y; - vectorZ[i] = DOUBLE(ghostData[nodeIndex + 1].z) - ghostData[nodeIndex + 2].z; + vectorX[i] = ((curGhostNode + 1)->x + (curGhostNode + 1)->x) - (curGhostNode + 2)->x; + curGhostNode++; + vectorY[i] = ((curGhostNode)->y + (curGhostNode)->y) - (curGhostNode + 1)->y; + vectorZ[i] = ((curGhostNode)->z + (curGhostNode)->z) - (curGhostNode + 1)->z; } else if (nodeIndex >= ghostNodeCount) { - vectorX[i] = DOUBLE(ghostData[nodeIndex].x) - ghostData[nodeIndex - 1].x; - vectorY[i] = DOUBLE(ghostData[nodeIndex].y) - ghostData[nodeIndex - 1].y; - vectorZ[i] = DOUBLE(ghostData[nodeIndex].z) - ghostData[nodeIndex - 1].z; + vectorX[i] = (curGhostNode->x + curGhostNode->x) - (curGhostNode - 1)->x; + vectorY[i] = (curGhostNode->y + curGhostNode->y) - (curGhostNode - 1)->y; + vectorZ[i] = (curGhostNode->z + curGhostNode->z) - (curGhostNode - 1)->z; } else { - vectorX[i] = ghostData[nodeIndex].x; - vectorY[i] = ghostData[nodeIndex].y; - vectorZ[i] = ghostData[nodeIndex].z; + vectorX[i] = curGhostNode->x; + vectorY[i] = curGhostNode->y; + vectorZ[i] = curGhostNode->z; } nodeIndex++; - curGhostNode++; } -#undef DOUBLE - catmullX = commonUnk0f32 - commonUnk0s32; + curGhostNode = &gGhostData[ghostDataIndex][commonUnk0s32]; + catmullX -= commonUnk0s32; + nextGhostNode = curGhostNode + 1; obj->segment.trans.x_position = catmull_rom_interpolation(vectorX, 0, catmullX); obj->segment.trans.y_position = catmull_rom_interpolation(vectorY, 0, catmullX); obj->segment.trans.z_position = catmull_rom_interpolation(vectorZ, 0, catmullX); - curGhostNode = &ghostData[commonUnk0s32]; - nextGhostNode = &ghostData[commonUnk0s32 + 1]; - - // It seems important to have a reference to the next ghost node before the first usage of the current one. - if (nextGhostNode) {} - // Y Rotation - rot = curGhostNode->yRotation; - rotDiff = nextGhostNode->yRotation - (rot & 0xFFFF); + rotDiff = nextGhostNode->yRotation - (curGhostNode->yRotation & 0xFFFF); if (rotDiff > 0x8000) { rotDiff -= 0xFFFF; } if (rotDiff < -0x8000) { rotDiff += 0xFFFF; } - obj->segment.trans.rotation.y_rotation = rot + (s32) (rotDiff * (commonUnk0f32 - commonUnk0s32)); + + obj->segment.trans.rotation.y_rotation = curGhostNode->yRotation + (s16) (rotDiff * catmullX); // X Rotation - rot = curGhostNode->xRotation; - rotDiff = nextGhostNode->xRotation - (rot & 0xFFFF); + rotDiff = nextGhostNode->xRotation - (curGhostNode->xRotation & 0xFFFF); if (rotDiff > 0x8000) { rotDiff -= 0xFFFF; } if (rotDiff < -0x8000) { rotDiff += 0xFFFF; } - obj->segment.trans.rotation.x_rotation = rot + (s32) (rotDiff * (commonUnk0f32 - commonUnk0s32)); + obj->segment.trans.rotation.x_rotation = curGhostNode->xRotation + (s16) (rotDiff * catmullX); // Z Rotation - rot = curGhostNode->zRotation; - rotDiff = nextGhostNode->zRotation - (rot & 0xFFFF); + rotDiff = nextGhostNode->zRotation - (curGhostNode->zRotation & 0xFFFF); if (rotDiff > 0x8000) { rotDiff -= 0xFFFF; } if (rotDiff < -0x8000) { rotDiff += 0xFFFF; } - obj->segment.trans.rotation.z_rotation = rot + (s32) (rotDiff * (commonUnk0f32 - commonUnk0s32)); - - if ((catmullX)) {} + obj->segment.trans.rotation.z_rotation = curGhostNode->zRotation + (s16) (rotDiff * catmullX); obj->particleEmittersEnabled = OBJ_EMIT_NONE; obj->segment.object.segmentID = get_level_segment_index_from_position( obj->segment.trans.x_position, obj->segment.trans.y_position, obj->segment.trans.z_position); - if (ghostNodeCount == (commonUnk0s32 + 3)) { + temp = commonUnk0s32 + 3; + if (ghostNodeCount == temp) { racer = &obj->unk64->racer; if (catmullX >= 0.8) { racer->transparency = 0; @@ -8578,9 +8570,6 @@ s32 set_ghost_position_and_rotation(Object *obj) { } return TRUE; } -#else -#pragma GLOBAL_ASM("asm/nonmatchings/racer/set_ghost_position_and_rotation.s") -#endif /** * Blocks the player's movement until the end of their update cycle. diff --git a/src/racer.h b/src/racer.h index b730b86b..17c53586 100644 --- a/src/racer.h +++ b/src/racer.h @@ -222,7 +222,7 @@ void func_80054FD0(Object *racerObj, Object_Racer *racer, s32 updateRate); void func_8004F7F4(s32 updateRate, f32 updateRateF, Object* racerObj, Object_Racer* racer); /* extern */ //Non Matching -s32 set_ghost_position_and_rotation(Object *obj); +s32 timetrial_ghost_read(Object *obj); void update_car_velocity_offground(Object *obj, Object_Racer *racer, s32, f32); s32 func_80017248(Object *obj, s32, s32 *, Vec3f *, f32 *, f32 *, s8 *surface); void func_80059208(Object* obj, Object_Racer* racer, s32 updateRate); /* extern */ diff --git a/src/tracks.c b/src/tracks.c index a240599d..e6a3f8c2 100644 --- a/src/tracks.c +++ b/src/tracks.c @@ -1072,12 +1072,7 @@ s32 void_generate_primitive(f32 *arg0, f32 *arg1, f32 arg2, f32 arg3) { return NULL; } -#ifdef NON_EQUIVALENT -typedef struct Unk80027568_2 { - s32 unk0; - u16 unk4; -} Unk80027568_2; - +#ifdef NON_MATCHING typedef struct Unk80027568_1 { u8 unk0[0x18]; Vec4f *unk18; @@ -1085,25 +1080,33 @@ typedef struct Unk80027568_1 { // https://decomp.me/scratch/duMgr s32 func_80027568(void) { - f32 projectedRacerPos; - f32 projectedCamPos; - f32 temp_f18_2; - f32 var_f16; - f32 scalingFactor; - s32 curViewport; - s32 isNegative; - s32 var_a1; + Unk80027568_1 *var_ra; // spE4 + f32 new_var; s32 ret; s32 var_t4; + f32 projectedRacerPos; + f32 projectedCamPos; + f32 scalingFactor; + f32 var_f14; + s32 numRacers; // spC4 + s32 curViewport; + s32 isNegative; s32 i; - u16 *var_v0_1; - u16 var_v0; Vec4f *vector; - Object **racerGroup; - s32 numRacers; - Unk80027568_1 *var_ra; // spE4 - Object *currentObjRacer; - f32 x, y, z; + s32 j; + f32 var_f18; + f32 temp; + f32 temp2; + f32 temp3; + f32 var_f20; + f32 var_f22; + f32 var_f24; + u16 *var_t2; + Object_64 *obj64; + f32 camXPos; + f32 camYPos; + Object **racerGroup; // sp80 + Object *currentObjRacer; // sp7C racerGroup = get_racer_objects(&numRacers); if (numRacers == 0) { @@ -1116,8 +1119,8 @@ s32 func_80027568(void) { curViewport = get_current_viewport(); currentObjRacer = NULL; for (i = 0; i < numRacers; i++) { - Object_Racer *racer = &racerGroup[i]->unk64->racer; - if (curViewport == racer->playerIndex) { + obj64 = racerGroup[i]->unk64; + if (curViewport == obj64->racer.playerIndex) { currentObjRacer = racerGroup[i]; i = numRacers; // Come on! Just use break! } @@ -1130,50 +1133,55 @@ s32 func_80027568(void) { // bug? var_ra can be undefined? for (var_t4 = 0; var_t4 < D_8011D378 && ret == FALSE; var_t4++) { if ((s32) D_8011D370[var_t4] > 0) { - var_ra = (void *) PHYS_TO_K0(D_8011D370[var_t4]); + var_ra = (Unk80027568_1 *) PHYS_TO_K0(D_8011D370[var_t4]); } else { - vector = &var_ra->unk18[D_8011D370[var_t4][0]]; - projectedCamPos = vector->x * gSceneActiveCamera->trans.x_position + - vector->y * gSceneActiveCamera->trans.y_position + - vector->z * gSceneActiveCamera->trans.z_position + vector->w - 14.0; + var_t2 = D_8011D370[var_t4]; + vector = var_ra->unk18; + vector += var_t2[0]; + new_var = vector->x; + + camXPos = gSceneActiveCamera->trans.x_position; + camYPos = gSceneActiveCamera->trans.y_position; + + projectedCamPos = (((camXPos * new_var) + (vector->y * camYPos) + + (vector->z * gSceneActiveCamera->trans.z_position) + vector->w) - + 14.0); if (projectedCamPos < -0.1) { - projectedRacerPos = vector->x * currentObjRacer->segment.trans.x_position + - vector->y * currentObjRacer->segment.trans.y_position + - vector->z * currentObjRacer->segment.trans.z_position + vector->w; + projectedRacerPos = (currentObjRacer->segment.trans.x_position * new_var) + + (vector->y * currentObjRacer->segment.trans.y_position) + + (vector->z * currentObjRacer->segment.trans.z_position) + vector->w; if (projectedRacerPos >= -0.1) { - ret = TRUE; + var_f20 = (camXPos - currentObjRacer->segment.trans.x_position); + var_f22 = (camYPos - currentObjRacer->segment.trans.y_position); + var_f24 = (gSceneActiveCamera->trans.z_position - currentObjRacer->segment.trans.z_position); if (projectedRacerPos != projectedCamPos) { scalingFactor = projectedRacerPos / (projectedRacerPos - projectedCamPos); } else { scalingFactor = 0.0f; } - for (var_a1 = 0; var_a1 < 3 && ret == TRUE; var_a1++) { - var_v0 = D_8011D370[var_t4][var_a1 + 1]; + + var_f20 = currentObjRacer->segment.trans.x_position + (var_f20 * scalingFactor); + var_f22 = currentObjRacer->segment.trans.y_position + (var_f22 * scalingFactor); + var_f24 = currentObjRacer->segment.trans.z_position + (var_f24 * scalingFactor); + + for (j = 0, ret = TRUE; j < 3 && ret == TRUE; j++) { isNegative = FALSE; - if (var_v0 & 0x8000) { - var_v0 &= 0x7FFF; + curViewport = var_t2[j + 1]; + if (curViewport & 0x8000) { + curViewport &= 0x7FFF; isNegative = TRUE; } - vector = &var_ra->unk18[var_v0]; - var_f16 = - vector->x * - (currentObjRacer->segment.trans.x_position + - (gSceneActiveCamera->trans.x_position - currentObjRacer->segment.trans.x_position) * - scalingFactor) + - vector->y * - (currentObjRacer->segment.trans.y_position + - (gSceneActiveCamera->trans.y_position - currentObjRacer->segment.trans.y_position) * - scalingFactor) + - vector->z * - (currentObjRacer->segment.trans.z_position + - (gSceneActiveCamera->trans.z_position - currentObjRacer->segment.trans.z_position) * - scalingFactor) + - vector->w; + vector = &var_ra->unk18[curViewport]; + temp = vector->x; + temp2 = vector->y; + temp3 = vector->z; + var_f14 = vector->w; + var_f18 = (temp * var_f20) + (temp2 * var_f22) + (temp3 * var_f24) + var_f14; if (isNegative) { - var_f16 = -var_f16; + var_f18 = -var_f18; } - if (var_f16 > 4.0f) { + if (var_f18 > 4.0f) { ret = FALSE; } } diff --git a/ver/symbols/symbol_addrs.jpn.v79.txt b/ver/symbols/symbol_addrs.jpn.v79.txt index 38e7abe2..93727980 100644 --- a/ver/symbols/symbol_addrs.jpn.v79.txt +++ b/ver/symbols/symbol_addrs.jpn.v79.txt @@ -744,7 +744,7 @@ timetrial_free_staff_ghost = 0x80059B5C; timetrial_write_player_ghost = 0x80059B8C; timetrial_ghost_write = 0x80059C00; timetrial_ghost_full = 0x80059E30; -set_ghost_position_and_rotation = 0x80059E50; +timetrial_ghost_read = 0x80059E50; disable_racer_input = 0x8005A3DC; racer_set_dialogue_camera = 0x8005A3EC; drm_checksum_balloon = 0x8005A3FC; diff --git a/ver/symbols/symbol_addrs.pal.v77.txt b/ver/symbols/symbol_addrs.pal.v77.txt index 32118fdf..3995e73e 100644 --- a/ver/symbols/symbol_addrs.pal.v77.txt +++ b/ver/symbols/symbol_addrs.pal.v77.txt @@ -744,7 +744,7 @@ timetrial_free_staff_ghost = 0x80059B4C; timetrial_write_player_ghost = 0x80059B7C; timetrial_ghost_write = 0x80059BF0; timetrial_ghost_full = 0x80059E20; -set_ghost_position_and_rotation = 0x80059E40; +timetrial_ghost_read = 0x80059E40; disable_racer_input = 0x8005A3B0; racer_set_dialogue_camera = 0x8005A3C0; drm_checksum_balloon = 0x8005A3D0; diff --git a/ver/symbols/symbol_addrs.pal.v80.txt b/ver/symbols/symbol_addrs.pal.v80.txt index 75fb44a7..69e2948f 100644 --- a/ver/symbols/symbol_addrs.pal.v80.txt +++ b/ver/symbols/symbol_addrs.pal.v80.txt @@ -732,7 +732,7 @@ timetrial_free_staff_ghost = 0x80059B9C; timetrial_write_player_ghost = 0x80059BCC; timetrial_ghost_write = 0x80059C40; timetrial_ghost_full = 0x80059E70; -set_ghost_position_and_rotation = 0x80059E90; // has a diff from v1 +timetrial_ghost_read = 0x80059E90; // has a diff from v1 disable_racer_input = 0x8005A41C; racer_set_dialogue_camera = 0x8005A42C; drm_checksum_balloon = 0x8005A43C; diff --git a/ver/symbols/symbol_addrs.us.v77.txt b/ver/symbols/symbol_addrs.us.v77.txt index 5b7b9024..a6ad5fe6 100644 --- a/ver/symbols/symbol_addrs.us.v77.txt +++ b/ver/symbols/symbol_addrs.us.v77.txt @@ -744,7 +744,7 @@ timetrial_free_staff_ghost = 0x80059B4C; timetrial_write_player_ghost = 0x80059B7C; timetrial_ghost_write = 0x80059BF0; timetrial_ghost_full = 0x80059E20; -set_ghost_position_and_rotation = 0x80059E40; +timetrial_ghost_read = 0x80059E40; disable_racer_input = 0x8005A3B0; racer_set_dialogue_camera = 0x8005A3C0; drm_checksum_balloon = 0x8005A3D0; diff --git a/ver/symbols/symbol_addrs.us.v80.txt b/ver/symbols/symbol_addrs.us.v80.txt index f4496c9b..d192daea 100644 --- a/ver/symbols/symbol_addrs.us.v80.txt +++ b/ver/symbols/symbol_addrs.us.v80.txt @@ -732,7 +732,7 @@ timetrial_free_staff_ghost = 0x80059B9C; timetrial_write_player_ghost = 0x80059BCC; timetrial_ghost_write = 0x80059C40; timetrial_ghost_full = 0x80059E70; -set_ghost_position_and_rotation = 0x80059E90; // has a diff from v1 +timetrial_ghost_read = 0x80059E90; // has a diff from v1 disable_racer_input = 0x8005A41C; racer_set_dialogue_camera = 0x8005A42C; drm_checksum_balloon = 0x8005A43C;