- weapon_fire.rs: use DDGame.level_width/level_height instead of
.add(0x77C0/0x77C4); use new CTaskWorm accessors instead of
.add(0x34/0x48) on raw worm pointer
- sound_ops.rs: use CGameTask.pos_y instead of .add(0x88)
- sound_ops.rs + active_sound.rs: use SoundEmitter.local_ref_count
instead of .add(8) on raw emitter pointer
- game_task.rs: split SoundEmitter._unknown_04 to expose ref count
field at offset 0x08
- worm.rs: add fire_subtype_1/set_fire_subtype_1_raw/set_action_field_raw
accessors; rewrite state() to use subclass_data slice indexing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add unsafe trait Vtable as a bound on CTask<V> and CGameTask<V>,
preventing arbitrary types from being used as vtable parameters.
- *const c_void implements Vtable (the default/untyped case)
- #[vtable] proc macro auto-generates `impl Vtable for *const MyVTable`
- CTask<V: Vtable> and CGameTask<V: Vtable> enforce the bound
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move all CTask* class blocks from address.rs into their respective
task/ module files. address.rs re-exports via pub use so all existing
va::* call sites are unchanged.
Moved to task/base.rs: CTask, CTaskLand, CTaskDirt, CTaskSpriteAnim,
CTaskCPU, CTaskSeaBubble, + 10 ctor-only entities
Moved to task/game_task.rs: CGameTask
Moved to task/worm.rs: CTaskWorm
Moved to task/turn_game.rs: CTaskTurnGame
Moved to task/missile.rs: CTaskMissile
Moved to task/mine_oil_drum.rs: CTaskMine, CTaskOilDrum
Moved to task/supply_crate.rs: CTaskCrate
Moved to task/cloud.rs: CTaskCloud
Moved to task/filter.rs: CTaskFilter
Moved to task/fire.rs: CTaskFire
Moved to task/team.rs: CTaskTeam
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
feat: replace hardcoded debug UI field labels with registry lookups
Remove CGAMETASK_FIELD_LABELS and all per-entity extra_labels arrays
from the debug UI inspector. Field names are now resolved via
registry::field_at_inherited() which walks the CTask inheritance chain
(entity → CGameTask → CTask).
Add #[derive(FieldRegistry)] to CGameTask and CTaskMissile. Add
field_at_inherited() helper for inheritance-aware offset → name lookup.
Entity types without Rust struct definitions (CTaskMine, CTaskOilDrum,
CTaskCrate) will show base class fields only until their structs are
defined — but any new struct fields are automatically picked up.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
refactor: rename CGameTask._unknown_30 to subclass_data, add CTaskWorm weapon accessors
Rename the polymorphic 84-byte region at CGameTask+0x30 to
subclass_data with documentation of per-subclass usage (worm weapon
state, filter subscriptions, missile params, team vtable, etc.).
Add CTaskWorm weapon fire accessor methods:
- weapon_fire_type(), weapon_fire_subtype_34/38()
- weapon_fire_complete() / weapon_fire_complete_mut()
- weapon_params_ptr(), weapon_params_34_ptr(), weapon_params_38_ptr()
- weapon_self_ptr field at +0x36C
Make task::worm and task::game_task modules public.
Update FireWeapon impl to use worm_eax (first cdecl param = EAX) for
field reads — must match original register source for determinism.
Verified: headless PASS (byte-identical), headful 133+3 / 0 FAIL.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
fix: remove extra loading progress ticks, cargo fmt
Reduce from 4 to 2 DDGameWrapper__LoadingProgressTick calls, matching
the original constructor. Tick counter +0x04D8 now matches exactly
(0x334). All DDGameWrapper fields match the original.
Remaining headless checksum mismatch is likely due to headless display
handling differences (our headless display is non-null vs original's
NULL display parameter).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
feat: add CTaskCrate struct, raw field debug UI, new task fields
Each task struct now lives in its own file. Tightly coupled types
are kept together (TurnGameCtx+CTaskTurnGame, CTaskMine+CTaskOilDrum,
SoundEmitter+CGameTask, CTaskWorm+CTaskWormVTable). mod.rs re-exports
all public types so external import paths are unchanged.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>