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 * Structs and constants for AI system.
23 * object.h depends on this.
24 * ai.h depends on object.h.
25 * Get it?
26 *
27 */
28
29 #pragma once
30
31 #include <physfs.h>
32
33 #ifdef __cplusplus
34 #include "polyobj.h"
35 #include "pack.h"
36 #include "objnum.h"
37 #include "fwd-segment.h"
38
39 #define GREEN_GUY 1
40
41 #define MAX_SEGMENTS_PER_PATH 20
42
43 namespace dcx {
44
45 enum class player_awareness_type_t : uint8_t
46 {
47 PA_NONE,
48 PA_NEARBY_ROBOT_FIRED = 1, // Level of robot awareness after nearby robot fires a weapon
49 PA_WEAPON_WALL_COLLISION = 2, // Level of robot awareness after player weapon hits nearby wall
50 // PA_PLAYER_VISIBLE = 2, // Level of robot awareness if robot is looking towards player, and player not hidden
51 PA_PLAYER_COLLISION = 3, // Level of robot awareness after player bumps into robot
52 PA_WEAPON_ROBOT_COLLISION = 4, // Level of robot awareness after player weapon hits nearby robot
53 };
54
55 enum class player_visibility_state : int8_t
56 {
57 no_line_of_sight,
58 visible_not_in_field_of_view,
59 visible_and_in_field_of_view,
60 };
61
player_is_visible(const player_visibility_state s)62 static inline unsigned player_is_visible(const player_visibility_state s)
63 {
64 return static_cast<unsigned>(s) > 0;
65 }
66
67 }
68
69 // Constants indicating currently moving forward or backward through
70 // path. Note that you can add aip->direction to aip_path_index to
71 // get next segment on path.
72 #define AI_DIR_FORWARD 1
73 #define AI_DIR_BACKWARD (-AI_DIR_FORWARD)
74
75 #ifdef dsx
76 namespace dsx {
77
78 enum class ai_behavior : uint8_t
79 {
80 // Behaviors
81 AIB_STILL = 0x80,
82 AIB_NORMAL = 0x81,
83 AIB_RUN_FROM = 0x83,
84 AIB_STATION = 0x85,
85 #if defined(DXX_BUILD_DESCENT_I)
86 AIB_HIDE = 0x82,
87 AIB_FOLLOW_PATH = 0x84,
88 #elif defined(DXX_BUILD_DESCENT_II)
89 AIB_BEHIND = 0x82,
90 AIB_SNIPE = 0x84,
91 AIB_FOLLOW = 0x86,
92 #endif
93 };
94
95 #define MIN_BEHAVIOR 0x80
96 #if defined(DXX_BUILD_DESCENT_I)
97 #define MAX_BEHAVIOR 0x85
98 #elif defined(DXX_BUILD_DESCENT_II)
99 #define MAX_BEHAVIOR 0x86
100 #endif
101
102 enum class ai_mode : uint8_t
103 {
104 // Modes
105 AIM_STILL = 0,
106 AIM_WANDER = 1,
107 AIM_FOLLOW_PATH = 2,
108 AIM_CHASE_OBJECT = 3,
109 AIM_RUN_FROM_OBJECT = 4,
110 AIM_FOLLOW_PATH_2 = 6,
111 AIM_OPEN_DOOR = 7,
112 #if defined(DXX_BUILD_DESCENT_I)
113 AIM_HIDE = 5,
114 #elif defined(DXX_BUILD_DESCENT_II)
115 AIM_BEHIND = 5,
116 AIM_GOTO_PLAYER = 8, // Only for escort behavior
117 AIM_GOTO_OBJECT = 9, // Only for escort behavior
118
119 AIM_SNIPE_ATTACK = 10,
120 AIM_SNIPE_FIRE = 11,
121 AIM_SNIPE_RETREAT = 12,
122 AIM_SNIPE_RETREAT_BACKWARDS = 13,
123 AIM_SNIPE_WAIT = 14,
124
125 AIM_THIEF_ATTACK = 15,
126 AIM_THIEF_RETREAT = 16,
127 AIM_THIEF_WAIT = 17,
128 #endif
129 };
130
131 }
132 #endif
133
134 #define AISM_GOHIDE 0
135 #define AISM_HIDING 1
136
137 #define AI_MAX_STATE 7
138 #define AI_MAX_EVENT 4
139
140 #define AIS_NONE 0
141 #define AIS_REST 1
142 #define AIS_SRCH 2
143 #define AIS_LOCK 3
144 #define AIS_FLIN 4
145 #define AIS_FIRE 5
146 #define AIS_RECO 6
147 #define AIS_ERR_ 7
148
149 #define AIE_FIRE 0
150 #define AIE_HITT 1
151 #define AIE_COLL 2
152 #define AIE_HURT 3
153
154 //typedef struct opath {
155 // sbyte path_index; // current index of path
156 // sbyte path_direction; // current path direction
157 // sbyte path_length; // length of current path
158 // sbyte nothing;
159 // short path[MAX_SEGMENTS_PER_PATH];
160 // short always_0xabc; // If this is ever not 0xabc, then someone overwrote
161 //} opath;
162 //
163 //typedef struct oai_state {
164 // short mode; //
165 // short counter; // kind of a hack, frame countdown until switch modes
166 // opath paths[2];
167 // vms_vector movement_vector; // movement vector for one second
168 //} oai_state;
169
170 #if defined(DXX_BUILD_DESCENT_II)
171 #define SUB_FLAGS_GUNSEG 0x01
172 #define SUB_FLAGS_SPROX 0x02 // If set, then this bot drops a super prox, not a prox, when it's time to drop something
173 #define SUB_FLAGS_CAMERA_AWAKE 0x04 // If set, a camera (on a missile) woke this robot up, so don't fire at player. Can look real stupid!
174 #endif
175
176 // Constants defining meaning of flags in ai_state
177 #define MAX_AI_FLAGS 11 // This MUST cause word (4 bytes) alignment in ai_static, allowing for one byte mode
178
179 #define CURRENT_GUN flags[0] // This is the last gun the object fired from
180 #define CURRENT_STATE flags[1] // current behavioral state
181 #define GOAL_STATE flags[2] // goal state
182 #define PATH_DIR flags[3] // direction traveling path, 1 = forward, -1 = backward, other = error!
183 #if defined(DXX_BUILD_DESCENT_I)
184 #define SUBMODE flags[4] // submode, eg AISM_HIDING if mode == AIM_HIDE
185 #elif defined(DXX_BUILD_DESCENT_II)
186 #define SUB_FLAGS flags[4] // bit 0: Set -> Robot's current gun in different segment than robot's center.
187 #endif
188 #define GOALSIDE flags[5] // for guys who open doors, this is the side they are going after.
189 #define CLOAKED flags[6] // Cloaked now.
190 #define SKIP_AI_COUNT flags[7] // Skip AI this frame, but decrement in do_ai_frame.
191 #define REMOTE_OWNER flags[8] // Who is controlling this remote AI object (multiplayer use only)
192 #define REMOTE_SLOT_NUM flags[9] // What slot # is this robot in for remote control purposes (multiplayer use only)
193
194 // This is the stuff that is permanent for an AI object.
195 #ifdef dsx
196 namespace dsx {
197
198 // Rather temporal AI stuff.
199 struct ai_local : public prohibit_void_ptr<ai_local>
200 {
201 // These used to be bytes, changed to ints so I could set watchpoints on them.
202 player_awareness_type_t player_awareness_type = player_awareness_type_t::PA_NONE; // type of awareness of player
203 uint8_t retry_count = 0; // number of retries in physics last time this object got moved.
204 uint8_t consecutive_retries = 0; // number of retries in consecutive frames (ie, without a retry_count of 0)
205 player_visibility_state previous_visibility{}; // Visibility of player last time we checked.
206 uint8_t rapidfire_count = 0; // number of shots fired rapidly
207 ai_mode mode{}; // current mode within behavior
208 segnum_t goal_segment{}; // goal segment for current path
209 fix next_action_time = 0; // time in seconds until something happens, mode dependent
210 fix next_fire = 0; // time in seconds until can fire again
211 #if defined(DXX_BUILD_DESCENT_II)
212 fix next_fire2 = 0; // time in seconds until can fire again from second weapon
213 #endif
214 fix player_awareness_time = 0; // time in seconds robot will be aware of player, 0 means not aware of player
215 fix time_since_processed = 0; // time since this robot last processed in do_ai_frame
216 fix64 time_player_seen = 0; // absolute time in seconds at which player was last seen, might cause to go into follow_path mode
217 fix64 time_player_sound_attacked = 0; // absolute time in seconds at which player was last seen with visibility of 2.
218 fix64 next_misc_sound_time = 0; // absolute time in seconds at which this robot last made an angry or lurking sound.
219 std::array<vms_angvec, MAX_SUBMODELS> goal_angles{}; // angles for each subobject
220 std::array<vms_angvec, MAX_SUBMODELS> delta_angles{}; // angles for each subobject
221 std::array<sbyte, MAX_SUBMODELS> goal_state{}; // Goal state for this sub-object
222 std::array<sbyte, MAX_SUBMODELS> achieved_state{}; // Last achieved state
223 };
224
225 struct ai_static : public prohibit_void_ptr<ai_static>
226 {
227 ai_behavior behavior = static_cast<ai_behavior>(0); //
228 std::array<sbyte, MAX_AI_FLAGS> flags{}; // various flags, meaning defined by constants
229 segnum_t hide_segment{}; // Segment to go to for hiding.
230 short hide_index{}; // Index in Path_seg_points
231 short path_length{}; // Length of hide path.
232 #if defined(DXX_BUILD_DESCENT_I)
233 short cur_path_index{}; // Current index in path.
234 #elif defined(DXX_BUILD_DESCENT_II)
235 sbyte cur_path_index{}; // Current index in path.
236 sbyte dying_sound_playing{}; // !0 if this robot is playing its dying sound.
237 #endif
238 objnum_t danger_laser_num{};
239 object_signature_t danger_laser_signature;
240 #if defined(DXX_BUILD_DESCENT_II)
241 fix64 dying_start_time{}; // Time at which this robot started dying.
242 #endif
243 ai_local ail;
244 };
245
246 // Same as above but structure Savegames/Multiplayer objects expect
247 struct ai_static_rw
248 {
249 ubyte behavior; //
250 sbyte flags[MAX_AI_FLAGS]; // various flags, meaning defined by constants
251 short hide_segment; // Segment to go to for hiding.
252 short hide_index; // Index in Path_seg_points
253 short path_length; // Length of hide path.
254 #if defined(DXX_BUILD_DESCENT_I)
255 short cur_path_index; // Current index in path.
256 short follow_path_start_seg; // Start segment for robot which follows path.
257 short follow_path_end_seg; // End segment for robot which follows path.
258 int danger_laser_signature;
259 short danger_laser_num;
260 #elif defined(DXX_BUILD_DESCENT_II)
261 sbyte cur_path_index; // Current index in path.
262 sbyte dying_sound_playing; // !0 if this robot is playing its dying sound.
263 short danger_laser_num;
264 int danger_laser_signature;
265 fix dying_start_time; // Time at which this robot started dying.
266 #endif
267 } __pack__;
268
269 // Same as above but structure Savegames expect
270 struct ai_local_rw
271 {
272 // These used to be bytes, changed to ints so I could set watchpoints on them.
273 #if defined(DXX_BUILD_DESCENT_I)
274 sbyte player_awareness_type; // type of awareness of player
275 sbyte retry_count; // number of retries in physics last time this object got moved.
276 sbyte consecutive_retries; // number of retries in consecutive frames (ie, without a retry_count of 0)
277 sbyte mode; // current mode within behavior
278 sbyte previous_visibility; // Visibility of player last time we checked.
279 sbyte rapidfire_count; // number of shots fired rapidly
280 short goal_segment; // goal segment for current path
281 fix last_see_time, last_attack_time; // For sound effects, time at which player last seen, attacked
282 #elif defined(DXX_BUILD_DESCENT_II)
283 int player_awareness_type; // type of awareness of player
284 int retry_count; // number of retries in physics last time this object got moved.
285 int consecutive_retries; // number of retries in consecutive frames (ie, without a retry_count of 0)
286 int mode; // current mode within behavior
287 int previous_visibility; // Visibility of player last time we checked.
288 int rapidfire_count; // number of shots fired rapidly
289 int goal_segment; // goal segment for current path
290 #endif
291 fix next_action_time; // time in seconds until something happens, mode dependent
292 fix next_fire; // time in seconds until can fire again
293 #if defined(DXX_BUILD_DESCENT_II)
294 fix next_fire2; // time in seconds until can fire again from second weapon
295 #endif
296 fix player_awareness_time; // time in seconds robot will be aware of player, 0 means not aware of player
297 fix time_player_seen; // absolute time in seconds at which player was last seen, might cause to go into follow_path mode
298 fix time_player_sound_attacked; // absolute time in seconds at which player was last seen with visibility of 2.
299 fix next_misc_sound_time; // absolute time in seconds at which this robot last made an angry or lurking sound.
300 fix time_since_processed; // time since this robot last processed in do_ai_frame
301 vms_angvec goal_angles[MAX_SUBMODELS]; // angles for each subobject
302 vms_angvec delta_angles[MAX_SUBMODELS]; // angles for each subobject
303 sbyte goal_state[MAX_SUBMODELS]; // Goal state for this sub-object
304 sbyte achieved_state[MAX_SUBMODELS]; // Last achieved state
305 };
306
307 struct ai_cloak_info : public prohibit_void_ptr<ai_cloak_info>
308 {
309 fix64 last_time;
310 #if defined(DXX_BUILD_DESCENT_II)
311 segnum_t last_segment;
312 #endif
313 vms_vector last_position;
314 };
315
316 // Same as above but structure Savegames expect
317 struct ai_cloak_info_rw
318 {
319 fix last_time;
320 #if defined(DXX_BUILD_DESCENT_II)
321 int last_segment;
322 #endif
323 vms_vector last_position;
324 };
325
326 #if defined(DXX_BUILD_DESCENT_II)
327
328 // Maximum number kept track of, will keep stealing, causes stolen weapons to be lost!
329 struct d_thief_unique_state
330 {
331 unsigned Stolen_item_index; // Used in ai.c for controlling rate of Thief flare firing.
332 std::array<uint8_t, 10> Stolen_items;
333 };
334
335 #endif
336 }
337 #endif
338
339 namespace dcx {
340
341 struct point_seg : prohibit_void_ptr<point_seg> {
342 segnum_t segnum;
343 vms_vector point;
344 };
345
346 struct seg_seg
347 {
348 segnum_t start, end;
349 };
350
351 constexpr std::integral_constant<unsigned, 2500> MAX_POINT_SEGS{};
352
353 }
354
355 // These are the information for a robot describing the location of
356 // the player last time he wasn't cloaked, and the time at which he
357 // was uncloaked. We should store this for each robot, but that's
358 // memory expensive.
359 //extern fix Last_uncloaked_time;
360 //extern vms_vector Last_uncloaked_position;
361
362 #ifdef dsx
363 namespace dsx {
364 extern void ai_do_cloak_stuff(void);
365 }
366 #endif
367
368 #endif
369