Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1 | pmbaty | 1 | /* |
2 | * Portions of this file are copyright Rebirth contributors and licensed as |
||
3 | * described in COPYING.txt. |
||
4 | * Portions of this file are copyright Parallax Software and licensed |
||
5 | * according to the Parallax license below. |
||
6 | * See COPYING.txt for license details. |
||
7 | |||
8 | THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX |
||
9 | SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO |
||
10 | END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A |
||
11 | ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS |
||
12 | IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS |
||
13 | SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE |
||
14 | FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE |
||
15 | CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS |
||
16 | AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. |
||
17 | COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. |
||
18 | */ |
||
19 | |||
20 | /* |
||
21 | * |
||
22 | * object system definitions |
||
23 | * |
||
24 | */ |
||
25 | |||
26 | #pragma once |
||
27 | |||
28 | #include <type_traits> |
||
29 | #include "dsx-ns.h" |
||
30 | #ifdef dsx |
||
31 | |||
32 | #include "pstypes.h" |
||
33 | #include "vecmat.h" |
||
34 | #include "aistruct.h" |
||
35 | #include "polyobj.h" |
||
36 | #include "laser.h" |
||
37 | |||
38 | #ifdef __cplusplus |
||
39 | #include <cassert> |
||
40 | #include <cstdint> |
||
41 | #include "dxxsconf.h" |
||
42 | #include "valptridx.h" |
||
43 | #include "objnum.h" |
||
44 | #include "fwd-segment.h" |
||
45 | #include <vector> |
||
46 | #include <stdexcept> |
||
47 | #include "fwd-object.h" |
||
48 | #include "weapon.h" |
||
49 | #include "powerup.h" |
||
50 | #include "compiler-poison.h" |
||
51 | #include "physics_info.h" |
||
52 | #include "player-flags.h" |
||
53 | #if defined(DXX_BUILD_DESCENT_II) |
||
54 | #include "escort.h" |
||
55 | #endif |
||
56 | #include <array> |
||
57 | #include <utility> |
||
58 | |||
59 | namespace dcx { |
||
60 | |||
61 | // Object types |
||
62 | enum object_type_t : uint8_t |
||
63 | { |
||
64 | OBJ_NONE = 255, // unused object |
||
65 | OBJ_WALL = 0, // A wall... not really an object, but used for collisions |
||
66 | OBJ_FIREBALL = 1, // a fireball, part of an explosion |
||
67 | OBJ_ROBOT = 2, // an evil enemy |
||
68 | OBJ_HOSTAGE = 3, // a hostage you need to rescue |
||
69 | OBJ_PLAYER = 4, // the player on the console |
||
70 | OBJ_WEAPON = 5, // a laser, missile, etc |
||
71 | OBJ_CAMERA = 6, // a camera to slew around with |
||
72 | OBJ_POWERUP = 7, // a powerup you can pick up |
||
73 | OBJ_DEBRIS = 8, // a piece of robot |
||
74 | OBJ_CNTRLCEN = 9, // the control center |
||
75 | OBJ_CLUTTER = 11, // misc objects |
||
76 | OBJ_GHOST = 12, // what the player turns into when dead |
||
77 | OBJ_LIGHT = 13, // a light source, & not much else |
||
78 | OBJ_COOP = 14, // a cooperative player object. |
||
79 | OBJ_MARKER = 15, // a map marker |
||
80 | }; |
||
81 | |||
82 | enum movement_type_t : uint8_t |
||
83 | { |
||
84 | MT_NONE = 0, // doesn't move |
||
85 | MT_PHYSICS = 1, // moves by physics |
||
86 | MT_SPINNING = 3, // this object doesn't move, just sits and spins |
||
87 | }; |
||
88 | |||
89 | enum render_type_t : uint8_t |
||
90 | { |
||
91 | RT_NONE = 0, // does not render |
||
92 | RT_POLYOBJ = 1, // a polygon model |
||
93 | RT_FIREBALL = 2, // a fireball |
||
94 | RT_LASER = 3, // a laser |
||
95 | RT_HOSTAGE = 4, // a hostage |
||
96 | RT_POWERUP = 5, // a powerup |
||
97 | RT_MORPH = 6, // a robot being morphed |
||
98 | RT_WEAPON_VCLIP = 7, // a weapon that renders as a vclip |
||
99 | }; |
||
100 | |||
101 | static inline bool valid_render_type(const uint8_t r) |
||
102 | { |
||
103 | switch (r) |
||
104 | { |
||
105 | case RT_NONE: |
||
106 | case RT_POLYOBJ: |
||
107 | case RT_FIREBALL: |
||
108 | case RT_LASER: |
||
109 | case RT_HOSTAGE: |
||
110 | case RT_POWERUP: |
||
111 | case RT_MORPH: |
||
112 | case RT_WEAPON_VCLIP: |
||
113 | return true; |
||
114 | default: |
||
115 | return false; |
||
116 | } |
||
117 | } |
||
118 | |||
119 | } |
||
120 | |||
121 | namespace dsx { |
||
122 | |||
123 | /* |
||
124 | * STRUCTURES |
||
125 | */ |
||
126 | |||
127 | struct reactor_static { |
||
128 | /* Location of the gun on the reactor object */ |
||
129 | std::array<vms_vector, MAX_CONTROLCEN_GUNS> gun_pos, |
||
130 | /* Orientation of the gun on the reactor object */ |
||
131 | gun_dir; |
||
132 | }; |
||
133 | |||
134 | struct player_info |
||
135 | { |
||
136 | fix energy; // Amount of energy remaining. |
||
137 | fix homing_object_dist; // Distance of nearest homing object. |
||
138 | fix Fusion_charge; |
||
139 | #if defined(DXX_BUILD_DESCENT_II) |
||
140 | fix Omega_charge; |
||
141 | fix Omega_recharge_delay; |
||
142 | #endif |
||
143 | player_flags powerup_flags; |
||
144 | objnum_t killer_objnum; // Who killed me.... (-1 if no one) |
||
145 | uint16_t vulcan_ammo; |
||
146 | #if defined(DXX_BUILD_DESCENT_I) |
||
147 | using primary_weapon_flag_type = uint8_t; |
||
148 | #elif defined(DXX_BUILD_DESCENT_II) |
||
149 | using primary_weapon_flag_type = uint16_t; |
||
150 | #endif |
||
151 | primary_weapon_flag_type primary_weapon_flags; |
||
152 | bool Player_eggs_dropped; |
||
153 | bool FakingInvul; |
||
154 | bool lavafall_hiss_playing; |
||
155 | uint8_t missile_gun; |
||
156 | player_selected_weapon<primary_weapon_index_t> Primary_weapon; |
||
157 | player_selected_weapon<secondary_weapon_index_t> Secondary_weapon; |
||
158 | stored_laser_level laser_level; |
||
159 | std::array<uint8_t, MAX_SECONDARY_WEAPONS> secondary_ammo; // How much ammo of each type. |
||
160 | uint8_t Spreadfire_toggle; |
||
161 | #if defined(DXX_BUILD_DESCENT_II) |
||
162 | uint8_t Primary_last_was_super; |
||
163 | uint8_t Secondary_last_was_super; |
||
164 | uint8_t Helix_orientation; |
||
165 | #endif |
||
166 | int16_t net_killed_total; // Number of times killed total |
||
167 | int16_t net_kills_total; // Number of net kills total |
||
168 | int16_t KillGoalCount; // Num of players killed this level |
||
169 | union { |
||
170 | struct { |
||
171 | int score; // Current score. |
||
172 | int last_score; // Score at beginning of current level. |
||
173 | uint16_t hostages_rescued_total; // Total number of hostages rescued. |
||
174 | uint8_t hostages_on_board; |
||
175 | } mission; |
||
176 | struct { |
||
177 | uint8_t orbs; |
||
178 | } hoard; |
||
179 | }; |
||
180 | enum |
||
181 | { |
||
182 | max_hoard_orbs = 12, |
||
183 | }; |
||
184 | fix64 cloak_time; // Time cloaked |
||
185 | fix64 invulnerable_time; // Time invulnerable |
||
186 | fix64 Next_flare_fire_time; |
||
187 | fix64 Next_laser_fire_time; |
||
188 | fix64 Next_missile_fire_time; |
||
189 | fix64 Last_bumped_local_player; |
||
190 | fix64 Auto_fire_fusion_cannon_time; |
||
191 | }; |
||
192 | |||
193 | } |
||
194 | |||
195 | namespace dcx { |
||
196 | |||
197 | // A compressed form for sending crucial data |
||
198 | struct shortpos : prohibit_void_ptr<shortpos> |
||
199 | { |
||
200 | std::array<int8_t, 9> bytemat; |
||
201 | int16_t xo, yo, zo; |
||
202 | segnum_t segment; |
||
203 | int16_t velx, vely, velz; |
||
204 | }; |
||
205 | |||
206 | // Another compressed form for object position, velocity, orientation and rotvel using quaternion |
||
207 | struct quaternionpos : prohibit_void_ptr<quaternionpos> |
||
208 | { |
||
209 | using packed_size = std::integral_constant<std::size_t, sizeof(vms_quaternion) + sizeof(segnum_t) + (sizeof(vms_vector) * 3)>; |
||
210 | vms_quaternion orient; |
||
211 | vms_vector pos; |
||
212 | segnum_t segment; |
||
213 | vms_vector vel; |
||
214 | vms_vector rotvel; |
||
215 | }; |
||
216 | |||
217 | // stuctures for different kinds of simulation |
||
218 | |||
219 | struct laser_parent |
||
220 | { |
||
221 | int16_t parent_type = {}; // The type of the parent of this object |
||
222 | objnum_t parent_num = {}; // The object's parent's number |
||
223 | object_signature_t parent_signature = object_signature_t{0}; // The object's parent's signature... |
||
224 | }; |
||
225 | |||
226 | struct laser_info : prohibit_void_ptr<laser_info>, laser_parent |
||
227 | { |
||
228 | fix64 creation_time = 0; // Absolute time of creation. |
||
229 | /* hitobj_pos specifies the next position to which a value should be |
||
230 | * written. That position may have a defined value if the array has |
||
231 | * wrapped, but should be treated as write-only in the general case. |
||
232 | * |
||
233 | * hitobj_count tells how many elements in hitobj_values[] are |
||
234 | * valid. Its valid values are [0, hitobj_values.size()]. When |
||
235 | * hitobj_count == hitobj_values.size(), hitobj_pos wraps around and |
||
236 | * begins erasing the oldest elements first. |
||
237 | */ |
||
238 | uint8_t hitobj_pos = 0, hitobj_count = 0; |
||
239 | std::array<objnum_t, 83> hitobj_values = {}; |
||
240 | objnum_t track_goal = 0; // Object this object is tracking. |
||
241 | fix multiplier = 0; // Power if this is a fusion bolt (or other super weapon to be added). |
||
242 | uint_fast8_t test_set_hitobj(const vcobjidx_t o); |
||
243 | uint_fast8_t test_hitobj(const vcobjidx_t o) const; |
||
244 | icobjidx_t get_last_hitobj() const; |
||
245 | void clear_hitobj() |
||
246 | { |
||
247 | hitobj_pos = hitobj_count = 0; |
||
248 | } |
||
249 | void reset_hitobj(const icobjidx_t o) |
||
250 | { |
||
251 | if (o == object_none) |
||
252 | { |
||
253 | /* Adding object_none to the array is harmless, since |
||
254 | * get_last_hitobj can return object_none for empty arrays. |
||
255 | * However, by filtering it here (which is called only when |
||
256 | * loading data into new objects), test_hitobj (which is |
||
257 | * called every time the object strikes a potential target) |
||
258 | * will not need to read a slot that is guaranteed not to |
||
259 | * match. |
||
260 | */ |
||
261 | clear_hitobj(); |
||
262 | return; |
||
263 | } |
||
264 | /* Assume caller already poisoned the unused array elements */ |
||
265 | hitobj_pos = hitobj_count = 1; |
||
266 | hitobj_values[0] = o; |
||
267 | } |
||
268 | }; |
||
269 | |||
270 | // Same as above but structure Savegames/Multiplayer objects expect |
||
271 | struct laser_info_rw |
||
272 | { |
||
273 | short parent_type; // The type of the parent of this object |
||
274 | short parent_num; // The object's parent's number |
||
275 | int parent_signature; // The object's parent's signature... |
||
276 | fix creation_time; // Absolute time of creation. |
||
277 | short last_hitobj; // For persistent weapons (survive object collision), object it most recently hit. |
||
278 | short track_goal; // Object this object is tracking. |
||
279 | fix multiplier; // Power if this is a fusion bolt (or other super weapon to be added). |
||
280 | } __pack__; |
||
281 | |||
282 | struct explosion_info : prohibit_void_ptr<explosion_info> |
||
283 | { |
||
284 | fix spawn_time; // when lifeleft is < this, spawn another |
||
285 | fix delete_time; // when to delete object |
||
286 | objnum_t delete_objnum; // and what object to delete |
||
287 | objnum_t attach_parent; // explosion is attached to this object |
||
288 | objnum_t prev_attach; // previous explosion in attach list |
||
289 | objnum_t next_attach; // next explosion in attach list |
||
290 | }; |
||
291 | |||
292 | struct explosion_info_rw |
||
293 | { |
||
294 | fix spawn_time; // when lifeleft is < this, spawn another |
||
295 | fix delete_time; // when to delete object |
||
296 | short delete_objnum; // and what object to delete |
||
297 | short attach_parent; // explosion is attached to this object |
||
298 | short prev_attach; // previous explosion in attach list |
||
299 | short next_attach; // next explosion in attach list |
||
300 | } __pack__; |
||
301 | |||
302 | struct light_info : prohibit_void_ptr<light_info> |
||
303 | { |
||
304 | fix intensity; // how bright the light is |
||
305 | }; |
||
306 | |||
307 | struct light_info_rw |
||
308 | { |
||
309 | fix intensity; // how bright the light is |
||
310 | } __pack__; |
||
311 | |||
312 | struct powerup_info : prohibit_void_ptr<powerup_info> |
||
313 | { |
||
314 | int count; // how many/much we pick up (vulcan cannon only?) |
||
315 | int flags; // spat by player? |
||
316 | fix64 creation_time; // Absolute time of creation. |
||
317 | }; |
||
318 | |||
319 | } |
||
320 | |||
321 | namespace dsx { |
||
322 | |||
323 | struct powerup_info_rw |
||
324 | { |
||
325 | int count; // how many/much we pick up (vulcan cannon only?) |
||
326 | #if defined(DXX_BUILD_DESCENT_II) |
||
327 | // Same as above but structure Savegames/Multiplayer objects expect |
||
328 | fix creation_time; // Absolute time of creation. |
||
329 | int flags; // spat by player? |
||
330 | #endif |
||
331 | } __pack__; |
||
332 | |||
333 | } |
||
334 | |||
335 | namespace dcx { |
||
336 | |||
337 | struct vclip_info : prohibit_void_ptr<vclip_info> |
||
338 | { |
||
339 | int vclip_num; |
||
340 | fix frametime; |
||
341 | uint8_t framenum; |
||
342 | }; |
||
343 | |||
344 | struct vclip_info_rw |
||
345 | { |
||
346 | int vclip_num; |
||
347 | fix frametime; |
||
348 | sbyte framenum; |
||
349 | } __pack__; |
||
350 | |||
351 | // structures for different kinds of rendering |
||
352 | |||
353 | struct polyobj_info : prohibit_void_ptr<polyobj_info> |
||
354 | { |
||
355 | int model_num = 0; // which polygon model |
||
356 | std::array<vms_angvec, MAX_SUBMODELS> anim_angles{}; // angles for each subobject |
||
357 | int subobj_flags = 0; // specify which subobjs to draw |
||
358 | int tmap_override = 0; // if this is not -1, map all face to this |
||
359 | int alt_textures = 0; // if not -1, use these textures instead |
||
360 | }; |
||
361 | |||
362 | struct polyobj_info_rw |
||
363 | { |
||
364 | int model_num; // which polygon model |
||
365 | vms_angvec anim_angles[MAX_SUBMODELS]; // angles for each subobject |
||
366 | int subobj_flags; // specify which subobjs to draw |
||
367 | int tmap_override; // if this is not -1, map all face to this |
||
368 | int alt_textures; // if not -1, use these textures instead |
||
369 | } __pack__; |
||
370 | |||
371 | struct object_base |
||
372 | { |
||
373 | object_signature_t signature; |
||
374 | object_type_t type; // what type of object this is... robot, weapon, hostage, powerup, fireball |
||
375 | ubyte id; // which form of object...which powerup, robot, etc. |
||
376 | objnum_t next,prev; // id of next and previous connected object in Objects, -1 = no connection |
||
377 | ubyte control_type; // how this object is controlled |
||
378 | movement_type_t movement_type; // how this object moves |
||
379 | render_type_t render_type; // how this object renders |
||
380 | ubyte flags; // misc flags |
||
381 | segnum_t segnum; // segment number containing object |
||
382 | objnum_t attached_obj; // number of attached fireball object |
||
383 | vms_vector pos; // absolute x,y,z coordinate of center of object |
||
384 | vms_matrix orient; // orientation of object in world |
||
385 | fix size; // 3d size of object - for collision detection |
||
386 | fix shields; // Starts at maximum, when <0, object dies.. |
||
387 | sbyte contains_type; // Type of object this object contains (eg, spider contains powerup) |
||
388 | sbyte contains_id; // ID of object this object contains (eg, id = blue type = key) |
||
389 | sbyte contains_count; // number of objects of type:id this object contains |
||
390 | sbyte matcen_creator; // Materialization center that created this object, high bit set if matcen-created |
||
391 | fix lifeleft; // how long until goes away, or 7fff if immortal |
||
392 | // -- Removed, MK, 10/16/95, using lifeleft instead: int lightlevel; |
||
393 | |||
394 | // movement info, determined by MOVEMENT_TYPE |
||
395 | union movement_info { |
||
396 | physics_info phys_info; // a physics object |
||
397 | vms_vector spin_rate; // for spinning objects |
||
398 | constexpr movement_info() : |
||
399 | phys_info{} |
||
400 | { |
||
401 | static_assert(sizeof(phys_info) == sizeof(*this), "insufficient initialization"); |
||
402 | } |
||
403 | } mtype; |
||
404 | |||
405 | // render info, determined by RENDER_TYPE |
||
406 | union render_info { |
||
407 | struct polyobj_info pobj_info; // polygon model |
||
408 | struct vclip_info vclip_info; // vclip |
||
409 | constexpr render_info() : |
||
410 | pobj_info{} |
||
411 | { |
||
412 | static_assert(sizeof(pobj_info) == sizeof(*this), "insufficient initialization"); |
||
413 | } |
||
414 | } rtype; |
||
415 | }; |
||
416 | |||
417 | } |
||
418 | |||
419 | namespace dsx { |
||
420 | |||
421 | #if defined(DXX_BUILD_DESCENT_II) |
||
422 | struct laser_info : public ::dcx::laser_info |
||
423 | { |
||
424 | fix64 last_afterburner_time = 0; // Time at which this object last created afterburner blobs. |
||
425 | }; |
||
426 | #endif |
||
427 | |||
428 | struct object : public ::dcx::object_base |
||
429 | { |
||
430 | // control info, determined by CONTROL_TYPE |
||
431 | union control_info { |
||
432 | constexpr control_info() : |
||
433 | ai_info{} |
||
434 | { |
||
435 | static_assert(sizeof(ai_info) == sizeof(*this), "insufficient initialization"); |
||
436 | } |
||
437 | struct laser_info laser_info; |
||
438 | struct explosion_info expl_info; // NOTE: debris uses this also |
||
439 | struct light_info light_info; // why put this here? Didn't know what else to do with it. |
||
440 | struct powerup_info powerup_info; |
||
441 | struct ai_static ai_info; |
||
442 | struct reactor_static reactor_info; |
||
443 | struct player_info player_info; |
||
444 | } ctype; |
||
445 | }; |
||
446 | |||
447 | } |
||
448 | |||
449 | namespace dcx { |
||
450 | |||
451 | // Same as above but structure Savegames/Multiplayer objects expect |
||
452 | struct object_rw |
||
453 | { |
||
454 | int signature; // Every object ever has a unique signature... |
||
455 | ubyte type; // what type of object this is... robot, weapon, hostage, powerup, fireball |
||
456 | ubyte id; // which form of object...which powerup, robot, etc. |
||
457 | short next,prev; // id of next and previous connected object in Objects, -1 = no connection |
||
458 | ubyte control_type; // how this object is controlled |
||
459 | ubyte movement_type; // how this object moves |
||
460 | ubyte render_type; // how this object renders |
||
461 | ubyte flags; // misc flags |
||
462 | short segnum; // segment number containing object |
||
463 | short attached_obj; // number of attached fireball object |
||
464 | vms_vector pos; // absolute x,y,z coordinate of center of object |
||
465 | vms_matrix orient; // orientation of object in world |
||
466 | fix size; // 3d size of object - for collision detection |
||
467 | fix shields; // Starts at maximum, when <0, object dies.. |
||
468 | vms_vector last_pos; // where object was last frame |
||
469 | sbyte contains_type; // Type of object this object contains (eg, spider contains powerup) |
||
470 | sbyte contains_id; // ID of object this object contains (eg, id = blue type = key) |
||
471 | sbyte contains_count; // number of objects of type:id this object contains |
||
472 | sbyte matcen_creator; // Materialization center that created this object, high bit set if matcen-created |
||
473 | fix lifeleft; // how long until goes away, or 7fff if immortal |
||
474 | // -- Removed, MK, 10/16/95, using lifeleft instead: int lightlevel; |
||
475 | |||
476 | // movement info, determined by MOVEMENT_TYPE |
||
477 | union { |
||
478 | physics_info_rw phys_info; // a physics object |
||
479 | vms_vector spin_rate; // for spinning objects |
||
480 | } __pack__ mtype ; |
||
481 | |||
482 | // control info, determined by CONTROL_TYPE |
||
483 | union { |
||
484 | laser_info_rw laser_info; |
||
485 | explosion_info_rw expl_info; // NOTE: debris uses this also |
||
486 | ai_static_rw ai_info; |
||
487 | light_info_rw light_info; // why put this here? Didn't know what else to do with it. |
||
488 | powerup_info_rw powerup_info; |
||
489 | } __pack__ ctype ; |
||
490 | |||
491 | // render info, determined by RENDER_TYPE |
||
492 | union { |
||
493 | polyobj_info_rw pobj_info; // polygon model |
||
494 | vclip_info_rw vclip_info; // vclip |
||
495 | } __pack__ rtype; |
||
496 | } __pack__; |
||
497 | |||
498 | struct obj_position |
||
499 | { |
||
500 | vms_vector pos; // absolute x,y,z coordinate of center of object |
||
501 | vms_matrix orient; // orientation of object in world |
||
502 | segnum_t segnum; // segment number containing object |
||
503 | }; |
||
504 | |||
505 | #define set_object_type(O,T) \ |
||
506 | ( DXX_BEGIN_COMPOUND_STATEMENT { \ |
||
507 | object_base &dxx_object_type_ref = (O); \ |
||
508 | const uint8_t &dxx_object_type_value = (T); \ |
||
509 | assert( \ |
||
510 | dxx_object_type_value == OBJ_NONE || \ |
||
511 | dxx_object_type_value == OBJ_FIREBALL || \ |
||
512 | dxx_object_type_value == OBJ_ROBOT || \ |
||
513 | dxx_object_type_value == OBJ_HOSTAGE || \ |
||
514 | dxx_object_type_value == OBJ_PLAYER || \ |
||
515 | dxx_object_type_value == OBJ_WEAPON || \ |
||
516 | dxx_object_type_value == OBJ_CAMERA || \ |
||
517 | dxx_object_type_value == OBJ_POWERUP || \ |
||
518 | dxx_object_type_value == OBJ_DEBRIS || \ |
||
519 | dxx_object_type_value == OBJ_CNTRLCEN || \ |
||
520 | dxx_object_type_value == OBJ_CLUTTER || \ |
||
521 | dxx_object_type_value == OBJ_GHOST || \ |
||
522 | dxx_object_type_value == OBJ_LIGHT || \ |
||
523 | dxx_object_type_value == OBJ_COOP || \ |
||
524 | dxx_object_type_value == OBJ_MARKER \ |
||
525 | ); \ |
||
526 | dxx_object_type_ref.type = static_cast<object_type_t>(dxx_object_type_value); \ |
||
527 | } DXX_END_COMPOUND_STATEMENT ) |
||
528 | |||
529 | #define set_object_movement_type(O,T) \ |
||
530 | ( DXX_BEGIN_COMPOUND_STATEMENT { \ |
||
531 | object_base &dxx_object_movement_type_ref = (O); \ |
||
532 | const uint8_t &dxx_object_movement_type_value = (T); \ |
||
533 | assert( \ |
||
534 | dxx_object_movement_type_value == MT_NONE || \ |
||
535 | dxx_object_movement_type_value == MT_PHYSICS || \ |
||
536 | dxx_object_movement_type_value == MT_SPINNING \ |
||
537 | ); \ |
||
538 | dxx_object_movement_type_ref.movement_type = static_cast<movement_type_t>(dxx_object_movement_type_value); \ |
||
539 | } DXX_END_COMPOUND_STATEMENT ) |
||
540 | |||
541 | template <typename T, std::size_t... N> |
||
542 | constexpr std::array<T, sizeof...(N)> init_object_number_array(std::index_sequence<N...>) |
||
543 | { |
||
544 | return {{((void)N, object_none)...}}; |
||
545 | } |
||
546 | |||
547 | template <typename T, std::size_t N> |
||
548 | struct object_number_array : std::array<T, N> |
||
549 | { |
||
550 | constexpr object_number_array() : |
||
551 | std::array<T, N>(init_object_number_array<T>(std::make_index_sequence<N>())) |
||
552 | { |
||
553 | } |
||
554 | }; |
||
555 | |||
556 | unsigned laser_parent_is_matching_signature(const laser_parent &l, const object_base &o); |
||
557 | |||
558 | struct d_level_unique_control_center_state |
||
559 | { |
||
560 | uint8_t Control_center_destroyed; |
||
561 | uint8_t Control_center_been_hit; |
||
562 | uint8_t Control_center_present; |
||
563 | player_visibility_state Control_center_player_been_seen; |
||
564 | objnum_t Dead_controlcen_object_num; |
||
565 | int Countdown_seconds_left; |
||
566 | fix Countdown_timer; |
||
567 | fix Frametime_until_next_fire; |
||
568 | /* If the player is not dead, this stays 0. If the player is dead, |
||
569 | * this accumulates FrameTime, up until it saturates. When it |
||
570 | * saturates, the reactor stops firing. |
||
571 | * |
||
572 | * FIXME: The original game defined this in terms of "the player", |
||
573 | * but reactors are present in multiplayer games. |
||
574 | */ |
||
575 | fix Frametime_since_player_died; |
||
576 | int Total_countdown_time; //in whole seconds |
||
577 | }; |
||
578 | |||
579 | struct d_level_unique_boss_state |
||
580 | { |
||
581 | fix64 Last_gate_time; |
||
582 | fix64 Boss_cloak_start_time; |
||
583 | fix64 Last_teleport_time; |
||
584 | fix64 Boss_dying_start_time; |
||
585 | int8_t Boss_hit_this_frame; |
||
586 | int8_t Boss_dying; |
||
587 | int8_t Boss_dying_sound_playing; |
||
588 | }; |
||
589 | |||
590 | } |
||
591 | |||
592 | #define Highest_object_index (Objects.get_count() - 1) |
||
593 | |||
594 | #include "morph.h" |
||
595 | |||
596 | namespace dcx { |
||
597 | |||
598 | struct d_level_unique_morph_object_state |
||
599 | { |
||
600 | std::array<morph_data::ptr, 5> morph_objects; |
||
601 | ~d_level_unique_morph_object_state(); |
||
602 | }; |
||
603 | |||
604 | } |
||
605 | |||
606 | namespace dsx { |
||
607 | |||
608 | #if defined(DXX_BUILD_DESCENT_II) |
||
609 | |||
610 | /* game_marker_index values are assigned as the object.id field for |
||
611 | * marker objects, and are used as an index into most marker-related |
||
612 | * arrays. These values are scoped to a single level. Each player |
||
613 | * marker has a unique value for game_marker_index, computed based on |
||
614 | * the player's ID and the player_marker_index active for that player |
||
615 | * when the marker was created. |
||
616 | */ |
||
617 | enum class game_marker_index : uint8_t |
||
618 | { |
||
619 | GuidebotDeathSite = 10, |
||
620 | None = UINT8_MAX |
||
621 | }; |
||
622 | |||
623 | /* player_marker_index are per-player marker indexes. Each player has |
||
624 | * their own private number space. Valid values range from [0, |
||
625 | * maxdrop), where maxdrop depends on the game type (single player, |
||
626 | * competitive multiplayer, or cooperative multiplayer). |
||
627 | */ |
||
628 | enum class player_marker_index : uint8_t |
||
629 | { |
||
630 | _0, |
||
631 | None = UINT8_MAX |
||
632 | }; |
||
633 | |||
634 | static inline game_marker_index &operator++(game_marker_index &i) |
||
635 | { |
||
636 | auto u = static_cast<unsigned>(i); |
||
637 | ++ u; |
||
638 | i = static_cast<game_marker_index>(u); |
||
639 | return i; |
||
640 | } |
||
641 | |||
642 | static inline player_marker_index &operator++(player_marker_index &i) |
||
643 | { |
||
644 | auto u = static_cast<unsigned>(i); |
||
645 | ++ u; |
||
646 | i = static_cast<player_marker_index>(u); |
||
647 | return i; |
||
648 | } |
||
649 | |||
650 | playernum_t get_marker_owner(unsigned, game_marker_index, unsigned max_numplayers); |
||
651 | |||
652 | struct d_unique_buddy_state |
||
653 | { |
||
654 | enum class Escort_goal_reachability : uint8_t |
||
655 | { |
||
656 | unreachable, |
||
657 | reachable, |
||
658 | }; |
||
659 | icobjidx_t Buddy_objnum = object_none; |
||
660 | icobjidx_t Escort_goal_objidx = object_none; |
||
661 | Escort_goal_reachability Escort_goal_reachable = Escort_goal_reachability::unreachable; |
||
662 | uint8_t Buddy_allowed_to_talk; |
||
663 | uint8_t Buddy_messages_suppressed; |
||
664 | uint8_t Buddy_gave_hint_count; |
||
665 | game_marker_index Looking_for_marker; |
||
666 | int Last_buddy_key; |
||
667 | int Last_buddy_polish_path_tick; |
||
668 | escort_goal_t Escort_goal_object; |
||
669 | escort_goal_t Escort_special_goal; |
||
670 | fix64 Buddy_sorry_time; |
||
671 | fix64 Buddy_last_seen_player; |
||
672 | fix64 Buddy_last_missile_time; |
||
673 | fix64 Last_time_buddy_gave_hint; |
||
674 | fix64 Last_come_back_message_time; |
||
675 | fix64 Escort_last_path_created; |
||
676 | fix64 Buddy_last_player_path_created; |
||
677 | fix64 Last_buddy_message_time; |
||
678 | }; |
||
679 | |||
680 | struct d_level_unique_control_center_state : |
||
681 | ::dcx::d_level_unique_control_center_state |
||
682 | { |
||
683 | fix64 Last_time_cc_vis_check; |
||
684 | }; |
||
685 | |||
686 | class d_guided_missile_indices : object_number_array<imobjidx_t, MAX_PLAYERS> |
||
687 | { |
||
688 | template <typename R, typename F> |
||
689 | R get_player_active_guided_missile_tmpl(F &fvcobj, unsigned pnum) const; |
||
690 | static bool debug_check_current_object(const object_base &); |
||
691 | public: |
||
692 | imobjidx_t get_player_active_guided_missile(unsigned pnum) const; |
||
693 | imobjptr_t get_player_active_guided_missile(fvmobjptr &vmobjptr, unsigned pnum) const; |
||
694 | imobjptridx_t get_player_active_guided_missile(fvmobjptridx &vmobjptridx, unsigned pnum) const; |
||
695 | void set_player_active_guided_missile(vmobjidx_t, unsigned pnum); |
||
696 | void clear_player_active_guided_missile(unsigned pnum); |
||
697 | }; |
||
698 | |||
699 | struct d_level_unique_boss_state : ::dcx::d_level_unique_boss_state |
||
700 | { |
||
701 | fix64 Boss_hit_time; |
||
702 | }; |
||
703 | |||
704 | const player &get_player_controlling_guidebot(const d_unique_buddy_state & /* reserved for future use */, const valptridx<player>::array_managed_type &Players); |
||
705 | #endif |
||
706 | |||
707 | struct d_level_unique_object_state |
||
708 | { |
||
709 | unsigned num_objects = 0; |
||
710 | /* `accumulated_robots` counts robots present at level entry and |
||
711 | * robots added later via materialization centers / boss gating. It |
||
712 | * never decreases, so it is not a shortcut for counting the number |
||
713 | * of currently live objects with type OBJ_ROBOT. |
||
714 | */ |
||
715 | unsigned accumulated_robots; |
||
716 | unsigned total_hostages; |
||
717 | unsigned Debris_object_count = 0; |
||
718 | #if defined(DXX_BUILD_DESCENT_II) |
||
719 | d_unique_buddy_state BuddyState; |
||
720 | d_thief_unique_state ThiefState; |
||
721 | d_guided_missile_indices Guided_missile; |
||
722 | #endif |
||
723 | object_number_array<imobjidx_t, MAX_OBJECTS> free_obj_list; |
||
724 | object_array Objects; |
||
725 | d_level_unique_boss_state BossState; |
||
726 | d_level_unique_control_center_state ControlCenterState; |
||
727 | vms_vector last_console_player_position; |
||
728 | d_level_unique_morph_object_state MorphObjectState; |
||
729 | auto &get_objects() |
||
730 | { |
||
731 | return Objects; |
||
732 | } |
||
733 | const auto &get_objects() const |
||
734 | { |
||
735 | return Objects; |
||
736 | } |
||
737 | }; |
||
738 | |||
739 | extern d_level_unique_object_state LevelUniqueObjectState; |
||
740 | |||
741 | unsigned laser_parent_is_player(fvcobjptr &, const laser_parent &, const object_base &); |
||
742 | unsigned laser_parent_is_object(fvcobjptr &, const laser_parent &, const object_base &); |
||
743 | unsigned laser_parent_is_object(const laser_parent &, vcobjptridx_t); |
||
744 | unsigned laser_parent_object_exists(fvcobjptr &, const laser_parent &); |
||
745 | |||
746 | static inline powerup_type_t get_powerup_id(const object_base &o) |
||
747 | { |
||
748 | return static_cast<powerup_type_t>(o.id); |
||
749 | } |
||
750 | |||
751 | static inline weapon_id_type get_weapon_id(const object_base &o) |
||
752 | { |
||
753 | return static_cast<weapon_id_type>(o.id); |
||
754 | } |
||
755 | |||
756 | #if defined(DXX_BUILD_DESCENT_II) |
||
757 | static inline game_marker_index get_marker_id(const object_base &o) |
||
758 | { |
||
759 | return game_marker_index{o.id}; |
||
760 | } |
||
761 | #endif |
||
762 | |||
763 | void set_powerup_id(const d_powerup_info_array &Powerup_info, const d_vclip_array &Vclip, object_base &o, powerup_type_t id); |
||
764 | |||
765 | static inline void set_weapon_id(object_base &o, weapon_id_type id) |
||
766 | { |
||
767 | o.id = static_cast<uint8_t>(id); |
||
768 | } |
||
769 | |||
770 | } |
||
771 | |||
772 | namespace dcx { |
||
773 | |||
774 | static inline uint8_t get_player_id(const object_base &o) |
||
775 | { |
||
776 | return o.id; |
||
777 | } |
||
778 | |||
779 | static inline uint8_t get_reactor_id(const object_base &o) |
||
780 | { |
||
781 | return o.id; |
||
782 | } |
||
783 | |||
784 | static inline uint8_t get_fireball_id(const object_base &o) |
||
785 | { |
||
786 | return o.id; |
||
787 | } |
||
788 | |||
789 | static inline uint8_t get_robot_id(const object_base &o) |
||
790 | { |
||
791 | return o.id; |
||
792 | } |
||
793 | |||
794 | static inline void set_player_id(object_base &o, const uint8_t id) |
||
795 | { |
||
796 | o.id = id; |
||
797 | } |
||
798 | |||
799 | static inline void set_reactor_id(object_base &o, const uint8_t id) |
||
800 | { |
||
801 | o.id = id; |
||
802 | } |
||
803 | |||
804 | static inline void set_robot_id(object_base &o, const uint8_t id) |
||
805 | { |
||
806 | o.id = id; |
||
807 | } |
||
808 | |||
809 | void check_warn_object_type(const object_base &, object_type_t, const char *file, unsigned line); |
||
810 | #define get_player_id(O) (check_warn_object_type(O, OBJ_PLAYER, __FILE__, __LINE__), get_player_id(O)) |
||
811 | #define get_powerup_id(O) (check_warn_object_type(O, OBJ_POWERUP, __FILE__, __LINE__), get_powerup_id(O)) |
||
812 | #define get_reactor_id(O) (check_warn_object_type(O, OBJ_CNTRLCEN, __FILE__, __LINE__), get_reactor_id(O)) |
||
813 | #define get_ghost_id(O) (check_warn_object_type(O, OBJ_GHOST, __FILE__, __LINE__), (get_player_id)(O)) |
||
814 | #define get_fireball_id(O) (check_warn_object_type(O, OBJ_FIREBALL, __FILE__, __LINE__), get_fireball_id(O)) |
||
815 | #define get_robot_id(O) (check_warn_object_type(O, OBJ_ROBOT, __FILE__, __LINE__), get_robot_id(O)) |
||
816 | #define get_weapon_id(O) (check_warn_object_type(O, OBJ_WEAPON, __FILE__, __LINE__), get_weapon_id(O)) |
||
817 | #if defined(DXX_BUILD_DESCENT_II) |
||
818 | #define get_marker_id(O) (check_warn_object_type(O, OBJ_MARKER, __FILE__, __LINE__), get_marker_id(O)) |
||
819 | #endif |
||
820 | #define set_player_id(O,I) (check_warn_object_type(O, OBJ_PLAYER, __FILE__, __LINE__), set_player_id(O, I)) |
||
821 | #define set_reactor_id(O,I) (check_warn_object_type(O, OBJ_CNTRLCEN, __FILE__, __LINE__), set_reactor_id(O, I)) |
||
822 | #define set_robot_id(O,I) (check_warn_object_type(O, OBJ_ROBOT, __FILE__, __LINE__), set_robot_id(O, I)) |
||
823 | #define set_weapon_id(O,I) (check_warn_object_type(O, OBJ_WEAPON, __FILE__, __LINE__), set_weapon_id(O, I)) |
||
824 | #ifdef DXX_CONSTANT_TRUE |
||
825 | #define check_warn_object_type(O,T,F,L) \ |
||
826 | ( DXX_BEGIN_COMPOUND_STATEMENT { \ |
||
827 | const object_base &dxx_check_warn_o = (O); \ |
||
828 | const auto dxx_check_warn_actual_type = dxx_check_warn_o.type; \ |
||
829 | const auto dxx_check_warn_expected_type = (T); \ |
||
830 | /* If the type is always right, omit the runtime check. */ \ |
||
831 | DXX_CONSTANT_TRUE(dxx_check_warn_actual_type == dxx_check_warn_expected_type) || ( \ |
||
832 | /* If the type is always wrong, force a compile-time error. */ \ |
||
833 | DXX_CONSTANT_TRUE(dxx_check_warn_actual_type != dxx_check_warn_expected_type) \ |
||
834 | ? DXX_ALWAYS_ERROR_FUNCTION(dxx_error_object_type_mismatch, "object type mismatch") \ |
||
835 | : ( \ |
||
836 | check_warn_object_type(dxx_check_warn_o, dxx_check_warn_expected_type, F, L) \ |
||
837 | ) \ |
||
838 | , 0); \ |
||
839 | } DXX_END_COMPOUND_STATEMENT ) |
||
840 | #endif |
||
841 | |||
842 | } |
||
843 | #endif |
||
844 | |||
845 | #endif |