FS2_Open
Open source remastering of the Freespace 2 engine
aibig.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) Volition, Inc. 1999. All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell
5  * or otherwise commercially exploit the source or things you created based on the
6  * source.
7  *
8 */
9 
10 
11 
12 #include "ai/aibig.h"
13 #include "ai/aigoals.h"
14 #include "freespace2/freespace.h"
15 #include "globalincs/linklist.h"
16 #include "iff_defs/iff_defs.h"
17 #include "io/timer.h"
18 #include "math/staticrand.h"
19 #include "mission/missionparse.h"
20 #include "object/object.h"
21 #include "ship/afterburner.h"
22 #include "ship/ship.h"
23 #include "weapon/weapon.h"
24 
25 
26 #ifdef _MSC_VER
27 #pragma optimize("", off)
28 #pragma auto_inline(off)
29 #endif
30 
31 #define SCAN_FIGHTERS_INTERVAL 2000 // how often an AI fighter/bomber should scan for enemy fighter/bombers
32  // if sitting still and pounding on a big ship. If enemy fighters are
33  // close ( < ENTER_STRAFE_THREAT_DIST ), then enter AIM_STRAFE
34 
35 #define ENTER_STRAFE_THREAT_DIST_SQUARED 360000 // use squared distance, instead of 600
36 
37 #define MIN_DOT_TO_ATTACK_SUBSYS 0.7f
38 #define MIN_DOT_TO_ATTACK_MOVING_SUBSYS 0.97f
39 
40 // AI BIG MAGIC NUMBERS
41 #define STRAFE_RETREAT_COLLIDE_TIME 2.0 // when anticipated collision time is less than this, begin retreat
42 #define STRAFE_RETREAT_COLLIDE_DIST 100 // when perpendicular distance to *surface* is less than this, begin retreat
43 #define STRAFE_RETREAT_BOX_DIST 300 // distance beyond the bounding box to retreat
44 #define STRAFE_MAX_UNHIT_TIME 20 // Maximum amount of time to stay in strafe mode if not hit
45 
46 #define EVADE_BOX_BASE_DISTANCE 300 // standard distance to end evade submode
47 #define EVADE_BOX_MIN_DISTANCE 200 // minimun distance to end evade submode, after long time
48 
49 #define ATTACK_STOP_DISTANCE 150 // when distance to target is less than this, put on brakes
50 
51 #define ATTACK_COLLIDE_BASE_DIST 300 // absolute distance at which to begin checking for possible collision
52 #define ATTACK_COLLIDE_AVOID_DIST 60 // perpendicular distance to attack surface at which begin avoiding
53 #define ATTACK_COLLIDE_AVOID_TIME 1.0 // anticipated collision time at which to begin evade
54 #define ATTACK_COLLIDE_SLOW_DIST 150 // perpendicular distance to attack surface at which begin slowing down
55 #define ATTACK_COLLIDE_SLOW_TIME 1.5 // anticipated collision time at which to begin slowing down
56 
57 #define GLIDE_STRAFE_DISTANCE 50.0f //Distance from the ship to pass when glide strafing
58 #define GLIDE_STRAFE_MIN_TIME 2 //Minimum amount of time to stay on one glide strafe approach vector
59 #define GLIDE_STRAFE_MAX_TIME 15 //Maximum amount of time for each glide strafe pass
60 
61 // forward declarations
62 void ai_big_evade_ship();
63 void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float dist_to_enemy, int modelnum);
64 void ai_big_avoid_ship();
65 int ai_big_maybe_follow_subsys_path(int do_dot_check=1);
67 
68 extern int model_which_octant_distant_many( vec3d *pnt, int model_num,matrix *model_orient, vec3d * model_pos, polymodel **pm, int *octs);
69 extern void compute_desired_rvec(vec3d *rvec, vec3d *goal_pos, vec3d *cur_pos);
70 extern void big_ship_collide_recover_start(object *objp, object *big_objp, vec3d *collide_pos, vec3d *collision_normal);
71 
72 
73 // Called by ai_big_pick_attack_point.
74 // Generates a random attack point.
75 // If truly_random flag set (haha), then generate a pretty random number. Otherwise, generate a static rand which
76 // tends to not change from frame to frame.
77 // Try four times and choose nearest point to increase chance of getting a good point.
78 void ai_bpap(object *objp, vec3d *attacker_objp_pos, vec3d *attacker_objp_fvec, vec3d *attack_point, vec3d *local_attack_point, float fov, float weapon_travel_dist, vec3d *surface_normal, ship_subsys *ss)
79 {
80  float nearest_dist;
81  vec3d result_point, best_point;
82  vec3d rel_point;
83  int num_tries;
84  model_octant *octp;
85  polymodel *pm;
86  int i, q, octs[4];
88  model_subsystem *tp = NULL;
89  if (ss != NULL)
90  tp = ss->system_info;
91 
92  best_point = objp->pos;
93  nearest_dist = weapon_travel_dist;
94 
95  model_which_octant_distant_many(attacker_objp_pos, sip->model_num, &objp->orient, &objp->pos, &pm, octs);
96 
97  num_tries = (int) (vm_vec_dist(&objp->pos, attacker_objp_pos)/objp->radius);
98 
99  if (num_tries >= 4)
100  num_tries = 1;
101  else
102  num_tries = 4 - num_tries;
103 
104  // Index #0 is best one.
105  if ( pm->octants[octs[0]].verts ) {
106  *local_attack_point = *pm->octants[octs[0]].verts[0]; // Set just in case it doesn't get set below.
107  } else {
108  vm_vec_zero(local_attack_point);
109  }
110 
111  for (q=0; q<4; q++) {
112  octp = &pm->octants[octs[q]];
113  if (octp->nverts > 0) {
114 
115  if (num_tries > octp->nverts)
116  num_tries = octp->nverts;
117 
118  if (num_tries > octp->nverts)
119  num_tries = octp->nverts;
120 
121  for (i=0; i<num_tries; i++) {
122  int index;
123  float dist, dot;
124  vec3d v2p;
125 
126  index = (int) (frand() * (octp->nverts));
127 
128  rel_point = *octp->verts[index];
129  vm_vec_unrotate(&result_point, &rel_point, &objp->orient);
130  vm_vec_add2(&result_point, &objp->pos);
131 
132  dist = vm_vec_normalized_dir(&v2p, &result_point, attacker_objp_pos);
133  bool in_fov = false;
134 
135  dot = vm_vec_dot(&v2p, attacker_objp_fvec);
136  if (tp == NULL) {
137  if (dot > fov)
138  in_fov = true;
139  } else {
140  in_fov = turret_fov_test(ss, attacker_objp_fvec, &v2p);
141  }
142 
143  if (in_fov) {
144  if (dist < nearest_dist) {
145  nearest_dist = dist;
146  best_point = result_point;
147  *local_attack_point = rel_point;
148  Assert( !vm_is_vec_nan(local_attack_point) );
149  if (dot > (1.0f + fov)/2.0f) // If this point is quite good, quit searching for a better one.
150  goto done_1;
151  }
152  }
153  }
154  }
155  }
156 done_1:
157 
158  *attack_point = best_point;
159 
160  // Cast from attack_objp_pos to local_attack_pos and check for nearest collision.
161  // If no collision, cast to (0,0,0) [center of big ship]** [best_point initialized to 000]
162 
163  // do in world coords to get attack point, then translate to local for local_attack_point
164  vec3d attack_dir, end_point, temp;
165  float dist;
166  dist = vm_vec_normalized_dir(&attack_dir, attack_point, attacker_objp_pos);
167 
168  if (dist > 0.1) {
169  vm_vec_scale_add(&end_point, attack_point, &attack_dir, 30.0f);
170  } else {
171  vm_vec_scale_add(&end_point, attack_point, attacker_objp_fvec, 30.0f);
172  }
173 
174  mc_info mc;
175  mc_info_init(&mc);
176 
177  mc.model_instance_num = Ships[objp->instance].model_instance_num;
178  mc.model_num = sip->model_num;
179  mc.orient = &objp->orient;
180  mc.pos = &objp->pos;
181  mc.p0 = attacker_objp_pos;
182  mc.p1 = &end_point;
183  mc.flags = MC_CHECK_MODEL;
184  mc.radius = 0.0f;
185  model_collide(&mc);
186 
187  if (mc.num_hits > 0) {
188  *attack_point = mc.hit_point_world;
189  vm_vec_sub(&temp, attack_point, &objp->pos);
190  vm_vec_rotate(local_attack_point, &temp, &objp->orient);
191  if (surface_normal) {
192  vm_vec_unrotate(surface_normal, &mc.hit_normal, &objp->orient);
193  }
194  } else {
195  vm_vec_zero(local_attack_point);
196  *attack_point = objp->pos;
197  if (surface_normal) {
198  vm_vec_zero(surface_normal);
199  }
200  }
201 }
202 
203 // Stuff a point to attack based on nearest octant.
204 // If no points in that octant, leave attack_point unmodified.
205 //
206 // Note: Default value for fov is 1.0f 1.0f means don't use fov parameter.
207 // If fov != 1.0f, try up to four times to find a point that's in the field of view.
208 void ai_big_pick_attack_point_turret(object *objp, ship_subsys *ssp, vec3d *gpos, vec3d *gvec, vec3d *attack_point, float fov, float weapon_travel_dist)
209 {
211  vec3d result_point;
212  vm_vec_unrotate(&result_point, &ssp->turret_big_attack_point, &objp->orient);
213  vm_vec_add(attack_point, &result_point, &objp->pos);
214  } else {
215  vec3d local_attack_point;
216  ssp->turret_pick_big_attack_point_timestamp = timestamp(2000 + (int) (frand()*500.0f));
217  ai_bpap(objp, gpos, gvec, attack_point, &local_attack_point, fov, weapon_travel_dist, NULL, ssp);
218  ssp->turret_big_attack_point = local_attack_point;
219  }
220 }
221 
222 // Stuff a point to attack based on nearest octant.
223 // If no points in that octant, leave attack_point unmodified.
224 //
225 // Note: Default value for fov is 1.0f 1.0f means don't use fov parameter.
226 // If fov != 1.0f, try up to four times to find a point that's in the field of view.
227 // Note, attacker_objp can be a ship or a weapon.
228 void ai_big_pick_attack_point(object *objp, object *attacker_objp, vec3d *attack_point, float fov)
229 {
230  Assert(objp->instance > -1);
231  Assert(objp->type == OBJ_SHIP);
232 
233  vec3d local_attack_point;
234 
235  switch (attacker_objp->type) {
236  case OBJ_SHIP: {
237  ai_info *attacker_aip;
238  attacker_aip = &Ai_info[Ships[attacker_objp->instance].ai_index];
240  vec3d result_point;
241 
242  vm_vec_unrotate(&result_point, &attacker_aip->big_attack_point, &objp->orient);
243  vm_vec_add(attack_point, &result_point, &objp->pos);
244 
245  return;
246  }
247 
248  attacker_aip->pick_big_attack_point_timestamp = timestamp(2000 + (int) (frand()*500.0f));
249  break;
250  }
251  case OBJ_WEAPON: {
252  weapon *wp = &Weapons[attacker_objp->instance];
253 
255  vec3d result_point;
256 
257  vm_vec_unrotate(&result_point, &wp->big_attack_point, &objp->orient);
258  vm_vec_add(attack_point, &result_point, &objp->pos);
259 
260  return;
261  }
262  wp->pick_big_attack_point_timestamp = timestamp(2000 + (int) (frand()*500.0f));
263 
264  break;
265  }
266  }
267 
268  // checks valid line to target
269  vec3d surface_normal;
270  ai_bpap(objp, &attacker_objp->pos, &attacker_objp->orient.vec.fvec, attack_point, &local_attack_point, fov, 99999.9f, &surface_normal, NULL);
271 
272  switch (attacker_objp->type) {
273  case OBJ_SHIP: {
274  ai_info *attacker_aip;
275  // if we can't find a new local_attack_point don't change local_attack_point
276  if (vm_vec_mag_squared(&local_attack_point) < 1) {
277  return;
278  }
279 
280  attacker_aip = &Ai_info[Ships[attacker_objp->instance].ai_index];
281  attacker_aip->big_attack_point = local_attack_point;
282  attacker_aip->big_attack_surface_normal = surface_normal;
283  break;
284  }
285  case OBJ_WEAPON: {
286  weapon *wp = &Weapons[attacker_objp->instance];
287  wp->big_attack_point = local_attack_point;
289  break;
290  }
291  }
292 
293  return;
294 }
295 
296 // Handler for SM_EVADE submode ( called from ai_big_chase() )
298 {
299  vec3d player_pos, enemy_pos;
300  float dist;
302  ai_info *aip = &Ai_info[shipp->ai_index];
303  vec3d randvec, semi_enemy_pos;
304 
305  ai_set_positions(Pl_objp, En_objp, aip, &player_pos, &enemy_pos);
306 
307  dist = vm_vec_dist_quick(&player_pos, &enemy_pos);
308  vm_vec_rand_vec_quick(&randvec);
309  if ((Missiontime>>14) & 1) {
310  vm_vec_scale_add(&semi_enemy_pos, &enemy_pos, &randvec, dist/2.0f);
311  aip->prev_goal_point = semi_enemy_pos;
312  } else {
313  semi_enemy_pos = aip->prev_goal_point;
314  }
315 
316  accelerate_ship(aip, 1.0f - ((Missiontime>>8) & 0x3f)/128.0f );
317  turn_away_from_point(Pl_objp, &semi_enemy_pos, 0.0f);
318 
319  float box_dist;
320  vec3d box_vec;
321  int is_inside;
322  box_dist = get_world_closest_box_point_with_delta(&box_vec, En_objp, &player_pos, &is_inside, EVADE_BOX_BASE_DISTANCE);
323  if (box_dist > EVADE_BOX_BASE_DISTANCE) {
324  aip->submode = SM_ATTACK;
326  } else if ((box_dist > EVADE_BOX_MIN_DISTANCE) && (Missiontime - aip->submode_start_time > i2f(5)) ) {
327  aip->submode = SM_ATTACK;
329  }
330 
331  //TODO TEST
332 
333 /* if (dist > 4*En_objp->radius) {
334  aip->submode = SM_ATTACK;
335  aip->submode_start_time = Missiontime;
336  } else if (dist > En_objp->radius) {
337  if (Missiontime - aip->submode_start_time > i2f(5)) {
338  aip->submode = SM_ATTACK;
339  aip->submode_start_time = Missiontime;
340  }
341  } */
342 }
343 
344 // Handler for SM_AVOID submode ( called from ai_big_chase() )
346 {
348 }
349 
350 // reset path following information
352 {
353  if ( aip->ai_flags & AIF_ON_SUBSYS_PATH ) {
354  aip->ai_flags &= ~AIF_ON_SUBSYS_PATH;
355  aip->path_goal_dist = -1;
356  aip->path_start = -1;
357  aip->path_cur = -1;
358  aip->path_length = 0;
359  }
360 }
361 
362 // Maybe Pl_objp needs to follow a path to get in line-of-sight to a subsystem
363 // input: do_dot_check => default value 0, flag to indicate whether check should be done to ensure
364 // subsystem is within certain field of view. We don't want to check fov when
365 // strafing, since ship is weaving to avoid turret fire
366 int ai_big_maybe_follow_subsys_path(int do_dot_check)
367 {
368  ai_info *aip;
369  float dot = 1.0f, min_dot;
370  object *target_objp;
371 
373 
374  if ( aip->target_objnum < 0 )
375  return 0;
376 
377  target_objp = &Objects[aip->target_objnum];
378 
379  if ( (aip->targeted_subsys != NULL) && (aip->targeted_subsys->system_info->path_num >= 0) ) {
380  int subsys_path_num, subsys_in_sight, checked_sight;
381  float dist;
382 
383  // Get models of both source and target
384  polymodel *pm = model_get( Ship_info[Ships[Pl_objp->instance].ship_info_index].model_num );
385  polymodel *pm_t = model_get( Ship_info[Ships[target_objp->instance].ship_info_index].model_num );
386 
387  // Necessary sanity check
388  Assertion(aip->targeted_subsys->system_info->path_num < pm_t->n_paths, "Invalid Path number %d for subsystem %s on ship %s (Model: %s)\n", aip->targeted_subsys->system_info->path_num, aip->targeted_subsys->system_info->name, Ship_info[Ships[target_objp->instance].ship_info_index].name, pm_t->filename );
389  if (aip->targeted_subsys->system_info->path_num >= pm_t->n_paths)
390  return 0;
391 
392  // If attacking a subsystem, ensure that we have an unobstructed line of sight... if not, then move
393  // towards path linked to subsystem
394  subsys_in_sight = 0; // assume Pl_objp doesn't have line of sight to subys
395 
396  // only check for subsystem sight every N milliseconds
397  checked_sight = 0;
399  vec3d geye, gsubpos;
400  eye *ep;
401 
403 
404  // get world pos of eye (stored in geye)
405  ep = &(pm->view_positions[Ships[Pl_objp->instance].current_viewpoint]);
406  model_find_world_point( &geye, &ep->pnt, pm->id, 0, &Pl_objp->orient, &Pl_objp->pos );
407 
408  // get world pos of subsystem
410  vm_vec_add2(&gsubpos, &En_objp->pos);
411 
412  checked_sight = 1;
413 
414  // Calc dot between subsys normal (based on using path info), and subsys_to_eye vector. This is
415  // useful later when we want to decide whether we have a realistic line-of-sight to the subsystem.
416  vec3d subsys_normal, subsys_to_eye;
417  if ( do_dot_check ) {
418  if ( !ship_return_subsys_path_normal(&Ships[target_objp->instance], aip->targeted_subsys, &gsubpos, &subsys_normal) ) {
419  vm_vec_normalized_dir(&subsys_to_eye, &geye, &gsubpos);
420  dot = vm_vec_dot(&subsys_normal, &subsys_to_eye);
421  }
422  }
423 
424  if ( ship_subsystem_in_sight(En_objp, aip->targeted_subsys, &geye, &gsubpos, 1) ) {
425  subsys_in_sight = 1;
426  }
427  }
428 
429  // check if subsystem not in sight
431  if ( (checked_sight && ((!subsys_in_sight) || (dot < min_dot)) ) ) {
432 
433  aip->path_goal_dist = 5;
434  subsys_path_num = aip->targeted_subsys->system_info->path_num;
435  if ( ((aip->path_start) == -1 || (aip->mp_index != subsys_path_num)) && subsys_path_num < pm_t->n_paths ) {
436  // maybe create a new path
437  if ( subsys_path_num >= 0 ) {
438  Assert(aip->target_objnum >= 0);
439  ai_find_path(Pl_objp, aip->target_objnum, subsys_path_num, 0, 1);
440  if ( aip->path_start >= 0 ) {
442  }
443  }
444  }
445  }
446 
447  if ( checked_sight && subsys_in_sight && (dot > min_dot) ) {
448  // we've got a clear shot, stay here for a bit
449  aip->path_subsystem_next_check = timestamp_rand(5000,8000);
450  }
451 
452  // If there is a path that we are tracking, see if ship has gotten to within
453  // aip->path_goal_dist units. If so, then ship can stop following the path. This
454  // is required since we don't want to follow the path all the way to the subsystem,
455  // and we want ships to stop different distances from their path destination
456  if ( aip->path_length > 0 ) {
457  int path_done=0;
458  int in_view=0;
459 
460  Assert(aip->path_length >= 2);
462 
463  if ( aip->path_cur >= (aip->path_start+aip->path_length-1) ) {
464  path_done=1;
465  }
466 
468  if ( (checked_sight && subsys_in_sight) && (dot > min_dot) ) {
469  in_view=1;
470  }
471 
472  // if we've reached the destination, then we can stop following the path
473  if ( path_done || ( dist < aip->path_goal_dist ) || in_view ) {
475  } else if ( dist > aip->path_goal_dist ) {
476  // If we have a path to follow, follow it and return
477  if ( aip->path_start != -1 ) {
478  // for now, only follow the path to the first point
479  if ( aip->path_cur < (aip->path_start+aip->path_length-1) ) {
480  if ( aip->goal_objnum != aip->target_objnum ) {
481  aip->previous_mode = aip->mode;
482  aip->mode = AIM_NONE;
483  aip->submode = -1;
485  return 1;
486  }
487  ai_path();
488  return 1;
489  }
490  }
491  }
492  }
493  }
494 
495  return 0;
496 }
497 
498 // This function is only called from ai_big_chase_attack() when a ship is flying very slowly and
499 // attacking a big ship. The ship should scan for enemy fighter/bombers... if any are close, then
500 // return 1, otherwise return 0;
501 //
502 // input: aip => ai_info pointer for Pl_objp
503 // sip => ship_info pointer for Pl_objp
504 //
505 // exit: 1 => ship should enter strafe mode
506 // 0 => ship should not change ai mode, no fighter/bomber threats are near
507 //
508 // NOTE: uses SCAN_FIGHTERS_INTERVAL and ENTER_STRAFE_THREAT_DIST_SQUARED which are defined in AiBig.h
510 {
511  // if moving slowly (or stopped), and SIF_SMALL_SHIP, then enter STRAFE mode if enemy fighter/bombers
512  // are near
513  if ( sip->flags & SIF_SMALL_SHIP ) {
515  ship_obj *so;
516  object *test_objp;
517  ship *test_sp;
518  float dist_squared;
519 
521  // iterate through ships, and see if any fighter/bomber from opposite team are near
522  so = GET_FIRST(&Ship_obj_list);
523  while( so != END_OF_LIST(&Ship_obj_list) ) {
524  test_objp = &Objects[so->objnum];
525  test_sp = &Ships[test_objp->instance];
526 
527  if ( iff_x_attacks_y(Ships[Pl_objp->instance].team, test_sp->team) ) {
528  if ( Ship_info[test_sp->ship_info_index].flags & SIF_SMALL_SHIP ) {
529  dist_squared = vm_vec_dist_squared(&Pl_objp->pos, &test_objp->pos);
530  if ( dist_squared < ENTER_STRAFE_THREAT_DIST_SQUARED ) {
531  return 1;
532  }
533  }
534  }
535  so = GET_NEXT(so);
536  }
537  }
538  }
539  // If we've reached here, there are no enemy fighter/bombers near
540  return 0;
541 }
542 
543 // ATTACK submode handler for chase mode.
544 void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float dist_to_enemy, int modelnum)
545 {
546  int start_bank;
547  float dot_to_enemy, time_to_hit;
548  polymodel *po = model_get( modelnum );
549 
550  // Maybe evade an incoming weapon.
551  if (((time_to_hit = ai_endangered_by_weapon(aip)) < 4.0f) && (time_to_hit >= 0.0f)) {
552  aip->submode = SM_EVADE_WEAPON;
554  aip->prev_goal_point = En_objp->pos;
555  } else {
556  // If moving slowly, maybe evade incoming fire.
557  if (Pl_objp->phys_info.speed < 3.0f) {
558  object *objp;
559  for ( objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
560  if ((objp->type == OBJ_WEAPON) && (iff_x_attacks_y(Ships[Pl_objp->instance].team, Weapons[objp->instance].team)))
562  vec3d in_vec;
563  float dist;
564 
565  vm_vec_sub(&in_vec, &objp->pos, &Pl_objp->pos);
566  if (vm_vec_dot(&in_vec, &objp->orient.vec.fvec) > 0.0f) {
567  dist = vm_vec_normalize(&in_vec);
568  if ((dist < 200.0f) && (vm_vec_dot(&in_vec, &objp->orient.vec.fvec) > 0.95f)) {
569  if ((Objects[objp->parent].signature == objp->parent_sig) && (vm_vec_dist_quick(&objp->pos, &Objects[objp->parent].pos) < 300.0f)) {
570  set_target_objnum(aip, objp->parent);
571  aip->submode = SM_ATTACK;
573  } else {
574  aip->submode = SM_EVADE;
576  aip->prev_goal_point = En_objp->pos;
577  }
578  }
579  }
580  }
581  }
582 
583  // Since ship is moving slowly and attacking a large ship, scan if enemy fighters are near, if so
584  // then enter strafe mode
585  if ( ai_big_maybe_start_strafe(aip, sip) ) {
586  aip->previous_mode = aip->mode;
587  aip->mode = AIM_STRAFE;
588  aip->submode_parm0 = Missiontime; // use parm0 as time strafe mode entered (i.e. MODE start time)
590  return;
591  }
592 
593  } // end if ( Pl_objp->phys_info.speed < 3.0f )
594 
595  //Maybe enter glide strafe (check every 8 seconds, on a different schedule for each ship)
596  if ((sip->can_glide == true) && !(aip->ai_flags & AIF_KAMIKAZE) && static_randf((Missiontime + static_rand(aip->shipnum)) >> 19) < aip->ai_glide_strafe_percent) {
597  aip->previous_mode = aip->mode;
598  aip->mode = AIM_STRAFE;
599  aip->submode_parm0 = Missiontime; // use parm0 as time strafe mode entered (i.e. MODE start time)
601  aip->submode_parm1 = 0;
603  }
604 
605  // see if Pl_objp needs to reposition to get a good shot at subsystem which is being attacked
609  }
610  return;
611  }
612 
613  vec3d *rel_pos;
614  vec3d vec_to_enemy;
615  float weapon_travel_dist;
616 
617  start_bank = Ships[aip->shipnum].weapons.current_primary_bank;
618 
619  if ((po->n_guns) && (start_bank != -1)) {
620  rel_pos = &po->gun_banks[start_bank].pnt[0];
621  } else
622  rel_pos = NULL;
623 
624  dist_to_enemy = vm_vec_normalized_dir(&vec_to_enemy, enemy_pos, &Pl_objp->pos);
625  dot_to_enemy = vm_vec_dot(&vec_to_enemy, &Pl_objp->orient.vec.fvec);
626 
627  vec3d rvec_vec, *rvec = &rvec_vec;
628 
629  if (dist_to_enemy > 500.0f)
630  compute_desired_rvec(rvec, enemy_pos, &Pl_objp->pos);
631  else
632  rvec = NULL;
633 
634  ai_turn_towards_vector(enemy_pos, Pl_objp, flFrametime, sip->srotation_time, NULL, rel_pos, 0.0f, 0, rvec);
635 
636  // calc range of primary weapon
637  weapon_travel_dist = ai_get_weapon_dist(&Ships[Pl_objp->instance].weapons);
638 
639  if ( aip->targeted_subsys != NULL ) {
640  if (dist_to_enemy > (weapon_travel_dist-20)) {
641  accelerate_ship(aip, 1.0f);
642 
644  if ((aip->ai_flags & AIF_FREE_AFTERBURNER_USE) && !(shipp->flags2 & SF2_AFTERBURNER_LOCKED) && (dot_to_enemy > 0.75f)) {
648  }
649  } else if ((Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) && !(aip->ai_flags & AIF_KAMIKAZE)) {
651  }
652  } else {
653  // AL 12-31-97: Move at least as quickly as your target is moving...
654  accelerate_ship(aip, MAX(1.0f - dot_to_enemy, Objects[aip->target_objnum].phys_info.fspeed/sip->max_speed));
655 
658  }
659  }
660 
661  } else {
662  float accel;
663  if (dot_to_enemy < 0.0f) {
664  accel = 0.5f;
665  } else if (dot_to_enemy < 0.75f) {
666  accel = 0.75f;
667  } else {
668  if (dist_to_enemy > weapon_travel_dist/2.0f) {
669  accel = 1.0f;
670  } else {
671  accel = 1.0f - dot_to_enemy;
672  }
673  }
674 
675  // use dist normal to enemy here (don't break 50 barrier)
676  if (dist_to_enemy < ATTACK_STOP_DISTANCE) {
677 // accelerate_ship(aip, accel * 0.5f);
678  accelerate_ship(aip, -1.0f);
681  }
682  } else {
683  accelerate_ship(aip, accel);
684 
686  if ((aip->ai_flags & AIF_FREE_AFTERBURNER_USE) && !(shipp->flags2 & SF2_AFTERBURNER_LOCKED) && (accel > 0.95f)) {
690  }
691  } else if ((Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) && !(aip->ai_flags & AIF_KAMIKAZE)) {
693  }
694  }
695  }
696  }
697 }
698 
699 // Handler for submode SM_CONTINUOUS_TURN
701 {
702  ai_chase_ct();
703 }
704 
705 extern void ai_select_secondary_weapon(object *objp, ship_weapon *swp, int priority1 = -1, int priority2 = -1);
706 extern float set_secondary_fire_delay(ai_info *aip, ship *shipp, weapon_info *swip, bool burst);
707 extern void ai_choose_secondary_weapon(object *objp, ai_info *aip, object *en_objp);
708 extern int maybe_avoid_big_ship(object *objp, object *ignore_objp, ai_info *aip, vec3d *goal_point, float delta_time);
709 
710 extern void maybe_cheat_fire_synaptic(object *objp, ai_info *aip);
711 
712 // Determine if Pl_objp should fire weapons at current target, based on input parameters
713 //
714 // dist_to_enemy => distance (in m) to attack point on current target
715 // dot_to_enemy => dot product between fvec of Pl_objp and vector from Pl_objp to attack point
716 //
717 void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy, vec3d *firing_pos, vec3d *enemy_pos, vec3d *enemy_vel)
718 {
719  ai_info *aip;
720  ship_weapon *swp;
721  int has_fired = -1;
722 
724  swp = &Ships[Pl_objp->instance].weapons;
725 
726  if (dot_to_enemy > 0.95f - 0.5f * En_objp->radius/MAX(1.0f, En_objp->radius + dist_to_enemy)) {
728 
729  // Chance of hitting ship is based on dot product of firing ship's forward vector with vector to ship
730  // and also the size of the target relative to distance to target.
731  if (dot_to_enemy > MAX(0.5f, 0.90f + aip->ai_accuracy/10.0f - En_objp->radius/MAX(1.0f,dist_to_enemy))) {
732 
733  ship *temp_shipp;
734  temp_shipp = &Ships[Pl_objp->instance];
735  ship_weapon *tswp = &temp_shipp->weapons;
736 
737  if ( tswp->num_primary_banks > 0 ) {
738  Assertion(tswp->current_primary_bank < tswp->num_primary_banks, "AI tried to select primary bank %d. Might be a model error\n", tswp->current_primary_bank);
740 
741  if (dist_to_enemy < MIN((wip->max_speed * wip->lifetime), wip->weapon_range)){
742  has_fired = 1;
744  has_fired = -1;
745  // ship_stop_fire_primary(Pl_objp);
746  }
747  }
748  }
749 
750  if (tswp->num_secondary_banks > 0) {
753  int current_bank = tswp->current_secondary_bank;
754  if (current_bank > -1) {
755  weapon_info *swip = &Weapon_info[tswp->secondary_bank_weapons[current_bank]];
756 
757  if(!(En_objp->flags & OF_PROTECTED) || ((aip->goals[0].ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP)) && swip->wi_flags & WIF_PUNCTURE )) { //override lockdown on protected ships when using anti subsystem weapons - Valathil
758  // If ship is protected and very low on hits, don't fire missiles.
759  if (!(En_objp->flags & OF_PROTECTED) || (En_objp->hull_strength > 10*swip->damage)) {
760  if (aip->ai_flags & AIF_UNLOAD_SECONDARIES) {
761  if (timestamp_until(swp->next_secondary_fire_stamp[current_bank]) > swip->fire_wait*1000.0f) {
762  swp->next_secondary_fire_stamp[current_bank] = timestamp((int) (swip->fire_wait*1000.0f));
763  }
764  }
765 
766  if (timestamp_elapsed(swp->next_secondary_fire_stamp[current_bank])) {
767  float firing_range;
768  if (swip->wi_flags2 & WIF2_LOCAL_SSM)
769  firing_range=swip->lssm_lock_range;
770  else
771  firing_range = MIN((swip->max_speed * swip->lifetime), swip->weapon_range);
772  // reduce firing range of secondaries in nebula
773  extern int Nebula_sec_range;
774  if ((The_mission.flags & MISSION_FLAG_FULLNEB) && Nebula_sec_range) {
775  firing_range *= 0.8f;
776  }
777 
778  float t = 0.25f; // default delay in seconds until next fire.
779 
780  if (dist_to_enemy < firing_range*1.0f) {
781 
782 
783  //vm_vec_scale_add(&future_enemy_pos, enemy_pos, enemy_vel, dist_to_enemy/swip->max_speed);
784  //if (vm_vec_dist_quick(&future_enemy_pos, firing_pos) < firing_range * 0.8f) {
786 
787  int current_bank_adjusted = MAX_SHIP_PRIMARY_BANKS + current_bank;
788 
789  if ((aip->ai_flags & AIF_UNLOAD_SECONDARIES) || (swip->burst_flags & WBF_FAST_FIRING)) {
790  if (swip->burst_shots > swp->burst_counter[current_bank_adjusted]) {
791  t = swip->burst_delay;
792  swp->burst_counter[current_bank_adjusted]++;
793  } else {
794  t = swip->fire_wait;
795  if ((swip->burst_shots > 0) && (swip->burst_flags & WBF_RANDOM_LENGTH)) {
796  swp->burst_counter[current_bank_adjusted] = myrand() % swip->burst_shots;
797  } else {
798  swp->burst_counter[current_bank_adjusted] = 0;
799  }
800  }
801  } else {
802  if (swip->burst_shots > swp->burst_counter[current_bank_adjusted]) {
803  t = set_secondary_fire_delay(aip, temp_shipp, swip, true);
804  swp->burst_counter[current_bank_adjusted]++;
805  } else {
806  t = set_secondary_fire_delay(aip, temp_shipp, swip, false);
807  if ((swip->burst_shots > 0) && (swip->burst_flags & WBF_RANDOM_LENGTH)) {
808  swp->burst_counter[current_bank_adjusted] = myrand() % swip->burst_shots;
809  } else {
810  swp->burst_counter[current_bank_adjusted] = 0;
811  }
812  }
813  }
814  swp->next_secondary_fire_stamp[current_bank] = timestamp((int) (t*1000.0f));
815  }
816  //}
817  }
818  swp->next_secondary_fire_stamp[current_bank] = timestamp((int) (t*1000.0f));
819  }
820  }
821  }
822  }
823  }
824  }
825  }
826  } else {
827  if (flFrametime < 1.0f)
828  aip->time_enemy_in_range *= (1.0f - flFrametime);
829  else
830  aip->time_enemy_in_range = 0;
831  }
832 
833  if(has_fired == -1){ //stuff that hapens when the ship stops fireing
835  }
836 
837 }
838 
839 // switch ai ship into chase mode
841 {
842  aip->previous_mode = aip->mode;
843  aip->mode = AIM_CHASE;
844  aip->submode = SM_ATTACK;
846 }
847 
848 extern int ai_big_strafe_maybe_retreat(float dist, vec3d *target_pos);
849 
850 // Make object Pl_objp chase object En_objp, which is a big ship, not a small ship.
852 {
853  float dist_to_enemy, dot_to_enemy;
854  vec3d player_pos, enemy_pos, vec_to_enemy;
856  ship *shipp = &Ships[Pl_objp->instance];
857  ai_info *aip = &Ai_info[shipp->ai_index];
858  vec3d predicted_enemy_pos;
859 
860  Assert(aip->mode == AIM_CHASE);
861 
863 
864  ai_set_positions(Pl_objp, En_objp, aip, &player_pos, &enemy_pos);
865 
866  player_pos = Pl_objp->pos;
867  ai_big_pick_attack_point(En_objp, Pl_objp, &enemy_pos, 0.8f);
868 
869  // Compute the predicted position of the center of the ship, then add the delta to the goal pos.
870  if (En_objp->phys_info.speed > 3.0f) {
871  set_predicted_enemy_pos(&predicted_enemy_pos, Pl_objp, &En_objp->pos, &En_objp->phys_info.vel, aip);
872  vm_vec_add2(&enemy_pos, &predicted_enemy_pos);
873  vm_vec_sub2(&enemy_pos, &En_objp->pos);
874  } else
875  predicted_enemy_pos = En_objp->pos;
876 
877  if (aip->targeted_subsys != NULL) {
878  get_subsystem_pos(&enemy_pos, En_objp, aip->targeted_subsys);
879  }
880 
881  dist_to_enemy = vm_vec_normalized_dir(&vec_to_enemy, &enemy_pos, &player_pos); // - En_objp->radius;
882  dot_to_enemy = vm_vec_dot(&vec_to_enemy, &Pl_objp->orient.vec.fvec);
883 
884  if (aip->ai_flags & AIF_TARGET_COLLISION) {
885  if ( ai_big_strafe_maybe_retreat(dist_to_enemy, &enemy_pos) ) {
886  aip->mode = AIM_STRAFE;
887  aip->submode_parm0 = Missiontime; // use parm0 as time strafe mode entered (i.e. MODE start time)
888  aip->submode = AIS_STRAFE_AVOID;
892  }
893  return;
894  }
895  }
896 
897  if (aip->ai_flags & AIF_KAMIKAZE) {
898  //nprintf(("AI", "Kamikaze: %7.3f %7.3f\n", dot_to_enemy, dist_to_enemy));
899  accelerate_ship(aip, 1.0f);
900  if ((dist_to_enemy < 400.0f) && ai_maybe_fire_afterburner(Pl_objp, aip)) {
903  }
904  }
905 
906  // If just acquired target, or target is not in reasonable cone, don't refine believed enemy position.
907  if ((dot_to_enemy < 0.25f) || (aip->target_time < 1.0f) || (aip->ai_flags & AIF_SEEK_LOCK)) {
908  update_aspect_lock_information(aip, &vec_to_enemy, dist_to_enemy - En_objp->radius, En_objp->radius);
909  } else if (aip->targeted_subsys != NULL) {
910  Assert(aip->targeted_subsys != NULL);
911  get_subsystem_pos(&enemy_pos, En_objp, aip->targeted_subsys);
912  vm_vec_add2(&enemy_pos, &predicted_enemy_pos);
913  vm_vec_sub2(&enemy_pos, &En_objp->pos);
914  dist_to_enemy = vm_vec_normalized_dir(&vec_to_enemy, &enemy_pos, &player_pos); // - En_objp->radius;
915  dot_to_enemy = vm_vec_dot(&vec_to_enemy, &Pl_objp->orient.vec.fvec);
916  update_aspect_lock_information(aip, &vec_to_enemy, dist_to_enemy, En_objp->radius);
917  } else if (En_objp->flags & OF_PROTECTED) { // If protected and we're not attacking a subsystem, stop attacking!
918  update_aspect_lock_information(aip, &vec_to_enemy, dist_to_enemy - En_objp->radius, En_objp->radius);
919  aip->target_objnum = -1;
922  return;
923  }
924  } else {
925  update_aspect_lock_information(aip, &vec_to_enemy, dist_to_enemy - En_objp->radius, En_objp->radius);
926  }
927 
928  // If recently acquired target and not looking at target, just turn a bit.
929  switch (aip->submode) {
930  case SM_ATTACK:
931  case SM_SUPER_ATTACK:
932  if (vm_vec_dist_quick(&Pl_objp->pos, &predicted_enemy_pos) > 100.0f + En_objp->radius * 2.0f) {
933  if (maybe_avoid_big_ship(Pl_objp, En_objp, aip, &predicted_enemy_pos, 10.0f)) {
936  }
937  return;
938  }
939  }
940 
941  if (aip->target_time < 2.0f)
942  if ((dot_to_enemy < 0.9f) || (dist_to_enemy > 300.0f)) {
944  aip->submode_start_time = Missiontime - fl2f(2.75f); // This backdated start time allows immediate switchout.
945  if (dot_to_enemy > 0.0f)
946  aip->target_time += flFrametime * dot_to_enemy;
947  }
948  break;
949  }
950 
951  //
952  // Set turn and acceleration based on submode.
953  //
954 
955  if (((aip->submode != SM_ATTACK) && (aip->submode != SM_SUPER_ATTACK) && (aip->submode != SM_ATTACK_FOREVER) && (aip->submode != SM_EVADE_WEAPON)) || (aip->mode == AIM_STRAFE)){
958  }
959  }
960 
961  switch (aip->submode) {
962  case SM_CONTINUOUS_TURN:
963  ai_big_chase_ct();
964  break;
965 
966  case SM_ATTACK:
967  case SM_SUPER_ATTACK:
968  case SM_ATTACK_FOREVER:
969  ai_big_chase_attack(aip, sip, &enemy_pos, dist_to_enemy, sip->model_num);
970  break;
971 
972  case SM_EVADE:
974  break;
975 
976  case SM_AVOID:
978  break;
979 
980  case SM_EVADE_WEAPON:
981  evade_weapon();
982  break;
983 
984  default:
986  aip->submode = SM_ATTACK;
988  break;
989  }
990 
991  // maybe Pl_objp was forced into strafe mode, if so return now
992  if ( aip->mode == AIM_STRAFE )
993  return;
994 
995  // Maybe choose a new submode.
996  if (aip->submode != SM_AVOID && aip->submode != SM_EVADE ) {
997  // If a very long time since attacked, attack no matter what!
998  if (aip->submode != SM_SUPER_ATTACK) {
999  if (Missiontime - aip->last_attack_time > i2f(6)) {
1000  aip->submode = SM_SUPER_ATTACK;
1003  }
1004  }
1005 
1006  // If a collision is expected, pull out!
1007  float dist_normal_to_enemy;
1008 
1009  if (vm_vec_mag_squared(&aip->big_attack_surface_normal) > 0.9) {
1010  dist_normal_to_enemy = fl_abs((dist_to_enemy * vm_vec_dot(&vec_to_enemy, &aip->big_attack_surface_normal)));
1011  } else {
1012  // don;t have normal so use a conservative value here
1013  dist_normal_to_enemy = 0.3f * dist_to_enemy;
1014  }
1015 
1016 // float time_to_enemy = dist_normal_to_enemy / Pl_objp->phys_info.speed * fl_abs(vm_vec_dot(&Pl_objp->phys_info.vel, &aip->big_attack_surface_normal));
1017 // if (Framecount % 30 == 1) {
1018 // mprintf(("normal dist; %.1f, time: %.1f\n", dist_normal_to_enemy, time_to_enemy));
1019 // }
1020 
1021  // since we're not in strafe and we may get a bad normal, cap dist_normal_to_enemy as MIN(0.3*dist_to_enemy, self)
1022  // this will allow us to get closer on a bad normal
1023  dist_normal_to_enemy = MAX(0.3f*dist_to_enemy, dist_normal_to_enemy);
1024 
1025  if (dist_to_enemy < ATTACK_COLLIDE_BASE_DIST) {
1026  // within 50m or 1sec
1027  float time_to_enemy;
1028  if (vm_vec_mag_squared(&aip->big_attack_surface_normal) > 0.9) {
1029  if (Pl_objp->phys_info.speed > 0.1) {
1030  time_to_enemy = dist_normal_to_enemy / fl_abs(vm_vec_dot(&Pl_objp->phys_info.vel, &aip->big_attack_surface_normal));
1031  } else {
1032  // a big time
1033  time_to_enemy = 100.0f;
1034  }
1035  } else {
1036  if (Pl_objp->phys_info.speed > 0.1) {
1037  time_to_enemy = dist_normal_to_enemy / Pl_objp->phys_info.speed;
1038  } else {
1039  // a big time
1040  time_to_enemy = 100.0f;
1041  }
1042  }
1043 
1044  float speed_dist = MAX(0.0f, (Pl_objp->phys_info.speed-50) * 2);
1045  if ((dist_normal_to_enemy < ATTACK_COLLIDE_AVOID_DIST + speed_dist) || (time_to_enemy < ATTACK_COLLIDE_AVOID_TIME) ) {
1046  // get away, simulate crsh recovery (don't use avoid)
1047 // accelerate_ship(aip, -1.0f);
1049 // aip->submode = SM_AVOID;
1050 // aip->submode_start_time = Missiontime;
1051  } else if ((dist_normal_to_enemy < ATTACK_COLLIDE_SLOW_DIST) || (time_to_enemy < ATTACK_COLLIDE_SLOW_TIME) ) {
1052  // slow down
1053  accelerate_ship(aip, -1.0f);
1054  }
1055  }
1056 
1057  /*
1058  if ((dot_to_enemy > 1.0f - 0.1f * En_objp->radius/(dist_to_enemy + 1.0f)) && (Pl_objp->phys_info.speed > dist_to_enemy/5.0f)) {
1059  if (might_collide_with_ship(Pl_objp, En_objp, dot_to_enemy, dist_to_enemy, (aip->targeted_subsys == NULL)*2.0f + 1.5f)) {
1060  if ((Missiontime - aip->last_hit_time > F1_0*4) && (dist_to_enemy < Pl_objp->radius*2 + En_objp->radius*2)) {
1061  accelerate_ship(aip, -1.0f);
1062  } else {
1063  aip->submode = SM_AVOID;
1064  aip->submode_start_time = Missiontime;
1065  }
1066  }
1067  } */
1068  }
1069 
1070  switch (aip->submode) {
1071  case SM_CONTINUOUS_TURN:
1072  if (Missiontime - aip->submode_start_time > i2f(3)) {
1074  aip->submode = SM_ATTACK;
1076  }
1077  break;
1078 
1079  case SM_ATTACK:
1080  case SM_ATTACK_FOREVER:
1081  break;
1082 
1083  case SM_EVADE:
1084  if (dist_to_enemy > 4*En_objp->radius) {
1085  aip->submode = SM_ATTACK;
1088  }
1089  break;
1090 
1091  case SM_SUPER_ATTACK:
1092  break;
1093 
1094  case SM_AVOID:
1095  // if outside box by > 300 m
1096  // DA 4/20/98 can never get here attacking a big ship
1097  {
1098  int is_inside;
1099  float box_dist = get_world_closest_box_point_with_delta(NULL, En_objp, &Pl_objp->pos, &is_inside, 0.0f);
1100 
1101  if (box_dist > 300) {
1102  aip->submode = SM_ATTACK;
1105  }
1106  }
1107  break;
1108 
1109 /* if (dot_to_enemy > -0.2f) {
1110  aip->submode_start_time = Missiontime;
1111  } else if (Missiontime - aip->submode_start_time > i2f(1)/2) {
1112  if (might_collide_with_ship(Pl_objp, En_objp, dot_to_enemy, dist_to_enemy, 3.0f)) {
1113  aip->submode_start_time = Missiontime;
1114  } else {
1115  aip->submode = SM_ATTACK;
1116  aip->submode_start_time = Missiontime;
1117  aip->last_attack_time = Missiontime;
1118  }
1119  }
1120 
1121  break;*/
1122 
1123  case SM_EVADE_WEAPON:
1124  if (aip->danger_weapon_objnum == -1) {
1125  aip->submode = SM_ATTACK;
1128  }
1129  break;
1130 
1131  default:
1132  aip->submode = SM_ATTACK;
1135  }
1136 
1137  //
1138  // Maybe fire primary weapon and update time_enemy_in_range
1139  //
1140  //nprintf(("AI", "time_enemy_in_range = %7.3f, dot = %7.3f\n", aip->time_enemy_in_range, dot_to_enemy));
1141 
1142  // AL: add condition that Pl_objp must not be following a path to fire. This may be too extreme, but
1143  // I noticed AI ships firing inappropriately when following a path near a big ship.
1144  // TODO: investigate why ships fire (and aren't close to hitting ship) when following a path near
1145  // a big ship
1146  if (aip->mode != AIM_EVADE && aip->path_start == -1 ) {
1147  ai_big_maybe_fire_weapons(dist_to_enemy, dot_to_enemy, &player_pos, &predicted_enemy_pos, &En_objp->phys_info.vel);
1148  } else {
1149  if (flFrametime < 1.0f)
1150  aip->time_enemy_in_range *= (1.0f - flFrametime);
1151  else
1152  aip->time_enemy_in_range = 0;
1153  }
1154 }
1155 
1156 void ai_big_ship(object *objp)
1157 {
1158  // do nothing
1159 }
1160 
1161 // all three parms are output parameters
1162 // Enemy object is En_objp
1163 // pos => world pos of attack point
1164 // dist => distance from Pl_objp front to attack point
1165 // dot => dot of Pl_objp fvec and vector to attack point
1166 // fire_pos => world pos from which firing
1167 void ai_big_attack_get_data(vec3d *enemy_pos, float *dist_to_enemy, float *dot_to_enemy)
1168 {
1169  vec3d player_pos, vec_to_enemy, predicted_enemy_pos;
1170  ship *shipp = &Ships[Pl_objp->instance];
1171  ai_info *aip = &Ai_info[shipp->ai_index];
1173 
1174  Assert(aip->mode == AIM_STRAFE);
1175 
1176  // ensure that Pl_objp is still targeting a big ship
1177  if ( !(esip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)) ) {
1179  return;
1180  }
1181 
1182  ai_set_positions(Pl_objp, En_objp, aip, &player_pos, enemy_pos);
1183 
1184  player_pos = Pl_objp->pos;
1185 
1186  if (aip->targeted_subsys != NULL) {
1187  Assert(aip->targeted_subsys != NULL);
1188  get_subsystem_pos(enemy_pos, En_objp, aip->targeted_subsys);
1189  } else {
1190  // checks valid line to target
1191  ai_big_pick_attack_point(En_objp, Pl_objp, enemy_pos, 0.8f);
1192  }
1193 
1194  // Take player pos to be center of ship + ship_radius
1195  vm_vec_scale_add2(&player_pos, &Pl_objp->orient.vec.fvec, Pl_objp->radius);
1196 
1197  // If seeking lock, try to point directly at ship, else predict position so lasers can hit it.
1198  // If just acquired target, or target is not in reasonable cone, don't refine believed enemy position.
1199  vm_vec_normalized_dir(&vec_to_enemy, enemy_pos, &player_pos);
1200  *dot_to_enemy=vm_vec_dot(&vec_to_enemy, &Pl_objp->orient.vec.fvec);
1201  if ((*dot_to_enemy < 0.25f) || (aip->target_time < 1.0f) || (aip->ai_flags & AIF_SEEK_LOCK)) {
1202  predicted_enemy_pos=*enemy_pos;
1203  } else {
1204  vec3d gun_pos, pnt;
1205  polymodel *po = model_get( Ship_info[shipp->ship_info_index].model_num );
1206  float weapon_speed;
1207 
1208  // Compute position of gun in absolute space and use that as fire position.
1210  pnt = po->gun_banks[0].pnt[0];
1211  vm_vec_unrotate(&gun_pos, &pnt, &Pl_objp->orient);
1212  vm_vec_add2(&gun_pos, &Pl_objp->pos);
1213  } else {
1214  //Use the convergence offset, if there is one
1215  vm_vec_copy_scale(&pnt, &Ship_info[shipp->ship_info_index].convergence_offset, 1.0f);
1216  }
1217  weapon_speed = ai_get_weapon_speed(&shipp->weapons);
1218 
1219  set_predicted_enemy_pos_turret(&predicted_enemy_pos, &gun_pos, Pl_objp, enemy_pos, &En_objp->phys_info.vel, weapon_speed, aip->time_enemy_in_range);
1220  }
1221 
1222  *dist_to_enemy = vm_vec_normalized_dir(&vec_to_enemy, &predicted_enemy_pos, &player_pos);
1223  *dot_to_enemy = vm_vec_dot(&vec_to_enemy, &Pl_objp->orient.vec.fvec);
1224  update_aspect_lock_information(aip, &vec_to_enemy, *dist_to_enemy, En_objp->radius);
1225 
1226  *enemy_pos = predicted_enemy_pos;
1227 }
1228 
1229 // check to see if Pl_objp has gotten too close to attacking point.. if so, break off by entering
1230 // AIS_STRAFE_RETREAT
1231 int ai_big_strafe_maybe_retreat(float dist, vec3d *target_pos)
1232 {
1233  ai_info *aip;
1235 
1236  vec3d vec_to_target;
1237  vm_vec_sub(&vec_to_target, target_pos, &Pl_objp->pos);
1238 
1239  float dist_to_target, dist_normal_to_target, time_to_target;
1240  dist_to_target = vm_vec_mag_quick(&vec_to_target);
1241  if (vm_vec_mag_quick(&aip->big_attack_surface_normal) > 0.9) {
1242  dist_normal_to_target = -vm_vec_dot(&vec_to_target, &aip->big_attack_surface_normal);
1243  } else {
1244  dist_normal_to_target = 0.2f * vm_vec_mag_quick(&vec_to_target);
1245  }
1246 
1247  dist_normal_to_target = MAX(0.2f*dist_to_target, dist_normal_to_target);
1248  time_to_target = dist_normal_to_target / Pl_objp->phys_info.speed;
1249 
1250  // add distance penalty for going too fast
1251  float speed_to_dist_penalty = MAX(0.0f, (Pl_objp->phys_info.speed-50));
1252 
1253  //if ((dot_to_enemy > 1.0f - 0.1f * En_objp->radius/(dist_to_enemy + 1.0f)) && (Pl_objp->phys_info.speed > dist_to_enemy/5.0f))
1254 
1255  // Inside 2 sec retreat, setting goal point to box point + 300m
1256  // If collision, use std collision resolution.
1257  if ( !(aip->ai_flags & AIF_KAMIKAZE) && ((aip->ai_flags & AIF_TARGET_COLLISION) || (time_to_target < STRAFE_RETREAT_COLLIDE_TIME) || (dist_normal_to_target < STRAFE_RETREAT_COLLIDE_DIST + speed_to_dist_penalty)) ) {
1258  if (aip->ai_flags & AIF_TARGET_COLLISION) {
1259  // use standard collision resolution
1260  aip->ai_flags &= ~AIF_TARGET_COLLISION;
1262  } else {
1263  // too close for comfort so fly to box point + 300
1266 
1267  int is_inside;
1268  vec3d goal_point;
1270 
1271  // set goal point
1272  aip->goal_point = goal_point;
1273 
1274  if (ai_maybe_fire_afterburner(Pl_objp, aip)) {
1277  }
1278  }
1279 
1280  return 1;
1281  } else {
1282  return 0;
1283  }
1284 }
1285 
1286 // attack directly to the turret and fire weapons
1288 {
1289  ai_info *aip;
1290  vec3d target_pos;
1291  vec3d rand_vec;
1292  float target_dist, target_dot, accel, t;
1293 
1295 
1297  return;
1298  }
1299 
1300  ai_big_attack_get_data(&target_pos, &target_dist, &target_dot);
1301  if ( ai_big_strafe_maybe_retreat(target_dist, &target_pos) )
1302  return;
1303 
1304  if (aip->ai_flags & AIF_KAMIKAZE) {
1305  if (target_dist < 1200.0f) {
1306  ai_turn_towards_vector(&target_pos, Pl_objp, flFrametime, Ship_info[Ships[Pl_objp->instance].ship_info_index].srotation_time, NULL, NULL, 0.0f, 0);
1307  accelerate_ship(aip, 1.0f);
1308  if ((target_dist < 400.0f) && ai_maybe_fire_afterburner(Pl_objp, aip)) {
1311  }
1312  return;
1313  }
1314  }
1315 
1316  if (!(aip->ai_flags & AIF_SEEK_LOCK) || (aip->aspect_locked_time < 2.0f)) {
1317  t = ai_endangered_by_weapon(aip);
1318  if ( t > 0.0f && t < 1.5f ) {
1319  // set up goal_point for avoid path to turn towards
1320  aip->goal_point = Pl_objp->pos;
1321  switch(rand()%4) {
1322  case 0:
1323  vm_vec_scale_add(&rand_vec, &Pl_objp->orient.vec.fvec, &Pl_objp->orient.vec.uvec, 2.0f);
1324  break;
1325  case 1:
1326  vm_vec_scale_add(&rand_vec, &Pl_objp->orient.vec.fvec, &Pl_objp->orient.vec.uvec, -2.0f);
1327  break;
1328  case 2:
1329  vm_vec_scale_add(&rand_vec, &Pl_objp->orient.vec.fvec, &Pl_objp->orient.vec.rvec, 2.0f);
1330  break;
1331  case 3:
1332  vm_vec_scale_add(&rand_vec, &Pl_objp->orient.vec.fvec, &Pl_objp->orient.vec.rvec, -2.0f);
1333  break;
1334  } // end switch
1335 
1336  vm_vec_scale(&rand_vec, 1000.0f);
1337  vm_vec_add2(&aip->goal_point, &rand_vec);
1338 
1339  aip->submode = AIS_STRAFE_AVOID;
1341 
1342  if (ai_maybe_fire_afterburner(Pl_objp, aip)) {
1344  aip->afterburner_stop_time = Missiontime + fl2f(0.5f);
1345  }
1346  }
1347  }
1348 
1349  // maybe fire weapons at target
1350  ai_big_maybe_fire_weapons(target_dist, target_dot, &Pl_objp->pos, &En_objp->pos, &En_objp->phys_info.vel);
1351  turn_towards_point(Pl_objp, &target_pos, NULL, 0.0f);
1352 
1353  // Slow down if we've not been hit for a while
1354  fix last_hit = Missiontime - aip->last_hit_time;
1355  if ( target_dist > 1200 || last_hit < F1_0*6) {
1356  accel = 1.0f;
1357  } else {
1358  float attack_time;
1359  attack_time = f2fl(Missiontime - aip->submode_start_time);
1360  if ( attack_time > 15 ) {
1361  accel = 0.2f;
1362  } else if ( attack_time > 10 ) {
1363  accel = 0.4f;
1364  } else if ( attack_time > 8 ) {
1365  accel = 0.6f;
1366  } else if ( attack_time > 5 ) {
1367  accel = 0.8f;
1368  } else {
1369  accel = 1.0f;
1370  }
1371  }
1372 
1373  accel = 1.0f;
1374  accelerate_ship(aip, accel);
1375 
1376  // if haven't been hit in quite a while, leave strafe mode
1377  fix long_enough;
1378  long_enough = F1_0 * STRAFE_MAX_UNHIT_TIME;
1379  if ( (last_hit > long_enough) && ( (Missiontime - aip->submode_parm0) > long_enough) ) {
1381  }
1382 }
1383 
1384 // SUSHI: Strafe attack using glide
1385 //submode_parm1 encodes the stage we're in.
1386 //0: Choosing goal point to fly towards
1387 //1: Accelerating towards the goal point.
1388 //2: Raining down fire and brimstone on the target.
1389 //3: Dummy stage used when resetting or exiting the mode
1391 {
1392  ai_info *aip;
1393  vec3d target_pos, vec_to_goal, predicted_enemy_pos, norm_vel_vec;
1394  float target_dist, target_dot, target_ship_dist, dot_to_goal, flight_dot_to_enemy;
1395  object *target_objp;
1396 
1398  target_objp = &Objects[aip->target_objnum];
1399 
1400  vm_vec_sub(&vec_to_goal, &aip->goal_point, &Pl_objp->pos);
1401  vm_vec_normalize(&vec_to_goal);
1402 
1403  if (vm_vec_mag(&Pl_objp->phys_info.vel) > 0.0f)
1404  vm_vec_copy_normalize(&norm_vel_vec, &Pl_objp->phys_info.vel);
1405  else
1406  vm_vec_copy_normalize(&norm_vel_vec, &Pl_objp->orient.vec.fvec);
1407 
1408  dot_to_goal = vm_vec_dot(&vec_to_goal, &norm_vel_vec); //Angle between flight path and goal point
1409  flight_dot_to_enemy = vm_vec_dot(&target_objp->pos, &norm_vel_vec); //Angle between flight path and target ship
1410 
1411  //If we're following a path, then we shouldn't be doing glide strafe
1413  return;
1414  }
1415 
1416  //Gets a point on the target ship to attack, as well as distance and the angle between the nose of the attacker and that point.
1417  ai_big_attack_get_data(&target_pos, &target_dist, &target_dot);
1418  target_ship_dist = vm_vec_dist(&target_objp->pos, &Pl_objp->pos);
1419 
1420  //If we haven't chosen the goal point yet, do so now
1421  if (aip->submode_parm1 == 0) {
1422  //Pick goal point. This should be a random point that passes through the circle whose normal is the vector between attacker and target
1423  vec3d targetToAttacker;
1424  vec3d tangentPoint;
1425  vm_vec_sub(&targetToAttacker, &Pl_objp->pos, &target_objp->pos);
1426  matrix orient;
1427  vm_vector_2_matrix(&orient, &targetToAttacker, NULL, NULL);
1428  vm_vec_random_in_circle(&tangentPoint, &target_objp->pos, &orient, target_objp->radius + GLIDE_STRAFE_DISTANCE, 1);
1429  //Get tangent point in coords relative to ship, scale it up so the actual goal point is far away, then put back in world coords
1430  vm_vec_sub2(&tangentPoint, &Pl_objp->pos);
1431  vm_vec_scale(&tangentPoint, 1000.0f);
1432  vm_vec_add(&aip->goal_point, &tangentPoint, &Pl_objp->pos);
1433  aip->submode_parm1 = 1;
1434  }
1435  if (aip->submode_parm1 == 1) {
1436  //Stay in acceleration stage?
1437  //Accelerate towards goal point until:
1438  // Mostly up to speed AND
1439  // Moving in the correct direction
1440  if ((Pl_objp->phys_info.fspeed > (Pl_objp->phys_info.max_vel.xyz.z * 0.85f)) && (dot_to_goal > 0.99f))
1441  aip->submode_parm1 = 2;
1442  }
1443  if (aip->submode_parm1 == 2) {
1444  //Should we stay in the fire stage?
1445  //Keep going until we are too far away.
1446  //If we are still on approach but too far away, this will still trigger. This will allow us to reposition the target
1447  //point and allow for a "jinking" effect.
1448  if (target_ship_dist > (STRAFE_RETREAT_BOX_DIST + target_objp->radius) &&
1450  //This checks whether we are moving toward the target or away from it. If moving towards, we reset the stage so that we
1451  //pick a new attack vector (jinking). If moving away, we're at the end of a run so do a full reset (possibly allowing a
1452  //switch back to conventional strafe).
1453  if (flight_dot_to_enemy > 0.0f) {
1454  aip->submode_parm1 = 0;
1455  }
1456  else {
1457  aip->submode_parm1 = 3;
1459  }
1461  }
1462  }
1463  //Time limit: if we've taken too long, reset
1465  aip->submode_parm1 = 3;
1468  }
1469 
1470  //Acceleration stage
1471  if (aip->submode_parm1 == 1) {
1472  accelerate_ship(aip, 1.0f);
1473  //Use afterburners if we have them and are pointed the right way
1474  if (dot_to_goal > 0.99f) {
1477  }
1478 
1479  turn_towards_point(Pl_objp, &aip->goal_point, NULL, 0.0f);
1480  }
1481  //Fire stage
1482  if (aip->submode_parm1 == 2) {
1484  accelerate_ship(aip, 0.0f);
1486 
1487  //Compensate for motion of ship and target
1488  set_predicted_enemy_pos(&predicted_enemy_pos, Pl_objp, &En_objp->pos, &En_objp->phys_info.vel, aip);
1489  vm_vec_add2(&target_pos, &predicted_enemy_pos);
1490  vm_vec_sub2(&target_pos, &En_objp->pos);
1491 
1492  turn_towards_point(Pl_objp, &target_pos, NULL, 0.0f);
1493  ai_big_maybe_fire_weapons(target_dist, target_dot, &Pl_objp->pos, &En_objp->pos, &En_objp->phys_info.vel);
1494  }
1495 
1496  // if haven't been hit in quite a while, leave strafe mode
1497  // (same as ai_big_strafe_attack)
1498  fix long_enough = F1_0 * STRAFE_MAX_UNHIT_TIME;
1499  if ( (Missiontime - aip->last_hit_time > long_enough) && ( (Missiontime - aip->submode_parm0) > long_enough) ) {
1501  }
1502 }
1503 
1504 // pick a new attack point when entering this state, and keep using it
1506 {
1507  ai_info *aip;
1508  vec3d target_pos;
1509  float target_dist, target_dot;
1510  fix mode_time;
1511 
1513 
1514  mode_time = Missiontime - aip->submode_start_time;
1515 
1516  ai_big_attack_get_data(&target_pos, &target_dist, &target_dot);
1517  if ( ai_big_strafe_maybe_retreat(target_dist, &target_pos) )
1518  return;
1519 
1520  if ( mode_time > fl2f(0.5)) {
1522  }
1523 
1524  turn_towards_point(Pl_objp, &aip->goal_point, NULL, 0.0f);
1525  accelerate_ship(aip, 1.0f);
1526 }
1527 
1528 // move towards aip->goal_point in an evasive manner
1530 {
1531  float dist;
1532  ai_info *aip;
1533  vec3d rand_vec;
1534 
1536 
1537  dist = vm_vec_dist_quick(&Pl_objp->pos, &aip->goal_point);
1538  if ( dist < 70 ) {
1541 // nprintf(("Alan","Ship %s entering AIS_STRAFE_POSITION\n", Ships[aip->shipnum].ship_name));
1542  return;
1543  }
1544 
1545  if (Missiontime - aip->submode_start_time > fl2f(1.50f)) {
1546  // set up goal_point for avoid path to turn towards
1547  aip->prev_goal_point = Pl_objp->pos;
1548  switch(rand()%4) {
1549  case 0:
1550  vm_vec_add(&rand_vec, &Pl_objp->orient.vec.fvec, &Pl_objp->orient.vec.uvec);
1551  break;
1552  case 1:
1553  vm_vec_scale_add(&rand_vec, &Pl_objp->orient.vec.fvec, &Pl_objp->orient.vec.uvec, -1.0f);
1554  break;
1555  case 2:
1556  vm_vec_add(&rand_vec, &Pl_objp->orient.vec.fvec, &Pl_objp->orient.vec.rvec);
1557  break;
1558  case 3:
1559  vm_vec_scale_add(&rand_vec, &Pl_objp->orient.vec.fvec, &Pl_objp->orient.vec.rvec, -1.0f);
1560  break;
1561  } // end switch
1562 
1563  //vm_vec_scale(&rand_vec, 200.0f);
1564  //vm_vec_add2(&aip->prev_goal_point, &rand_vec);
1565  vm_vec_scale_add(&aip->prev_goal_point, &aip->goal_point, &rand_vec, 200.0f);
1566 
1569  }
1570 
1571  turn_towards_point(Pl_objp, &aip->goal_point, NULL, 0.0f);
1572  accelerate_ship(aip, 1.0f);
1573 }
1574 
1576 {
1577  float dist;
1578  ai_info *aip;
1579 
1581 
1583  if (Missiontime > aip->afterburner_stop_time) {
1584  //nprintf(("AI", "Frame %i, turning off afterburner.\n", AI_FrameCount));
1586  }
1587  }
1588 
1589  dist = vm_vec_dist_quick(&Pl_objp->pos, &aip->goal_point);
1590  if ( dist < 70 ) {
1593 // nprintf(("Alan","Ship %s entering AIS_STRAFE_POSITION\n", Ships[aip->shipnum].ship_name));
1594  return;
1595  }
1596 
1597  if (Missiontime - aip->submode_start_time > fl2f(0.70f)) {
1600 
1601  if ( (Missiontime - aip->last_hit_time) < F1_0*5 ) {
1602  if (ai_maybe_fire_afterburner(Pl_objp, aip)) {
1605  }
1606  }
1607  }
1608 
1609  turn_towards_point(Pl_objp, &aip->prev_goal_point, NULL, 0.0f);
1610  accelerate_ship(aip, 1.0f);
1611 }
1612 
1613 // reposition self to begin another strafing run
1615 {
1616  ship_info *sip;
1617  ai_info *aip;
1619  aip = &Ai_info[Ships[Pl_objp->instance].ai_index];
1620 
1621  //Maybe use AIS_STRAFE_GLIDE_ATTACK
1622  if ((sip->can_glide == true) && !(aip->ai_flags & AIF_KAMIKAZE) && (frand() < aip->ai_glide_strafe_percent)) {
1624  aip->submode_parm1 = 0;
1625  } else {
1626  aip->submode = AIS_STRAFE_ATTACK;
1627  }
1629 }
1630 
1631 // --------------------------------------------------------------------------
1632 // #define AIS_STRAFE_ATTACK 201 // fly towards target and attack
1633 // #define AIS_STRAFE_AVOID 202 // fly evasive vector to avoid incoming fire
1634 // #define AIS_STRAFE_RETREAT1 203 // fly away from attack point (directly)
1635 // #define AIS_STRAFE_RETREAT1 204 // fly away from attack point (on an avoid vector)
1636 // #define AIS_STRAFE_POSITION 205 // re-position to resume strafing attack
1637 //
1639 {
1640  ai_info *aip;
1641 
1643 
1644  Assert(aip->mode == AIM_STRAFE);
1645 
1646 /*
1647  if ( aip->goal_objnum != aip->target_objnum ) {
1648  Int3(); // what is going on here? - Get Alan
1649  aip->mode = AIM_NONE;
1650  return;
1651  }
1652 */
1653  // check if target is still a big ship... if not enter chase mode
1654  if ( !(Ship_info[Ships[En_objp->instance].ship_info_index].flags & (SIF_BIG_SHIP|SIF_HUGE_SHIP)) ) {
1656  return;
1657  }
1658 
1659  switch (aip->submode) {
1660  case AIS_STRAFE_ATTACK:
1662  break;
1663  case AIS_STRAFE_AVOID:
1665  break;
1666  case AIS_STRAFE_RETREAT1:
1668  break;
1669  case AIS_STRAFE_RETREAT2:
1671  break;
1672  case AIS_STRAFE_POSITION:
1674  break;
1677  break;
1678  default:
1679 
1680  Int3(); // Illegal submode for AIM_STRAFE
1681  break;
1682  }
1683 
1684  //Maybe apply random sidethrust, depending on the current submode
1685  //The following are valid targets for random sidethrust (circle strafe uses it too, but that is handled separately)
1686  if (aip->submode == AIS_STRAFE_ATTACK ||
1687  aip->submode == AIS_STRAFE_AVOID ||
1688  aip->submode == AIS_STRAFE_RETREAT1 ||
1689  aip->submode == AIS_STRAFE_RETREAT2 ||
1690  aip->submode == AIS_STRAFE_POSITION)
1691  {
1692  //Re-roll for random sidethrust every 2 seconds
1694  do_random_sidethrust(aip, &Ship_info[Ships[Objects[aip->target_objnum].instance].ship_info_index]);
1695  }
1696  }
1697 }
1698 
1699 // See if Pl_objp should enter strafe mode (This is called from maybe_evade_dumbfire_weapon(), and the
1700 // weapon_objnum is for a weapon that is about to collide with Pl_objp
1701 //
1702 // Check if weapon_objnum was fired by Pl_objp's target, and whether Pl_objp's target is a big ship, if
1703 // so, enter AIM_STRAFE
1704 int ai_big_maybe_enter_strafe_mode(object *pl_objp, int weapon_objnum, int consider_target_only)
1705 {
1706  ai_info *aip;
1707  ship_info *sip;
1708  object *weapon_objp, *parent_objp;
1709 
1710  aip = &Ai_info[Ships[pl_objp->instance].ai_index];
1711  Assert(aip->mode != AIM_STRAFE); // can't happen
1712 
1713  // if Pl_objp has no target, then we can't enter strafe mode
1714  if ( aip->target_objnum < 0 ) {
1715  return 0;
1716  }
1717 
1718  // if target is not a ship, stafe mode is not possible
1719  if ( Objects[aip->target_objnum].type != OBJ_SHIP ) {
1720  return 0;
1721  }
1722 
1723  sip = &Ship_info[Ships[Objects[aip->target_objnum].instance].ship_info_index];
1724 
1725  // if Pl_objp's target is not a big/capital ship, then cannot enter strafe mode
1726  // AL 12-31-97: Even though transports are considered big ships, don't enter strafe mode on them
1727  if ( !(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)) || (sip->flags & SIF_TRANSPORT) ) {
1728  return 0;
1729  }
1730 
1731  // If Pl_objp not a fighter or bomber, don't enter strafe mode. -- MK, 11/11/97.
1732  if ( !(Ship_info[Ships[pl_objp->instance].ship_info_index].flags & (SIF_FIGHTER | SIF_BOMBER)) ) {
1733  return 0;
1734  }
1735 
1736  Assert(weapon_objnum >= 0 && weapon_objnum < MAX_OBJECTS);
1737  weapon_objp = &Objects[weapon_objnum];
1738  Assert(weapon_objp->type == OBJ_WEAPON);
1739 
1740  Assert(weapon_objp->parent >= 0 && weapon_objp->parent < MAX_OBJECTS);
1741  parent_objp = &Objects[weapon_objp->parent];
1742  if ( (parent_objp->signature != weapon_objp->parent_sig) || (parent_objp->type != OBJ_SHIP) ) {
1743  return 0;
1744  }
1745 
1746  // Maybe the ship which fired the weapon isn't the current target
1747  if ( OBJ_INDEX(parent_objp) != aip->target_objnum ) {
1748 
1749 //JAS IMPOSSIBLE if (1) { // consider_target_only ) {
1750 //JAS IMPOSSIBLE return 0;
1751 //JAS IMPOSSIBLE } else {
1752  // switch targets
1753  sip = &Ship_info[Ships[parent_objp->instance].ship_info_index];
1754  if ( !(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)) || (sip->flags & SIF_TRANSPORT) ) {
1755  return 0;
1756  }
1757  set_target_objnum(aip, OBJ_INDEX(parent_objp));
1758 //JAS IMPOSSIBLE }
1759  }
1760 
1761  ai_big_strafe_maybe_attack_turret(pl_objp, weapon_objp);
1762 
1763  // if we've got this far, the weapon must have come from the player's target, and it is a
1764  // big/capital ship... so enter strafe mode
1765  aip->previous_mode = aip->mode;
1766  aip->mode = AIM_STRAFE;
1767  aip->submode_parm0 = Missiontime; // use parm0 as time strafe mode entered (i.e. MODE start time)
1768  aip->submode = AIS_STRAFE_AVOID;
1770 // nprintf(("Alan","%s Accepted strafe mode\n", Ships[pl_objp->instance].ship_name));
1771 
1772  return 1;
1773 }
1774 
1775 // Consider attacking a turret, if a turret actually fired the weapon
1776 // input: ship_objp => ship that will attack the turret
1777 // weapon_objp =>
1778 void ai_big_strafe_maybe_attack_turret(object *ship_objp, object *weapon_objp)
1779 {
1780  ai_info *aip;
1781  object *parent_objp;
1782 
1783  Assert(ship_objp->type == OBJ_SHIP);
1784  aip = &Ai_info[Ships[ship_objp->instance].ai_index];
1785 
1786  // Make decision to attack turret based on AI class. The better AI ships will realize that
1787  // it is better to take out the turrets first on a big ship.
1788  if ( (frand()*100) > (aip->ai_courage-15) )
1789  return;
1790 
1791  // If ship is already attacking a subsystem, don't switch
1792  if ( aip->targeted_subsys != NULL ) {
1793  return;
1794  }
1795 
1796  // If the weapon is not from a turret, return
1797  if ( Weapons[weapon_objp->instance].turret_subsys == NULL ) {
1798  return;
1799  }
1800 
1801  Assert(weapon_objp->parent >= 0 && weapon_objp->parent < MAX_OBJECTS);
1802  parent_objp = &Objects[weapon_objp->parent];
1803 
1804  // UnknownPlayer : Decide whether or not this weapon was a beam, in which case it might be a good
1805  // idea to go after it even if its not on the current target. This is randomized so
1806  // the ai will not always go after different ships firing beams at them.
1807  // Approx 1/4 chance we'll go after the other ship's beam.
1808 
1809  bool attack_turret_on_different_ship = (aip->ai_profile_flags & AIPF_BIG_SHIPS_CAN_ATTACK_BEAM_TURRETS_ON_UNTARGETED_SHIPS)
1810  && (Weapon_info[Weapons[weapon_objp->instance].weapon_info_index].wi_flags & WIF_BEAM) && (frand()*100 < 25.0f);
1811 
1812  // unless we're making an exception, we should only attack a turret if it sits on the current target
1813  if ( !attack_turret_on_different_ship )
1814  {
1815  if ( (parent_objp->signature != weapon_objp->parent_sig) || (parent_objp->type != OBJ_SHIP) ) {
1816  return;
1817  }
1818 
1819  if ( aip->target_objnum != OBJ_INDEX(parent_objp) ) {
1820  return;
1821  }
1822  }
1823 
1824  // attack the turret
1825  set_targeted_subsys(aip, Weapons[weapon_objp->instance].turret_subsys, OBJ_INDEX(parent_objp));
1826 }
vec3d ** verts
Definition: model.h:587
void mc_info_init(mc_info *mc)
Definition: model.h:1138
float ai_glide_strafe_percent
Definition: ai.h:456
#define AIF_ON_SUBSYS_PATH
Definition: ai.h:49
fix last_attack_time
Definition: ai.h:419
int model_collide(mc_info *mc_info_obj)
fix submode_start_time
Definition: ai.h:400
int timestamp(int delta_ms)
Definition: timer.cpp:226
int n_paths
Definition: model.h:783
float get_world_closest_box_point_with_delta(vec3d *closest_box_point, object *box_obj, vec3d *start_point, int *is_inside, float delta)
int i
Definition: multi_pxo.cpp:466
fix Missiontime
Definition: systemvars.cpp:19
#define AIS_STRAFE_RETREAT1
Definition: ai.h:290
model_subsystem * system_info
Definition: ship.h:314
weapon Weapons[MAX_WEAPONS]
Definition: weapons.cpp:78
int primary_bank_weapons[MAX_SHIP_PRIMARY_BANKS]
Definition: ship.h:103
#define MIN(a, b)
Definition: pstypes.h:296
void ai_big_switch_to_chase_mode(ai_info *aip)
Definition: aibig.cpp:840
#define MAX_SHIP_PRIMARY_BANKS
Definition: globals.h:62
vec3d * pos
Definition: model.h:1113
int team
Definition: ship.h:606
void model_find_world_point(vec3d *outpnt, vec3d *mpnt, int model_num, int submodel_num, const matrix *objorient, const vec3d *objpos)
Definition: modelread.cpp:4099
void ai_big_strafe_attack()
Definition: aibig.cpp:1287
float vm_vec_mag_quick(const vec3d *v)
Definition: vecmat.cpp:371
int num_primary_banks
Definition: ship.h:99
int ai_maybe_fire_afterburner(object *objp, ai_info *aip)
Definition: aicode.cpp:4825
#define F1_0
Definition: fix.h:15
void vm_vec_scale_add(vec3d *dest, const vec3d *src1, const vec3d *src2, float k)
Definition: vecmat.cpp:266
#define MISSION_FLAG_FULLNEB
Definition: missionparse.h:70
#define GLIDE_STRAFE_MIN_TIME
Definition: aibig.cpp:58
polymodel * model_get(int model_num)
Definition: modelread.cpp:3134
weapon_info Weapon_info[MAX_WEAPON_TYPES]
Definition: weapons.cpp:79
ship_weapon weapons
Definition: ship.h:658
float fire_wait
Definition: weapon.h:359
float vm_vec_mag(const vec3d *v)
Definition: vecmat.cpp:325
#define SCAN_FIGHTERS_INTERVAL
Definition: aibig.cpp:31
float flFrametime
Definition: fredstubs.cpp:22
int ai_fire_primary_weapon(object *objp)
Definition: aicode.cpp:5626
Definition: weapon.h:163
GLuint index
Definition: Glext.h:5608
#define SM_ATTACK
Definition: ai.h:247
physics_info phys_info
Definition: object.h:157
int path_subsystem_next_check
Definition: ai.h:391
int id
Definition: model.h:732
int pick_big_attack_point_timestamp
Definition: weapon.h:198
int model_num
Definition: ship.h:1189
#define EVADE_BOX_BASE_DISTANCE
Definition: aibig.cpp:46
int path_start
Definition: ai.h:378
int next_secondary_fire_stamp[MAX_SHIP_SECONDARY_BANKS]
Definition: ship.h:115
void set_predicted_enemy_pos_turret(vec3d *predicted_enemy_pos, vec3d *gun_pos, object *pobjp, vec3d *enemy_pos, vec3d *enemy_vel, float weapon_speed, float time_enemy_in_range)
Definition: aicode.cpp:6344
#define PF_GLIDING
Definition: physics.h:32
Assert(pm!=NULL)
int target_objnum
Definition: ai.h:339
int submode
Definition: ai.h:394
vec3d prev_goal_point
Definition: ai.h:429
object * Pl_objp
Definition: aicode.cpp:169
int path_goal_dist
Definition: ai.h:390
Definition: pstypes.h:88
int ai_index
Definition: ship.h:538
#define STRAFE_RETREAT_BOX_DIST
Definition: aibig.cpp:43
w_bank * gun_banks
Definition: model.h:772
fix afterburner_stop_time
Definition: ai.h:503
int ai_big_maybe_follow_subsys_path(int do_dot_check=1)
Definition: aibig.cpp:366
int model_which_octant_distant_many(vec3d *pnt, int model_num, matrix *model_orient, vec3d *model_pos, polymodel **pm, int *octs)
vec3d turret_big_attack_point
Definition: ship.h:349
float srotation_time
Definition: ship.h:1199
#define EVADE_BOX_MIN_DISTANCE
Definition: aibig.cpp:47
int ship_stop_fire_primary(object *obj)
Definition: ship.cpp:10711
float target_time
Definition: ai.h:350
void ai_big_strafe_glide_attack()
Definition: aibig.cpp:1390
void big_ship_collide_recover_start(object *objp, object *big_objp, vec3d *collide_pos, vec3d *collision_normal)
Definition: aicode.cpp:14843
struct vec3d::@225::@227 xyz
int path_cur
Definition: ai.h:379
vec3d max_vel
Definition: physics.h:49
GLclampf f
Definition: Glext.h:7097
#define MAX_OBJECTS
Definition: globals.h:83
int ship_subsystem_in_sight(object *objp, ship_subsys *subsys, vec3d *eye_pos, vec3d *subsys_pos, int do_facing_check, float *dot_out, vec3d *vec_out)
Definition: ship.cpp:14881
void ai_big_evade_ship()
Definition: aibig.cpp:297
bool can_glide
Definition: ship.h:1406
ai_info Ai_info[MAX_AI_INFO]
Definition: ai.cpp:23
vec3d * vm_vec_rotate(vec3d *dest, const vec3d *src, const matrix *m)
Definition: vecmat.cpp:933
#define Assertion(expr, msg,...)
Definition: clang.h:41
#define MIN_DOT_TO_ATTACK_MOVING_SUBSYS
Definition: aibig.cpp:38
object obj_used_list
Definition: object.cpp:53
#define f2fl(fx)
Definition: floating.h:37
void ai_select_secondary_weapon(object *objp, ship_weapon *swp, int priority1=-1, int priority2=-1)
#define AI_GOAL_DISARM_SHIP
Definition: aigoals.h:40
int current_primary_bank
Definition: ship.h:106
void accelerate_ship(ai_info *aip, float accel)
Definition: aicode.cpp:1370
ship_subsys * targeted_subsys
Definition: ai.h:472
float set_secondary_fire_delay(ai_info *aip, ship *shipp, weapon_info *swip, bool burst)
Definition: aicode.cpp:7785
float max_speed
Definition: weapon.h:354
void vm_vec_scale_add2(vec3d *dest, const vec3d *src, float k)
Definition: vecmat.cpp:284
int burst_flags
Definition: weapon.h:534
#define AIF_SEEK_LOCK
Definition: ai.h:42
Definition: ai.h:329
#define AIM_NONE
Definition: ai.h:175
vec3d big_attack_point
Definition: weapon.h:199
void ai_big_avoid_ship()
Definition: aibig.cpp:345
float weapon_range
Definition: weapon.h:390
hull_check orient
Definition: lua.cpp:5049
int mp_index
Definition: ai.h:388
object * objp
Definition: lua.cpp:3105
#define SM_AVOID
Definition: ai.h:252
int current_secondary_bank
Definition: ship.h:107
float ai_endangered_by_weapon(ai_info *aip)
Definition: aicode.cpp:6584
int subtype
Definition: weapon.h:326
#define Int3()
Definition: pstypes.h:292
#define AIF_KAMIKAZE
Definition: ai.h:55
int Nebula_sec_range
Definition: hudlock.cpp:307
Definition: model.h:594
void ai_big_pick_attack_point(object *objp, object *attacker_objp, vec3d *attack_point, float fov)
Definition: aibig.cpp:228
ship * shipp
Definition: lua.cpp:9162
vec3d pos
Definition: object.h:152
float ai_path()
Definition: aicode.cpp:4087
vec3d * p0
Definition: model.h:1114
int ai_flags
Definition: ai.h:330
float vm_vec_mag_squared(const vec3d *v)
Definition: vecmat.cpp:339
vec3d pnt[MAX_SLOTS]
Definition: model.h:434
int signature
Definition: object.h:145
#define ATTACK_COLLIDE_AVOID_DIST
Definition: aibig.cpp:52
int model_num
Definition: model.h:1110
pnode Path_points[MAX_PATH_POINTS]
Definition: aicode.cpp:263
float ai_random_sidethrust_percent
Definition: ai.h:457
#define GLIDE_STRAFE_DISTANCE
Definition: aibig.cpp:57
void ai_big_chase()
Definition: aibig.cpp:851
int weapon_info_index
Definition: weapon.h:164
float lifetime
Definition: weapon.h:382
void ai_big_strafe_avoid()
Definition: aibig.cpp:1505
int path_length
Definition: ai.h:380
int objnum
Definition: ship.h:1483
int ai_profile_flags
Definition: ai.h:463
vec3d pnt
Definition: model.h:596
void evade_weapon()
Definition: aicode.cpp:4904
void ai_big_strafe_retreat1()
Definition: aibig.cpp:1529
int turret_pick_big_attack_point_timestamp
Definition: ship.h:348
vec3d pos
Definition: ai.h:317
#define SIF_BOMBER
Definition: ship.h:886
typedef int(SCP_EXT_CALLCONV *SCPDLL_PFVERSION)(SCPDLL_Version *)
vec3d big_attack_point
Definition: ai.h:524
int instance
Definition: object.h:150
void ai_bpap(object *objp, vec3d *attacker_objp_pos, vec3d *attacker_objp_fvec, vec3d *attack_point, vec3d *local_attack_point, float fov, float weapon_travel_dist, vec3d *surface_normal, ship_subsys *ss)
Definition: aibig.cpp:78
void afterburners_stop(object *objp, int key_released)
matrix * vm_vector_2_matrix(matrix *m, const vec3d *fvec, const vec3d *uvec, const vec3d *rvec)
Definition: vecmat.cpp:850
void vm_vec_add2(vec3d *dest, const vec3d *src)
Definition: vecmat.cpp:178
void turn_towards_point(object *objp, vec3d *point, vec3d *slide_vec, float bank_override)
Definition: aicode.cpp:1491
#define GLIDE_STRAFE_MAX_TIME
Definition: aibig.cpp:59
int danger_weapon_objnum
Definition: ai.h:482
ship_subsys * turret_subsys
Definition: weapon.h:183
#define SIF_BIG_SHIP
Definition: ship.h:944
int flags
Definition: model.h:1116
struct matrix::@228::@230 vec
float ai_get_weapon_speed(ship_weapon *swp)
Definition: aicode.cpp:6304
void vm_vec_scale(vec3d *dest, float s)
Definition: vecmat.cpp:248
int timestamp_until(int stamp)
Definition: timer.cpp:242
int submode_parm1
Definition: ai.h:402
void maybe_cheat_fire_synaptic(object *objp, ai_info *aip)
Definition: aicode.cpp:15575
#define AIS_STRAFE_POSITION
Definition: ai.h:292
void ai_big_strafe_position()
Definition: aibig.cpp:1614
int team
Definition: weapon.h:167
int find_enemy(int objnum, float range, int max_attackers)
Definition: aicode.cpp:2186
void ai_big_strafe_retreat2()
Definition: aibig.cpp:1575
#define MIN_DOT_TO_ATTACK_SUBSYS
Definition: aibig.cpp:37
vec3d * p1
Definition: model.h:1115
int flags
Definition: ship.h:1227
ai_profile_t * ai_profile
Definition: missionparse.h:168
#define SIF_SMALL_SHIP
Definition: ship.h:943
float ai_accuracy
Definition: ai.h:432
void update_aspect_lock_information(ai_info *aip, vec3d *vec_to_enemy, float dist_to_enemy, float enemy_radius)
Definition: aicode.cpp:7576
float speed
Definition: physics.h:79
int num_secondary_banks
Definition: ship.h:100
ai_goal goals[MAX_AI_GOALS]
Definition: ai.h:412
#define OBJ_WEAPON
Definition: object.h:33
int mode
Definition: ai.h:336
float time_enemy_in_range
Definition: ai.h:417
int shipnum
Definition: ai.h:331
float ai_get_weapon_dist(ship_weapon *swp)
Definition: aicode.cpp:6288
#define WP_LASER
Definition: weapon.h:27
float hull_strength
Definition: object.h:160
void ai_find_path(object *pl_objp, int objnum, int path_num, int exit_flag, int subsys_path=0)
Definition: aicode.cpp:2875
void vm_vec_sub2(vec3d *dest, const vec3d *src)
Definition: vecmat.cpp:187
int parent
Definition: object.h:147
#define ATTACK_COLLIDE_SLOW_DIST
Definition: aibig.cpp:54
int ai_mode
Definition: ai.h:136
#define SM_SUPER_ATTACK
Definition: ai.h:251
#define SM_EVADE_WEAPON
Definition: ai.h:255
void compute_desired_rvec(vec3d *rvec, vec3d *goal_pos, vec3d *cur_pos)
Definition: aicode.cpp:6995
#define OF_PROTECTED
Definition: object.h:108
void ai_do_default_behavior(object *obj)
Definition: aicode.cpp:14564
bool turret_fov_test(ship_subsys *ss, vec3d *gvec, vec3d *v2e, float size_mod)
Definition: aiturret.cpp:2873
#define fl_abs(fl)
Definition: floating.h:31
int secondary_bank_weapons[MAX_SHIP_SECONDARY_BANKS]
Definition: ship.h:104
#define AIPF2_AI_AIMS_FROM_SHIP_CENTER
Definition: ai_profiles.h:60
fix last_hit_time
Definition: ai.h:420
void ai_choose_secondary_weapon(object *objp, ai_info *aip, object *en_objp)
Definition: aicode.cpp:7700
#define AIM_CHASE
Definition: ai.h:166
float vm_vec_normalized_dir(vec3d *dest, const vec3d *end, const vec3d *start)
Definition: vecmat.cpp:591
float vm_vec_dist(const vec3d *v0, const vec3d *v1)
Definition: vecmat.cpp:355
Definition: ship.h:534
vec3d big_attack_surface_normal
Definition: ai.h:525
#define AIF_FREE_AFTERBURNER_USE
Definition: ai.h:67
int maybe_avoid_big_ship(object *objp, object *ignore_objp, ai_info *aip, vec3d *goal_point, float delta_time)
Definition: aicode.cpp:6955
#define AIF_UNLOAD_SECONDARIES
Definition: ai.h:48
float radius
Definition: model.h:1117
#define AIPF_BIG_SHIPS_CAN_ATTACK_BEAM_TURRETS_ON_UNTARGETED_SHIPS
Definition: ai_profiles.h:22
GLdouble GLdouble t
Definition: Glext.h:5329
void do_random_sidethrust(ai_info *aip, ship_info *sip)
Definition: aicode.cpp:6609
int submode_parm0
Definition: ai.h:401
void ai_big_strafe()
Definition: aibig.cpp:1638
int max_attackers[NUM_SKILL_LEVELS]
Definition: ai_profiles.h:88
vec3d * vm_vec_unrotate(vec3d *dest, const vec3d *src, const matrix *m)
Definition: vecmat.cpp:959
#define SM_CONTINUOUS_TURN
Definition: ai.h:246
float vm_vec_dist_squared(const vec3d *v0, const vec3d *v1)
Definition: vecmat.cpp:344
void ai_chase_ct()
Definition: aicode.cpp:6505
int iff_x_attacks_y(int team_x, int team_y)
Definition: iff_defs.cpp:605
int get_subsystem_pos(vec3d *pos, object *objp, ship_subsys *subsysp)
Definition: ship.cpp:12975
int ai_big_strafe_maybe_retreat(float dist, vec3d *target_pos)
Definition: aibig.cpp:1231
object Objects[MAX_OBJECTS]
Definition: object.cpp:62
long fix
Definition: pstypes.h:54
int wi_flags
Definition: weapon.h:384
#define vm_vec_zero(v)
Definition: vecmat.h:37
uint flags
Definition: physics.h:37
int nverts
Definition: model.h:586
int previous_mode
Definition: ai.h:337
#define OBJ_INDEX(objp)
Definition: object.h:235
#define STRAFE_RETREAT_COLLIDE_DIST
Definition: aibig.cpp:42
vec3d hit_point_world
Definition: model.h:1124
matrix orient
Definition: object.h:153
#define AIS_STRAFE_AVOID
Definition: ai.h:289
int wi_flags2
Definition: weapon.h:385
void ai_big_strafe_maybe_attack_turret(object *ship_objp, object *weapon_objp)
Definition: aibig.cpp:1778
void vm_vec_copy_scale(vec3d *dest, const vec3d *src, float s)
Definition: vecmat.cpp:257
#define WBF_FAST_FIRING
Definition: weapon.h:149
#define OBJ_SHIP
Definition: object.h:32
void ai_big_attack_get_data(vec3d *enemy_pos, float *dist_to_enemy, float *dot_to_enemy)
Definition: aibig.cpp:1167
float max_speed
Definition: ship.h:1230
#define AIS_STRAFE_RETREAT2
Definition: ai.h:291
void vm_vec_random_in_circle(vec3d *out, const vec3d *in, const matrix *orient, float radius, int on_edge)
Definition: vecmat.cpp:2481
void vm_vec_rand_vec_quick(vec3d *rvec)
Definition: vecmat.cpp:1379
#define ENTER_STRAFE_THREAT_DIST_SQUARED
Definition: aibig.cpp:35
#define WBF_RANDOM_LENGTH
Definition: weapon.h:150
#define ATTACK_STOP_DISTANCE
Definition: aibig.cpp:49
#define SIF_HUGE_SHIP
Definition: ship.h:945
void vm_vec_sub(vec3d *dest, const vec3d *src0, const vec3d *src1)
Definition: vecmat.cpp:168
vec3d vel
Definition: physics.h:77
#define AIM_EVADE
Definition: ai.h:167
float fspeed
Definition: physics.h:80
#define STRAFE_RETREAT_COLLIDE_TIME
Definition: aibig.cpp:41
int num_hits
Definition: model.h:1121
ship Ships[MAX_SHIPS]
Definition: ship.cpp:122
int pick_big_attack_point_timestamp
Definition: ai.h:526
void ai_big_ship(object *objp)
Definition: aibig.cpp:1156
int scan_for_enemy_timestamp
Definition: ai.h:511
void afterburners_start(object *objp)
Definition: afterburner.cpp:68
#define SM_ATTACK_FOREVER
Definition: ai.h:257
GLdouble GLdouble GLdouble GLdouble q
Definition: Glext.h:5345
#define STRAFE_MAX_UNHIT_TIME
Definition: aibig.cpp:44
vec3d pnt
Definition: model.h:178
float vm_vec_dist_quick(const vec3d *v0, const vec3d *v1)
Definition: vecmat.cpp:417
float frand()
Return random value in range 0.0..1.0- (1.0- means the closest number less than 1.0)
Definition: floating.cpp:35
#define AIS_STRAFE_GLIDE_ATTACK
Definition: ai.h:293
#define AI_GOAL_DISABLE_SHIP
Definition: aigoals.h:39
float lssm_lock_range
Definition: weapon.h:492
int set_target_objnum(ai_info *aip, int objnum)
Definition: aicode.cpp:1250
#define ATTACK_COLLIDE_AVOID_TIME
Definition: aibig.cpp:53
#define MC_CHECK_MODEL
Definition: model.h:1169
#define WIF_BEAM
Definition: weapon.h:76
int ship_return_subsys_path_normal(ship *shipp, ship_subsys *ss, vec3d *gsubpos, vec3d *norm)
Definition: ship.cpp:14837
float vm_vec_copy_normalize(vec3d *dest, const vec3d *src)
Definition: vecmat.cpp:427
void ai_turn_towards_vector(vec3d *dest, object *objp, float frametime, float turn_time, vec3d *slide_vec, vec3d *rel_pos, float bank_override, int flags, vec3d *rvec=NULL, int sexp_flags=0)
Definition: aicode.cpp:1131
ship_obj Ship_obj_list
Definition: ship.cpp:162
#define vm_is_vec_nan(v)
Definition: vecmat.h:19
int ship_info_index
Definition: ship.h:539
#define MAX_ENEMY_DISTANCE
Definition: ai.h:192
SCP_vector< ship_info > Ship_info
Definition: ship.cpp:164
#define SIF_TRANSPORT
Definition: ship.h:890
#define SF2_AFTERBURNER_LOCKED
Definition: ship.h:499
#define SIF_FIGHTER
Definition: ship.h:885
float burst_delay
Definition: weapon.h:533
int static_rand(int num)
Return a pseudo random 32 bit value given a reasonably small number.
Definition: staticrand.cpp:38
#define timestamp_elapsed(stamp)
Definition: timer.h:102
void ai_big_chase_ct()
Definition: aibig.cpp:700
#define WIF_PUNCTURE
Definition: weapon.h:49
void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy, vec3d *firing_pos, vec3d *enemy_pos, vec3d *enemy_vel)
Definition: aibig.cpp:717
int Game_skill_level
Definition: fredstubs.cpp:170
int model_instance_num
Definition: model.h:1109
int n_guns
Definition: model.h:768
float vm_vec_dot(const vec3d *v0, const vec3d *v1)
Definition: vecmat.cpp:312
float fov
Definition: lua.cpp:9155
#define SM_EVADE
Definition: ai.h:250
void ai_big_subsys_path_cleanup(ai_info *aip)
Definition: aibig.cpp:351
#define timestamp_rand(a, b)
Definition: timer.h:92
#define i2f(a)
Definition: fix.h:23
eye view_positions[MAX_EYES]
Definition: model.h:753
int path_num
Definition: model.h:222
uint flags2
Definition: ship.h:645
int temp
Definition: lua.cpp:4996
#define PF_AFTERBURNER_ON
Definition: physics.h:20
int goal_objnum
Definition: ai.h:355
polymodel * pm
Definition: lua.cpp:1598
vec3d hit_normal
Definition: model.h:1129
model_octant octants[8]
Definition: model.h:791
#define MAX(a, b)
Definition: pstypes.h:299
#define ATTACK_COLLIDE_SLOW_TIME
Definition: aibig.cpp:55
int ai_big_maybe_enter_strafe_mode(object *pl_objp, int weapon_objnum, int consider_target_only)
Definition: aibig.cpp:1704
#define ATTACK_COLLIDE_BASE_DIST
Definition: aibig.cpp:51
uint flags
Definition: object.h:151
float radius
Definition: object.h:154
void set_predicted_enemy_pos(vec3d *predicted_enemy_pos, object *pobjp, vec3d *enemy_pos, vec3d *enemy_vel, ai_info *aip)
Definition: aicode.cpp:6397
mission The_mission
void turn_away_from_point(object *objp, vec3d *point, float bank_override)
Definition: aicode.cpp:1513
#define WIF2_LOCAL_SSM
Definition: weapon.h:87
int model_num
Definition: lua.cpp:4996
int ai_big_maybe_start_strafe(ai_info *aip, ship_info *sip)
Definition: aibig.cpp:509
char type
Definition: object.h:146
float damage
Definition: weapon.h:363
char filename[FILESPEC_LENGTH]
Definition: model.h:734
#define wp(p)
Definition: modelsinc.h:69
#define AIS_STRAFE_ATTACK
Definition: ai.h:288
matrix * orient
Definition: model.h:1112
int burst_counter[MAX_SHIP_PRIMARY_BANKS+MAX_SHIP_SECONDARY_BANKS]
Definition: ship.h:156
void vm_vec_add(vec3d *dest, const vec3d *src0, const vec3d *src1)
Definition: vecmat.cpp:159
void ai_set_positions(object *pl_objp, object *en_objp, ai_info *aip, vec3d *player_pos, vec3d *enemy_pos)
Definition: aicode.cpp:3469
void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float dist_to_enemy, int modelnum)
Definition: aibig.cpp:544
float static_randf(int num)
Return a random float in 0.0f .. 1.0f- (ie, it will never return 1.0f).
Definition: staticrand.cpp:61
int parent_sig
Definition: object.h:148
#define AIF_TARGET_COLLISION
Definition: ai.h:47
ship_subsys * set_targeted_subsys(ai_info *aip, ship_subsys *new_subsys, int parent_objnum)
Definition: aicode.cpp:1289
vec3d goal_point
Definition: ai.h:428
object * En_objp
Definition: aicode.cpp:170
float ai_courage
Definition: ai.h:432
int myrand()
Definition: systemvars.cpp:102
int ai_fire_secondary_weapon(object *objp, int priority1=-1, int priority2=-1)
Definition: aicode.cpp:6050
#define AIM_STRAFE
Definition: ai.h:181
void ai_big_pick_attack_point_turret(object *objp, ship_subsys *ssp, vec3d *gpos, vec3d *gvec, vec3d *attack_point, float fov, float weapon_travel_dist)
Definition: aibig.cpp:208
#define fl2f(fl)
Definition: floating.h:38
int burst_shots
Definition: weapon.h:532
char name[MAX_NAME_LEN]
Definition: model.h:171
float aspect_locked_time
Definition: ai.h:476
float vm_vec_normalize(vec3d *v)
Definition: vecmat.cpp:460