16 float distance, impact_time = 0, i, mintime;
18 turret_tag_fire_update(
this);
21 return real_origin(this.
enemy);
26 pre_pos = real_origin(this.
enemy);
36 impact_time = distance / this.shot_speed;
38 prep = pre_pos + (this.
enemy.velocity * (impact_time + mintime));
46 vz = this.
enemy.velocity_z;
56 pre_pos = pre_pos + this.
enemy.velocity * mintime;
70 float turret_targetscore_support(
entity _turret,
entity _target)
73 float s_score = 0, d_score;
75 if (_turret.enemy == _target) s_score = 1;
79 score = (d_score * _turret.target_select_rangebias) +
80 (s_score * _turret.target_select_samebias);
88 float turret_targetscore_generic(
entity _turret,
entity _target)
98 if (_turret.tur_defend)
100 d_dist =
vlen(real_origin(_target) - _turret.tur_defend.origin);
101 ikr =
vlen(_turret.origin - _turret.tur_defend.origin);
102 d_score = 1 - d_dist / _turret.target_range;
107 ikr = _turret.target_range_optimal;
111 a_score = 1 -
tvt_thadf / _turret.aim_maxrot;
113 if ((_turret.target_select_missilebias > 0) && (_target.flags & FL_PROJECTILE))
116 if ((_turret.target_select_playerbias > 0) &&
IS_CLIENT(_target))
119 d_score =
max(d_score, 0);
120 a_score =
max(a_score, 0);
121 m_score =
max(m_score, 0);
122 p_score =
max(p_score, 0);
124 score = (d_score * _turret.target_select_rangebias) +
125 (a_score * _turret.target_select_anglebias) +
126 (m_score * _turret.target_select_missilebias) +
127 (p_score * _turret.target_select_playerbias);
129 if(
vdist((_turret.tur_shotorg - real_origin(_target)), >, _turret.target_range))
136 string sd,sa,sm,sp,ss;
137 string sdt,sat,smt,spt;
140 d_score *= _turret.target_select_rangebias;
148 a_score *= _turret.target_select_anglebias;
152 m_score *= _turret.target_select_missilebias;
156 p_score *= _turret.target_select_playerbias;
161 bprint(
"^3Target scores^7 \[ ",_turret.netname,
" \] ^3for^7 \[ ", _target.netname,
" \]\n");
162 bprint(
"^5Range:\[ ",sd,
" \]^2+bias:\[ ",sdt,
" \]\n");
163 bprint(
"^5Angle:\[ ",sa,
" \]^2+bias:\[ ",sat,
" \]\n");
164 bprint(
"^5Missile:\[ ",sm,
" \]^2+bias:\[ ",smt,
" \]\n");
165 bprint(
"^5Player:\[ ",sp,
" \]^2+bias:\[ ",spt,
" \]\n");
166 bprint(
"^3Total (w/bias):\[^1",ss,
"\]\n");
174 void turret_hide(
entity this)
204 Send_Effect(EFFECT_ROCKET_EXPLODE, this.
origin,
'0 0 0', 1);
206 tur.tr_death(tur,
this);
218 tur.tr_death(tur,
this);
268 bool turret_heal(
entity targ,
entity inflictor,
float amount,
float limit)
270 float true_limit = ((limit !=
RES_LIMIT_NONE) ? limit : targ.max_health);
279 void turret_think(
entity this);
290 this.event_damage = turret_damage;
291 this.event_heal = turret_heal;
298 this.
ammo = this.ammo_max;
306 tur.tr_setup(tur,
this);
314 if((client_only ? this.clientframe : this.
frame ) != _frame)
321 this.clientframe = _frame;
329 WriteHeader(MSG_ENTITY, ENT_CLIENT_TURRET);
335 WriteVector(MSG_ENTITY, this.
origin);
337 WriteAngleVector2D(MSG_ENTITY, this.
angles);
354 WriteVector(MSG_ENTITY, this.
origin);
356 WriteVector(MSG_ENTITY, this.
velocity);
380 void load_unit_settings(
entity ent,
bool is_reload)
385 if(!ent.turret_scale_damage) ent.turret_scale_damage = 1;
386 if(!ent.turret_scale_range) ent.turret_scale_range = 1;
387 if(!ent.turret_scale_refire) ent.turret_scale_refire = 1;
388 if(!ent.turret_scale_ammo) ent.turret_scale_ammo = 1;
389 if(!ent.turret_scale_aim) ent.turret_scale_aim = 1;
390 if(!ent.turret_scale_health) ent.turret_scale_health = 1;
391 if(!ent.turret_scale_respawn) ent.turret_scale_respawn = 1;
396 ent.tur_head.avelocity =
'0 0 0';
398 ent.tur_head.angles =
'0 0 0';
401 string unitname = ent.netname;
402 #define X(class, prefix, fld, type) ent.fld = cvar(strcat("g_turrets_unit_", prefix, "_", #fld)); 406 ent.ammo_max *= ent.turret_scale_ammo;
407 ent.ammo_recharge *= ent.turret_scale_ammo;
408 ent.aim_speed *= ent.turret_scale_aim;
410 ent.respawntime *= ent.turret_scale_respawn;
411 ent.shot_dmg *= ent.turret_scale_damage;
412 ent.shot_refire *= ent.turret_scale_refire;
413 ent.shot_radius *= ent.turret_scale_damage;
414 ent.shot_force *= ent.turret_scale_damage;
415 ent.shot_volly_refire *= ent.turret_scale_refire;
416 ent.target_range *= ent.turret_scale_range;
417 ent.target_range_min *= ent.turret_scale_range;
418 ent.target_range_optimal *= ent.turret_scale_range;
422 tur.tr_setup(tur, ent);
433 d =
RadiusDamage (
this, this.
owner, this.
owner.shot_dmg, 0,
this.owner.shot_radius,
this,
NULL,
this.owner.shot_force,
this.projectiledeathtype,
DMG_NOWEP,
NULL);
434 this.
owner.tur_debug_dmg_t_h = this.
owner.tur_debug_dmg_t_h + d;
435 this.
owner.tur_debug_dmg_t_f = this.
owner.tur_debug_dmg_t_f + this.
owner.shot_dmg;
437 RadiusDamage (
this, this.
realowner, this.
owner.shot_dmg, 0,
this.owner.shot_radius,
this,
NULL,
this.owner.shot_force,
this.projectiledeathtype,
DMG_NOWEP,
NULL);
442 void turret_projectile_touch(
entity this,
entity toucher)
465 setsize(proj,
'-0.5 -0.5 -0.5' * _size,
'0.5 0.5 0.5' * _size);
467 proj.realowner = actor;
468 proj.bot_dodge =
true;
469 proj.bot_dodgerating = actor.shot_dmg;
471 settouch(proj, turret_projectile_touch);
472 proj.nextthink =
time + 9;
474 proj.velocity =
normalize(actor.tur_shotdir_updated +
randomvec() * actor.shot_spread) * actor.shot_speed;
475 proj.flags = FL_PROJECTILE;
478 proj.enemy = actor.enemy;
479 proj.projectiledeathtype = _death;
485 proj.event_damage = turret_projectile_damage;
501 vector enemy_pos = real_origin(t_turret.enemy);
503 turret_tag_fire_update(t_turret);
505 t_turret.tur_shotdir_updated =
v_forward;
506 t_turret.tur_dist_enemy =
vlen(t_turret.tur_shotorg - enemy_pos);
507 t_turret.tur_dist_aimpos =
vlen(t_turret.tur_shotorg - t_turret.tur_aimpos);
522 tracebox(t_turret.tur_shotorg,
'-1 -1 -1',
'1 1 1', t_turret.tur_shotorg + (t_turret.tur_shotdir_updated * t_turret.tur_dist_aimpos),
MOVE_NORMAL,t_turret);
524 t_turret.tur_dist_impact_to_aimpos =
vlen(
trace_endpos - t_turret.tur_aimpos) - (
vlen(t_turret.enemy.maxs - t_turret.enemy.mins) * 0.5);
526 t_turret.tur_impacttime =
vlen(t_turret.tur_shotorg -
trace_endpos) / t_turret.shot_speed;
533 .float turret_framecounter;
534 void turret_track(
entity this)
547 target_angle = this.
idle_aim - (
'1 0 0' * this.aim_maxpitch);
570 switch(this.track_type)
573 f_tmp = this.aim_speed * this.
ticrate;
577 if(this.
tur_head.angles_x >
this.aim_maxpitch)
578 this.
tur_head.angles_x = this.aim_maxpitch;
580 if(this.
tur_head.angles_x < -
this.aim_maxpitch)
581 this.
tur_head.angles_x = this.aim_maxpitch;
586 this.
tur_head.angles_y +=
bound(-f_tmp, move_angle_y, f_tmp);
587 if(this.
tur_head.angles_y >
this.aim_maxrot)
588 this.
tur_head.angles_y = this.aim_maxrot;
590 if(this.
tur_head.angles_y < -
this.aim_maxrot)
591 this.
tur_head.angles_y = this.aim_maxrot;
600 f_tmp = this.aim_speed * this.
ticrate;
601 move_angle_x =
bound(-this.aim_speed, move_angle_x * this.track_accel_pitch * f_tmp, this.aim_speed);
602 move_angle_y =
bound(-this.aim_speed, move_angle_y * this.track_accel_rot * f_tmp, this.aim_speed);
603 move_angle = (this.
tur_head.avelocity * this.track_blendrate) + (move_angle * (1 - this.track_blendrate));
608 move_angle_y =
bound(-this.aim_speed, move_angle_y, this.aim_speed);
609 move_angle_x =
bound(-this.aim_speed, move_angle_x, this.aim_speed);
617 this.
tur_head.avelocity_x = move_angle_x;
618 if((this.
tur_head.angles_x +
this.tur_head.avelocity_x *
this.ticrate) >
this.aim_maxpitch)
621 this.
tur_head.angles_x = this.aim_maxpitch;
626 if((this.
tur_head.angles_x +
this.tur_head.avelocity_x *
this.ticrate) < -
this.aim_maxpitch)
629 this.
tur_head.angles_x = -this.aim_maxpitch;
638 this.
tur_head.avelocity_y = move_angle_y;
640 if((this.
tur_head.angles_y +
this.tur_head.avelocity_y *
this.ticrate) >
this.aim_maxrot)
643 this.
tur_head.angles_y = this.aim_maxrot;
648 if((this.
tur_head.angles_y +
this.tur_head.avelocity_y *
this.ticrate) < -
this.aim_maxrot)
651 this.
tur_head.angles_y = -this.aim_maxrot;
660 this.turret_framecounter += 1;
661 if(this.turret_framecounter >= 10)
664 this.turret_framecounter = 0;
696 if(e_target.owner == e_turret)
699 if(!
checkpvs(e_target.origin, e_turret))
702 if(e_target.alpha != 0 && e_target.alpha <= 0.3)
705 if(
MUTATOR_CALLHOOK(TurretValidateTarget, e_turret, e_target, validate_flags))
718 else if (STAT(FROZEN, e_target))
740 if(e_target.owner.tur_head == e_target)
741 if(e_target.team != e_turret.team)
745 if (e_target.flags & FL_PROJECTILE)
750 if(!(e_target.flags & FL_PROJECTILE))
758 if (e_target.team != e_turret.team)
761 if (e_turret.team != e_target.owner.team)
764 if (e_turret.team != e_target.aiment.team)
769 if (e_target.team == e_turret.team)
772 if (e_turret.team == e_target.owner.team)
775 if (e_turret.team == e_target.aiment.team)
781 tvt_dist =
vlen(e_turret.origin - real_origin(e_target));
784 if (
tvt_dist < e_turret.target_range_min)
787 if (
tvt_dist > e_turret.target_range)
792 tvt_thadv =
angleofs3(e_turret.tur_head.origin, e_turret.angles + e_turret.tur_head.angles, e_target.origin);
806 if (
fabs(tvt_tadv_x) > e_turret.aim_maxpitch)
809 if (
fabs(tvt_tadv_y) > e_turret.aim_maxrot)
816 v_tmp = real_origin(e_target) + ((e_target.mins + e_target.maxs) * 0.5);
818 traceline(e_turret.origin +
'0 0 16', v_tmp, 0, e_turret);
824 if (e_target.classname ==
"grapplinghook")
832 #ifdef TURRET_DEBUG_TARGETSELECT 833 LOG_TRACE(
"Target:",e_target.netname,
" is a valid target for ",e_turret.netname);
849 e_enemy = this.
enemy;
850 m_score = this.turret_score_target(
this,e_enemy) * this.target_select_samebias;
855 e = findradius(this.
origin, this.target_range);
869 score = this.turret_score_target(
this,e);
870 if ((score > m_score) && (score > 0))
922 if(this.
ammo >= this.shot_dmg)
932 if (this.
ammo < this.shot_dmg)
937 if (this.
enemy.ammo >=
this.enemy.ammo_max)
969 if (this.shot_volly > 1)
971 if (this.
ammo < (this.shot_dmg * this.shot_volly))
981 bool turret_checkfire(
entity this)
986 return this.turret_firecheckfunc(
this);
989 void turret_fire(
entity this)
998 info.tr_attack(info,
this);
1001 this.
ammo -= this.shot_dmg;
1011 if (this.shot_volly > 1)
1020 void turret_think(
entity this)
1027 if (this.tur_debug_tmr1 <
time)
1029 if (this.
enemy) paint_target (this.
enemy,128,this.tur_debug_rvec,0.9);
1030 paint_target(
this,256,this.tur_debug_rvec,0.9);
1031 this.tur_debug_tmr1 =
time + 1;
1037 if (this.
ammo < this.ammo_max)
1038 this.
ammo =
min(this.
ammo + this.ammo_recharge, this.ammo_max);
1064 if (turret_checkfire(
this))
1088 if (turret_checkfire(
this))
1108 if (turret_checkfire(
this))
1112 tur.tr_think(tur,
this);
1120 float do_target_scan = 0;
1151 tur.tr_think(tur,
this);
1170 if (turret_checkfire(
this))
1175 tur.tr_think(tur,
this);
1186 this.
team = actor.team;
1195 void turret_link(
entity this)
1197 Net_LinkEntity(
this,
true, 0, turret_send);
1203 void turrets_manager_think(
entity this)
1211 load_unit_settings(it,
true);
1213 tur.tr_think(tur, it);
1215 cvar_set(
"g_turrets_reloadcvars",
"0");
1219 void turret_initparams(
entity tur)
1221 #define TRY(x) (x) ? (x) 1222 tur.respawntime =
max (-1, (TRY(tur.respawntime) : 60 ));
1223 tur.shot_refire =
bound(0.01, (TRY(tur.shot_refire) : 1 ), 9999);
1224 tur.shot_dmg =
max (1, (TRY(tur.shot_dmg) : tur.shot_refire * 50 ));
1225 tur.shot_radius =
max (1, (TRY(tur.shot_radius) : tur.shot_dmg * 0.5 ));
1226 tur.shot_speed =
max (1, (TRY(tur.shot_speed) : 2500 ));
1227 tur.shot_spread =
bound(0.0001, (TRY(tur.shot_spread) : 0.0125 ), 500);
1228 tur.shot_force =
bound(0.001, (TRY(tur.shot_force) : tur.shot_dmg * 0.5 + tur.shot_radius * 0.5 ), 5000);
1229 tur.shot_volly =
bound(1, (TRY(tur.shot_volly) : 1 ),
floor(tur.ammo_max / tur.shot_dmg));
1230 tur.shot_volly_refire =
bound(tur.shot_refire, (TRY(tur.shot_volly_refire) : tur.shot_refire * tur.shot_volly ), 60);
1231 tur.target_range =
bound(0, (TRY(tur.target_range) : tur.shot_speed * 0.5 ), max_shot_distance);
1232 tur.target_range_min =
bound(0, (TRY(tur.target_range_min) : tur.shot_radius * 2 ), max_shot_distance);
1233 tur.target_range_optimal =
bound(0, (TRY(tur.target_range_optimal) : tur.target_range * 0.5 ), max_shot_distance);
1234 tur.aim_maxrot =
bound(0, (TRY(tur.aim_maxrot) : 90 ), 360);
1235 tur.aim_maxpitch =
bound(0, (TRY(tur.aim_maxpitch) : 20 ), 90);
1236 tur.aim_speed =
bound(0.1, (TRY(tur.aim_speed) : 36 ), 1000);
1237 tur.aim_firetolerance_dist =
bound(0.1, (TRY(tur.aim_firetolerance_dist) : 5 + (tur.shot_radius * 2) ), max_shot_distance);
1238 tur.target_select_rangebias =
bound(-10, (TRY(tur.target_select_rangebias) : 1 ), 10);
1239 tur.target_select_samebias =
bound(-10, (TRY(tur.target_select_samebias) : 1 ), 10);
1240 tur.target_select_anglebias =
bound(-10, (TRY(tur.target_select_anglebias) : 1 ), 10);
1241 tur.target_select_missilebias =
bound(-10, (TRY(tur.target_select_missilebias) : 1 ), 10);
1242 tur.target_select_playerbias =
bound(-10, (TRY(tur.target_select_playerbias) : 1 ), 10);
1243 tur.ammo_max =
max (tur.shot_dmg, (TRY(tur.ammo_max) : tur.shot_dmg * 10 ));
1244 tur.ammo_recharge =
max (0, (TRY(tur.ammo_recharge) : tur.shot_dmg * 0.5 ));
1250 vector path_extra_size =
'64 64 64';
1251 return boxesoverlap(targ - path_extra_size, targ + path_extra_size, this.
absmin - path_extra_size, this.
absmax + path_extra_size);
1254 void turret_findtarget(
entity this)
1260 setthink(e, turrets_manager_think);
1261 e.nextthink =
time + 2;
1265 if(targ.classname ==
"turret_checkpoint")
1271 LOG_TRACE(
"Turret has invalid defendpoint!");
1278 void turret_reset(
entity this)
1293 tur.tr_precache(tur);
1302 load_unit_settings(
this, 0);
1307 if(!this.shot_refire) { this.shot_refire = 1; }
1324 this.aim_speed =
bound(0.1, ((!this.aim_speed) ? 180 : this.aim_speed), 1000);
1326 if(!this.track_accel_pitch) { this.track_accel_pitch = 0.5; }
1327 if(!this.track_accel_rot) { this.track_accel_rot = 0.5; }
1328 if(!this.track_blendrate) { this.track_blendrate = 0.35; }
1331 turret_initparams(
this);
1348 this.turret_score_target = turret_targetscore_support;
1350 this.turret_score_target = turret_targetscore_generic;
1354 _setmodel(
this, tur.model);
1364 this.
ammo = this.ammo_max;
1365 this.ammo_recharge *= this.
ticrate;
1372 this.event_damage = turret_damage;
1373 this.event_heal = turret_heal;
1374 this.
use = turret_use;
1377 this.reset = turret_reset;
1380 _setmodel(this.
tur_head, tur.head_model);
1381 setsize(this.
tur_head,
'0 0 0',
'0 0 0');
1383 setattachment(this.
tur_head,
this,
"tag_head");
1399 while(
vdist(this.tur_debug_rvec, <, 2))
1402 this.tur_debug_rvec_x =
fabs(this.tur_debug_rvec_x);
1403 this.tur_debug_rvec_y =
fabs(this.tur_debug_rvec_y);
1404 this.tur_debug_rvec_z =
fabs(this.tur_debug_rvec_z);
1409 turret_tag_fire_update(
this);
1411 tur.tr_setup(tur,
this);
#define get_turretinfo(i)
entity turret_select_target(entity this)
#define IL_EACH(this, cond, body)
const int TFL_TARGETSELECT_ANGLELIMITS
const int TFL_DMG_HEADSHAKE
float turret_validate_target(entity e_turret, entity e_target, float validate_flags)
void turret_respawn(entity this)
ERASEABLE float anglemods(float v)
#define PROJECTILE_MAKETRIGGER(e)
const int TFL_TARGETSELECT_NOTURRETS
const int TUR_FLAG_SPLASH
const int TFL_FIRECHECK_AFF
bool SetResourceExplicit(entity e, Resource res_type, float amount)
Sets the resource amount of an entity without calling any hooks.
const int TUR_FLAG_MISSILE
const int TFL_AIM_ZPREDICT
ERASEABLE vector angleofs3(vector from, vector ang, vector to)
string turret_name
human readable name
int target_validate_flags
float target_validate_time
const int TFL_FIRECHECK_AMMO_OWN
#define TR_PROPS_COMMON(P, class, prefix)
bool turret_initialize(entity this, Turret tur)
float checkpvs(vector viewpos, entity viewee)
const int TUR_FLAG_SUPPORT
const int TFL_TRACK_ROTATE
const int TUR_FLAG_PLAYER
const int TFL_SHOOT_VOLLYALWAYS
void turrets_setframe(entity this, float _frame, float client_only)
void CSQCProjectile(entity e, float clientanimate, int type, float docull)
void turret_do_updates(entity e_turret)
updates aim org, shot org, shot dir and enemy org for selected turret
void turret_projectile_explode(entity this)
float autocvar_g_turrets_targetscan_maxdelay
const int TFL_AMMO_RECHARGE
IntrusiveList g_bot_dodge
IntrusiveList g_bot_targets
void TakeResource(entity receiver, Resource res_type, float amount)
Takes an entity some resource.
const int TFL_TARGETSELECT_PLAYERS
const int TFL_TARGETSELECT_LOS
#define PROJECTILE_TOUCH(e, t)
const int TFL_DMG_DEATH_NORESPAWN
const int TUR_FLAG_MEDPROJ
bool autocvar_g_turrets_nofire
const int TFL_TARGETSELECT_OWNTEAM
ERASEABLE entity IL_PUSH(IntrusiveList this, entity it)
Push to tail.
const int TFL_FIRECHECK_NO
float autocvar_g_turrets_targetscan_mindelay
void GiveResourceWithLimit(entity receiver, Resource res_type, float amount, float limit)
Gives an entity some resource but not more than a limit.
const int TFL_FIRECHECK_AMMO_OTHER
ERASEABLE float boxesoverlap(vector m1, vector m2, vector m3, vector m4)
requires that m2>m1 in all coordinates, and that m4>m3
#define angleofs(from, to)
bool autocvar_g_turrets_reloadcvars
const int TFL_FIRECHECK_REFIRE
void W_PrepareExplosionByDamage(entity this, entity attacker, void(entity this) explode)
const int TFL_FIRECHECK_DISTANCES
bool turret_firecheck(entity this)
const int TFL_SHOOT_CUSTOM
vector m_mins
turret hitbox size
float autocvar_g_turrets_aimidle_delay
const int TFL_SHOOT_HITALLVALID
const int TFL_TRACK_PITCH
float autocvar_g_friendlyfire
entity turret_projectile(entity actor, Sound _snd, float _size, float _health, float _death, float _proj_type, float _cull, float _cli_anim)
const int TFL_FIRECHECK_AIMDIST
const float TFL_TRACKTYPE_STEPMOTOR
vector(float skel, float bonenum) _skel_get_boneabs_hidden
const int TSF_NO_AMMO_REGEN
float MOVETYPE_FLYMISSILE
IntrusiveList g_projectiles
const int TFL_TARGETSELECT_TEAMCHECK
float GetResource(entity e, Resource res_type)
Returns the current amount of resource the given entity has.
const int TFL_TARGETSELECT_NO
void InitializeEntity(entity e, void(entity this) func, int order)
#define vdist(v, cmp, f)
Vector distance comparison, avoids sqrt()
const int TFL_FIRECHECK_DEAD
const float TFL_TRACKTYPE_FLUIDPRECISE
const int TFL_DMG_AIMSHAKE
bool turret_closetotarget(entity this, vector targ)
const int TFL_AMMO_ENERGY
const int TFL_TARGETSELECT_VEHICLES
float RadiusDamage(entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float forceintensity, int deathtype,.entity weaponentity, entity directhitentity)
#define MUTATOR_CALLHOOK(id,...)
const int TFL_TARGETSELECT_MISSILES
float frame
primary framegroup animation (strength = 1 - lerpfrac - lerpfrac3 - lerpfrac4)
entity weaponentities[MAX_WEAPONSLOTS]
#define new_pure(class)
purely logical entities (.origin doesn't work)
const int TFL_FIRECHECK_TEAMCHECK
const int TUR_FLAG_ISTURRET
void turret_die(entity this)
const float TFL_TRACKTYPE_FLUIDINERTIA
ERASEABLE vector shortangle_vxy(vector ang1, vector ang2)
const int TFL_FIRECHECK_LOS
#define sound(e, c, s, v, a)
const int TFL_AIM_SHOTTIMECOMPENSATE
vector m_maxs
turret hitbox size
float tur_dist_impact_to_aimpos
const int TNSF_FULL_UPDATE
void set_movetype(entity this, int mt)
const int TFL_TARGETSELECT_RANGELIMITS
const int TFL_DMG_RETALIATE
float attack_finished_single[MAX_WEAPONSLOTS]
const int TFL_SHOOT_CLEARTARGET
const int TFL_TARGETSELECT_MISSILESONLY