From 9ed15c88ae97d9d9a951b7d39eb4b5503367e23d Mon Sep 17 00:00:00 2001 From: Greer Guthrie Date: Fri, 14 Aug 2026 01:20:40 -0500 Subject: [PATCH 01/19] Improve particle command interpreter match --- src/sysdolphin/baselib/particle.c | 597 ++++++++++++++++-------------- 1 file changed, 326 insertions(+), 271 deletions(-) diff --git a/src/sysdolphin/baselib/particle.c b/src/sysdolphin/baselib/particle.c index a23d9ab9fd..8c54ed977b 100644 --- a/src/sysdolphin/baselib/particle.c +++ b/src/sysdolphin/baselib/particle.c @@ -612,103 +612,8 @@ s32 hsd_803991D8(HSD_Generator* gen, HSD_JObj* jobj, f32 force, f32 range) return 0; } -static inline void psUpdateParticle(HSD_Particle* pp) -{ - if (pp->kind & Tornado) { - HSD_Generator* gp = pp->gen; - f32 sinA, sinB, cosA, cosB; - f32 R; - f32 d, e, nd, vz; - f32 t0, t1, t2, t3, t4; - - sinA = sinf(pp->grav); - sinB = sinf(pp->fric); - cosA = cosf(pp->grav); - cosB = cosf(pp->fric); - - pp->vel.z += gp->aux.tornado.vel; - - R = gp->radius; - if (R < 0.0F) { - R = -R; - } - { - f32 ang = gp->angle; - if (ang < 0.0F) { - ang = -ang; - } - R = pp->vel.z * tanf(ang) + R; - } - pp->vel.x += gp->grav; - R *= pp->vel.y; - - d = R * cosf(pp->vel.x); - e = R * sinf(pp->vel.x); - nd = -d; - vz = pp->vel.z; - - t0 = vz * sinB; - t1 = e * cosA; - t2 = nd * sinA; - t3 = d * cosB + t0; - t0 = vz * sinA; - t1 = sinB * t2 + t1; - pp->pos.x = gp->pos.x + t3; - t2 = nd * cosA; - t4 = e * sinA; - t1 = cosB * t0 + t1; - t0 = vz * cosA; - t4 = sinB * t2 - t4; - pp->pos.y = gp->pos.y + t1; - t4 = cosB * t0 + t4; - pp->pos.z = gp->pos.z + t4; - } else { - if (pp->kind & 1) { - pp->vel.y -= pp->grav; - } - if (pp->kind & 2) { - pp->vel.x *= pp->fric; - pp->vel.y *= pp->fric; - pp->vel.z *= pp->fric; - } - pp->pos.x += pp->vel.x; - pp->pos.y += pp->vel.y; - pp->pos.z += pp->vel.z; - } - - if (pp->kind & 0x8000) { - s32 jobj_idx = (pp->kind >> 12) & 7; - HSD_JObj* jobj; - HSD_JObj** jobj_slot; - - if (hsd_804D08E8[jobj_idx] == NULL) { - HSD_JObj* new_jobj = HSD_JObjAlloc(); - if (new_jobj != NULL) { - hsd_8039CF4C(jobj_idx + 1, new_jobj); - HSD_JObjUnref(new_jobj); - } - } - - jobj_slot = &hsd_804D08E8[jobj_idx]; - jobj = *jobj_slot; - - if (jobj != NULL) { - HSD_JObjSetupMatrix(jobj); - - jobj = *jobj_slot; - HSD_JObjAddTranslationX(jobj, pp->pos.x - jobj->mtx[0][3]); - - jobj = *jobj_slot; - HSD_JObjAddTranslationY(jobj, pp->pos.y - jobj->mtx[1][3]); - - jobj = *jobj_slot; - HSD_JObjAddTranslationZ(jobj, pp->pos.z - jobj->mtx[2][3]); - } - } -} - -// @TODO: Currently 93.95% match - register allocation differences (stmw -// r20 vs r21), r27/r28 swap, and PC advance codegen patterns +// @TODO: Currently 95.43% match - register allocation differences and +// remaining PC advance codegen patterns void* hsd_8039930C(void* pp_arg, void* prev_arg) { HSD_Particle* pp = pp_arg; @@ -865,33 +770,30 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) case 0x80: /* Set position */ if (opcode & 1) { - u8* _p = pc + 1; - ((u8*) &fval)[0] = pc[0]; - _p += 3; - ((u8*) &fval)[1] = pc[1]; - ((u8*) &fval)[2] = pc[2]; - ((u8*) &fval)[3] = pc[3]; - pc = _p; + u8* p = pc; + fbytes[0] = *p++; + fbytes[1] = *p++; + fbytes[2] = *p++; + fbytes[3] = *p++; + pc = p; pp->pos.x = fval; } if (opcode & 2) { - u8* _p = pc + 1; - ((u8*) &fval)[0] = pc[0]; - _p += 3; - ((u8*) &fval)[1] = pc[1]; - ((u8*) &fval)[2] = pc[2]; - ((u8*) &fval)[3] = pc[3]; - pc = _p; + u8* p = pc; + fbytes[0] = *p++; + fbytes[1] = *p++; + fbytes[2] = *p++; + fbytes[3] = *p++; + pc = p; pp->pos.y = fval; } if (opcode & 4) { - u8* _p = pc + 1; - ((u8*) &fval)[0] = pc[0]; - _p += 3; - ((u8*) &fval)[1] = pc[1]; - ((u8*) &fval)[2] = pc[2]; - ((u8*) &fval)[3] = pc[3]; - pc = _p; + u8* p = pc; + fbytes[0] = *p++; + fbytes[1] = *p++; + fbytes[2] = *p++; + fbytes[3] = *p++; + pc = p; pp->pos.z = fval; } break; @@ -899,27 +801,30 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) case 0x88: /* Add to position */ if (opcode & 1) { - ((u8*) &fval)[0] = pc[0]; - ((u8*) &fval)[1] = pc[1]; - ((u8*) &fval)[2] = pc[2]; - ((u8*) &fval)[3] = pc[3]; - pc += 4; + u8* p = pc; + fbytes[0] = *p++; + fbytes[1] = *p++; + fbytes[2] = *p++; + fbytes[3] = *p++; + pc = p; pp->pos.x += fval; } if (opcode & 2) { - ((u8*) &fval)[0] = pc[0]; - ((u8*) &fval)[1] = pc[1]; - ((u8*) &fval)[2] = pc[2]; - ((u8*) &fval)[3] = pc[3]; - pc += 4; + u8* p = pc; + fbytes[0] = *p++; + fbytes[1] = *p++; + fbytes[2] = *p++; + fbytes[3] = *p++; + pc = p; pp->pos.y += fval; } if (opcode & 4) { - ((u8*) &fval)[0] = pc[0]; - ((u8*) &fval)[1] = pc[1]; - ((u8*) &fval)[2] = pc[2]; - ((u8*) &fval)[3] = pc[3]; - pc += 4; + u8* p = pc; + fbytes[0] = *p++; + fbytes[1] = *p++; + fbytes[2] = *p++; + fbytes[3] = *p++; + pc = p; pp->pos.z += fval; } break; @@ -927,27 +832,30 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) case 0x90: /* Set velocity */ if (opcode & 1) { - ((u8*) &fval)[0] = pc[0]; - ((u8*) &fval)[1] = pc[1]; - ((u8*) &fval)[2] = pc[2]; - ((u8*) &fval)[3] = pc[3]; - pc += 4; + u8* p = pc; + fbytes[0] = *p++; + fbytes[1] = *p++; + fbytes[2] = *p++; + fbytes[3] = *p++; + pc = p; pp->vel.x = fval; } if (opcode & 2) { - ((u8*) &fval)[0] = pc[0]; - ((u8*) &fval)[1] = pc[1]; - ((u8*) &fval)[2] = pc[2]; - ((u8*) &fval)[3] = pc[3]; - pc += 4; + u8* p = pc; + fbytes[0] = *p++; + fbytes[1] = *p++; + fbytes[2] = *p++; + fbytes[3] = *p++; + pc = p; pp->vel.y = fval; } if (opcode & 4) { - ((u8*) &fval)[0] = pc[0]; - ((u8*) &fval)[1] = pc[1]; - ((u8*) &fval)[2] = pc[2]; - ((u8*) &fval)[3] = pc[3]; - pc += 4; + u8* p = pc; + fbytes[0] = *p++; + fbytes[1] = *p++; + fbytes[2] = *p++; + fbytes[3] = *p++; + pc = p; pp->vel.z = fval; } break; @@ -955,27 +863,30 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) case 0x98: /* Add to velocity */ if (opcode & 1) { - ((u8*) &fval)[0] = pc[0]; - ((u8*) &fval)[1] = pc[1]; - ((u8*) &fval)[2] = pc[2]; - ((u8*) &fval)[3] = pc[3]; - pc += 4; + u8* p = pc; + fbytes[0] = *p++; + fbytes[1] = *p++; + fbytes[2] = *p++; + fbytes[3] = *p++; + pc = p; pp->vel.x += fval; } if (opcode & 2) { - ((u8*) &fval)[0] = pc[0]; - ((u8*) &fval)[1] = pc[1]; - ((u8*) &fval)[2] = pc[2]; - ((u8*) &fval)[3] = pc[3]; - pc += 4; + u8* p = pc; + fbytes[0] = *p++; + fbytes[1] = *p++; + fbytes[2] = *p++; + fbytes[3] = *p++; + pc = p; pp->vel.y += fval; } if (opcode & 4) { - ((u8*) &fval)[0] = pc[0]; - ((u8*) &fval)[1] = pc[1]; - ((u8*) &fval)[2] = pc[2]; - ((u8*) &fval)[3] = pc[3]; - pc += 4; + u8* p = pc; + fbytes[0] = *p++; + fbytes[1] = *p++; + fbytes[2] = *p++; + fbytes[3] = *p++; + pc = p; pp->vel.z += fval; } break; @@ -991,11 +902,14 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) pp->sizeCount = cnt; } } - ((u8*) &fval)[0] = pc[0]; - ((u8*) &fval)[1] = pc[1]; - ((u8*) &fval)[2] = pc[2]; - ((u8*) &fval)[3] = pc[3]; - pc += 4; + { + u8* p = pc; + fbytes[0] = *p++; + fbytes[1] = *p++; + fbytes[2] = *p++; + fbytes[3] = *p++; + pc = p; + } pp->sizeTarget = fval; if (pp->sizeCount == 0) { pp->size = pp->sizeTarget; @@ -1010,11 +924,14 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) case 0xA2: /* Set gravity */ - ((u8*) &fval)[0] = pc[0]; - ((u8*) &fval)[1] = pc[1]; - ((u8*) &fval)[2] = pc[2]; - ((u8*) &fval)[3] = pc[3]; - pc += 4; + { + u8* p = pc; + fbytes[0] = *p++; + fbytes[1] = *p++; + fbytes[2] = *p++; + fbytes[3] = *p++; + pc = p; + } pp->grav = fval; if (pp->grav == 0.0F) { pp->kind &= ~1; @@ -1025,11 +942,14 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) case 0xA3: /* Set friction */ - ((u8*) &fval)[0] = pc[0]; - ((u8*) &fval)[1] = pc[1]; - ((u8*) &fval)[2] = pc[2]; - ((u8*) &fval)[3] = pc[3]; - pc += 4; + { + u8* p = pc; + fbytes[0] = *p++; + fbytes[1] = *p++; + fbytes[2] = *p++; + fbytes[3] = *p++; + pc = p; + } pp->fric = fval; if (pp->fric == 1.0F) { pp->kind &= ~2; @@ -1387,11 +1307,14 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) case 0xA9: /* Call force function with float parameter */ - ((u8*) &fval)[0] = pc[0]; - ((u8*) &fval)[1] = pc[1]; - ((u8*) &fval)[2] = pc[2]; - ((u8*) &fval)[3] = pc[3]; - pc += 4; + { + u8* p = pc; + fbytes[0] = *p++; + fbytes[1] = *p++; + fbytes[2] = *p++; + fbytes[3] = *p++; + pc = p; + } hsd_80398F8C(pp, fval); break; @@ -1463,11 +1386,14 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) case 0xAB: /* Velocity scale */ - ((u8*) &fval)[0] = pc[0]; - ((u8*) &fval)[1] = pc[1]; - ((u8*) &fval)[2] = pc[2]; - ((u8*) &fval)[3] = pc[3]; - pc += 4; + { + u8* p = pc; + fbytes[0] = *p++; + fbytes[1] = *p++; + fbytes[2] = *p++; + fbytes[3] = *p++; + pc = p; + } pp->vel.x *= fval; pp->vel.y *= fval; pp->vel.z *= fval; @@ -1485,17 +1411,22 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) pp->sizeCount = cnt; } } - ((u8*) &fval)[0] = pc[0]; - ((u8*) &fval)[1] = pc[1]; - ((u8*) &fval)[2] = pc[2]; - ((u8*) &fval)[3] = pc[3]; - pp->sizeTarget = fval; - ((u8*) &fval)[0] = pc[4]; - ((u8*) &fval)[1] = pc[5]; - ((u8*) &fval)[2] = pc[6]; - ((u8*) &fval)[3] = pc[7]; - range = fval; - pc += 8; + { + u8* p = pc + 1; + u8* next = p + 4; + fbytes[0] = pc[0]; + next += 3; + fbytes[1] = pc[1]; + fbytes[2] = pc[2]; + fbytes[3] = pc[3]; + pp->sizeTarget = fval; + fbytes[0] = pc[4]; + fbytes[1] = pc[5]; + fbytes[2] = pc[6]; + fbytes[3] = pc[7]; + range = fval; + pc = next; + } pp->sizeTarget += range * HSD_Randf(); if (pp->sizeCount == 0) { pp->size = pp->sizeTarget; @@ -1627,11 +1558,14 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) pp->rotateCount = cnt; } } - ((u8*) &fval)[0] = pc[0]; - ((u8*) &fval)[1] = pc[1]; - ((u8*) &fval)[2] = pc[2]; - ((u8*) &fval)[3] = pc[3]; - pc += 4; + { + u8* p = pc; + fbytes[0] = *p++; + fbytes[1] = *p++; + fbytes[2] = *p++; + fbytes[3] = *p++; + pc = p; + } pp->rotateTarget += fval; if (pp->rotateCount == 0) { pp->rotate = pp->rotateTarget; @@ -1642,12 +1576,10 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) case 0xB7: /* Aim velocity toward JObj */ { - int idx = *pc++; - HSD_JObj* jobj; + HSD_JObj* jobj = hsd_804D08E8[*pc++ + pp->pJObjOfs]; f32 dx, dy, dz, dist_sq, dist; - f32 vel_mag_sq, vel_mag; + f32 vel_mag_sq; - jobj = hsd_804D08E8[idx + pp->pJObjOfs]; if (jobj == NULL) { break; } @@ -1660,7 +1592,18 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) dy -= pp->pos.y; dz = jobj->mtx[2][3]; dz -= pp->pos.z; - vel_mag = sqrtf(vel_mag_sq); + if (vel_mag_sq > 0.0F) { + double guess = __frsqrte((double) vel_mag_sq); + volatile f32 result; + guess = + 0.5 * guess * (3.0 - guess * guess * vel_mag_sq); + guess = + 0.5 * guess * (3.0 - guess * guess * vel_mag_sq); + guess = + 0.5 * guess * (3.0 - guess * guess * vel_mag_sq); + result = (f32) (vel_mag_sq * guess); + vel_mag_sq = result; + } dist_sq = dy * dy + dx * dx; dist_sq += dz * dz; if (dist_sq == 0.0) { @@ -1668,7 +1611,7 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) } dist = sqrtf(dist_sq); { - f32 scale = vel_mag / dist; + f32 scale = vel_mag_sq / dist; pp->vel.x = dx * scale; pp->vel.y = dy * scale; pp->vel.z = dz * scale; @@ -1679,21 +1622,24 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) case 0xB8: /* Force toward JObj with kill on proximity */ { - int idx = *pc++; + u8* p = pc; + int idx = *p++; f32 force, range; - ((u8*) &fval)[0] = *pc++; - ((u8*) &fval)[1] = *pc++; - ((u8*) &fval)[2] = *pc++; - ((u8*) &fval)[3] = *pc++; + idx += pp->pJObjOfs; + fbytes[0] = *p++; + fbytes[1] = *p++; + fbytes[2] = *p++; + fbytes[3] = *p++; force = fval; - ((u8*) &fval)[0] = *pc++; - ((u8*) &fval)[1] = *pc++; - ((u8*) &fval)[2] = *pc++; - ((u8*) &fval)[3] = *pc++; + fbytes[0] = *p++; + fbytes[1] = *p++; + fbytes[2] = *p++; + fbytes[3] = *p++; range = fval; + pc = p; { - HSD_JObj* jobj = hsd_804D08E8[idx + pp->pJObjOfs]; + HSD_JObj* jobj = hsd_804D08E8[idx]; if (hsd_803991D8((HSD_Generator*) pp, jobj, force, range) != 0) { @@ -2039,17 +1985,20 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) f32 base_speed, random_range, target_speed; f32 mag; - ((u8*) &fval)[0] = pc[0]; - ((u8*) &fval)[1] = pc[1]; - ((u8*) &fval)[2] = pc[2]; - ((u8*) &fval)[3] = pc[3]; - base_speed = fval; - ((u8*) &fval)[0] = pc[4]; - ((u8*) &fval)[1] = pc[5]; - ((u8*) &fval)[2] = pc[6]; - ((u8*) &fval)[3] = pc[7]; - random_range = fval; - pc += 8; + { + u8* p = pc; + fbytes[0] = *p++; + fbytes[1] = *p++; + fbytes[2] = *p++; + fbytes[3] = *p++; + base_speed = fval; + fbytes[0] = *p++; + fbytes[1] = *p++; + fbytes[2] = *p++; + fbytes[3] = *p++; + random_range = fval; + pc = p; + } target_speed = base_speed + random_range * HSD_Randf(); mag = pp->vel.x * pp->vel.x + pp->vel.y * pp->vel.y + pp->vel.z * pp->vel.z; @@ -2065,22 +2014,25 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) case 0xBE: /* Velocity component multiply */ - ((u8*) &fval)[0] = pc[0]; - ((u8*) &fval)[1] = pc[1]; - ((u8*) &fval)[2] = pc[2]; - ((u8*) &fval)[3] = pc[3]; - pp->vel.x *= fval; - ((u8*) &fval)[0] = pc[4]; - ((u8*) &fval)[1] = pc[5]; - ((u8*) &fval)[2] = pc[6]; - ((u8*) &fval)[3] = pc[7]; - pp->vel.y *= fval; - ((u8*) &fval)[0] = pc[8]; - ((u8*) &fval)[1] = pc[9]; - ((u8*) &fval)[2] = pc[10]; - ((u8*) &fval)[3] = pc[11]; - pc += 12; - pp->vel.z *= fval; + { + u8* p = pc; + fbytes[0] = *p++; + fbytes[1] = *p++; + fbytes[2] = *p++; + fbytes[3] = *p++; + pp->vel.x *= fval; + fbytes[0] = *p++; + fbytes[1] = *p++; + fbytes[2] = *p++; + fbytes[3] = *p++; + pp->vel.y *= fval; + fbytes[0] = *p++; + fbytes[1] = *p++; + fbytes[2] = *p++; + fbytes[3] = *p++; + pc = p; + pp->vel.z *= fval; + } break; case 0xBF: @@ -2568,11 +2520,12 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) /* UserData set */ { int idx = *pc++; - ((u8*) &fval)[0] = pc[0]; - ((u8*) &fval)[1] = pc[1]; - ((u8*) &fval)[2] = pc[2]; - ((u8*) &fval)[3] = pc[3]; - pc += 4; + u8* p = pc; + fbytes[0] = *p++; + fbytes[1] = *p++; + fbytes[2] = *p++; + fbytes[3] = *p++; + pc = p; if (pp->gen->userfunc != NULL && pp->gen->userfunc->setUserData != NULL) { @@ -2655,11 +2608,14 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) case 0xE8: /* Trail control */ - ((u8*) &fval)[0] = pc[0]; - ((u8*) &fval)[1] = pc[1]; - ((u8*) &fval)[2] = pc[2]; - ((u8*) &fval)[3] = pc[3]; - pc += 4; + { + u8* p = pc; + fbytes[0] = *p++; + fbytes[1] = *p++; + fbytes[2] = *p++; + fbytes[3] = *p++; + pc = p; + } if (fval < 0.0F) { pp->kind &= ~Trail; } else { @@ -2755,23 +2711,28 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) case 0xED: /* Rotate interpolation with random */ { - f32 base_val; f32 range_val; + f32 base_val; int timing; f32 result; - ((u8*) &fval)[0] = pc[0]; - ((u8*) &fval)[1] = pc[1]; - ((u8*) &fval)[2] = pc[2]; - ((u8*) &fval)[3] = pc[3]; - base_val = fval; - ((u8*) &fval)[0] = pc[4]; - ((u8*) &fval)[1] = pc[5]; - ((u8*) &fval)[2] = pc[6]; - ((u8*) &fval)[3] = pc[7]; - range_val = fval; - timing = pc[8]; - pc += 9; + { + u8* p = pc + 1; + u8* pc2; + fbytes[0] = pc[0]; + pc2 = p + 4; + fbytes[1] = pc[1]; + fbytes[2] = pc[2]; + fbytes[3] = pc[3]; + base_val = fval; + fbytes[0] = pc[4]; + fbytes[1] = pc[5]; + fbytes[2] = pc[6]; + fbytes[3] = pc[7]; + range_val = fval; + pc = pc2 + 4; + timing = p[7]; + } if (timing != 0) { s32 randi = (s32) ((f32) (timing + 1) * HSD_Randf()); @@ -2872,7 +2833,101 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) } } - psUpdateParticle(pp); + /* --- Physics update --- */ + if (pp->kind & Tornado) { + /* Tornado rotational physics */ + HSD_Generator* gp = pp->gen; + f32 sinA, sinB, cosA, cosB; + f32 R; + f32 d, e, nd, vz; + f32 t0, t1, t2, t3, t4; + + sinA = sinf(pp->grav); + sinB = sinf(pp->fric); + cosA = cosf(pp->grav); + cosB = cosf(pp->fric); + + pp->vel.z += gp->aux.tornado.vel; + + if ((R = gp->radius) < 0.0F) { + R = -R; + } + { + f32 ang; + if ((ang = gp->angle) < 0.0F) { + ang = -ang; + } + R = pp->vel.y * (pp->vel.z * tanf(ang) + R); + } + pp->vel.x += gp->grav; + + d = R * cosf(pp->vel.x); + e = R * sinf(pp->vel.x); + nd = -d; + vz = pp->vel.z; + + /* Rotation matrix application */ + t0 = vz * sinB; + t1 = e * cosA; + t2 = nd * sinA; + t3 = d * cosB + t0; + t0 = vz * sinA; + t1 = sinB * t2 + t1; + pp->pos.x = gp->pos.x + t3; + t2 = nd * cosA; + t4 = e * sinA; + t1 = cosB * t0 + t1; + t0 = vz * cosA; + t4 = sinB * t2 - t4; + pp->pos.y = gp->pos.y + t1; + t4 = cosB * t0 + t4; + pp->pos.z = gp->pos.z + t4; + } else { + /* Simple physics */ + if (pp->kind & 1) { + pp->vel.y -= pp->grav; + } + if (pp->kind & 2) { + pp->vel.x *= pp->fric; + pp->vel.y *= pp->fric; + pp->vel.z *= pp->fric; + } + pp->pos.x += pp->vel.x; + pp->pos.y += pp->vel.y; + pp->pos.z += pp->vel.z; + } + + /* JObj attachment - update JObj position to match particle */ + if (pp->kind & 0x8000) { + s32 jobj_idx = (pp->kind >> 12) & 7; + HSD_JObj* jobj; + HSD_JObj** jobj_slot; + + /* Allocate JObj if slot is empty */ + if (hsd_804D08E8[jobj_idx] == NULL) { + HSD_JObj* new_jobj = HSD_JObjAlloc(); + if (new_jobj != NULL) { + hsd_8039CF4C(jobj_idx + 1, new_jobj); + HSD_JObjUnref(new_jobj); + } + } + + jobj_slot = &hsd_804D08E8[jobj_idx]; + jobj = *jobj_slot; + + if (jobj != NULL) { + HSD_JObjSetupMatrix(jobj); + + jobj = *jobj_slot; + HSD_JObjAddTranslationX(jobj, pp->pos.x - jobj->mtx[0][3]); + + jobj = *jobj_slot; + HSD_JObjAddTranslationY(jobj, pp->pos.y - jobj->mtx[1][3]); + + jobj = *jobj_slot; + HSD_JObjAddTranslationZ(jobj, pp->pos.z - jobj->mtx[2][3]); + } + } /* Callback */ if (pp->callback != NULL) { From 77bf546f634fabb675c8794e465236eb1222cbc0 Mon Sep 17 00:00:00 2001 From: Greer Guthrie Date: Fri, 14 Aug 2026 11:17:20 -0500 Subject: [PATCH 02/19] Improve particle size command decoding --- src/sysdolphin/baselib/particle.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/sysdolphin/baselib/particle.c b/src/sysdolphin/baselib/particle.c index 8c54ed977b..689d769d07 100644 --- a/src/sysdolphin/baselib/particle.c +++ b/src/sysdolphin/baselib/particle.c @@ -902,14 +902,11 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) pp->sizeCount = cnt; } } - { - u8* p = pc; - fbytes[0] = *p++; - fbytes[1] = *p++; - fbytes[2] = *p++; - fbytes[3] = *p++; - pc = p; - } + fbytes[0] = pc[0]; + fbytes[1] = pc[1]; + fbytes[2] = pc[2]; + fbytes[3] = pc[3]; + pc += 4; pp->sizeTarget = fval; if (pp->sizeCount == 0) { pp->size = pp->sizeTarget; From 8693b659b8de469141c9deec5dc3acd1168e9df6 Mon Sep 17 00:00:00 2001 From: Greer Guthrie Date: Fri, 14 Aug 2026 11:20:55 -0500 Subject: [PATCH 03/19] Improve particle rotation command decoding --- src/sysdolphin/baselib/particle.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/sysdolphin/baselib/particle.c b/src/sysdolphin/baselib/particle.c index 689d769d07..a0665d72ab 100644 --- a/src/sysdolphin/baselib/particle.c +++ b/src/sysdolphin/baselib/particle.c @@ -1556,12 +1556,11 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) } } { - u8* p = pc; - fbytes[0] = *p++; - fbytes[1] = *p++; - fbytes[2] = *p++; - fbytes[3] = *p++; - pc = p; + fbytes[0] = pc[0]; + fbytes[1] = pc[1]; + fbytes[2] = pc[2]; + fbytes[3] = pc[3]; + pc += 4; } pp->rotateTarget += fval; if (pp->rotateCount == 0) { From 47b522416c1c32c5aa7b3b8fc7c5b10a04925fcb Mon Sep 17 00:00:00 2001 From: Greer Guthrie Date: Fri, 14 Aug 2026 11:34:29 -0500 Subject: [PATCH 04/19] Improve particle aim command matching --- src/sysdolphin/baselib/particle.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sysdolphin/baselib/particle.c b/src/sysdolphin/baselib/particle.c index a0665d72ab..784095d98f 100644 --- a/src/sysdolphin/baselib/particle.c +++ b/src/sysdolphin/baselib/particle.c @@ -1573,17 +1573,18 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) /* Aim velocity toward JObj */ { HSD_JObj* jobj = hsd_804D08E8[*pc++ + pp->pJObjOfs]; - f32 dx, dy, dz, dist_sq, dist; + f32 dz, dy, dx, dist_sq, dist; f32 vel_mag_sq; if (jobj == NULL) { break; } HSD_JObjSetupMatrix(jobj); - vel_mag_sq = pp->vel.x * pp->vel.x + pp->vel.y * pp->vel.y; + vel_mag_sq = pp->vel.x * pp->vel.x + + pp->vel.y * pp->vel.y + + pp->vel.z * pp->vel.z; dx = jobj->mtx[0][3]; dx -= pp->pos.x; - vel_mag_sq += pp->vel.z * pp->vel.z; dy = jobj->mtx[1][3]; dy -= pp->pos.y; dz = jobj->mtx[2][3]; From b1c03b8c30c85d348f917181d83330683fd1887d Mon Sep 17 00:00:00 2001 From: Greer Guthrie Date: Fri, 14 Aug 2026 11:37:30 -0500 Subject: [PATCH 05/19] Match particle random pose calculation --- src/sysdolphin/baselib/particle.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sysdolphin/baselib/particle.c b/src/sysdolphin/baselib/particle.c index 784095d98f..890481e84a 100644 --- a/src/sysdolphin/baselib/particle.c +++ b/src/sysdolphin/baselib/particle.c @@ -1948,11 +1948,11 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) case 0xBC: /* PoseNum with random */ { - int randRange; + f32 randRange; pp->poseNum = *pc++; randRange = *pc++; - pp->poseNum = (u8) (s32) ((f32) randRange * HSD_Randf() + + pp->poseNum = (u8) (s32) (randRange * HSD_Randf() + (f32) pp->poseNum); { u8 bank = pp->bank; From 63602c198d67926d1c7647a3351d7f56d55f1ad0 Mon Sep 17 00:00:00 2001 From: Greer Guthrie Date: Fri, 14 Aug 2026 11:42:03 -0500 Subject: [PATCH 06/19] Match particle velocity normalization --- src/sysdolphin/baselib/particle.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sysdolphin/baselib/particle.c b/src/sysdolphin/baselib/particle.c index 890481e84a..74d954feac 100644 --- a/src/sysdolphin/baselib/particle.c +++ b/src/sysdolphin/baselib/particle.c @@ -1979,7 +1979,7 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) case 0xBD: /* Normalize velocity to target speed */ { - f32 base_speed, random_range, target_speed; + f32 base_speed, random_range; f32 mag; { @@ -1996,15 +1996,15 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) random_range = fval; pc = p; } - target_speed = base_speed + random_range * HSD_Randf(); + base_speed += random_range * HSD_Randf(); mag = pp->vel.x * pp->vel.x + pp->vel.y * pp->vel.y + pp->vel.z * pp->vel.z; mag = sqrtf(mag); if (mag > 0.0F) { - target_speed /= mag; - pp->vel.x *= target_speed; - pp->vel.y *= target_speed; - pp->vel.z *= target_speed; + base_speed /= mag; + pp->vel.x *= base_speed; + pp->vel.y *= base_speed; + pp->vel.z *= base_speed; } } break; From 427e4dbc9450546ae721612bce7dc1a4fcebb45f Mon Sep 17 00:00:00 2001 From: Greer Guthrie Date: Fri, 14 Aug 2026 11:48:56 -0500 Subject: [PATCH 07/19] Match particle command operand width --- src/sysdolphin/baselib/particle.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sysdolphin/baselib/particle.c b/src/sysdolphin/baselib/particle.c index 74d954feac..e92506c434 100644 --- a/src/sysdolphin/baselib/particle.c +++ b/src/sysdolphin/baselib/particle.c @@ -619,7 +619,7 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) HSD_Particle* pp = pp_arg; HSD_Particle* prev = prev_arg; u8* pc; - int operand; + u16 operand; u8 opcode; u8 cls; HSD_Particle* child; From 789b81768da06549c24cb8940979176d6f8dee74 Mon Sep 17 00:00:00 2001 From: Greer Guthrie Date: Fri, 14 Aug 2026 11:56:21 -0500 Subject: [PATCH 08/19] Match particle command pointer walks --- src/sysdolphin/baselib/particle.c | 60 +++++++++++++++++-------------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/src/sysdolphin/baselib/particle.c b/src/sysdolphin/baselib/particle.c index e92506c434..0a7ef21a89 100644 --- a/src/sysdolphin/baselib/particle.c +++ b/src/sysdolphin/baselib/particle.c @@ -894,19 +894,20 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) case 0xA0: /* Set size interpolation target */ { - pp->sizeCount = *pc++; + u8* p = pc; + pp->sizeCount = *p++; { u16 cnt = pp->sizeCount; if (cnt & 0x80) { - cnt = ((cnt & 0x7F) << 8) + *pc++; + cnt = ((cnt & 0x7F) << 8) + *p++; pp->sizeCount = cnt; } } - fbytes[0] = pc[0]; - fbytes[1] = pc[1]; - fbytes[2] = pc[2]; - fbytes[3] = pc[3]; - pc += 4; + fbytes[0] = *p++; + fbytes[1] = *p++; + fbytes[2] = *p++; + fbytes[3] = *p++; + pc = p; pp->sizeTarget = fval; if (pp->sizeCount == 0) { pp->size = pp->sizeTarget; @@ -1547,21 +1548,20 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) case 0xB6: /* Rotate interpolation setup */ { - pp->rotateCount = *pc++; + u8* p = pc; + pp->rotateCount = *p++; { u16 cnt = pp->rotateCount; if (cnt & 0x80) { - cnt = ((cnt & 0x7F) << 8) + *pc++; + cnt = ((cnt & 0x7F) << 8) + *p++; pp->rotateCount = cnt; } } - { - fbytes[0] = pc[0]; - fbytes[1] = pc[1]; - fbytes[2] = pc[2]; - fbytes[3] = pc[3]; - pc += 4; - } + fbytes[0] = *p++; + fbytes[1] = *p++; + fbytes[2] = *p++; + fbytes[3] = *p++; + pc = p; pp->rotateTarget += fval; if (pp->rotateCount == 0) { pp->rotate = pp->rotateTarget; @@ -2070,11 +2070,15 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) (s32) pp->primColTarget.a)) >> 16); } - pp->primColCount = *pc++; - cnt = pp->primColCount; - if (cnt & 0x80) { - cnt = ((cnt & 0x7F) << 8) + *pc++; - pp->primColCount = cnt; + { + u8* p = pc; + pp->primColCount = *p++; + cnt = pp->primColCount; + if (cnt & 0x80) { + cnt = ((cnt & 0x7F) << 8) + *p++; + pp->primColCount = cnt; + } + pc = p; } pp->primColTarget = pp->primCol; if (opcode & 1) { @@ -2128,11 +2132,15 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) (s32) pp->envColTarget.a)) >> 16); } - pp->envColCount = *pc++; - cnt = pp->envColCount; - if (cnt & 0x80) { - cnt = ((cnt & 0x7F) << 8) + *pc++; - pp->envColCount = cnt; + { + u8* p = pc; + pp->envColCount = *p++; + cnt = pp->envColCount; + if (cnt & 0x80) { + cnt = ((cnt & 0x7F) << 8) + *p++; + pp->envColCount = cnt; + } + pc = p; } pp->envColTarget = pp->envCol; if (opcode & 1) { From b9a81058ef67c3f5140a7850ee40a582d1b7186f Mon Sep 17 00:00:00 2001 From: Greer Guthrie Date: Fri, 14 Aug 2026 12:06:19 -0500 Subject: [PATCH 09/19] Improve particle tornado register allocation --- src/sysdolphin/baselib/particle.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sysdolphin/baselib/particle.c b/src/sysdolphin/baselib/particle.c index 0a7ef21a89..0a63623ec4 100644 --- a/src/sysdolphin/baselib/particle.c +++ b/src/sysdolphin/baselib/particle.c @@ -2843,9 +2843,9 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) /* Tornado rotational physics */ HSD_Generator* gp = pp->gen; f32 sinA, sinB, cosA, cosB; - f32 R; - f32 d, e, nd, vz; f32 t0, t1, t2, t3, t4; + f32 d, e, nd, vz; + f32 R; sinA = sinf(pp->grav); sinB = sinf(pp->fric); From 957b5a78d83ce4d001d33eda86e8c140c7fe5c4c Mon Sep 17 00:00:00 2001 From: Greer Guthrie Date: Fri, 14 Aug 2026 12:28:52 -0500 Subject: [PATCH 10/19] Improve particle physics and attachment matching --- src/sysdolphin/baselib/particle.c | 32 +++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/sysdolphin/baselib/particle.c b/src/sysdolphin/baselib/particle.c index 0a63623ec4..1c6f90a467 100644 --- a/src/sysdolphin/baselib/particle.c +++ b/src/sysdolphin/baselib/particle.c @@ -55,6 +55,8 @@ typedef union { u8 bytes[4]; } ParticleFloatBytes; +static const f32 particle_zero = 0.0F; + void hsd_803983A4(HSD_Generator* gen) { HSD_JObj* jobj; @@ -1581,8 +1583,7 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) } HSD_JObjSetupMatrix(jobj); vel_mag_sq = pp->vel.x * pp->vel.x + - pp->vel.y * pp->vel.y + - pp->vel.z * pp->vel.z; + pp->vel.y * pp->vel.y + pp->vel.z * pp->vel.z; dx = jobj->mtx[0][3]; dx -= pp->pos.x; dy = jobj->mtx[1][3]; @@ -2854,12 +2855,12 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) pp->vel.z += gp->aux.tornado.vel; - if ((R = gp->radius) < 0.0F) { + if ((R = gp->radius) < *(volatile const f32*) &particle_zero) { R = -R; } { f32 ang; - if ((ang = gp->angle) < 0.0F) { + if ((ang = gp->angle) < *(volatile const f32*) &particle_zero) { ang = -ang; } R = pp->vel.y * (pp->vel.z * tanf(ang) + R); @@ -2905,8 +2906,6 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) /* JObj attachment - update JObj position to match particle */ if (pp->kind & 0x8000) { s32 jobj_idx = (pp->kind >> 12) & 7; - HSD_JObj* jobj; - HSD_JObj** jobj_slot; /* Allocate JObj if slot is empty */ if (hsd_804D08E8[jobj_idx] == NULL) { @@ -2917,20 +2916,21 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) } } - jobj_slot = &hsd_804D08E8[jobj_idx]; - jobj = *jobj_slot; + { + HSD_JObj* jobj; - if (jobj != NULL) { - HSD_JObjSetupMatrix(jobj); + if ((jobj = hsd_804D08E8[jobj_idx]) != NULL) { + HSD_JObjSetupMatrix(jobj); - jobj = *jobj_slot; - HSD_JObjAddTranslationX(jobj, pp->pos.x - jobj->mtx[0][3]); + jobj = hsd_804D08E8[jobj_idx]; + HSD_JObjAddTranslationX(jobj, pp->pos.x - jobj->mtx[0][3]); - jobj = *jobj_slot; - HSD_JObjAddTranslationY(jobj, pp->pos.y - jobj->mtx[1][3]); + jobj = hsd_804D08E8[jobj_idx]; + HSD_JObjAddTranslationY(jobj, pp->pos.y - jobj->mtx[1][3]); - jobj = *jobj_slot; - HSD_JObjAddTranslationZ(jobj, pp->pos.z - jobj->mtx[2][3]); + jobj = hsd_804D08E8[jobj_idx]; + HSD_JObjAddTranslationZ(jobj, pp->pos.z - jobj->mtx[2][3]); + } } } From 5aa4ab1fa590555e07d1254d8e87bdd1d2b2cdf1 Mon Sep 17 00:00:00 2001 From: Greer Guthrie Date: Fri, 14 Aug 2026 12:35:37 -0500 Subject: [PATCH 11/19] Match particle aim distance ordering --- src/sysdolphin/baselib/particle.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sysdolphin/baselib/particle.c b/src/sysdolphin/baselib/particle.c index 1c6f90a467..15d9d63233 100644 --- a/src/sysdolphin/baselib/particle.c +++ b/src/sysdolphin/baselib/particle.c @@ -1602,7 +1602,7 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) result = (f32) (vel_mag_sq * guess); vel_mag_sq = result; } - dist_sq = dy * dy + dx * dx; + dist_sq = dx * dx + dy * dy; dist_sq += dz * dz; if (dist_sq == 0.0) { break; From 31293430d974201562c62512693ea0bb51853c18 Mon Sep 17 00:00:00 2001 From: Greer Guthrie Date: Fri, 14 Aug 2026 12:42:03 -0500 Subject: [PATCH 12/19] Match particle alpha random delta ordering --- src/sysdolphin/baselib/particle.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sysdolphin/baselib/particle.c b/src/sysdolphin/baselib/particle.c index 15d9d63233..ff9047feb1 100644 --- a/src/sysdolphin/baselib/particle.c +++ b/src/sysdolphin/baselib/particle.c @@ -2473,9 +2473,10 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) f32 a_rand; a_rand = HSD_Randf(); delta = (s8) *pc++; - delta_float = - (f32) (s32) ((f32) (timing + 1) * a_rand) / - (f32) timing * (f32) (delta * 2); + delta_float = (f32) (delta * 2); + delta_float *= + (f32) (s32) ((f32) (timing + 1) * a_rand); + delta_float /= (f32) timing; if (flags & 0x10) { val = delta_float + (f32) pp->primColTarget.a; if (val < 0.0F) { From 8fb3d1088638d16f93857c443d96cb2794fde408 Mon Sep 17 00:00:00 2001 From: Greer Guthrie Date: Fri, 14 Aug 2026 12:44:52 -0500 Subject: [PATCH 13/19] Refine particle alpha random evaluation --- src/sysdolphin/baselib/particle.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sysdolphin/baselib/particle.c b/src/sysdolphin/baselib/particle.c index ff9047feb1..eede48bdf6 100644 --- a/src/sysdolphin/baselib/particle.c +++ b/src/sysdolphin/baselib/particle.c @@ -2473,9 +2473,9 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) f32 a_rand; a_rand = HSD_Randf(); delta = (s8) *pc++; - delta_float = (f32) (delta * 2); - delta_float *= + delta_float = (f32) (s32) ((f32) (timing + 1) * a_rand); + delta_float *= (f32) (delta * 2); delta_float /= (f32) timing; if (flags & 0x10) { val = delta_float + (f32) pp->primColTarget.a; From 0baaa06904bf31bfcffef5f63099c14850703a1c Mon Sep 17 00:00:00 2001 From: Greer Guthrie Date: Fri, 14 Aug 2026 13:24:24 -0500 Subject: [PATCH 14/19] Match particle size count cursor --- src/sysdolphin/baselib/particle.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/sysdolphin/baselib/particle.c b/src/sysdolphin/baselib/particle.c index eede48bdf6..d8c00647b5 100644 --- a/src/sysdolphin/baselib/particle.c +++ b/src/sysdolphin/baselib/particle.c @@ -1403,13 +1403,16 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) /* Size interpolation with random */ { f32 range; - pp->sizeCount = *pc++; { - u16 cnt = pp->sizeCount; + u8* count_pc = pc; + u16 cnt; + pp->sizeCount = *count_pc++; + cnt = pp->sizeCount; if (cnt & 0x80) { - cnt = ((cnt & 0x7F) << 8) + *pc++; + cnt = ((cnt & 0x7F) << 8) + *count_pc++; pp->sizeCount = cnt; } + pc = count_pc; } { u8* p = pc + 1; From 80b821c7a03ac3842a5da339aea973c6e64c1448 Mon Sep 17 00:00:00 2001 From: Greer Guthrie Date: Fri, 14 Aug 2026 13:28:03 -0500 Subject: [PATCH 15/19] Match particle decoded float lifetimes --- src/sysdolphin/baselib/particle.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/sysdolphin/baselib/particle.c b/src/sysdolphin/baselib/particle.c index d8c00647b5..3ee66de40d 100644 --- a/src/sysdolphin/baselib/particle.c +++ b/src/sysdolphin/baselib/particle.c @@ -1387,16 +1387,18 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) case 0xAB: /* Velocity scale */ { + f32 scale; u8* p = pc; fbytes[0] = *p++; fbytes[1] = *p++; fbytes[2] = *p++; fbytes[3] = *p++; pc = p; + scale = fval; + pp->vel.x *= scale; + pp->vel.y *= scale; + pp->vel.z *= scale; } - pp->vel.x *= fval; - pp->vel.y *= fval; - pp->vel.z *= fval; break; case 0xAC: @@ -1984,7 +1986,7 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) /* Normalize velocity to target speed */ { f32 base_speed, random_range; - f32 mag; + f32 mag, root; { u8* p = pc; @@ -2003,9 +2005,9 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) base_speed += random_range * HSD_Randf(); mag = pp->vel.x * pp->vel.x + pp->vel.y * pp->vel.y + pp->vel.z * pp->vel.z; - mag = sqrtf(mag); - if (mag > 0.0F) { - base_speed /= mag; + root = sqrtf(mag); + if (root > 0.0) { + base_speed /= root; pp->vel.x *= base_speed; pp->vel.y *= base_speed; pp->vel.z *= base_speed; @@ -2619,18 +2621,20 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) case 0xE8: /* Trail control */ { + f32 trail; u8* p = pc; fbytes[0] = *p++; fbytes[1] = *p++; fbytes[2] = *p++; fbytes[3] = *p++; pc = p; - } - if (fval < 0.0F) { - pp->kind &= ~Trail; - } else { - pp->kind |= Trail; - pp->trail = fval; + trail = fval; + if (trail < 0.0F) { + pp->kind &= ~Trail; + } else { + pp->kind |= Trail; + pp->trail = trail; + } } break; From a79266c4ae2c1b5403e25e9475194ace8a5812b9 Mon Sep 17 00:00:00 2001 From: Greer Guthrie Date: Fri, 14 Aug 2026 13:37:58 -0500 Subject: [PATCH 16/19] Reuse particle zero constant --- src/sysdolphin/baselib/particle.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sysdolphin/baselib/particle.c b/src/sysdolphin/baselib/particle.c index 3ee66de40d..479ae8327e 100644 --- a/src/sysdolphin/baselib/particle.c +++ b/src/sysdolphin/baselib/particle.c @@ -55,7 +55,7 @@ typedef union { u8 bytes[4]; } ParticleFloatBytes; -static const f32 particle_zero = 0.0F; +static volatile const f32 particle_zero = 0.0F; void hsd_803983A4(HSD_Generator* gen) { @@ -2863,12 +2863,12 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) pp->vel.z += gp->aux.tornado.vel; - if ((R = gp->radius) < *(volatile const f32*) &particle_zero) { + if ((R = gp->radius) < particle_zero) { R = -R; } { f32 ang; - if ((ang = gp->angle) < *(volatile const f32*) &particle_zero) { + if ((ang = gp->angle) < particle_zero) { ang = -ang; } R = pp->vel.y * (pp->vel.z * tanf(ang) + R); From 40a39b579ae9e2f14cd32c9171fdf9e0d017dce4 Mon Sep 17 00:00:00 2001 From: Greer Guthrie Date: Fri, 14 Aug 2026 13:50:22 -0500 Subject: [PATCH 17/19] Match particle spawn index scheduling --- src/sysdolphin/baselib/particle.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/sysdolphin/baselib/particle.c b/src/sysdolphin/baselib/particle.c index 479ae8327e..b3c442c38f 100644 --- a/src/sysdolphin/baselib/particle.c +++ b/src/sysdolphin/baselib/particle.c @@ -966,7 +966,8 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) int idx; int palflag; - idx = (pc[0] << 8) + pc[1]; + idx = pc[0] << 8; + idx += pc[1]; pc += 2; if (linkNo >= 8) { @@ -1017,7 +1018,8 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) int bank; bank = pp->bank; - idx = (pc[0] << 8) + pc[1]; + idx = pc[0] << 8; + idx += pc[1]; pc += 2; if (ptclref_804D0E5C[bank] != NULL) { @@ -1070,7 +1072,8 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) { int idx; - idx = (pc[0] << 8) + pc[1]; + idx = pc[0] << 8; + idx += pc[1]; pc += 2; gchild = hsd_8039F05C(pp->linkNo, pp->bank, idx); if (gchild != NULL) { @@ -1131,7 +1134,8 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) u8 flags; HSD_psAppSRT* srt; - idx = (pc[0] << 8) + pc[1]; + idx = pc[0] << 8; + idx += pc[1]; flags = pc[2]; pc += 3; gchild = hsd_8039F05C(pp->linkNo, pp->bank, idx); @@ -1195,7 +1199,8 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) u8 flags; HSD_psAppSRT* srt; - idx = (pc[0] << 8) + pc[1]; + idx = pc[0] << 8; + idx += pc[1]; flags = pc[2]; pc += 3; @@ -1262,8 +1267,10 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) { int baseLife; int randomRange; - baseLife = (pc[0] << 8) + pc[1]; - randomRange = (pc[2] << 8) + pc[3]; + baseLife = pc[0] << 8; + baseLife += pc[1]; + randomRange = pc[2] << 8; + randomRange += pc[3]; pc += 4; pp->life = baseLife + (s32) ((f32) randomRange * HSD_Randf()); @@ -1661,7 +1668,8 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) int idx; int palflag; - idx = (pc[0] << 8) + pc[1]; + idx = pc[0] << 8; + idx += pc[1]; pc += 2; if (linkNo >= 8) { @@ -1718,7 +1726,8 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) int bank; bank = pp->bank; - idx = (pc[0] << 8) + pc[1]; + idx = pc[0] << 8; + idx += pc[1]; pc += 2; if (ptclref_804D0E5C[bank] != NULL) { From 2999d4e781c2d4af32435562ce2940d068856108 Mon Sep 17 00:00:00 2001 From: Greer Guthrie Date: Fri, 14 Aug 2026 14:29:04 -0500 Subject: [PATCH 18/19] Improve particle randomization and aim matching --- src/sysdolphin/baselib/particle.c | 51 +++++++++++++++++++------------ 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/src/sysdolphin/baselib/particle.c b/src/sysdolphin/baselib/particle.c index b3c442c38f..964b43a697 100644 --- a/src/sysdolphin/baselib/particle.c +++ b/src/sysdolphin/baselib/particle.c @@ -1587,7 +1587,7 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) /* Aim velocity toward JObj */ { HSD_JObj* jobj = hsd_804D08E8[*pc++ + pp->pJObjOfs]; - f32 dz, dy, dx, dist_sq, dist; + f32 dz, dy, dx, dist_sq; f32 vel_mag_sq; if (jobj == NULL) { @@ -1619,9 +1619,17 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) if (dist_sq == 0.0) { break; } - dist = sqrtf(dist_sq); + if (dist_sq > 0.0F) { + double guess = __frsqrte((double) dist_sq); + volatile f32 result; + guess = 0.5 * guess * (3.0 - guess * guess * dist_sq); + guess = 0.5 * guess * (3.0 - guess * guess * dist_sq); + guess = 0.5 * guess * (3.0 - guess * guess * dist_sq); + result = (f32) (dist_sq * guess); + dist_sq = result; + } { - f32 scale = vel_mag_sq / dist; + f32 scale = vel_mag_sq / dist_sq; pp->vel.x = dx * scale; pp->vel.y = dy * scale; pp->vel.z = dz * scale; @@ -2184,7 +2192,10 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) { s32 step; s8 delta; - f32 rand_val; + f32 rand_r; + f32 rand_g; + f32 rand_b; + f32 rand_a; f32 val; if (pp->primColCount != 0) { @@ -2236,11 +2247,11 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) 16); } - rand_val = HSD_Randf(); + rand_r = HSD_Randf(); delta = (s8) *pc++; - rand_val *= (f32) (delta * 2); - val = rand_val + (f32) pp->primColTarget.r; + rand_r *= (f32) (delta * 2); + val = rand_r + (f32) pp->primColTarget.r; if (val < 0.0F) { val = 0.0F; } @@ -2248,7 +2259,7 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) val = 255.0F; } pp->primColTarget.r = (u8) (s32) val; - val = rand_val + (f32) pp->envColTarget.r; + val = rand_r + (f32) pp->envColTarget.r; if (val < 0.0F) { val = 0.0F; } @@ -2257,10 +2268,10 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) } pp->envColTarget.r = (u8) (s32) val; - rand_val = HSD_Randf(); + rand_g = HSD_Randf(); delta = (s8) *pc++; - rand_val *= (f32) (delta * 2); - val = rand_val + (f32) pp->primColTarget.g; + rand_g *= (f32) (delta * 2); + val = rand_g + (f32) pp->primColTarget.g; if (val < 0.0F) { val = 0.0F; } @@ -2268,7 +2279,7 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) val = 255.0F; } pp->primColTarget.g = (u8) (s32) val; - val = rand_val + (f32) pp->envColTarget.g; + val = rand_g + (f32) pp->envColTarget.g; if (val < 0.0F) { val = 0.0F; } @@ -2277,10 +2288,10 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) } pp->envColTarget.g = (u8) (s32) val; - rand_val = HSD_Randf(); + rand_b = HSD_Randf(); delta = (s8) *pc++; - rand_val *= (f32) (delta * 2); - val = rand_val + (f32) pp->primColTarget.b; + rand_b *= (f32) (delta * 2); + val = rand_b + (f32) pp->primColTarget.b; if (val < 0.0F) { val = 0.0F; } @@ -2288,7 +2299,7 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) val = 255.0F; } pp->primColTarget.b = (u8) (s32) val; - val = rand_val + (f32) pp->envColTarget.b; + val = rand_b + (f32) pp->envColTarget.b; if (val < 0.0F) { val = 0.0F; } @@ -2297,10 +2308,10 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) } pp->envColTarget.b = (u8) (s32) val; - rand_val = HSD_Randf(); + rand_a = HSD_Randf(); delta = (s8) *pc++; - rand_val *= (f32) (delta * 2); - val = rand_val + (f32) pp->primColTarget.a; + rand_a *= (f32) (delta * 2); + val = rand_a + (f32) pp->primColTarget.a; if (val < 0.0F) { val = 0.0F; } @@ -2308,7 +2319,7 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) val = 255.0F; } pp->primColTarget.a = (u8) (s32) val; - val = rand_val + (f32) pp->envColTarget.a; + val = rand_a + (f32) pp->envColTarget.a; if (val < 0.0F) { val = 0.0F; } From 8814e5a690c7dea312acc966c18840550785d492 Mon Sep 17 00:00:00 2001 From: Greer Guthrie Date: Fri, 14 Aug 2026 17:26:35 -0500 Subject: [PATCH 19/19] Recover alpha compare bytecode cursor --- src/sysdolphin/baselib/particle.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/sysdolphin/baselib/particle.c b/src/sysdolphin/baselib/particle.c index 964b43a697..36bd6a9829 100644 --- a/src/sysdolphin/baselib/particle.c +++ b/src/sysdolphin/baselib/particle.c @@ -1526,18 +1526,21 @@ void* hsd_8039930C(void* pp_arg, void* prev_arg) 16); } { - pp->aCmpCount = *pc++; + u8* p = pc; + pp->aCmpCount = *p++; { u16 cnt = pp->aCmpCount; if (cnt & 0x80) { - cnt = ((cnt & 0x7F) << 8) + *pc++; + cnt = ((cnt & 0x7F) << 8) + *p++; pp->aCmpCount = cnt; } } + pc = p; + pp->aCmpMode = *pc++; + pp->aCmpParam1Target = pc[0]; + pp->aCmpParam2Target = pc[1]; + pc += 2; } - pp->aCmpMode = *pc++; - pp->aCmpParam1Target = *pc++; - pp->aCmpParam2Target = *pc++; if (pp->aCmpCount == 0) { pp->aCmpParam1 = pp->aCmpParam1Target; pp->aCmpParam2 = pp->aCmpParam2Target;