Repository navigation
decomp: clarify function, field and state names (batch 37) - #277
Merged
pezzadev merged 758 commits intoNov 2, 2026
Merged
Conversation
unk64 -> path_progress: BackgroundShip1Vars f32 unk64 is initialized from unk74 times the path's first integer at retail 0x002ec608-0x002ec61c. In FOLLOW_PATH, 0x002ec664-0x002ec678 adds travel speed times frame_time divided by first_path_segment_length to this field; 0x002ec67c-0x002ec698 wraps it by the path count. 0x002ec6ac loads it into f12 for sample_camera_path at 0x002ec6c0/0x002ec6e0, which writes moby position and rotation. These operations prove it stores path sampling progress.
unk110 -> path_endpoint_distance: Retail 0x00294d44-0x00294d5c loads the path pointer, selects first node at path+0x10 and last node at path+count*0x10, calls fast_vec_dist, and stores f0 at pvars+0x110, matching source unk110. 0x00294d7c-0x00294d9c derives glide_speed from this endpoint distance. 0x00294e34 and 0x00294e60-0x00294e64 use the stored full distance to offset the second easing half and reflect traveled distance; 0x00294e68-0x00294ec4 scales the last-minus-first vector and adds the first endpoint to produce moby position.
unk170 -> aim_quaternion_storage: Retail 0x002b3698 forms pvars+0x170; 0x002b36a8-0x002b36b4 builds an axis-2 quaternion there from aim_yaw_offset. 0x002b3768-0x002b3774 uses that same address as destination and first input to multiply_quaternions with the optional axis-1 pitch quaternion. Authoritative C passes &state->unk170 in exactly those operations, proving storage beginning with the composed aim quaternion, without assigning roles to its trailing bytes. unk26C -> aim_yaw_angular_velocity: Retail 0x002b3668/0x002b3684 passes pvars+0x268 and +0x26c to the same easing helper at 0x002b36a0. Authoritative C identifies +0x268 as aim_yaw_offset, with clamped heading-relative turn as target and &unk26C as the helper's float velocity argument. The same FUN_L00_0025be00 signature is used with heading_angular_velocity in follow_plasmabot_path and aim_joint_angular_velocity in approach_angle; initialization clears this persistent yaw velocity. unk280 -> aim_pitch_angle: Retail 0x002b36ec-0x002b3724 derives horizontal range and adjusted vertical displacement from target position minus plasmabot position. The negative arctangent becomes the target passed with pvars+0x280 at 0x002b3730-0x002b3750. 0x002b3758 loads that eased field as the angle for an axis-1 quaternion, then 0x002b3770 composes it into the aim quaternion. Authoritative C's target_pitch_angle and float reinterpretation of unk280 confirm persistent aim pitch angle storage. unk284 -> aim_pitch_angular_velocity: Retail 0x002b373c-0x002b3750 passes pvars+0x280 and +0x284 as the persistent angle and velocity pointers to the same easing helper used for yaw at 0x002b36a0, with negative target-displacement arctangent as pitch target. Authoritative C supplies &unk284 in the velocity position paired with &unk280, whose eased value builds the axis-1 pitch quaternion at 0x002b3758-0x002b3764. This matches the established heading_angular_velocity helper role, and initialization clears the persistent field.
f24 -> burst_timer: SparkData.f24 is passed to fast_dec_timer in SPARK_EMITTER_TIMED_BURSTS. Retail 0x00308da0/0x00308da4 checks pvars+0x24 (original Ghidra piVar2+9); completion selects five sparks at 0x00308dc4. Instructions 0x00308db0-0x00308dd8 sample 60.0..120.0, scale/truncate, and store the reset to pvars+0x24 (Ghidra piVar2[9]). The count drives spawn_spark calls at 0x00308fb0, proving this member schedules bursts rather than individual spark attributes.
unk194 -> joint_1_target_pitch: Retail 0x002d4678-0x002d4704 computes negative atan of local delta XY length and Z, then clamps pitch to +/-pi/4. 0x002d4718 halves it and 0x002d4728 stores it to pvars+0x194. This is +0x64 within the +0x130 animation block passed with joint index 1 at 0x002d4874/0x002d4884/0x002d488c. Supplied update_joint_animation consumes block+0x64 as a spring_angle target; source assigns halfPitch. unk198 -> joint_1_target_yaw: Retail 0x002d465c-0x002d4668 obtains yaw from local delta X/Y; 0x002d4690-0x002d46c4 clamps it to +/-pi/4. 0x002d4714 halves yaw and 0x002d4724 stores it to pvars+0x198, +0x68 within block +0x130. That block is passed with joint index 1 at 0x002d4874/0x002d4884/0x002d488c, and supplied update_joint_animation uses block+0x68 as its rotation spring target. Source assigns halfYaw. unk214 -> joint_2_target_pitch: Retail negative atan of local delta XY length and Z at 0x002d4678/0x002d469c produces pitch, clamped through 0x002d4704 and halved at 0x002d4718. Store 0x002d4720 writes pvars+0x214, the +0x64 rotation target within animation block +0x1B0. Retail 0x002d48a0/0x002d48a4/0x002d48ac passes this block with joint index 2. Supplied update_joint_animation springs toward block+0x64; source assigns halfPitch. unk218 -> joint_2_target_yaw: Retail 0x002d4660 computes atan of local delta X/Y, clamps yaw through 0x002d46c4, halves it at 0x002d4714 and stores it at pvars+0x218 at 0x002d471c. This is the +0x68 rotation target of block +0x1B0, passed to update_joint_animation with joint index 2 at 0x002d48a0/0x002d48a4/0x002d48ac. Supplied helper springs toward block+0x68; source assigns halfYaw. unk298 -> joint_3_target_yaw: For states 4/5, retail 0x002d4790-0x002d47a4 forms the adjusted aim delta in local coordinates; 0x002d47c4/0x002d47e8 computes and negates its X/Y atan. 0x002d4810-0x002d4850 clamps this yaw to +/-0.34906584 and 0x002d4858 stores it at pvars+0x298. This is +0x68 in block +0x230, passed with joint index 3 at 0x002d48c0/0x002d48c4/0x002d48cc. Supplied helper consumes +0x68 as a spring rotation target; source assigns yaw2.
unk218 -> beam_target_moby: In the supplied source, ScoutbotVars.unk218 is the char * field at +0x218, corresponding to Data_3DF8.current_target, which scoutbot_update assigns from its target. Retail 0x002d3950 loads this pointer from 0x218(s5); 0x002d3964 adds 0x10 and fast_vec_sub subtracts the moby point-2 beam origin. Retail 0x002d3978/0x002d3984 reload the pointer and its +0x18 position Z, then 0x002d398c-0x002d3998 compute (target Z + 0.25) - origin Z. The resulting delta determines length and pitch/yaw at 0x002d3994-0x002d39e4 for the beam geometry. Thus the field points to the moby whose position aims the beam, rather than storing a vector or packet.
f218 -> fog_near_distance: Retail 0x002a4124/0x002a4138 loads camera +0x218 and saves it to 0x001612f8, named textured_grid_saved_fog_near_distance in authoritative C. At 0x002a4154/0x002a4158 caller +0x20 replaces this camera field outside camera fog-source mode; restore_view_after_textured_grid writes the named saved near distance back to +0x218. f21C -> fog_far_distance: Retail 0x002a4128/0x002a4140 loads camera +0x21c and saves it to 0x001612fc, named textured_grid_saved_fog_far_distance in authoritative C. At 0x002a415c/0x002a4160 caller +0x24 replaces it outside camera fog-source mode; the supplied restore function writes the saved far distance back to this field. f228 -> fog_near_intensity: Retail 0x002a412c/0x002a4148 saves camera +0x228 to 0x00161300, named textured_grid_saved_fog_near_intensity in authoritative C. Caller +0x28 overrides it at 0x002a4164/0x002a4168. Retail 0x002a42ac/0x002a42bc emits it beside far intensity in the view packet; the supplied restore function restores the named saved near intensity to this field. f22C -> fog_far_intensity: Retail 0x002a4130/0x002a4150 saves camera +0x22c to the GP-backed textured_grid_saved_fog_far_intensity in authoritative C. Caller +0x2c overrides it at 0x002a416c/0x002a4170. Retail 0x002a428c/0x002a429c emits it beside near intensity in the view packet; the supplied restore function restores the saved far intensity to this field.
unk110 -> voice_handle: Retail 0x002c2d60 loads pvars+0x110 into a1, compares it to -1 at 0x002c2d64-68, and passes it with the moby to playback check 0x00297c78 at 0x002c2d70 (current C voice_is_playing). If absent or inactive, 0x002c2d84-94 calls allocator 0x00297fa0 with (1,4,moby) and stores its returned token at +0x110. Original Ghidra and current C agree; caller initialization sets this s32 to -1. This is the moby's maintained voice handle, without asserting a sound identity. unk67 -> hit_reaction_interpolation_target: Original retail Ghidra and C assign pvars+0x67 from hit_reaction_code: retail 0x002c3144-4c stores 250, 0x002c3150-58 stores 120, and 0x002c3170-78 stores 240 for removal reactions. At 0x002c318c-98 pvars+0x60 is passed to trooper_anim_finish (level-13 0x00269580). Checked evidence request 33f48f2386ea486d91c5dd63ab3831e1 shows relative +7 loaded at 0x00269610/30 and used in saved component +4 plus (target minus component) times progress at 0x0026962c-58. Reverse phase 0x002696dc-0x00269720 interpolates from this target back to saved +4. Thus this u8 is the hit-reaction interpolation target, without asserting the component's physical meaning.
unk67 -> hit_flash_target_red: Original retail 0x002ad990-0x002ad9a0 selects 100 for reactions 9/10 or 200 for 3-8 and stores that byte at pvars+0x67 before blending hit sequence 1. The same pvars+0x60 state is passed to trooper_anim_finish at 0x002ad9f8-0x002ad9fc. Checked level-14 helper 0x002658c8 retains that state pointer; 0x00265948-0x00265998 interpolates byte +7 from saved color byte +4 into s2, and 0x00265af0 passes s2 as the red channel a1 to the color setter, agreeing with supplied trooper_anim_finish r1/r0 source. Its return phase at 0x00265a14-0x00265a60 interpolates back from that same target. This proves a hit-flash red target rather than an offset-only role.
unk64 -> start_in_leap_wait: In sharkigator_update, retail 0x002d16bc loads SharkigatorVars from moby+0x78; 0x002d16f4 loads its s32 +0x64 and 0x002d16f8 branches on zero. Nonzero stores state 2 at 0x002d1710 (SHARKIGATOR_WAIT_TO_LEAP), sets flags/update distance, saves moby Z at vars+0x74 and initializes the 30-frame leap timer via 0x002d1718/0x002d1b58. Zero instead reaches path initialization at 0x002d1728 and eventually stores state 1 at 0x002d17c0. The supplied C tests unk64 only in SHARKIGATOR_INITIALIZE, proving that it selects starting in leap wait.
unk18C -> bob_phase_radians: Authoritative src/overlays/shared/enemies/armed_transport.c SHA-256 1c072ceb541f2545a8586a6dc3c929b2dacd700b0a82a7f3a9173f8a23ad392e declares this f32 in ArmedTransportVars. Retail 0x002e2ae8-0x002e2b0c multiplies armed_transport_bob_phase_speed_degrees by 0.017453292 (DEG_TO_RAD) and frame_time and loads private+0x18C as the other argument to fast_add_rotations (0x001fe950). At 0x002e2b10-0x002e2b18 the returned wrapped angle is stored back to +0x18C and passed to fast_sin (0x001fe068). At 0x002e2b1c-0x002e2b34 its sine is multiplied by armed_transport_bob_amplitude, added to private+0x194/base_height and stored to Moby pos.z (+0x18). This data flow proves the stored scalar is the vertical bob phase in radians.
unk114 -> roll_spring_velocity: The assigned retail update clears pvars+0x114 at 0x0029E068 while setting initial rotation. Supplied C update_spline_moby_orientation passes this float's address as spring_turn's vel parameter for moby->rot.x. Bounded retail helper evidence f8a1340498cc4330a29ecc953605ed7a confirms +0x114 passed in a0 at 0x0029D158, current rot.x loaded from moby+0x40 at 0x0029D16C, spring call 0x0029D184 and result stored to that same rotation at 0x0029D18C. This is persistent roll spring velocity, not merely an offset-based guess. unk14A -> respawn_timer: Assigned retail 0x0029E134 clears the s16 at pvars+0x14A before entering spline movement. Supplied C update_spline_moby_destruction_and_respawn sets this field to scale_game_frames(600) after a qualifying hit and decrements it with fast_dec_timer_s16. Bounded retail helper confirms scale call with 600 at 0x0029D404-0x0029D408, store +0x14A at 0x0029D40C, nonzero test and timer-pointer call at 0x0029DAD8-0x0029DAE8. Expiration together with the existing flag restores collision and flags at 0x0029DAEC-0x0029DB14; otherwise the moby is hidden and collision disabled. The field therefore holds the respawn countdown. unk90 -> segment_start_tangent: At segment advancement the assigned retail 0x0029E1F0 loads the previous path tangent from pvars+0xA0 and 0x0029E208 stores the full quad at +0x90 before 0x0029E20C recomputes the next tangent into +0xA0. At 0x0029E28C-0x0029E2A0 evaluate_cubic_hermite_segment receives endpoints +0xB0/+0xC0 and tangent inputs +0x90/+0xA0. Authoritative C and original retail Ghidra agree on this copy-before-recompute flow, proving +0x90 is the current segment's starting tangent, paired with its ending tangent at +0xA0.
unkBA -> launch_burst_index: Authoritative C resets unkBA to zero on BOMBOMATIC_WAIT_TO_LAUNCH -> BOMBOMATIC_LAUNCH_BURST, passes it as spawn_bombomatic_projectile's existing short burst_index argument, then increments it once after each launch. Original retail decompilation agrees. Retail 0x0030d844 stores zero at pvars+0xBA; 0x0030dae0 loads that signed halfword into a3 for the 0x0030daec projectile-spawn call; 0x0030daf4..0x0030dafc loads, adds one and stores it back. The same-file spawn helper copies burst_index into the spawned projectile data+0x14. This proves a per-burst launch index, preserving s16 and all operations.
unk6E -> hit_cooldown_latched: Authoritative DecoyVars declares this s8 at +0x6e. Original retail Ghidra case 0 and sb zero at 0x002c4608 initialize it clear. In shared settled/pre-removal hit processing, 0x002c4cc8..0x002c4ccc first require short cooldown +0x6c zero. The hit-record type comparison at 0x002c4cd4..0x002c4cdc requires 0x101; ld/mask at 0x002c4ce4..0x002c4cfc tests bytes +0x6c,+0x6d,+0x6e, thereby also requiring this flag clear. 0x002c4d04..0x002c4d14 then stores scaled 100 to the short cooldown and 1 to this byte. Other processed hit conditions clear the byte at 0x002c4ce0/0x002c4d00. C uses agree: the flag survives timer expiry to inhibit immediate rearming, proving a hit-cooldown latch without identifying type 0x101. unk6F -> collision_voice_cooldown: Authoritative DecoyVars declares this s8 at +0x6f. Original retail Ghidra case 2 and instructions 0x002c4ba0..0x002c4bc8 pass its address to FUN_001fefc8 after collision response; a nonzero return calls the established allocate_voice_for_target_entry(0,0,moby), then reloads the byte with scale_game_frames(20). Bounded helper evidence request 78c41797b4fb497fbe305347214b218d confirms 0x001fefc8 loads the byte unsigned, returns 1 when already zero, otherwise decrements/stores it at 0x001fefd8..0x001fefe4 and returns 2 upon expiry or 0 while still positive. The zero-return branch instead perturbs velocity. This proves a collision-branch voice-allocation cooldown, without claiming unconditional frame ticking or a particular sound.
unkBD -> pre_fall_delay: In the authoritative C, command 2 enters PLATFORM_TIMED_SWAY_BEFORE_FALL and copies this u8 into unkAC. Retail 0x0031137c-0x00311380 loads pvars+0xBD unsigned and stores it at +0xAC; 0x003115a8-0x003115d8 decrements that timer and only on expiry enters PLATFORM_TILT_AND_FALL. This establishes the configured delay before falling. unkBE -> fall_signaling_enabled: Retail 0x003114ac-0x003114c0 tests pvars+0xBE before passing moby+0x21 and command 2 to 0x00281be0. Checked level-07 helper 0x00281be0-0x00281c2c iterates a selected list of moby indices and writes that command to each moby+0xBC. At 0x003115b8-0x003115cc the same nonzero flag gates the parent pvars signal write and parent state 12 immediately before the platform enters falling state 3. The C uses agree: this flag enables fall-related group and parent signaling. unkBF -> parent_fall_signal: The authoritative C copies this u8 to parent_data[0x19D] when timed sway expires, then sets parent state 12 and platform state PLATFORM_TILT_AND_FALL. Retail 0x00311354-0x0031135c resolves parent and parent pvars; 0x003115c4 loads pvars+0xBF, 0x003115c8 stores the byte into parent pvars+0x19D, and 0x003115cc-0x003115d8 sets the parent and platform states. This is the configured byte signaled to the parent as falling begins; its enum interpretation is unknown.
f160 -> selected_target_moby: Retail root 0x002e4794-0x002e47a8 defaults pvars+0x160 to hero.moby. Bounded helper 0x002527c8 receives pvars+0x120; 0x00252974 writes the selected moby at output+0x40 (=pvars+0x160), alongside its position. The supplied toxic_crab_update reads the same field as tgt and uses its position for pursuit and melee. f164 -> target_selection_status: Root 0x002e4620/0x002e468c writes 2 at pvars+0x164 when tracked position exceeds home range or vertical tolerance. Bounded helper 0x002527c8 receives pvars+0x120 and stores selection status s5 at output+0x44 at 0x002529bc/0x002529f0/0x00252a0c: 0 for hero fallback, 1 for selected candidate, 2 when no target is available. Caller tests i164 to activate, pursue or return home. f1AC -> target_range_boost_timer_frames: Retail 0x002e3f80-0x002e3fa8 initializes pvars+0x1AC from scaled random 180..240 and 0x002e3fb0-0x002e3fb4 decrements it with fast_dec_timer. At 0x002e4534-0x002e4548 its nonzero state increases targeting range f1A0 by 6; 0x002e45b4-0x002e45c8 selects direct target refresh while active. This proves a timed target-range boost without assuming its gameplay trigger. f1B0 -> target_path_index: Retail 0x002e4670 loads pvars+0x1B0; 0x002e4690-0x002e46ac multiplies it by four and indexes the level path table at 0x001b0930. 0x002e46b8-0x002e46c0 passes that path's count and points to the targeting helper. Current C expresses exactly l10_paths[moby_data->f1B0]->points/count. f1D4 -> target_loss_frames: Retail 0x002e46c4-0x002e46f8 increments pvars+0x1D4 once per update only outside WAIT_FOR_ACTIVATION with target selection status 2, and compares it with scale_game_frames(300). 0x002e4704-0x002e4784 then returns home or waits. 0x002e4530/0x002e4790 and the non-2 branch reset it. Status 2 is the helper's no-target status and is also forced for out-of-range targets. f38 -> target_range_boost_pending: At retail 0x002e3f6c-0x002e3f78 nonzero pvars+0x38 triggers the reaction helper; 0x002e3f80-0x002e3fa8 initializes the scaled 180..240 timer at pvars+0x1AC, and 0x002e3fac clears pvars+0x38. That timer's nonzero state boosts targeting range by 6 at 0x002e4534-0x002e4548. The field is thus a consumed pending request for that boost; its producer and original trigger are not inferred. f88 -> knockback_xy_scale: Retail 0x002e43f0/0x002e4494 passes pvars+0x88 as the third pointer to the source-bound trooper_knockback_arc call at 0x002e4400/0x002e44a4. Supplied helper source multiplies that pointed scalar by vector_length_xy(input_vector_copy) when the hit vector uses the 5627.9248046875 sentinel. Current C passes &moby_data->f88 in both hit-knockback branches. f8C -> knockback_z_scale: Retail 0x002e43f8/0x002e449c passes pvars+0x8C as the fourth pointer to trooper_knockback_arc at 0x002e4400/0x002e44a4. Supplied helper source multiplies that pointed scalar by the hit vector z component in its sentinel branch. Current C passes &moby_data->f8C while configuring state HIT_KNOCKBACK, proving the vertical knockback scale role.
b53 -> requested_animation_sequence: Retail blend helper 0024a318 saves sequence argument a1 in s3, uses it to index animation records at model+0x48, and 0024a3dc stores s3 to moby+0x53 while +0x52 is separately cleared to 0xff at 0024a3c0. Assigned 002e51dc-002e5200 compares +0x53 with sequence 3 before requesting that same sequence; this is the requested sequence, distinct from current +0x52. f160 -> firing_duration_seconds: At 002e4fd8 state becomes FIRE_AT_TARGET and 002e4fe8 loads private +0x160. The shared chain 002e57dc-002e57f4 multiplies by 60, frame-scales, truncates and stores +0x168. The same field reloads on cooldown expiry 002e55bc and hit recovery 002e5774, proving configured firing-phase duration in seconds. f164 -> cooldown_duration_seconds: At 002e53bc state becomes FIRE_COOLDOWN, then 002e53c4 loads private +0x164. 002e55c0-002e55d0 frame-scales its product with 60, truncates and stores countdown +0x168. Hit recovery into cooldown repeats this at 002e57d4-002e57f4; the field supplies cooldown duration in seconds. f198 -> heading_turn_velocity: Assigned 002e4d0c computes target-minus-ship XY atan, and 002e4d24-002e4d34 passes that desired heading and private +0x198 to FUN_L00_00258278. Its supplied declaration identifies the pointer argument as vel; the same heading spring chain repeats at 002e4ee4, 002e5138 and 002e551c. f19C -> pitch_turn_velocity: Private +0x19c is zeroed at 002e4b6c, then passed by address to spring_turn at 002e4d74-002e4d78 with current ship+0x44 and negative aim elevation. The supplied spring_turn declaration identifies this pointer as vel; pitch smoothing repeats at 002e4f34, 002e5188 and 002e556c. f44 -> pitch: 002e4d50 computes atan(horizontal distance,target Z minus ship Z); 002e4d60 negates elevation and spring_turn reads ship+0x44 at 002e4d64 and writes it at 002e4d88. 002e527c-002e5290 negates this same field as the elevation input to build_spherical_offset, proving the stored pitch angle. f48 -> heading: 002e5194-002e51ac computes atan(target XY minus ship XY), then 002e51b0-002e51b8 compares it with ship+0x48 via fast_difference_between_rotations. 002e5284 passes +0x48 as the heading input to build_spherical_offset with unit radius and negative pitch, proving the ship heading angle. f58 -> animation_speed: Assigned 002e5204-002e5208 writes blarg_ship_firing_animation_speed_gp to ship+0x58 after requesting firing sequence 3; 002e55b0 and 002e5768 repeat this on firing entry. Checked blend_moby_animation resets +0x58 to 1.0 at 0024a3e0, separately setting reciprocal blend duration at +0x5c, consistent with the supplied animation-window context unk58*unk5C. i114 -> targeting_status: Assigned 002e521c-002e5224 tests private +0x114 against 2 to suppress rocket emission. Supplied directly called update_blarg_ship_hit_reactions_and_targeting maps the same +0x114 to unk114, setting 2 when target selection fails or the target is outside its allowed path, and 0 when the selected target is inside. This proves a targeting status without inventing all status meanings. i140 -> entry_path_index: 002e4ad8-002e4af4 checks private +0x140 against -1 and prints the missing-path error before removal. 002e4b7c-002e4b94 uses it to index l10_paths and copies the first point to ship position; 002e4e4c-002e4e7c follows its points in FOLLOW_ENTRY_PATH until state 4 is entered. i144 -> firing_path_index: 002e55d4-002e5600 loads private +0x144, indexes l10_paths, and fetches the point selected by +0x158. Assigned states FIRE_AT_TARGET and FIRE_COOLDOWN share this motion chain; 002e5660-002e568c bounds point advancement using that path's count, proving the path used during firing and cooldown. i148 -> activation_volume_index: 002e4c10 loads private +0x148 as the clip-volume argument, while 002e4c18 passes target position to is_point_inside_clip_volume. Its true result changes state from WAIT_FOR_TARGET_IN_VOLUME to RISE_TO_ENTRY_PATH at 002e4c1c-002e4c30, proving the target activation volume index. i158 -> path_point_index: 002e4e58-002e4e78 shifts private +0x158 by four to select an aligned point from the entry path. 002e4fac-002e4fcc increments it only below path count and 002e4fd4 resets it when entry completes. 002e55e0-002e5600 and 002e5664-002e568c reuse it to select and advance firing-path points. i168 -> firing_phase_timer: 002e5378-002e5380 passes private +0x168 to fast_dec_timer and on expiry enters cooldown at 002e53bc. 002e5578-002e55ac decrements the same timer in cooldown and returns to firing on expiry. 002e55c0-002e55d0 reloads the frame-scaled duration, proving a countdown shared by both firing phases. i1B0 -> departure_volume_index: 002e4ff0-002e5000 supplies private +0x1b0 and hero position to is_point_inside_clip_volume. A true result branches to 002e53e4-002e53e8 and writes FLY_AWAY state 6. Cooldown repeats the test at 002e53cc-002e53dc, proving the volume index that triggers departure.
unk148 -> selected_clip_volume_index: Retail 0x002ca8b4-0x002ca8c4 copies the acquired clip-volume candidate byte into pvars+0x148. At 0x002ca63c-0x002ca68c and 0x002ca720-0x002ca744 it indexes l04_cuboids with stride 0x80 to read the selected volume heading and position, matching the authoritative C. unk149 -> clip_volume_movement_state: Retail 0x002ca564-0x002ca594 dispatches pvars+0x149 among four movement cases. Acquisition writes 1 at 0x002ca8bc, arrival writes 2 at 0x002ca718, timer expiry writes 3 at 0x002ca794, and return completion writes 0 at 0x002ca838. These correspond to the four established clip-volume movement enum labels in C. unk14A -> clip_volume_movement_timer: Retail 0x002ca55c-0x002ca560 decrements the signed halfword at pvars+0x14a. Zero gates clip-volume acquisition at 0x002ca5f8-0x002ca604 and transition from waiting to return at 0x002ca780-0x002ca794. Arrival stores scaled 300 frames at 0x002ca710-0x002ca71c; return completion stores scaled 600 frames at 0x002ca83c-0x002ca844, proving the shared movement wait/cooldown timer. unk14C -> saved_return_heading: Retail 0x002ca8cc-0x002ca8d4 saves moby->rot.z from owner+0x48 into pvars+0x14c upon clip-volume acquisition. Return movement loads it as the spring-turn target at 0x002ca7cc and compares it against current heading at 0x002ca80c-0x002ca814. The authoritative C uses it only to restore and test the saved heading. unk160 -> saved_return_position: Retail 0x002ca8a8-0x002ca8b0 copies the full 16-byte owner position to pvars+0x160 upon clip-volume acquisition. Return movement uses that saved vector for distance at 0x002ca7d4-0x002ca7ec and subtracts current moby position from it at 0x002ca858-0x002ca864 before stepping toward it, exactly as the C return case shows. unk170 -> hit_recovery_timer: In the hit branches retail 0x002cad64-0x002cad78 and 0x002caef4-0x002caf00 store scaled 600 frames into pvars+0x170 and set the recovery flag. At 0x002cb668-0x002cb670 fast_dec_timer consumes this field; only its completion enables the camera-angle check before restoring class collision. The C shows the same hit-triggered recovery delay. unk174 -> hit_recovery_active: Retail hit branches write 1 to pvars+0x174 at 0x002cad78 and 0x002caf00. At 0x002cb65c-0x002cb660 zero bypasses the recovery block; while active the block disables collision and sets flags 0x41. After timer completion and the camera-angle test, 0x002cb6c4-0x002cb6dc restores class collision, clears those flags and resets this field to zero, proving a hit-recovery active flag. unk178 -> saved_draw_distance: Initialization sets owner draw_dist to 0x7f at retail 0x002ca528, then loads that signed halfword from owner+0x32 at 0x002ca538 and stores it into pvars+0x178 at 0x002ca53c. The authoritative C explicitly assigns this field from moby->draw_dist, proving a saved draw distance without claiming a later use. unk17C -> linked_moby_index: Retail 0x002caa88-0x002caaa4 tests pvars+0x17c against -1 and forms a Moby pointer by shifting the field left eight bits and adding the Moby array base. The linked object receives transformed position/rotation at 0x002caac8-0x002cab78 and shares recovery flag changes at 0x002cb6e0-0x002cb700 and 0x002cb724-0x002cb740. C independently computes the same linked Moby pointer in these blocks.
f94 -> active_collision: Retail 0x002b49e8-0x002b4a04 clears hidden flags 0x41, loads moby class at +0x24, loads class+0x10 and stores that word at moby+0x94 on transition from WAIT_TO_FOLLOW_PATH to FOLLOW_INTRO_OR_EXIT_PATH. Authoritative C expresses this as moby->f94 = moby->cls->f10. The supplied hide_minibomber_and_release_voice definition (FUN_L14_002b5c98, called by initialization and completed retracing) sets moby->flags |= 0x41 and moby->collision = 0; the supplied checked prior retail annotation explicitly identifies the reverse transition as restoring class collision. Together these establish f94 as the active collision member restored for visible path following, rather than an arbitrary class word.
unk210 -> beam_start_position_storage: Retail 0x002b295c loads moby pvars; 0x002b2af0 retains pvars+0x210 in s5 and 0x002b2c98..0x002b2c9c copies its 16-byte vector into the fourth quad translation. Original Ghidra reads +0x210..+0x21c there. In the authoritative C this member supplies beam_start_position. The same pvars storage is ShipVars.beam_start in update_plasmabot_visual_effects, computed by adding bone-2 translation and scaled x/y/z basis offsets before queuing this renderer. Thus this is beam start position storage, not merely an offset-derived name. unk220 -> beam_end_position_storage: Retail 0x002b2ac0..0x002b2ac8 saves pvars+0x220 at sp+0xe0; 0x002b2da0..0x002b2da8 reloads it and copies its leading 16-byte vector into the fifth quad translation. Original Ghidra's puStack_c0 has the same +0x220 source and final vector copy. In authoritative C, pp points to this member. update_plasmabot_visual_effects writes the same pvars location as ShipVars.beam_end by adding -2 times the scaled bone-2 y offset to beam_start, then queues this renderer. Only the leading position vector is semantically established; the trailing four bytes of this 0x14-byte storage remain unresolved.
unk5C8 -> vertical_oscillation_previous_offset: Retail 00306c4c and 00306df8 pass pvars+0x5C8 as the final pointer to 0027b120, repeated at 00306f04 and 0030721c. Authoritative C calls update_moby_vertical_oscillation; supplied helper C subtracts the previous sine offset from pos.z, replaces it with amplitude*sin(phase), and adds it back. unk5E4 -> rotation_common_factor_phase: Retail 00306c50/00306e20 supplies pvars+0x5E4 as the first phase pointer to 0027b1a0, repeated at 00306f24 and 0030723c. Source update_moby_rotation_oscillation uses its first phase sine as a common multiplier for both rotation components, and advances it with the established common_factor_phase_rate_degrees. unk5E8 -> rotation_component_mix_phase: Retail 00306c54/00306e28 supplies pvars+0x5E8 as the second phase pointer to 0027b1a0, repeated at 00306f2c and 00307244. Supplied rotation-oscillation helper C uses sin/cos of this second phase to mix the two rotation components, then advances it by the established component_mix_phase_rate_degrees. unk5EC -> path_start_clip_volume: Retail 00306e64..00306e80 tests this stored clip-volume argument against point 0013f3d0; a nonzero test or the alternate global trigger reaches the state=2 store at 00306ed8. Source identifies this transition as WAIT_FOR_PATH_TRIGGER to FOLLOW_PATH. unk5F0 -> path_movement_step: Retail 00306f88..00306fe4 approaches this float toward zero or frame-scaled 8.0. At 00307028..00307044 it becomes the normalization magnitude of the waypoint difference vector that is added to moby position. Authoritative C fast_vec_normalize(v,v,unk5F0) and fast_vec_add prove per-update path displacement length. unk5F4 -> yaw_turn_step: Retail 003070a0 passes pvars+0x5F4 to the yaw steering helper 00270fb8, with target heading computed from waypoint XY; 003071a0 passes the same storage to spring_angle for moby+0x48. Supplied FUN_L00_00258278 helper C updates this persistent turn step and adds it to moby->rot.z. unk5FA -> detached_parts_update_count: Retail 00307588..003075cc checks this signed-short field for zero before transferring linked slots; 003075dc..00307600 initializes motion for all 18 slots only on that zero case. At 00307604..00307614 the field increments once before the detached-parts update. Source state 4 mirrors this one-time initialization guard and update counter. unk5FC -> remaining_gun_health: Retail 00306c00/00306c0c initializes this s16 to 100. Checked gun helper request 2d8bbc57b6ed4bf2843fde3b27e315cc shows 00305d18..00305d48 subtracting 20 and clamping this owner field at zero when a gun's float health reaches zero; 003062d8..00306308 enters DROP_PARTS_AND_TRANSITION when depleted. Same-file C agrees. unk604 -> voice_slot: Retail 00307634..00307654 stores allocate_voice_for_target_entry's returned index in this field. At 00307658..00307690 that index selects a voice-pool record with stride 0x70, checks owner and active status, and is passed to release_voice_slot. Initialization and release reset it to -1. unk60C -> transition_target_camera_point: Retail 00307378..003073a8 multiplies this record index by 128 and uses record+0x30 as the second lerp endpoint, with camera_point as first endpoint. 003073b8..003074bc uses its +0x70/+0x74/+0x78 rotation components as angular targets. Source feeds the interpolated outputs to set_camera_position and set_camera_rotation. unk610 -> camera_transition_fraction: Retail 00307320..00307374 compares this float with 1.0 and advances it toward 1.0. Retail 00307394 passes it as the lerp factor and 003073e4/00307440/00307498 scales angular differences by it. Authoritative C applies these interpolated vectors to the camera and finishes interpolation once it reaches 1.0. unk614 -> camera_transition_step: Retail 00307340..00307374 passes pvars+0x614 as the second pointer of advance_accelerated_scalar, with the transition fraction as first pointer. Checked helper request 653d47b40dff4ede86c06b3d4645fcb2 shows second-pointer storage retained in s0 at 00274874, adjusted via approach_value, and added to first-pointer scalar at 002749b8..002749c8 and 002749e4..002749f0. This is the persistent interpolation step. unk61C -> height_timer_refresh_clip_volume: Retail 00306d54..00306d78 passes this stored volume to the point-inside-clip test and, on success, stores scale_game_frames(90) in pvars+0x620. Retail 00306d7c..00306d90 tests that timer to select the 19.0 height offset; authoritative C uses this volume specifically to refresh the height-control timer. unk624 -> linked_parts_flags_clip_volume: Retail 00306c1c..00306c28 tests point 00167240 against this clip-volume argument. Retail 00306c30..00306cf4 sets or clears mask 0x41 on the owner and all 17 present linked mobys according to the test. Authoritative C confirms it gates the linked group's flags; no particular meaning of either flag bit is assumed. unk628 -> height_raise_clip_volume: Retail 00306cfc..00306d28 tests point 0013f3d0 against this volume and combines the result with the point's Z>52 test to choose simple baseline-height approach versus spring handling. Retail 00306d48..00306d5c selects a 10.0 raised-height offset when inside, otherwise 3.0 before timer override; source matches this height-control role. unk62C -> height_spring_velocity: Retail 00306d94..00306ddc passes moby+0x18 as current scalar and pvars+0x62C as the second pointer to 002747b0, targeting saved height plus the selected offset. Authoritative C identifies vendor_spring; supplied helper C names the second pointer velocity, updates it using target-current error, and adds it to the current scalar.
unk90 -> cached_aim_point_position: Retail 0x002aebe4 sets s4=pvars+0x170, corresponding to aim_point_position. After the visibility gate at 0x002aec44, 0x002aecf4-0x002aecfc copies all 16 bytes from s4 to pvars+0x90 (lq/sq), matching qcopy(unk90, aim_point_position) in the authoritative C. The patrol caller updates aim_point_position after this function, then uses unk90 and the midpoint to unkD0 for positional scan queries. draw_blarg_heavy_interceptor_camera_pulled_glow copies unk90 to glow_quad_position before applying its small Z offset and camera pull. Thus this f32[4] caches the aim-point position, rather than holding a direction, transform, or final camera-adjusted position.
…ibility unk114 -> target_mode: SentrybotVars s32 field is loaded at retail 0x0029aa5c and compared with mode 1 at 0x0029aa64; target visibility failures write mode 2 at 0x0029aac0 and passive detection writes 2 at 0x0029ab10. Authoritative sentrybot_update already reads this member into local mode and compares it with SENTRYBOT_TARGET_MODE_SUPPRESS_DIRECT_EMISSION before entering projectile emission states. This proves a target behavior mode, without assigning meanings to every value. unk12C -> sight_line_ignored_moby_index: Retail 0x0029a940 loads this SentrybotVars s32, checks -1 at 0x0029a944, shifts the valid index by 8 at 0x0029a94c and adds l15_moby_array at 0x0029a950. The resulting moby pointer is collision_line argument a3 at 0x0029a960 for the sight test whose result becomes has_line_of_sight. Source explicitly identifies it as the moby index the sight line ignores; its other uses remove that same indexed moby and reset the index to -1. unk158 -> target_detected_without_engagement: Retail 0x0029aaa4 branches on accepted visibility. No visibility clears this s16 at 0x0029aac8; failed target-point query clears it at 0x0029ab64. With accepted visibility but the alert/suppression conditions at 0x0029aacc..0x0029ab08, 0x0029ab10 forces target mode 2 (source's SUPPRESS_DIRECT_EMISSION) and 0x0029ab18 sets this member to 1. Source sentrybot_update uses its nonzero value as glow alert level 1 when neither alert_timer nor an emitting target mode supplies level 2. Name describes this detected but nonengaging condition, not a timer. unk19F -> target_in_view: Retail 0x0029a9c0..0x0029aa58 establishes accepted visibility from target heading/height and has_line_of_sight, with explicit attack-state bypasses. 0x0029aaa8 sets this u8 to 1, 0x0029aabc clears it when that accepted visibility is zero, and 0x0029ab5c clears it when the target-point query fails. Source update_sentrybot_joint_aim tests the matching raw byte +0x19F to select remembered target coordinates for aiming. It records accepted target visibility, distinct from the existing unrestricted has_line_of_sight member. unk67 -> first_channel_blend_target: Root retail 0x0029a6c8 and 0x0029a868 write this u8, then 0x0029a86c..0x0029a888 passes data+0x60 to reaction animation helpers. Checked helper request 3e21e68b29674a5f8b2c3b16ed20d01c shows 0x0024ce8c..0x0024ceb8 interpolating helper offset 4 toward offset 7, and 0x0024cf58..0x0024cf80 interpolating back. The computed first channel is passed in a1 at 0x0024d018. Since data+0x67 is helper record+7, this is the first channel blend target; no physical color/channel identity is assumed.
f270 -> target_selection_range: At 0x002c9cd4 retail loads moby->data into s0; 0x002c9cdc loads its float +0x270 into f12 for select_moby_target_with_hero_fallback at 0x002c9ce4. Bounded level-03 helper 0x0024e830 preserves f12 in f20 at 0x0024e858, compares source/candidate XY distance against it at 0x0024e928 and 0x0024e9ac, and replaces the selected moby and threshold only for a nearer candidate at 0x0024e938-0x0024e93c and 0x0024e9bc-0x0024e9c0. Supplied authoritative C also passes f270 to select_moby_combat_target and compares target_distance against it for facing/projectile behavior. update_kerwan_path_enemy_hit_reaction refreshes it from f26C or f26C+5.0f according to s252, proving an adjustable target-selection range rather than an offset-only field name.
b50 -> animation_entry_index: WalkMoby byte +0x50 is converted to float at 0x002a3930-0x002a3950 and added to the interpolation fraction to form the current entry position used for landing playback correction. Checked helper 0x0024edc8 compares +0x50 with next entry byte +0x51 when choosing record interpolation at 0x0024ee28-0x0024ee40; this is an animation entry index, not a sequence id (+0x52). f0C -> animation_position_origin: WalkAnim +0x0C is subtracted from phase marker positions before wrapping by cycle length and looking up an animation entry, e.g. 0x002a1b14-0x002a1b74 and 0x002a19ec-0x002a1a34. Conversely it is added to the cycle length before comparison with current interpolated animation position at 0x002a35d8-0x002a35e8, proving the origin translating relative cycle positions to animation positions. f54 -> animation_interpolation_fraction: Checked helper 0x0024edc8, request e39c867287824854b6af76cf0034d010, loads moby +0x54 and weights two animation record positions with (1-fraction) and fraction at 0x0024ee68-0x0024eea0. Assigned landing synchronization adds this same float to the converted entry index at 0x002a3940-0x002a3950 and 0x002a39d0-0x002a3a00. f58 -> animation_playback_rate: In landing synchronization, 0x002a39dc-0x002a3a40 computes a target animation position from landing time, clamps it above current entry index plus interpolation fraction, and stores frame_scale_inv*(target-current) to moby +0x58. The same float is subtracted from animation end position for takeoff completion at 0x002a35d4-0x002a35e8 and tested for slow playback at 0x002a1870-0x002a1888. i14 -> initial_animation_position: On idle departure the selected WalkAnim +0x14 integer is converted to float and passed to find_nearest_animation_sequence_entry at 0x002a1734-0x002a1748 or 0x002a17f4-0x002a1808; the resulting entry starts the blend. The same integer position initializes the gait mask at 0x002a1834-0x002a1844, proving the initial animation position shared by playback and gait phase bookkeeping. v60 -> jump_target_position: In takeoff cases, retail 0x002a354c-0x002a359c passes walker position and gait_data+0x60 to the checked ballistic velocity helper FUN_L00_0025abf0 as start and target positions. 0x002a35a4-0x002a35c4 subtracts walker XY from its XY to calculate jump heading. Supplied compute_walker_time_to_landing also subtracts its Z from walker Z, proving a three-coordinate jump target position.
unk66 -> reposition_timer: In reposition_moby_with_collision_check, the zero-collision branch initializes moby_data->unk66 = scale_game_frames(0xB4) after restoring animation, flags and class collision and assigning state 4. Retail 0x002c467c loads s0 from the repositioned moby's pvars at s1+0x78; 0x002c46bc passes 180 in a0, 0x002c46d4 calls scale_game_frames (0x001fd788), and 0x002c46dc stores its returned v0 as a halfword at s0+0x66. Original Ghidra independently shows uVar1=func_0x001fd788(0xb4) followed by the private +0x66 store. This proves a frame-scaled reposition timer initialization, without asserting the timer's later expiry behavior.
domain_0_value_1 -> MINE_STATE_FREE_MOTION: Retail 0x002aa024 preserves the initialized moby argument in s1; 0x002aa088/0x002aa098 stores 1 into its state byte at +0x20. The checked mine_glove_update release branch passes mine_glove_vars->held and held->pvars to this function, proving this is the released mine's moby-state domain. At 0x002aa050 and 0x002aa0ec-0x002aa128 its private motion receives base motion, random offset and optional hero displacement, and 0x002aa1d4-0x002aa278 initializes collision-adjusted position and reflected motion. The authoritative same-file mine_update uses the existing MINE_STATE_FREE_MOTION member when releasing a mine from an attached collision surface or invalid homing target, resetting velocity and the same private+0x34 timer. This establishes the existing mine moby-state member, rather than the unrelated equal-valued homing phase or hero enum members.
f128 -> lateral_launch_aim_angle: Retail 0x002f4b44-0x002f4b54 stores atan(1, lateral coefficient +0x3BC) into +0x128 during forward/lateral launch; C matches the angle calculation. f140 -> joint_19_animation_state: Retail 0x002f450c-0x002f451c passes +0x140 to relative-aim setup, and 0x002f5d18-0x002f5d28 passes the same storage to update_joint_animation with joint 0x13. f1C0 -> big_head_manipulator_state: Retail 0x002f2c3c-0x002f2c5c passes this +0x1C0 buffer together with the attached manipulator owner and big-head scale to the manipulator helper; bound C agrees. f200 -> class_247_group_index: C passes this integer to find_nearest_class_247_moby_in_list and find_class_247_moby_with_largest_xy_angle_in_list; retail loads +0x200 at 0x002f3d1c and 0x002f3d74. f210 -> gadgebot_group_index: Retail 0x002f5130-0x002f513c and 0x002f5160-0x002f5164 pass +0x210 to the established group launch and count_group_gadgebots_not_in_state_8 helpers. f214 -> missile_group_index: Retail 0x002f40d8-0x002f40dc loads +0x214 as the group argument to activate_drek_fight_missiles_in_group; C supplies the raised boss position separately. f21C -> thruster_lock_moby_index: Retail 0x002f3f54-0x002f3f74 scales +0x21C by 0x100 into the moby table and calls request_thruster_pack_lock_red_wait; 0x002f5920-0x002f5934 uses it for ending that wait. f220 -> paired_transition_moby_index: Retail 0x002f2d50-0x002f2d90 scales +0x220 by 0x100 into the moby table and stores its pointer at +0x334, used by start_camera_transition and progress polling. f240 -> alternate_platform_activation_moby_indices: Retail 0x002f38b4-0x002f38e4 iterates four +0x240 indices when phase is not 1, scales each by 0x100 and calls activate_drek_boss_class_0565_moby; phase 1 uses +0x230. f270 -> encounter_trigger_path_index: Retail 0x002f2f7c-0x002f2fa4 indexes the path table with +0x270 then passes path count and +0x10 points to point_in_path_xy on the hero position. f274 -> encounter_trigger_clip_volume_index: Retail 0x002f2ef8-0x002f2f04 passes +0x274 with hero position to is_point_inside_clip_volume, gating the giant-Clank encounter trigger in bound C. f280 -> aim_candidate_node_indices: Retail 0x002f4344-0x002f43d8 iterates three integers at +0x280, indexes 0x80-byte nodes, compares XY angles and saves the winning node to +0x3A8. f294 -> scene_camera_node_index: Retail 0x002f2ed0-0x002f2ee4 uses +0x294 to select node position/rotation for jet_reset_camera; 0x002f5990-0x002f59b8 copies that node transform into scene state. f298 -> paired_transition_node_index: Retail 0x002f3ef0-0x002f3f20 indexes a node using +0x298, copies position and yaw into the fifth vector passed to start_camera_transition. f29C -> class_238_launch_group_index: Retail 0x002f4f74-0x002f4f88 loads +0x29C as the list/group argument to launch_class_238_moby_from_list, with separate launch and ground target vectors. f2A0 -> race_camera_node_index: Retail 0x002f3374-0x002f3398 indexes 0x80-byte nodes with +0x2A0 and supplies node position +0x30 and rotation +0x70 to set_race_camera. f310 -> saved_transition_rotation: Retail 0x002f3fa0-0x002f3fac copies this four-float +0x310 vector into moby rotation +0x40 after the paired transition state check; bound C qcopy agrees. f320 -> stored_aim_target_position: Retail 0x002f5518-0x002f5524 copies aim-target position to +0x320; 0x002f4498-0x002f4520 aims toward it and 0x002f4604-0x002f4608 subtracts launch origin from it. f330 -> selected_class_247_moby: Retail 0x002f3d18-0x002f3d24 stores the class-247 selection helper return at +0x330; 0x002f5530-0x002f55b4 turns and advances toward that moby's position. f334 -> paired_transition_moby: Retail 0x002f2d90 stores a resolved moby pointer here; 0x002f3f30-0x002f3f34 initializes its transition and 0x002f403c-0x002f4040 polls its transition progress. f338 -> hero_follow_ring_effect_moby: Retail 0x002f4488-0x002f4494 stores create_class_274_ring_effect return at +0x338; 0x002f528c-0x002f52a0 refreshes it at boss position during FOLLOW_HERO. f33C -> pending_electric_ball_moby: Retail 0x002f4020-0x002f402c and 0x002f45a0-0x002f45ac store spawn_drek_boss_electric_ball return here; release calls refresh_moby_position_and_activate then clears the pointer. f340 -> active_movement_path: Retail 0x002f2fd0-0x002f2fe4 resolves the path table into +0x340; 0x002f39f8-0x002f3a14 indexes its points and 0x002f3bb8-0x002f3bc4 compares its count. f344 -> arena_center_node_index: Retail 0x002f30d0-0x002f30d8 stores configured arena node here; 0x002f4884-0x002f48ec uses that node as the center for ground-target radius clamping; supplied circling source agrees. f348 -> path_point_index: Retail 0x002f39f8-0x002f3a14 scales +0x348 by 16 and selects active path point +0x10; 0x002f3a34-0x002f3a40 increments it upon reaching the point. f34C -> encounter_phase: Retail 0x002f3140 and 0x002f3270 store arena phases 1 and 2; 0x002f55c0 dispatches phase timers and 0x002f5664-0x002f5674 increments the same phase selector. f350 -> previous_action_state: Retail 0x002f4fb0 stores the completed attack state before returning to action selection; supplied select_drek_boss_next_action reads +0x350 and excludes repeating that state. f354 -> action_event_timer_frames: Retail 0x002f4090-0x002f40a8 decrements and reloads +0x354 with scaled frames for missile events; 0x002f45b0-0x002f45e4 similarly gates timed electric-ball release. f358 -> action_frame_counter: Retail 0x002f41c8-0x002f41d0 initializes +0x358 from scaled frames and 0x002f4a6c decrements it to end an action; death state 0x002f56f4-0x002f571c instead increments it for timed explosions. f35C -> secondary_action_timer_frames: Retail 0x002f4240-0x002f4268 initializes +0x35C with phase-scaled frames; 0x002f4d64-0x002f4d7c decrements it after +0x358 before ending forward-launch action. f360 -> ring_launch_cooldown_frames: Retail 0x002f4c14-0x002f4c1c stores scaled 300 frames here on ring launch; supplied scalar-update source decrements +0x360 and requires zero for gated follow behavior. f364 -> hero_follow_action_blocked: Retail 0x002f5668-0x002f566c sets +0x364 after selected-moby arrival; supplied action selector rejects FOLLOW_HERO when it is nonzero and damage-transition source clears it upon rearm. f368 -> health_hud_animation_handle: Retail 0x002f2d88 initializes +0x368 to -1; supplied scalar-update source assigns queue_animation_update for the health counter and cancels it through set_animation_parameter(handle,0). f370 -> yaw_approach_state: Retail 0x002f32d0-0x002f3318 passes moby yaw +0x48 and +0x370 as mutable state to approach_angle with target hero yaw and frame-scaled acceleration/speed limits. f374 -> movement_step_distance: Retail 0x002f39ac-0x002f39d8 approaches +0x374 toward frame_time*12; 0x002f3a18-0x002f3a58 compares remaining path distance to it and uses it to scale the displacement. f38C -> boss_health: Retail 0x002f2d8c initializes +0x38C to 350; supplied damage helper subtracts damage, clamps phase health floors and enters death-explosion state when this float reaches zero. f390 -> rail_mode_damage_accumulated: Retail 0x002f4a7c-0x002f4abc tests +0x390 against 25 to end the ground-target action; supplied damage helper adds damage to this field specifically when hero control_mode is 0xF. f398 -> platform_target_group_index: Retail 0x002f2d64-0x002f2d80 saves initial moby group here and 0x002f3fe0 uses it to show the group; supplied platform-target helper indexes its group-entry table using +0x398. f39C -> post_scene_resume_state: Retail 0x002f3d6c saves state 5 at +0x39C before starting scene 2; 0x002f2df0-0x002f2dfc restores its low byte into moby state when scene mode ends. f3A0 -> boss_joint_glow_attachment_moby: Retail 0x002f5b88-0x002f5b8c removes this attachment on cleanup; supplied damage source creates class 0x58F here and attaches it to joint 4; glow renderer uses its joints 1 and 2. f3A4 -> big_head_attachment_moby: Retail 0x002f2c3c-0x002f2c5c passes this moby to the big-head manipulator helper; supplied damage source creates class 0x4E1 here and attaches it to the joint-glow attachment. f3A8 -> selected_aim_node_index: Retail 0x002f43c8-0x002f43d0 stores the winning candidate node here; 0x002f54b0-0x002f54e0 scales it by 0x80 and supplies its position as movement target. f3AC -> ending_scene_4_delay_counter: Retail 0x002f5a14-0x002f5a24 starts +0x3AC at 1 after grounded class-247 hero condition; 0x002f5a44-0x002f5a60 increments it until scaled 40 frames elapse, then starts scene 4. f3B0 -> hero_follow_voice_slot: Retail 0x002f52a4-0x002f52c8 checks and allocates a voice for this moby into +0x3B0; 0x002f53d8-0x002f541c validates ownership, releases the slot and stores -1. f3B4 -> tint_cycle_angle: Retail 0x002f5d30-0x002f5d7c advances +0x3B4 by frame_time*3.4906585, takes sine and remaps it to 0..1 for fast_tween_color; bound C agrees. f3B8 -> green_biased_joint_glow_color: Retail 0x002f5d84-0x002f5dcc preserves alpha/green and divides red/blue by three into +0x3B8; supplied glow renderer consumes this field as color for eight joint quads. f3BC -> ring_launch_lateral_coefficient: Retail 0x002f4264-0x002f4270 initializes +0x3BC randomly; 0x002f4c40-0x002f4c64 scales moby lateral vector by it and adds that to forward direction for ring launch. f3C0 -> unbobbed_boss_position: Retail 0x002f2ccc-0x002f2cd8 initializes +0x3C0 from moby position; movement updates it, then 0x002f5c4c-0x002f5d04 copies it to moby position and adds bob displacement only to moby Z. f3D0 -> bob_amplitude: Retail 0x002f2d94 initializes +0x3D0 to 0.75; 0x002f5c9c-0x002f5ccc multiplies it by sine of bob phase to produce the vertical interpolation target. f3D4 -> bob_cycle_angle: Retail 0x002f5c6c-0x002f5c98 advances +0x3D4 by frame_time*pi, stores the wrapped angle, and takes its sine for the vertical bob target. f3D8 -> bob_target_height_offset: Retail 0x002f4530 sets +0x3D8 to -3 during aimed action; 0x002f5cbc-0x002f5ccc adds it to sinusoidal bob target and 0x002f5d0c clears it each update. f3DC -> bob_height_displacement: Retail 0x002f5ca0-0x002f5cd8 passes +0x3DC as interpolated bob output; 0x002f5cdc-0x002f5d04 adds that float to moby position Z after copying unbobbed position. f3E0 -> bob_interpolation_state: Retail 0x002f5cac-0x002f5cd8 passes +0x3E0 as the second mutable state beside bob output +0x3DC to aas_c, with the sinusoidal height target and scaled limits. f53 -> animation_sequence_index: Retail 0x002f4198-0x002f41c0 compares moby+0x53 to sequence 10 before blend_moby_animation(moby,10,...); repeated sequence checks and requests throughout the assigned function prove this animation-sequence index. f78 -> boss_private_data: Retail 0x002f2c24 loads moby+0x78 into s4, used for all boss phase/path/position fields; bound C casts this pointer to the file-private BossData type. f90 -> animated_tint_color: Retail 0x002f5d78-0x002f5da0 stores fast_tween_color's packed color directly into moby+0x90 after the sinusoidal blend between two packed colors. f94 -> collision_data: Retail 0x002f2de8-0x002f2dec restores this member from class+0x10 when enabling the boss and clears it at 0x002f5944; supplied group helpers identify the same moby member as collision.
unkA2 -> contact_sound_entry_index: Retail 00311bf0 loads pvars into s2. In the hero-contact branch 00311cd8-00311ce0, 00311cfc loads signed halfword pvars+0xA2 into a0; 00311d00-00311d04 skips the call for -1, and 00311d0c-00311d14 passes that index, zero flags and the moby to the checked allocate_voice_for_target_entry call. Authoritative C binds these reads to HeroFallingPlatformVars.unkA2. Supplied allocator source uses entry_index to bounds-check pclass->sound_def_count, select sound_defs+(entry_index<<5), allocate a voice and record slot->entry_index, proving this is the optional sound-definition entry index triggered by hero contact.
unk64 -> oscillation_amplitude_degrees: Retail 0x002f3c28-0x002f3c50 takes sin of pvars +0x7c, loads the float at +0x64, multiplies it by 0.017453292 (DEG_TO_RAD) and by that sine. 0x002f3c54-0x002f3c68 adds this heading offset to saved heading +0x84 and writes moby rot.z at +0x48. Thus +0x64 is the sine oscillation's heading amplitude in degrees, matching source unk64 * DEG_TO_RAD * fast_sin(unk7C). unk84 -> initial_heading_radians: In oscillating initialization, retail 0x002f3bb8 loads the moby's rot.z at +0x48 and 0x002f3bc0 stores it to pvars +0x84. During oscillation 0x002f3c54 loads that saved float and 0x002f3c5c-0x002f3c68 uses fast_add_rotations to add the sine offset already converted to radians and writes rot.z. Source likewise initializes unk84 from MOBY(vent_moby)->rot.z and uses it as the fixed heading around which the vent oscillates.
unk7E -> resolved_sound_id: In the authoritative src/audio/voices/is_voice_active.c snapshot (SHA-256 7bf84038d4dd90dff5755e3e822b113cb8e59ac52b5a60dc2cf106e57be6528a), voice->unk7E is compared with sound_id + D_0015F5B4. Retail 0x001eb760 loads the base, 0x001eb764 adds the requested sound ID, 0x001eb76c loads this signed halfword from the selected voice at +0x7e, and 0x001eb770 rejects unequal identifiers before the active-state check. The supplied original Ghidra decompilation likewise compares nSound_index with sound_index + g_nSoundIndexBase. These uses establish the stored resolved sound ID rather than merely an offset.
unk174 -> transfer_layout_mode: In the authoritative cpr8.c snapshot (SHA-256 41f8be22effa06dd7ca90c649265c654770f4b0c6b6967d8b552c8ad33974d13), this s32 member is tested against 3 to select transfer layout. Retail 0x001298f0 loads decoder+0x174 and 0x001298fc-0x00129900 compares it with 3, branching to the single-pass sizing path at 0x0012991c. That path uses copy_params->unk10 * 0x180 for source stride/count and assigns one pass at 0x00129948-0x00129950. For other mode values with nonzero decoder+0xe0, 0x00129954-0x00129978 halves copy_params->unk10 before sizing, uses (layout_width >> 4) * 0xc0 for destination stride, and assigns two passes. The original retail Ghidra decompilation corroborates both branches. Thus it selects the DMA transfer layout rather than representing an address, count, or width.
unk64 -> slot_item_id: In remove_hud_item, HudSlotArray.unk64 is compared directly with hud_item_id. Retail 0x001ff494 loads this s32 at D_00199B60+0x64 and 0x001ff498 compares it with the input preserved in a1 at 0x001ff490. Instructions 0x001ff4a4-0x001ff4c0 search the same item-key position across 13 slots with 0x90 stride. On equality the separate slot index in a0 is supplied to queue_animation_update at 0x001ff4e8 with ID 0xffff, proving this member is the slot's HUD item identifier rather than the slot index.
unk35 -> refresh_pending: In the SHA-256-bound assigned C, TfragLightLink.unk35 is set to 1 only when tfrag_packed_lights becomes 0xFFFF after removal/compaction of the requested point-light nibble. Retail 0x002020d8-0x002020e4 selects the tfrag record from 0x00160e8c with 64-byte stride and loads its packed indices at +0x36; 0x00202154-0x00202164 compares those indices with 0xFFFF and stores byte 1 at +0x35, followed by the packed-index store at 0x0020216c. The prepared original Ghidra decompilation identifies this exact member as TfragRenderRecord.bRefreshPending, supporting refresh_pending rather than an offset-only name.
unk7D -> current_voice_slot_index: In MobyVoiceFlags, retail 0x0020c958 loads moby+0x7D; 0x0020c95c tests 0xFF for absence. 0x0020c960-0x0020c974 uses that byte as the index into voice_pool with stride 0x70, and 0x0020c998-0x0020c99c passes the same index to release_voice_slot. The allocation return is stored back into moby+0x7D at 0x0020c9c0; invalid ownership or changed entry clears it to 0xFF. This is the moby's current voice-slot index. unk7E -> voice_entry_index: In MobyVoiceEntry, retail 0x0020c980 loads the selected pool record's signed halfword at +0x7E after checking that record's owner against moby at 0x0020c978-0x0020c97c. 0x0020c98c-0x0020c990 compares it to moby+0x7C, the same requested entry byte passed as argument zero to allocate_voice_for_target_entry at 0x0020c9a8-0x0020c9b8. A mismatch releases the slot. Thus this field identifies the slot's voice entry, consistent with the supplied Ghidra nSound_index access and prior entry-index findings.
unk52 -> primary_binding_selector: The supplied original retail Ghidra decompilation names the corresponding ResidentObjectState member bPrimary_binding_selector. Retail 0x0020cc8c loads the byte at moby+0x52, 0x0020cc90 compares it to a2=0xFF, and 0x0020cc94 clears the current reference slot on inequality. The authoritative C expresses the identical data flow as moby->unk52 != mask, with mask=0xFF, in prune_moby_references. Thus primary_binding_selector preserves the supplied semantic identification and the observed selector sentinel test rather than inventing an offset-only name.
unk210 -> selection_entry_count: In source src/ui/vendor/render_vendor_item_icon_strip_pass.c (SHA-256 e63680defc2179068a6c86526e57893f8e09cbfbb444e4277f6cbf11a32d0d3a), this s32 field chooses direct versus wrapped rendering at <8, bounds item_index while walking 0x14-byte selection entries, and is the divisor for wrapped entry indices. Retail 0x0023873c-0x00238744 loads state+0x210 and compares with 8; 0x002387c8-0x002387cc skips an empty list; 0x00238834-0x00238848 increments the entry counter, compares it with state+0x210, and advances the entry pointer by 0x14. At 0x00238918-0x00238940 the same field supplies twice the count and the modulo divisor before multiplying the remainder by 0x14 to address item-index/purchase-kind entries at state+0xD0/+0xD4. Original retail Ghidra names this quantity g_nVendorSelectionEntryCount, corroborating the operational proof.
f174 -> activation_target_search_range: Retail 0x002d1368-0x002d138c selects data+0x174 only when the moby is in state 1 (ULTRAMECH_WAIT_FOR_ACTIVATION), then copies it into data+0x1b8 for search and distance testing. Authoritative ultramech_unlimited_update initializes this float to 90.0f; other states select data+0x178. This is the activation-state target-search range. f1B8 -> current_target_search_range: Retail 0x002d138c/0x002d13b8 stores the state-selected range at data+0x1b8; 0x002d1394-0x002d13e0 passes it to simple or path-constrained targeting. 0x002d13e8-0x002d1404 compares it against distance from moby position to the search output. Authoritative ULTRAMECH_APPROACH_TARGET also passes this field as the established target_search_range argument of compute_ultramech_flocking_steering_point. w164 -> target_range_status: Retail 0x002d1364 resets data+0x164 to 0, then 0x002d13e8-0x002d1404 computes distance to the targeting output and stores 2 exactly when that distance exceeds data+0x1b8. Authoritative caller tests this field against 2 to gate entry-path activation, aiming, firing and approach behavior, proving a target-range status with existing 0/2 encoding. w1C8 -> damage_reaction_this_update: Retail 0x002d0fec clears data+0x1c8 on every helper invocation. Following health subtraction, cases 9/10 set it to 1 at 0x002d1170 and knockback cases 3-8 set it at 0x002d11b0; death and no-action branches do not. Authoritative caller invokes this helper first and tests this field in ULTRAMECH_FIRE_BURST to permit a ballistic path move after that update's damage reaction. w1D0 -> target_constraint_path_index: Retail 0x002d1374-0x002d13e0 treats data+0x1d0=-1 as absent; otherwise multiplies it by 4 to index D_L15_001B0AB0 and passes that LevelPath's points and count to the path-constrained targeting call. Authoritative ULTRAMECH_WAIT_FOR_ACTIVATION also indexes the same path with this field and checks hero position with point_in_path_xy before enabling entry movement, proving the targeting constraint path index.
unk64 -> target_path_point_index: In assigned rail_lift_update, retail 0x002dcefc, 0x002dcf98 and 0x002dcfc4 initialize pvars+0x64 to 1 when starting initial travel, rider departure or recall. The direct advance_moby_along_rail_path call at 0x002dd01c receives the selected path. Checked level-03 helper 0x002d3918 loads the same Moby pvars at 0x002d3960 and this member at 0x002d3968, shifts it left four bits at 0x002d3970 and loads the target Vec4 from path+0x10+index*16 at 0x002d3974-0x002d3980. It subtracts the lift position from that point at 0x002d3994. On the proximity branch, 0x002d39c8-0x002d39d0 increments and stores the member; 0x002d39d4-0x002d39e0 compares the incremented index with the path point count to produce completion. Thus this is the target path point index, not a ride-start boolean.
unk02 -> bottom: Retail 0x0021f82c loads menu+0x24 and 0x0021f840 stores its low halfword at sp+0x22, the source text_region_settings.unk02. The 24-byte copy at 0x0021f858-0x0021f884 places this in the TextRegion passed at 0x0021f8a4; original Ghidra explicitly assigns this value to TStack_f0.nSBottom, paired with zero nSTop. unk06 -> right: Retail 0x0021f834 loads menu+0x20 and 0x0021f850 stores it at sp+0x26, matching text_region_settings.unk06. The same menu dimension limits wrapped text at 0x0021f780-0x0021f7a8 after subtracting 0x11 from it. Original Ghidra identifies the copied field as TStack_f0.nSRight, paired with zero nSLeft; the region is passed to rendering at 0x0021f8a4. unk0A -> anchor_y: Retail 0x0021f838 computes a3=s5+8, where s5 is mission_text_y passed as wrapped text Y at 0x0021f7a0 and advanced per mission at 0x0021f808. Store 0x0021f844 writes this trailing text Y to sp+0x2a, matching text_region_settings.unk0A. Original Ghidra copies it to TStack_f0.nSAnchor_y before the renderer call at 0x0021f8a4. unk12 -> flags: Retail 0x0021f830 sets a1=1 and 0x0021f84c writes this halfword to sp+0x32, matching text_region_settings.unk12. The 24-byte copy at 0x0021f858-0x0021f884 preserves it into the render region passed at 0x0021f8a4. Original Ghidra explicitly maps this initialization to TStack_f0.wFlags=1; the name flags does not assert any particular bit meaning.
vC0 -> transform_basis_x: Authoritative crate.c declares M2d1428.vC0 as u8[0x10] and passes it to transform_vector_by_basis after subtracting moby position from hero position. Retail 0x002d1530-0x002d1558 binds a2=moby+0xC0 and a0=a1=hero_local_offset. Checked level-00 helper 0x001ff6d0 loads basis vectors at a2+0,+0x10,+0x20; 0x001ff6e0 vmulax weights the first vector by input X, then vmadday/vmaddaz add the Y/Z vectors. Retail 0x002d155c-0x002d15b4 tests the resulting spatial offset for crate overlap. Thus the existing 16-byte member is the X-weighted transform basis vector, not an arbitrary byte buffer.
f8 -> hit_direction_z: Shot5BD0 begins with the melee hit vector: source sets f0/f4 to cos/sin(moby->rot.z)*0.2, f8 to zero, and passes the struct address as both vector arguments to set_vector_length_xy. Retail 002c5ed0-002c5f20 constructs this vector at sp+0xA0, clearing its Z at sp+0xA8; 002c5f3c then sets that component to 1.0 before record_moby_hit at 002c5f78. Checked consumer 0024caf8-0024cafc and 0024cb70-0024cb74 copies the vector intact into the hit record. Thus f8 is the hit direction vector's Z component, rather than an arbitrary scalar. h1A -> hit_source_class: The melee branch assigns (u16)moby->oclass to Shot5BD0.h1A while p10 is assigned the attacking trooper moby, then passes this struct to record_moby_hit(target,...). Retail 002c5f08 stores s3 as the source pointer at sp+0xB0; 002c5f24 loads the same moby's object class from 0xA6(s3), and 002c5f48 stores it to sp+0xBA, the h1A member. Checked record_moby_hit 0024cba4-0024cba8 copies that halfword into queued hit record+0x2A. The field records the hit source's object class.
unk110 -> second_gate_arrival_cuboid_index: In the authoritative C, this s32 indexes l11_cuboids: initialization lowers its pos.z by 500, while RESORT_OWNER_SECOND_PATH_LEG arrival constructs the second gate jump target and raises that same cuboid by 500. Retail 002d1848-002d187c loads pvars+0x110, multiplies by 0x80 and subtracts 500 at cuboid+0x38; 002d1c60-002d1c90 performs the matching addition in the leg-1 branch. Original retail Ghidra cases 0 and 6 agree. This proves a cuboid index tied to second-gate arrival, without claiming its physical purpose. unk114 -> final_path_arrival_cuboid_index: Authoritative C lowers l11_cuboids[this s32].pos.z by 500 during fresh initialization and resume at leg 1, then raises it by 500 on RESORT_OWNER_FINAL_PATH_LEG arrival immediately before entering completion-dialogue checking. Retail 002d1800-002d182c and 002d1880-002d1894 load pvars+0x114, use 0x80 cuboid stride, and subtract 500 at +0x38; 002d1cb8-002d1ce8 adds 500 on leg 3 arrival. Original retail Ghidra corroborates all three uses, proving this final-path-arrival cuboid index. unk118 -> post_path_dialogue_condition_index: In RESORT_OWNER_CHECK_POST_PATH_DIALOGUE, authoritative C uses this s32 as the index contribution in D_0014C050[field + D_0015ED84 * 16], requiring the selected byte to equal 0xFF before checking camera mode and update_npc_dialogue. Retail 002d1fb0-002d1fd8 loads pvars+0x118, adds the global row offset shifted by 4 and table base 0x0014c050, loads a byte and compares with 0xFF; 002d1fe0-002d201c then gates dialogue and enters state 15. Original retail Ghidra case 0xe agrees. This proves the post-path dialogue condition index without assigning story or persistence semantics.
unk158 -> knockback_extension_timer: Original retail decompilation and SHA-bound source agree: 003106bc-003106c0 pass this s32 member to fast_dec_timer each handler invocation. On the nonlethal knockback branch only, 003108d8-003108ec add scale_game_frames(60) to its current count after starting state 7. This identifies a countdown extended by knockback; the name does not claim immunity, attack cooldown, or another unobserved expiry effect. unk160 -> held_projectile: Authoritative psytcopus.c stores spawn_class_511_moby_with_sparks into this void * in CREATE_PROJECTILE and releases/clears it in FIRE_PROJECTILE. Retail 003106d8-00310718 positions this pointed-to object at the owner's forward/Z offset; 003108c0-003108d4 and 003109b4-003109c8 cancel and clear it during knockback. unk67 -> hit_reaction_channel_target: Retail 00310818, 003108bc and 003109b0 write 250/120/240 to pvars+67 for hurt/knockback/death. Assigned 003109fc passes pvars+60 to checked 002833d8. Its 00283468-002834b8 reads block+7, interpolates from block+4 toward it, and 00283534-00283580 interpolates back; 00283610-0028361c forwards the interpolated channel to 00276120. Thus the member is the hit-reaction channel interpolation target; no RGB identity is claimed. unk84 -> knockback_speed_approach_step: Retail 003107e4 initializes this f32 to 0.0005 before reaction setup on pvars+70. Checked sibling 002825a0-002825d8 computes that block's vector magnitude into sp+60, passes block+14 (=pvars+84) in f13 to 00281708, then rescales the velocity vector to the updated magnitude. Checked 00281710-0028174c clamps target-minus-current to plus/minus f13 before adding it, proving this is the per-update speed approach step. unk8C -> knockback_vertical_speed: Retail 00310828-00310850 and 00310908-00310944 store the established hurt/death base vertical speed times frame_time here. Hit-vector adjustment receives its address at 00310890/00310984. Checked setup 00282450-0028246c copies block+1c (=pvars+8c) to velocity Z at block+8; sibling 002825dc-002825f0 also caps that vertical velocity with this field. It is the knockback vertical-speed input/limit, not the evolving velocity itself.
…_and_fade b08 -> projected_link_rotation: In authoritative C O_26e670_26e670.b08 receives truncate_float_to_s32(fast_arc_tan(acc.f[0], acc.f[1]) * 128.0f / pi) - 0x20. Retail 0026e964-0026e9f4 subtracts the reference position from the target and candidate, transforms each by 00166D40, divides by its fourth component, and subtracts the projected candidate from projected target. 0026e9f8-0026ea28 applies atan, angle-to-byte scaling and bias, then sb to particle+8. Original Ghidra cVar1 and *(char *)(iVar7+8) agree: this is the projected link-direction rotation encoding. i04 -> packed_rgba_color: Authoritative C reads particle->i04 >> 24 into faded_alpha, subtracts two and reinserts positive alpha while preserving i04 & 0xFFFFFF. Retail 0026eaec loads particle+4, 0026eaf0 extracts its top byte, 0026eaf4 decrements by two, and 0026eb00-0026eb14 shifts the faded alpha back by 24, preserves the low 24 bits and stores the packed word. Original Ghidra *(uint *)(iVar7+4) confirms the same packed color/alpha flow, with terminal unlink/free when alpha is exhausted.
f0C -> dialogue_activation_threshold: Assigned retail 0x002f0f38-0x002f0f4c passes pvars to initialize_npc_dialogue then stores 4.0f at +0x0c, matching moby_vars->f0C in the authoritative C. Checked level-11 helper update_npc_dialogue (request 75fcab1c69174e42bf6e7017de951d59) preserves that pvars argument in s1 at 0x0028b84c. At 0x0028b8a4-0x0028b8bc it computes hero-to-moby distance, loads +0x0c, doubles it, and returns false if distance exceeds it. At 0x0028b8f4-0x0028b914 it computes heading difference, compares it with the same +0x0c float, and returns false if greater. This proves a threshold gating dialogue activation with both proximity and angle uses, rather than a radius alone. h04 -> dialogue_result: The assigned C passes moby_vars to initialize_npc_dialogue and update_npc_dialogue; checked level-11 initializer request f08320df03714c289e9e6bdc03f6f001 preserves pvars in s0 at 0x0028bc80 and writes signed sentinel -1 into short +4 at 0x0028bcd4. Assigned retail 0x002f1130-0x002f1140 waits until dialogue status is no longer 2, returns the moby to dialogue checking, then loads signed pvars+4 and tests it against 2. Only this outcome gates the persistent item/pricing flag changes, queued message, save, and help calls at 0x002f1148-0x002f1188. The source h04 thus records the dialogue result consumed after dialogue ends; the name does not assign semantic labels to individual result codes.
f2C -> damage: Retail 0030649C..003064C0 validates the indexed hit row's owner then loads its +0x2C float, adds 1.0 and stores it back; authoritative C expresses target_hit_entry->f2C += 1.0f. The alternate branch calls record_moby_hit with a descriptor damage of 1.0f; supplied record_moby_hit context writes hit_descriptor->f to hit_record->damage at this same row position, proving accumulated hit damage. i24 -> hit_flags: Retail 00306464 passes s3=0x10001 to make_hit_descriptor, and 003064F8..00306508 reselects the owner-matched target's hit row and stores the identical s3 mask at +0x24. Authoritative C writes matched_target_hit_entry->i24 = hit_mask; supplied record_moby_hit context transfers descriptor y into hit_record->flags, proving hit flags rather than a generic integer. p34 -> owner_moby: Retail 00306488..003064A4 indexes a 0x40-byte hit row by ent's Moby hit_slot (+0xA4), loads its +0x34 pointer and compares it with ent. Authoritative C tests target_hit_entry->p34 != ent before calling record_moby_hit. Supplied record_moby_hit context stores owner_moby into hit_record->owner and uses the same owner equality to validate a slot, proving this pointer owns the hit record. s2A -> source_oclass: Retail 003064E4..003064F4 loads the projectile moby's unsigned halfword at +0xA6 and stores it in the matched target hit row at +0x2A; 00306474..00306480 copies the same source into the new hit descriptor. Authoritative C mirrors both transfers. Supplied retail annotation also identifies Moby +0xA6 as oclass in the collision-target zero-class check at 003067D0, establishing the hit's source moby class.
f88 -> travel_yaw_offset: Retail 0x002f2460-0x002f2484 reads pvars+0x88 as an angle: cosine scales the path-derived moby pitch at +0x44, and fast_add_rotations adds it to path yaw at +0x48. At 0x002f261c-0x002f2658 its address is approached toward pi after travel progress exceeds 0.8. These C uses establish the shuttle travel yaw offset. f8C -> travel_yaw_step: Assigned retail 0x002f262c passes pvars+0x8c as the second mutable scalar to approach_angle at 0x002f2658, alongside the yaw offset address. Checked level-17 helper 0x002566c4 retains this pointer in s0; 0x00256700-0x00256740 uses its signed scalar and squared value for direction/stopping calculations, and 0x00256844-0x00256850 loads it and adds it via fast_add_rotations directly into the first angle. It is the persistent signed yaw increment per update, hence travel_yaw_step. fA4 -> travel_fraction: Retail 0x002f21e4 and 0x002f2234-0x002f2240 approach pvars+0xa4 toward 1 by 1/scale_game_frames(900). Its float value multiplies all three path point counts minus one at 0x002f225c, 0x002f22b8 and 0x002f22f0; it blends endpoint scales at 0x002f25dc-0x002f2604 and equality with 1 determines completion at 0x002f2670. This is the normalized travel fraction, distinct from the existing integer-view travel_progress binding.
domain_0_value_3 -> MPEG_TRANSFER_LAYOUT_SINGLE_PASS: Retail 0x001298f0 loads decoder +0x174 (source decoder_transfer_layout->transfer_layout_mode); 0x001298fc-0x00129900 compares it with 3 and branches to 0x0012991c. That path uses the full copy_params +0x10 times 0x180 byte count at 0x00129924-0x0012992c, computes destination stride, and unconditionally stores transfer_pass_count=1 at 0x00129948-0x00129950. It bypasses the other-mode nonzero-width path at 0x00129954-0x00129978 that halves source sizing and sets two passes. Stack +4 bounds the outer transfer loop at 0x00129ae8-0x00129b00, proving single-pass transfer-layout behavior independently of any MPEG frame/field interpretation.
unk117 -> hit_flash_red_target: Retail 00315bd4/00315c8c/00315d64 writes 250/120/240 to pvars+117 after hit reactions. Calls 00315d7c/00315d90 pass pvars+110 as the color-animation record. Checked helper fda38dd28203420484e3dd4ba23463ea at 00283394-002833bc maps get_moby_color's first (red) output to record+4, agreeing with supplied trooper_anim_update source r/g/b capture. Checked helper 4f7954ba8e4b42e183fc705aebe2a193 loads record+7 (pvars+117) at 00283468/00283488 and interpolates from record+4 toward it at 00283484-002834b0, then back toward the saved channel at 00283534-00283578. The interpolated first channel is passed as a1 at 00283610, alongside the other two channels. Thus this byte is the hit color flash's red target, not duration. unk1A4 -> horizontal_movement_step_limit: Retail 00315990 loads established l11_puffoid_horizontal_speed_limit, 0031599c loads frame_time, 003159a8 multiplies them, and 003159b4 stores the product to pvars+1A4. Authoritative C assigns exactly l11_puffoid_horizontal_speed_limit * frame_time to this f32 field. Supplied update_moby_target_heading_and_conditional_movement repeats this assignment at moby_vars+1A4 immediately before constructing the yaw-derived planar heading vector and invoking move_moby_with_ground_and_collision_checks on moby_vars+180. This is the horizontal movement speed limit scaled to the update step.
unk52 -> blend_source_animation: Assigned retail 0x002e12cc-0x002e12f8 compares moby+0x52 with established current anim at +0x53 before compute_interpolated_record_value and enabling hit flags. Checked helper 0x0024edc8 (request 947c29a08162473a8b1403712b0dcc9e) selects source record +0x68 unless +0x52 is 0xFF, then uses +0x6c (0x0024ede4-0x0024edf0); +0x52 versus +0x53 controls interpolation of the two records (0x0024ee28-0x0024eea0). Checked blend_moby_animation 0x00257880 (request 8087a988108440b997b0e7301af2d4a3) captures a source pose, preserves non-FF +0x52 at +0xa5, sets +0x52=0xFF for that captured source (0x00257910-0x00257950), and writes requested animation to +0x53 at 0x00257964. Thus +0x52 identifies the blend source animation, including captured-pose sentinel, rather than the requested destination animation.
domain_0_value_2 -> ULTRAMECH_TARGET_OUTSIDE_SEARCH_RANGE: This token compares ultramech_vars->target_range_status at data+0x164, as retail 0x002cf648-0x002cf650 (activation) confirms. Supplied process_ultramech_hits_and_update_target C resets status to 0 and stores 2 only if current_target_search_range is less than distance to the selected target position at data+0x120. Checked helper evidence cb406c75f77a416f9e43b45d58bf7d9f, 0x002d13e4-0x002d1404, confirms distance call, load +0x1b8, c.lt.S and conditional sw 2,+0x164. It is a target-range status domain, separate from moby state and hero enums. domain_1_value_2 -> ULTRAMECH_TARGET_OUTSIDE_SEARCH_RANGE: This token compares ultramech_vars->target_range_status at data+0x164, as retail 0x002cfc18-0x002cfc20 (attack selection) confirms. Supplied process_ultramech_hits_and_update_target C resets status to 0 and stores 2 only if current_target_search_range is less than distance to the selected target position at data+0x120. Checked helper evidence cb406c75f77a416f9e43b45d58bf7d9f, 0x002d13e4-0x002d1404, confirms distance call, load +0x1b8, c.lt.S and conditional sw 2,+0x164. It is a target-range status domain, separate from moby state and hero enums. domain_2_value_2 -> ULTRAMECH_TARGET_OUTSIDE_SEARCH_RANGE: This token compares ultramech_vars->target_range_status at data+0x164, as retail 0x002cfd88-0x002cfd90 (firing) confirms. Supplied process_ultramech_hits_and_update_target C resets status to 0 and stores 2 only if current_target_search_range is less than distance to the selected target position at data+0x120. Checked helper evidence cb406c75f77a416f9e43b45d58bf7d9f, 0x002d13e4-0x002d1404, confirms distance call, load +0x1b8, c.lt.S and conditional sw 2,+0x164. It is a target-range status domain, separate from moby state and hero enums. domain_3_value_2 -> ULTRAMECH_TARGET_OUTSIDE_SEARCH_RANGE: This token compares ultramech_vars->target_range_status at data+0x164, as retail 0x002d0198-0x002d01a0 (burst wait) confirms. Supplied process_ultramech_hits_and_update_target C resets status to 0 and stores 2 only if current_target_search_range is less than distance to the selected target position at data+0x120. Checked helper evidence cb406c75f77a416f9e43b45d58bf7d9f, 0x002d13e4-0x002d1404, confirms distance call, load +0x1b8, c.lt.S and conditional sw 2,+0x164. It is a target-range status domain, separate from moby state and hero enums. domain_4_value_2 -> ULTRAMECH_TARGET_OUTSIDE_SEARCH_RANGE: This token compares ultramech_vars->target_range_status at data+0x164, as retail 0x002d03e0-0x002d03e4 (approach) confirms. Supplied process_ultramech_hits_and_update_target C resets status to 0 and stores 2 only if current_target_search_range is less than distance to the selected target position at data+0x120. Checked helper evidence cb406c75f77a416f9e43b45d58bf7d9f, 0x002d13e4-0x002d1404, confirms distance call, load +0x1b8, c.lt.S and conditional sw 2,+0x164. It is a target-range status domain, separate from moby state and hero enums. f188 -> burst_pause_duration: Authoritative C uses f188 only when FIRE_BURST enters WAIT_BETWEEN_BURSTS. Retail 0x002cff70-0x002cff90 loads data+0x188, multiplies by 60.0, frame-scales and truncates it into data+0x1c0 timer; 0x002d0378-0x002d0398 resumes firing on timer expiry. This proves the inter-burst pause duration input without asserting units. fE8 -> ground_fall_step: In the nonmoving active-state ground handling, retail 0x002d0ed0-0x002d0ef0 increases data+0xe8 by frame_time_sq*30; 0x002d0ef4-0x002d0f20 subtracts this step from position Z through two probe-offset adjustments. 0x002d0f24-0x002d0f28 clamps to probed ground and resets the field to zero. Source fE8 follows precisely this downward ground-motion accumulator flow. v1A0 -> previous_melee_endpoint: Source MELEE_ATTACK obtains attack_end from moby point 1, passes &v1A0 as the previous endpoint argument of sweep_hit_segment, then copies attack_end into v1A0. Retail 0x002d082c retains data+0x1a0 in s1; 0x002d08b8-0x002d08d4 passes it as a3 with current start/end, and 0x002d08e4-0x002d08e8 saves the current endpoint there for the next sweep. w1CC -> activation_wait_group_id: Source WAIT_FOR_ACTIVATION treats w1CC=-1 as no group gate; otherwise count_active_moby_group_members(w1CC,0x40) must return zero before activation proceeds. Retail 0x002cf5d0-0x002cf610 loads data+0x1cc into a0 for that count with a1=0x40, then branches out of the update when the returned count is nonzero. This identifies the group whose members delay activation. w1D4 -> combat_path_moves_disabled: Retail 0x002cf55c-0x002cf578 sets data+0x1d4=1 if either combat path index at +0x180/+0x184 is -1. The zero tests at 0x002d0084-0x002d0098, 0x002d023c-0x002d0288, 0x002d065c-0x002d06ac and 0x002d094c-0x002d0960 gate ballistic combat-path repositioning from firing, burst wait, melee and knockback recovery. Source w1D4 has this same disabling polarity; it does not disable entry-path traversal. w1D8 -> suppress_close_combat_and_knockback_motion: Source uses nonzero w1D8 to bypass approach/melee selection and firing-state close-combat/path interruptions. Retail 0x002cfc98-0x002cfca0 sends nonzero data+0x1d8 directly to firing; 0x002cff94-0x002cff98 and 0x002d0208-0x002d020c bypass movement decisions. In recovery 0x002d08f4-0x002d0920 nonzero bypasses step_moby_motion and restores animation speed; 0x002d0930-0x002d0944 then waits for animation completion. The name states those proven suppressions, not a universal immobility guarantee. w1DC -> activation_clip_volume: When no activation wait group is selected, source passes w1DC with hero.motion.pos to is_point_inside_clip_volume before enabling the moby. Retail 0x002cf5e0-0x002cf5ec supplies data+0x1dc as a1 and hero position 0x0013f3d0 as a0 to the clip-volume test; 0x002cf5f0 bypasses enabling when the test returns zero. The name describes its activation-volume selector role without asserting its representation.
unk90 -> knockback_collision_radius: unk90 -> knockback_collision_radius. SHA-bound psytcopus.c and original retail Ghidra agree: 0031079c-003107d8 truncate 512.0f and store this s32 at pvars+90 before knockback setup with pvars+70. Checked common-owner motion sibling 00282538 receives that block in s2; 00282bb0-00282bc8 converts block+20 (=pvars+90) to float, scales by 1/1024 and passes f12 with the candidate position to 002225c8. Checked query 002225e4-00222628 loads the position, transfers f12 to vf30, constructs center-minus/plus-radius bounds and scales both center and radius by 1024; 00222660 squares the radius. Triangle distance checks 00222aa0-00222ad8 and 00222b78-00222b98 compare squared separation against this squared radius. This proves a fixed-point collision radius used during knockback, rather than a mask, diameter or speed.
unk148 -> knockback_collision_z_offset: Retail 00315b98 initializes pvars+148 to 0.2; 00315c58/00315d30 pass pvars+120 as knockback record. Checked consumer request c6ca66008b6c4dcf8d2d11a72add9514 saves record in s2 at 00282558. At 002825f8-00282628 it copies moby position, adds record+28 to its Z, then probes ground. At 00282a6c-00282abc it adds the same field to pre/post movement collision positions; after collision position replacement 00282be0-00282c10 subtracts that field from moby Z. Thus the field is a knockback collision/probe vertical position offset, not a velocity or duration. unk170 -> knockback_apex_animation_frame: Assigned retail 00315c00/00315cd8 sets pvars+170 to 7.5 in ordinary/death knockback before passing pvars+120 to start. Checked step request c6ca66008b6c4dcf8d2d11a72add9514 maps it to record+50. In rising phase (record+3e=0), 0028289c-002828a8 computes absolute vertical velocity / per-step vertical decrement (the latter subtracted at 00282574-00282588), giving steps to apex. 002828c8-002828dc subtracts current animation frame from record+50 and divides by those steps, then 002829f0-00282a04 approaches that rate in moby+58 animation speed. Helper request ae1114a8bc9d48f9a14ea5053b09a472 shows 00274bf8 returns animation record frame (+4 converted and scaled by 1/16), interpolated using moby animation blend state at +54. This proves an animation frame target synchronized to apex. unk174 -> knockback_landing_animation_frame: Retail 00315c04/00315cdc sets pvars+174 to 11.0 for ordinary/death knockback; it is record+54 relative to pvars+120. Checked step request c6ca66008b6c4dcf8d2d11a72add9514: descending phase record+3e=1 at 00282864-0028286c selects 002828f8; 00282900-00282918 compares current animation frame to record+54 and zeroes moby+58 speed when reached. Otherwise 0028291c-00282978 estimates remaining landing time using vertical decrement, vertical velocity and moby Z minus probed ground height. 0028299c-002829e4 divides record+54 minus current animation frame by that time, clamps speed to 0..2, and approaches it at 002829f0-00282a04. Checked helper ae1114a8bc9d48f9a14ea5053b09a472 establishes the returned interpolated animation frame from record+4 and moby animation blend fields. Thus this is the knockback landing animation frame target.
w94 -> collision_geometry: w94 -> collision_geometry (private UMoby int member). Authoritative src/overlays/l15/mobys/ultramech_unlimited.c SHA-256 f3701a08166dbff89429ec60de7c258bb66ff61dc18cc8920007dc49c97c2885 and original retail Ghidra/instructions agree: activation 0x002cf630-0x002cf644 copies class+0x10 to moby+0x94; disabling/reset paths at 0x002cf428, 0x002cf54c, 0x002cf6bc and 0x002d0bc8 clear it. Bounded checked direct collect_mobies_in_sphere evidence e3b845e951034841a74ba1487a282ff4 proves semantics: 0x001ec0e8 loads candidate moby+0x94 into s4, 0x001ec128 skips null, 0x001ec1b8-0x001ec1dc loads moby position, basis and scale, and 0x001ec1d0-0x001ec538 reads geometry-relative offsets, transforms vertices and tests indexed triangles against the query sphere. The alternate 0x001ec538-0x001ec730 walks 0x20-byte primitive records and tests transformed shapes. Thus this is the enabled collision-geometry reference, not merely an offset-derived name; retain the declared int type.
Decompilation progress
No function changed its match state compared with main (7ab5514). Compared with main (7ab5514). C_FUZZY uses main's last measurement. |
pezzadev
marked this pull request as ready for review
November 2, 2026 21:54
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Before
Already matching boot and level code still used offset-style field names, unnamed data labels, generic parameters and numeric state checks.
After
controller_socket_params,VoiceState.resolved_sound_id, enemy targeting and knockback fields, and particle lifetime/color parameters.This is readability work on code that already matches retail; it does not claim an increase in matched-byte coverage. Data placement, struct layout and game behavior are preserved.
Verification
make elfends withPASS: reconstructed boot ELF matches retailmake overlaysends withPASSmake checkpasses