File size: 4,188 Bytes
f3cbb8a
04e939e
0f1b207
f3cbb8a
94ea94e
 
 
 
1a163b2
94ea94e
 
 
 
 
 
 
 
 
 
 
1a163b2
 
 
f3cbb8a
 
 
 
 
 
 
 
0f1b207
f3cbb8a
af1e67a
f3cbb8a
c6d4e73
0706c93
 
 
 
 
 
 
 
 
f3cbb8a
 
 
 
2835c9a
 
f3cbb8a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c7778ea
 
 
 
 
f3cbb8a
 
 
 
 
 
 
 
 
 
 
 
1a163b2
f3cbb8a
1a163b2
 
 
 
 
 
 
 
 
 
 
1d3de83
 
f3cbb8a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
use super::base::CTask;
use crate::fixed::Fixed;
use crate::FieldRegistry;

crate::define_addresses! {
    class "CGameTask" {
        /// CGameTask vtable - extends CTask vtable with 12 more methods
        vtable CGAMETASK_VTABLE = 0x0066_41F8;
        // Sound emitter vtable now defined via #[vtable(...)] on SoundEmitterVTable
        /// CGameTask constructor - calls CTask ctor, sets physics defaults
        ctor/Stdcall CGAMETASK_CONSTRUCTOR = 0x004F_ED50;
        /// CGameTask::vtable0 override
        vmethod CGAMETASK_VT0 = 0x004F_F1C0;
        /// CGameTask::Free override
        vmethod CGAMETASK_VT1_FREE = 0x004F_EF10;
        /// CGameTask::HandleMessage override
        vmethod CGAMETASK_VT2_HANDLE_MESSAGE = 0x004F_F280;
    }
}

/// Backward-compatible alias for the SoundEmitter vtable const.
pub const CGAMETASK_SOUND_EMITTER_VT: u32 = SOUND_EMITTER_VTABLE;

/// Game task - extends CTask with physics and gameplay data.
///
/// PARTIAL: Most fields between 0x30-0x83 and 0x98-0xE7 are unknown.
/// Only position and velocity fields have been verified.
///
/// Source: wkJellyWorm CGameTask.h
///
/// Additional vtable (12 methods at offsets 0x1C-0x48 in vtable)
#[derive(FieldRegistry)]
#[repr(C)]
pub struct CGameTask<V: super::base::Vtable = *const core::ffi::c_void> {
    /// 0x00-0x2F: Base CTask fields
    pub base: CTask<V>,
    /// 0x30-0x83: Subclass-specific data (84 bytes). Each CGameTask derivative
    /// uses this region differently:
    /// - CTaskWorm: weapon fire state (+0x30 type, +0x34/+0x38 subtypes, +0x3C flag)
    /// - CTaskFilter: boolean message subscription table (+0x30..+0x93)
    /// - CTaskMissile: spawn/physics parameters
    /// - CTaskTeam: secondary vtable pointer (+0x30)
    /// - CTaskCloud: parallax scroll depth (+0x30)
    /// Access via subclass accessor methods, not directly.
    pub subclass_data: [u8; 0x54],
    /// 0x84: X position in fixed-point
    pub pos_x: Fixed,
    /// 0x88: Y position in fixed-point
    pub pos_y: Fixed,
    /// 0x8C: Rotation angle (fixed-point 16.16).
    pub angle: Fixed,
    /// 0x90: X velocity in fixed-point
    pub speed_x: Fixed,
    /// 0x94: Y velocity in fixed-point
    pub speed_y: Fixed,
    /// 0x98-0xE7: Unknown gameplay fields
    pub _unknown_98: [u8; 0x50],
    /// 0xE8: Embedded sound emitter sub-object (MSVC multiple inheritance).
    pub sound_emitter: SoundEmitter,
}

const _: () = assert!(core::mem::size_of::<CGameTask>() == 0xFC);

/// Sound emitter sub-object embedded in CGameTask via MSVC multiple inheritance.
///
/// Provides spatial audio support. The `this` pointer for its vtable methods
/// points to the start of this sub-object (CGameTask+0xE8), not the CGameTask.
#[repr(C)]
pub struct SoundEmitter {
    /// +0x00: Vtable pointer
    pub vtable: *const SoundEmitterVTable,
    /// +0x04: Unknown field
    pub _unknown_04: u32,
    /// +0x08: Reference count — incremented when an ActiveSoundEntry holds this emitter,
    /// decremented when the entry is released.
    pub local_ref_count: i32,
    /// +0x0C: Number of active local sounds
    pub local_sound_count: i32,
    /// +0x10: Back-pointer to containing CGameTask
    pub owner: *mut CGameTask,
}

const _: () = assert!(core::mem::size_of::<SoundEmitter>() == 0x14);

/// Vtable for the SoundEmitter sub-object (0x669CF8, 12 slots).
///
/// Slots [0]-[4] are the sound emitter's own interface.
/// Slots [5]-[11] are inherited CTask base methods.
#[openwa_core::vtable(size = 12, va = 0x0066_9CF8, class = "SoundEmitter")]
pub struct SoundEmitterVTable {
    /// GetPosition(this, out_x, out_y) — reads pos_x/pos_y via owner
    #[slot(0)]
    pub get_position: fn(this: *const SoundEmitter, out_x: *mut u32, out_y: *mut u32),
    /// GetPosition2 — reads CGameTask+0x38/0x3C
    #[slot(1)]
    pub get_position2: fn(this: *const SoundEmitter, out_x: *mut u32, out_y: *mut u32),
    /// Destructor
    #[slot(3)]
    pub destructor: fn(this: *mut SoundEmitter, flags: u32) -> *mut SoundEmitter,
    /// HandleMessage — sound queue manager
    #[slot(4)]
    pub handle_message:
        fn(this: *mut SoundEmitter, sender: u32, msg_type: u32, size: u32, data: u32),
}