]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/server/tturrets/system/system_main.qc
Spawnflags TSL_NO_RESPAWN
[divverent/nexuiz.git] / data / qcsrc / server / tturrets / system / system_main.qc
1 #define cvar_base "g_turrets_unit_"\r
2 \r
3 void load_unit_settings(entity ent,string unitname,float is_reload)\r
4 {\r
5 \r
6     string sbase;\r
7 \r
8     // dprint("Reloading turret ",e_turret.netname,"\n");\r
9 \r
10     if (ent == world)\r
11         return;\r
12 \r
13     if (!ent.turret_scale_damage)    ent.turret_scale_damage  = 1;\r
14     if (!ent.turret_scale_range)     ent.turret_scale_range   = 1;\r
15     if (!ent.turret_scale_refire)    ent.turret_scale_refire  = 1;\r
16     if (!ent.turret_scale_ammo)      ent.turret_scale_ammo    = 1;\r
17     if (!ent.turret_scale_aim)       ent.turret_scale_aim     = 1;\r
18     if (!ent.turret_scale_health)    ent.turret_scale_health  = 1;\r
19     if (!ent.turret_scale_respawn)   ent.turret_scale_respawn = 1;\r
20 \r
21     sbase = strcat(cvar_base,unitname);\r
22     if (is_reload)\r
23     {\r
24         ent.enemy = world;\r
25         ent.tur_head.avelocity = '0 0 0';\r
26 \r
27         if (ent.turrcaps_flags & TFL_TURRCAPS_HEADATTACHED)\r
28             ent.tur_head.angles = '0 0 0';\r
29         else\r
30             ent.tur_head.angles = ent.angles;\r
31     }\r
32 \r
33     ent.health      = cvar(strcat(sbase,"_health")) * ent.turret_scale_health;\r
34     ent.respawntime = cvar(strcat(sbase,"_respawntime")) * ent.turret_scale_respawn;\r
35 \r
36     ent.shot_dmg          = cvar(strcat(sbase,"_shot_dmg")) * ent.turret_scale_damage;\r
37     ent.shot_refire       = cvar(strcat(sbase,"_shot_refire")) * ent.turret_scale_refire;\r
38     ent.shot_radius       = cvar(strcat(sbase,"_shot_radius")) * ent.turret_scale_damage;\r
39     ent.shot_speed        = cvar(strcat(sbase,"_shot_speed"));\r
40     ent.shot_spread       = cvar(strcat(sbase,"_shot_spread"));\r
41     ent.shot_force        = cvar(strcat(sbase,"_shot_force")) * ent.turret_scale_damage;\r
42     ent.shot_volly        = cvar(strcat(sbase,"_shot_volly"));\r
43     ent.shot_volly_refire = cvar(strcat(sbase,"_shot_volly_refire")) * ent.turret_scale_refire;\r
44 \r
45     ent.target_range         = cvar(strcat(sbase,"_target_range")) * ent.turret_scale_range;\r
46     ent.target_range_min     = cvar(strcat(sbase,"_target_range_min")) * ent.turret_scale_range;\r
47     ent.target_range_fire    = cvar(strcat(sbase,"_target_range_fire")) * ent.turret_scale_range;\r
48     ent.target_range_optimal = cvar(strcat(sbase,"_target_range_optimal")) * ent.turret_scale_range;\r
49 \r
50     ent.target_select_rangebias  = cvar(strcat(sbase,"_target_select_rangebias"));\r
51     ent.target_select_samebias   = cvar(strcat(sbase,"_target_select_samebias"));\r
52     ent.target_select_anglebias  = cvar(strcat(sbase,"_target_select_anglebias"));\r
53     ent.target_select_playerbias = cvar(strcat(sbase,"_target_select_playerbias"));\r
54     //ent.target_select_fov = cvar(cvar_gets(sbase,"_target_select_fov"));\r
55 \r
56     ent.ammo_max      = cvar(strcat(sbase,"_ammo_max")) * ent.turret_scale_ammo;\r
57     ent.ammo_recharge = cvar(strcat(sbase,"_ammo_recharge")) * ent.turret_scale_ammo;\r
58 \r
59     ent.aim_firetolerance_dist = cvar(strcat(sbase,"_aim_firetolerance_dist"));\r
60     ent.aim_speed    = cvar(strcat(sbase,"_aim_speed")) * ent.turret_scale_aim;\r
61     ent.aim_maxrot   = cvar(strcat(sbase,"_aim_maxrot"));\r
62     ent.aim_maxpitch = cvar(strcat(sbase,"_aim_maxpitch"));\r
63 \r
64     ent.track_type        = cvar(strcat(sbase,"_track_type"));\r
65     ent.track_accel_pitch = cvar(strcat(sbase,"_track_accel_pitch"));\r
66     ent.track_accel_rot   = cvar(strcat(sbase,"_track_accel_rot"));\r
67     ent.track_blendrate   = cvar(strcat(sbase,"_track_blendrate"));\r
68 \r
69     if(is_reload)\r
70         if(ent.turret_respawnhook)\r
71             ent.turret_respawnhook();\r
72 \r
73 }\r
74 \r
75 /*\r
76 float turret_stdproc_true()\r
77 {\r
78     return 1;\r
79 }\r
80 \r
81 float turret_stdproc_false()\r
82 {\r
83     return 0;\r
84 }\r
85 \r
86 \r
87 void turret_stdproc_nothing()\r
88 {\r
89     return;\r
90 }\r
91 */\r
92 \r
93 /**\r
94 ** updates enemy distances, predicted impact point/time\r
95 ** and updated aim<->predict impact distance.\r
96 **/\r
97 void turret_do_updates(entity t_turret)\r
98 {\r
99     vector enemy_pos;\r
100     entity oldself;\r
101 \r
102     oldself = self;\r
103     self = t_turret;\r
104 \r
105     enemy_pos = real_origin(self.enemy);\r
106 \r
107     turret_tag_fire_update();\r
108 \r
109     self.tur_shotdir_updated = v_forward;\r
110 \r
111     self.tur_dist_enemy  = vlen(self.tur_shotorg - enemy_pos);\r
112     self.tur_dist_aimpos = vlen(self.tur_shotorg - self.tur_aimpos);\r
113 \r
114     if(self.firecheck_flags & TFL_FIRECHECK_VERIFIED)\r
115     if(self.enemy)\r
116     {\r
117         enemy_pos = self.enemy.origin;\r
118         setorigin(self.enemy,self.tur_aimpos);\r
119     }\r
120 \r
121     //dprint("NN: ", self.netname," THVN: ",self.tur_head.classname," frame:",ftos(self.tur_head.frame),"\n");\r
122     //dprint("self.tur_shotorg: ",vtos(self.tur_shotorg),"\n");\r
123     tracebox(self.tur_shotorg, '-1 -1 -1','1 1 1',self.tur_shotorg + (self.tur_shotdir_updated * self.tur_dist_aimpos),MOVE_NORMAL,self);\r
124 \r
125     if(self.firecheck_flags & TFL_FIRECHECK_VERIFIED)\r
126         if(self.enemy)\r
127             setorigin(self.enemy,enemy_pos);\r
128 \r
129     self.tur_impactpoint           = trace_endpos;\r
130     self.tur_impactent             = trace_ent;\r
131     self.tur_dist_impact_to_aimpos = vlen(trace_endpos - self.tur_aimpos);\r
132     self.tur_impacttime            = vlen(self.tur_shotorg - trace_endpos) / self.shot_speed;\r
133 \r
134     self = oldself;\r
135 }\r
136 \r
137 /*\r
138 vector turret_fovsearch_pingpong()\r
139 {\r
140     vector wish_angle;\r
141     if(self.phase < time)\r
142     {\r
143         if( self.tur_head.phase )\r
144             self.tur_head.phase = 0;\r
145         else\r
146             self.tur_head.phase = 1;\r
147         self.phase = time + 5;\r
148     }\r
149 \r
150     if( self.tur_head.phase)\r
151         wish_angle = self.idle_aim + '0 1 0' * (self.aim_maxrot * (self.target_select_fov / 360));\r
152     else\r
153         wish_angle = self.idle_aim - '0 1 0' * (self.aim_maxrot * (self.target_select_fov / 360));\r
154 \r
155     return wish_angle;\r
156 }\r
157 \r
158 vector turret_fovsearch_steprot()\r
159 {\r
160     vector wish_angle;\r
161     //float rot_add;\r
162 \r
163     wish_angle   = self.tur_head.angles;\r
164     wish_angle_x = self.idle_aim_x;\r
165 \r
166     if (self.phase < time)\r
167     {\r
168         //rot_add = self.aim_maxrot / self.target_select_fov;\r
169         wish_angle_y += (self.target_select_fov * 2);\r
170 \r
171         if(wish_angle_y > 360)\r
172             wish_angle_y = wish_angle_y - 360;\r
173 \r
174          self.phase = time + 1.5;\r
175     }\r
176 \r
177     return wish_angle;\r
178 }\r
179 \r
180 vector turret_fovsearch_random()\r
181 {\r
182     vector wish_angle;\r
183 \r
184     if (self.phase < time)\r
185     {\r
186         wish_angle_y = random() * self.aim_maxrot;\r
187         if(random() < 0.5)\r
188             wish_angle_y *= -1;\r
189 \r
190         wish_angle_x = random() * self.aim_maxpitch;\r
191         if(random() < 0.5)\r
192             wish_angle_x *= -1;\r
193 \r
194         self.phase = time + 5;\r
195 \r
196         self.tur_aimpos = wish_angle;\r
197     }\r
198 \r
199     return self.idle_aim + self.tur_aimpos;\r
200 }\r
201 */\r
202 \r
203 /**\r
204 ** Handles head rotation according to\r
205 ** the units .track_type and .track_flags\r
206 **/\r
207 //.entity aim_mark;\r
208 void turret_stdproc_track()\r
209 {\r
210     vector target_angle; // This is where we want to aim\r
211     vector move_angle;   // This is where we can aim\r
212     float f_tmp;\r
213 \r
214     if (self.track_flags == TFL_TRACK_NO)\r
215         return;\r
216 \r
217     if(!self.tur_active)\r
218         target_angle = self.idle_aim - ('1 0 0' * self.aim_maxpitch);\r
219     else if (self.enemy == world)\r
220     {\r
221         if(time > self.lip)\r
222             if (self.turrcaps_flags & TFL_TURRCAPS_HEADATTACHED)\r
223                 target_angle = self.idle_aim + self.angles;\r
224             else\r
225                 target_angle = self.idle_aim;\r
226         else\r
227             target_angle = vectoangles(normalize(self.tur_aimpos - self.tur_shotorg));\r
228     }\r
229     else\r
230     {\r
231         // Find the direction\r
232         target_angle = normalize(self.tur_aimpos - self.tur_shotorg);\r
233         target_angle = vectoangles(target_angle); // And make a angle\r
234     }\r
235 \r
236     self.tur_head.angles_x = safeangle(self.tur_head.angles_x);\r
237     self.tur_head.angles_y = safeangle(self.tur_head.angles_y);\r
238 \r
239     // Find the diffrence between where we currently aim and where we want to aim\r
240     vector a_off;\r
241 \r
242 \r
243     if (self.turrcaps_flags & TFL_TURRCAPS_HEADATTACHED)\r
244     {\r
245         move_angle = target_angle - (self.angles + self.tur_head.angles);\r
246         move_angle = shortangle_vxy(move_angle,(self.angles + self.tur_head.angles));\r
247         a_off = '0 0 0';\r
248 \r
249     }\r
250     else\r
251     {\r
252         move_angle = target_angle - self.tur_head.angles;\r
253         move_angle = shortangle_vxy(move_angle,self.tur_head.angles);\r
254         a_off = self.angles;\r
255     }\r
256 \r
257     switch(self.track_type)\r
258     {\r
259         case TFL_TRACKTYPE_STEPMOTOR:\r
260             f_tmp = self.aim_speed * self.ticrate; // dgr/sec -> dgr/tic\r
261             if (self.track_flags & TFL_TRACK_PITCH)\r
262             {\r
263                 self.tur_head.angles_x += bound(-f_tmp,move_angle_x, f_tmp);\r
264                 if(self.tur_head.angles_x + a_off_x > self.aim_maxpitch)\r
265                     self.tur_head.angles_x = a_off_x + self.aim_maxpitch;\r
266 \r
267                 if(self.tur_head.angles_x + a_off_x < -self.aim_maxpitch)\r
268                     self.tur_head.angles_x = a_off_x - self.aim_maxpitch;\r
269             }\r
270 \r
271             if (self.track_flags & TFL_TRACK_ROT)\r
272             {\r
273                 self.tur_head.angles_y += bound(-f_tmp, move_angle_y, f_tmp);\r
274                 if((self.tur_head.angles_y - a_off_y) > self.aim_maxrot)\r
275                     self.tur_head.angles_y = a_off_y + self.aim_maxrot;\r
276 \r
277                 if((self.tur_head.angles_y - a_off_y) < -self.aim_maxrot)\r
278                     self.tur_head.angles_y = a_off_y - self.aim_maxrot;\r
279             }\r
280 \r
281             return;\r
282 \r
283         case TFL_TRACKTYPE_FLUIDINERTIA:\r
284             f_tmp = self.aim_speed * self.ticrate; // dgr/sec -> dgr/tic\r
285             move_angle_x = bound(-self.aim_speed, move_angle_x * self.track_accel_pitch * f_tmp,self.aim_speed);\r
286             move_angle_y = bound(-self.aim_speed, move_angle_y * self.track_accel_rot * f_tmp,self.aim_speed);\r
287             move_angle = (self.tur_head.avelocity * self.track_blendrate) + (move_angle * (1 - self.track_blendrate));\r
288             break;\r
289 \r
290         case TFL_TRACKTYPE_FLUIDPRECISE:\r
291 \r
292             move_angle_y = bound(-self.aim_speed, move_angle_y, self.aim_speed);\r
293             move_angle_x = bound(-self.aim_speed, move_angle_x, self.aim_speed);\r
294 \r
295             break;\r
296     }\r
297 \r
298     //  pitch\r
299     if (self.track_flags & TFL_TRACK_PITCH)\r
300     {\r
301         self.tur_head.avelocity_x = move_angle_x;\r
302         if((self.tur_head.angles_x + self.tur_head.avelocity_x * self.ticrate) + a_off_x > self.aim_maxpitch)\r
303         {\r
304             self.tur_head.avelocity_x = 0;\r
305             self.tur_head.angles_x = a_off_x + self.aim_maxpitch;\r
306         }\r
307         if((self.tur_head.angles_x + self.tur_head.avelocity_x * self.ticrate) + a_off_x < -self.aim_maxpitch)\r
308         {\r
309             self.tur_head.avelocity_x = 0;\r
310             self.tur_head.angles_x = a_off_x - self.aim_maxpitch;\r
311         }\r
312 \r
313     }\r
314 \r
315     //  rot\r
316     if (self.track_flags & TFL_TRACK_ROT)\r
317     {\r
318         self.tur_head.avelocity_y = move_angle_y;\r
319 \r
320         if(((self.tur_head.angles_y + self.tur_head.avelocity_y * self.ticrate)- a_off_y) > self.aim_maxrot)\r
321         {\r
322             self.tur_head.avelocity_y = 0;\r
323             self.tur_head.angles_y = a_off_y + self.aim_maxrot;\r
324         }\r
325 \r
326         if(((self.tur_head.angles_y + self.tur_head.avelocity_y * self.ticrate) - a_off_y) < -self.aim_maxrot)\r
327         {\r
328             self.tur_head.avelocity_y = 0;\r
329             self.tur_head.angles_y = a_off_y - self.aim_maxrot;\r
330         }\r
331 \r
332     }\r
333 \r
334 }\r
335 \r
336 \r
337 /*\r
338  + = implemented\r
339  - = not implemented\r
340 \r
341  + TFL_FIRECHECK_NO\r
342  + TFL_FIRECHECK_WORLD\r
343  + TFL_FIRECHECK_DEAD\r
344  + TFL_FIRECHECK_DISTANCES\r
345  - TFL_FIRECHECK_LOS\r
346  + TFL_FIRECHECK_AIMDIST\r
347  + TFL_FIRECHECK_REALDIST\r
348  - TFL_FIRECHECK_ANGLEDIST\r
349  - TFL_FIRECHECK_TEAMCECK\r
350  + TFL_FIRECHECK_AFF\r
351  + TFL_FIRECHECK_OWM_AMMO\r
352  + TFL_FIRECHECK_OTHER_AMMO\r
353  + TFL_FIRECHECK_REFIRE\r
354 */\r
355 \r
356 /**\r
357 ** Preforms pre-fire checks based on the uints firecheck_flags\r
358 **/\r
359 float turret_stdproc_firecheck()\r
360 {\r
361     // This one just dont care =)\r
362     if (self.firecheck_flags & TFL_FIRECHECK_NO) return 1;\r
363 \r
364     // Ready?\r
365     if (self.firecheck_flags & TFL_FIRECHECK_REFIRE)\r
366         if (self.attack_finished_single >= time) return 0;\r
367 \r
368     // Special case: volly fire turret that has to fire a full volly if a shot was fired.\r
369     if((self.shoot_flags & TFL_SHOOT_VOLLYALWAYS) && (self.volly_counter != self.shot_volly))\r
370         return 1;\r
371 \r
372     // Lack of zombies makes shooting dead things unnecessary :P\r
373     if (self.firecheck_flags & TFL_FIRECHECK_DEAD)\r
374         if (self.enemy.deadflag != DEAD_NO) return 0;\r
375 \r
376     // Plz stop killing the world!\r
377     if (self.firecheck_flags & TFL_FIRECHECK_WORLD)\r
378         if (self.enemy == world) return 0;\r
379 \r
380     // Own ammo?\r
381     if (self.firecheck_flags & TFL_FIRECHECK_OWM_AMMO)\r
382         if (self.ammo < self.shot_dmg) return 0;\r
383 \r
384     // Other's ammo? (support-supply units)\r
385     if (self.firecheck_flags & TFL_FIRECHECK_OTHER_AMMO)\r
386         if (self.enemy.ammo >= self.enemy.ammo_max) return 0;\r
387 \r
388     if (self.firecheck_flags & TFL_FIRECHECK_DISTANCES)\r
389     {\r
390         // Not close enougth?\r
391         if (self.tur_dist_aimpos > self.target_range_fire) return 0;\r
392 \r
393         // To close?\r
394         if (self.tur_dist_aimpos < self.target_range_min) return 0;\r
395     }\r
396 \r
397     // Try to avoid FF?\r
398     if (self.firecheck_flags & TFL_FIRECHECK_AFF)\r
399         if (self.tur_impactent.team == self.team) return 0;\r
400 \r
401     // aim<->predicted impact\r
402     if (self.firecheck_flags & TFL_FIRECHECK_AIMDIST)\r
403         if (self.tur_dist_impact_to_aimpos  > self.aim_firetolerance_dist) return 0;\r
404 \r
405     // Volly status\r
406     if (self.shot_volly > 1)\r
407         if (self.volly_counter == self.shot_volly)\r
408             if (self.ammo < (self.shot_dmg * self.shot_volly))\r
409                 return 0;\r
410 \r
411     if(self.firecheck_flags & TFL_FIRECHECK_VERIFIED)\r
412         if(self.tur_impactent != self.enemy)\r
413             return 0;\r
414 \r
415     return 1;\r
416 }\r
417 \r
418 /*\r
419  + TFL_TARGETSELECT_NO\r
420  + TFL_TARGETSELECT_LOS\r
421  + TFL_TARGETSELECT_PLAYERS\r
422  + TFL_TARGETSELECT_MISSILES\r
423  - TFL_TARGETSELECT_TRIGGERTARGET\r
424  + TFL_TARGETSELECT_ANGLELIMITS\r
425  + TFL_TARGETSELECT_RANGELIMTS\r
426  + TFL_TARGETSELECT_TEAMCHECK\r
427  - TFL_TARGETSELECT_NOBUILTIN\r
428  + TFL_TARGETSELECT_OWNTEAM\r
429 */\r
430 \r
431 /**\r
432 ** Evaluate a entity for target valitity based on validate_flags\r
433 **/\r
434 float turret_validate_target(entity e_turret,entity e_target,float validate_flags)\r
435 {\r
436     vector v_tmp;\r
437 \r
438     //if(!validate_flags & TFL_TARGETSELECT_NOBUILTIN)\r
439     //    return -0.5;\r
440 \r
441     if(e_target.owner == e_turret)\r
442         return -0.5;\r
443 \r
444     if not(checkpvs(e_target.origin, e_turret))\r
445         return -1;\r
446 \r
447     if (!e_target)// == world)\r
448         return -2;\r
449 \r
450         if(g_onslaught)\r
451                 if (substring(e_target.classname, 0, 10) == "onslaught_") // don't attack onslaught targets, that's the player's job!\r
452                         return - 3;\r
453 \r
454     if (validate_flags & TFL_TARGETSELECT_NO)\r
455         return -4;\r
456 \r
457     // If only this was used more..\r
458     if (e_target.flags & FL_NOTARGET)\r
459         return -5;\r
460 \r
461     // Cant touch this\r
462     if ((e_target.takedamage == DAMAGE_NO) || (e_target.health < 0))\r
463         return -6;\r
464 \r
465     // player\r
466     if (e_target.flags & FL_CLIENT)\r
467     {\r
468         if not (validate_flags & TFL_TARGETSELECT_PLAYERS)\r
469             return -7;\r
470 \r
471         if (e_target.deadflag != DEAD_NO)\r
472             return -8;\r
473     }\r
474 \r
475         // enemy turrets\r
476         if (validate_flags & TFL_TARGETSELECT_NOTURRETS)\r
477         if (e_target.turret_firefunc || e_target.owner.tur_head == e_target)\r
478             if(e_target.team != e_turret.team) // Dont break support units.\r
479                 return -9;\r
480 \r
481     // Missile\r
482     if (e_target.flags & FL_PROJECTILE)\r
483         if not (validate_flags & TFL_TARGETSELECT_MISSILES)\r
484             return -10;\r
485 \r
486     // Team check\r
487     if (validate_flags & TFL_TARGETSELECT_TEAMCHECK)\r
488     {\r
489         if (validate_flags & TFL_TARGETSELECT_OWNTEAM)\r
490         {\r
491             if (e_target.team != e_turret.team)\r
492                 return -11;\r
493 \r
494             if (e_turret.team != e_target.owner.team)\r
495                 return -12;\r
496         }\r
497         else\r
498         {\r
499             if (e_target.team == e_turret.team)\r
500                 return -13;\r
501 \r
502             if (e_turret.team == e_target.owner.team)\r
503                 return -14;\r
504         }\r
505     }\r
506 \r
507     // Range limits?\r
508     tvt_dist = vlen(e_turret.origin - real_origin(e_target));\r
509     if (validate_flags & TFL_TARGETSELECT_RANGELIMTS)\r
510     {\r
511         if (tvt_dist < e_turret.target_range_min)\r
512             return -15;\r
513 \r
514         if (tvt_dist > e_turret.target_range)\r
515             return -16;\r
516     }\r
517 \r
518     // Can we even aim this thing?\r
519     if(e_turret.turrcaps_flags & TFL_TURRCAPS_HEADATTACHED)\r
520     {\r
521         tvt_thadv = angleofs3(e_turret.tur_head.origin,e_turret.angles + e_turret.tur_head.angles ,e_target);\r
522         //tvt_thadv = angleofs(e_turret.angles,e_target);\r
523     }\r
524     else\r
525     {\r
526         tvt_thadv = angleofs(e_turret.tur_head,e_target);\r
527     }\r
528 \r
529     tvt_tadv  = shortangle_vxy(angleofs(e_turret,e_target),e_turret.angles);\r
530     tvt_thadf = vlen(tvt_thadv);\r
531     tvt_tadf  = vlen(tvt_tadv);\r
532 \r
533     /*\r
534     if(validate_flags & TFL_TARGETSELECT_FOV)\r
535     {\r
536         if(e_turret.target_select_fov < tvt_thadf)\r
537             return -21;\r
538     }\r
539     */\r
540 \r
541     if (validate_flags & TFL_TARGETSELECT_ANGLELIMITS)\r
542     {\r
543         if (fabs(tvt_tadv_x) > e_turret.aim_maxpitch)\r
544             return -17;\r
545 \r
546         if (fabs(tvt_tadv_y) > e_turret.aim_maxrot)\r
547             return -18;\r
548     }\r
549 \r
550     // Line of sight?\r
551     if (validate_flags & TFL_TARGETSELECT_LOS)\r
552     {\r
553         v_tmp = real_origin(e_target) + ((e_target.mins + e_target.maxs) * 0.5);\r
554         traceline(e_turret.tur_shotorg,v_tmp,0,e_turret);\r
555 \r
556         if (e_turret.aim_firetolerance_dist < vlen(v_tmp - trace_endpos))\r
557             return -19;\r
558     }\r
559 \r
560     if (e_target.classname == "grapplinghook")\r
561         return -20;\r
562 \r
563 #ifdef TURRET_DEBUG_TARGETSELECT\r
564     dprint("Target:",e_target.netname," is a valid target for ",e_turret.netname,"\n");\r
565 #endif\r
566 \r
567     return 1;\r
568 }\r
569 \r
570 entity turret_select_target()\r
571 {\r
572     entity e;        // target looper entity\r
573     float  score;    // target looper entity score\r
574     entity e_enemy;  // currently best scoreing target\r
575     float  m_score;  // currently best scoreing target's score\r
576     float f;\r
577 \r
578     m_score = 0;\r
579     if(self.enemy)\r
580     if(turret_validate_target(self,self.enemy,self.target_validate_flags) > 0)\r
581     {\r
582         e_enemy = self.enemy;\r
583         m_score = self.turret_score_target(self,e_enemy) * self.target_select_samebias;\r
584     }\r
585 \r
586     e = findradius(self.origin,self.target_range);\r
587 \r
588     // Nothing to aim at?\r
589     if (!e) return world;\r
590 \r
591     while (e)\r
592     {\r
593         f = turret_validate_target(self,e,self.target_select_flags);\r
594         if (f > 0)\r
595         {\r
596             score = self.turret_score_target(self,e);\r
597             if ((score > m_score) && (score > 0))\r
598             {\r
599                 e_enemy = e;\r
600                 m_score = score;\r
601             }\r
602         }\r
603         e = e.chain;\r
604     }\r
605 \r
606     return e_enemy;\r
607 }\r
608 \r
609 void turret_think()\r
610 {\r
611     entity e;\r
612 \r
613     self.nextthink = time + self.ticrate;\r
614 \r
615     // ONS uses somewhat backwards linking.\r
616     if (teamplay)\r
617     {\r
618         if not (g_onslaught)\r
619             if (self.target)\r
620             {\r
621                 e = find(world,targetname,self.target);\r
622                 if (e != world)\r
623                     self.team = e.team;\r
624             }\r
625 \r
626         if (self.team != self.tur_head.team)\r
627             turret_stdproc_respawn();\r
628     }\r
629 \r
630 \r
631     if (cvar("g_turrets_reloadcvars") == 1)\r
632     {\r
633         e = nextent(world);\r
634         while (e)\r
635         {\r
636             if (e.tur_head != world)\r
637             {\r
638 \r
639                 load_unit_settings(e,e.cvar_basename,1);\r
640                 if(e.turret_postthink)\r
641                     e.turret_postthink();\r
642             }\r
643 \r
644             e = nextent(e);\r
645         }\r
646 \r
647         cvar_set("g_turrets_reloadcvars","0");\r
648     }\r
649 \r
650 #ifdef TURRET_DEBUG\r
651     if (self.tur_dbg_tmr1 < time)\r
652     {\r
653         if (self.enemy) paint_target (self.enemy,128,self.tur_dbg_rvec,0.9);\r
654         paint_target(self,256,self.tur_dbg_rvec,0.9);\r
655         self.tur_dbg_tmr1 = time + 1;\r
656     }\r
657 #endif\r
658 \r
659     // Handle ammo\r
660     if not (self.spawnflags & TSF_NO_AMMO_REGEN)\r
661     if (self.ammo < self.ammo_max)\r
662         self.ammo = min(self.ammo + self.ammo_recharge,self.ammo_max);\r
663 \r
664 \r
665     // Inactive turrets needs to run the think loop,\r
666     // So they can handle animation and wake up if need be.\r
667     if not (self.tur_active)\r
668     {\r
669         turret_stdproc_track();\r
670         return;\r
671     }\r
672 \r
673     //This is just wrong :|\r
674     if(self.deadflag != DEAD_NO)\r
675     {\r
676         dprint("WARNING: dead turret running the think function!\n");\r
677         return;\r
678     }\r
679 \r
680     // This is typicaly used for zaping every target in range\r
681     // turret_fusionreactor uses this to recharge friendlys.\r
682     if (self.shoot_flags & TFL_SHOOT_HITALLVALID)\r
683     {\r
684 \r
685         // Do a self.turret_fire for every valid target.\r
686         e = findradius(self.origin,self.target_range);\r
687         while (e)\r
688         {\r
689             if (turret_validate_target(self,e,self.target_validate_flags))\r
690             {\r
691                 self.enemy = e;\r
692 \r
693                 turret_do_updates(self);\r
694 \r
695                 if (self.turret_firecheckfunc())\r
696                     turret_fire();\r
697             }\r
698 \r
699             e = e.chain;\r
700         }\r
701         self.enemy = world;\r
702     }\r
703     else if(self.shoot_flags & TFL_SHOOT_CUSTOM)\r
704     {\r
705         // This one is doing something oddball. assume its handles what needs to be handled.\r
706 \r
707         // Predict?\r
708         if not((self.aim_flags & TFL_AIM_NO))\r
709             self.tur_aimpos = turret_stdproc_aim_generic();\r
710 \r
711         // Turn & pitch?\r
712         if (!self.track_flags & TFL_TRACK_NO)\r
713             turret_stdproc_track();\r
714 \r
715         turret_do_updates(self);\r
716 \r
717         // Fire?\r
718         if (self.turret_firecheckfunc())\r
719             turret_fire();\r
720     }\r
721     else\r
722     {\r
723         // Special case for volly always. if it fired once it must compleate the volly.\r
724         if(self.shoot_flags & TFL_SHOOT_VOLLYALWAYS)\r
725             if(self.volly_counter != self.shot_volly)\r
726             {\r
727                 // Predict or whatnot\r
728                 if not((self.aim_flags & TFL_AIM_NO))\r
729                     self.tur_aimpos = turret_stdproc_aim_generic();\r
730 \r
731                 // Turn & pitch\r
732                 if (!self.track_flags & TFL_TRACK_NO)\r
733                     turret_stdproc_track();\r
734 \r
735                 turret_do_updates(self);\r
736 \r
737                 // Fire!\r
738                 if (self.turret_firecheckfunc() != 0)\r
739                     turret_fire();\r
740 \r
741                 if(self.turret_postthink)\r
742                     self.turret_postthink();\r
743 \r
744                 return;\r
745             }\r
746 \r
747         // Check if we have a vailid enemy, and try to find one if we dont.\r
748         if ((turret_validate_target(self,self.enemy,self.target_validate_flags) <= 0) && (self.cnt < time))\r
749         {\r
750             self.enemy = turret_select_target();\r
751             self.cnt = time + cvar("g_turrets_targetscan_mindelay");\r
752         }\r
753 \r
754 \r
755         // No target, just go to idle, do any custom stuff and bail.\r
756         if (self.enemy == world)\r
757         {\r
758             // Turn & pitch\r
759             if (!self.track_flags & TFL_TRACK_NO)\r
760                 turret_stdproc_track();\r
761 \r
762             // do any per-turret stuff\r
763             if(self.turret_postthink)\r
764                 self.turret_postthink();\r
765 \r
766             // And bail.\r
767             return;\r
768         }\r
769         else\r
770             self.lip = time + cvar("g_turrets_aimidle_delay"); // Keep track of the last time we had a target.\r
771 \r
772         // Predict?\r
773         if not((self.aim_flags & TFL_AIM_NO))\r
774             self.tur_aimpos = turret_stdproc_aim_generic();\r
775 \r
776         // Turn & pitch?\r
777         if (!self.track_flags & TFL_TRACK_NO)\r
778             turret_stdproc_track();\r
779 \r
780         turret_do_updates(self);\r
781         // Fire?\r
782         if (self.turret_firecheckfunc())\r
783             turret_fire();\r
784     }\r
785 \r
786     // do any per-turret stuff\r
787     if(self.turret_postthink)\r
788         self.turret_postthink();\r
789 }\r
790 \r
791 void turret_fire()\r
792 {\r
793     if (cvar("g_turrets_nofire") != 0)\r
794         return;\r
795 \r
796     if ((!self.tur_active) || (self.deadflag != DEAD_NO))\r
797         return;\r
798 \r
799     self.turret_firefunc();\r
800 \r
801     self.attack_finished_single = time + self.shot_refire;\r
802     self.ammo                   = self.ammo - self.shot_dmg;\r
803     self.volly_counter          = self.volly_counter - 1;\r
804     if (self.volly_counter <= 0)\r
805     {\r
806         self.volly_counter = self.shot_volly;\r
807 \r
808         if (self.shoot_flags & TFL_SHOOT_CLEARTARGET)\r
809             self.enemy = world;\r
810 \r
811         if (self.shot_volly > 1)\r
812             self.attack_finished_single = time + self.shot_volly_refire;\r
813     }\r
814 \r
815 \r
816 #ifdef TURRET_DEBUG\r
817     if (self.enemy) paint_target3(self.tur_aimpos, 64, self.tur_dbg_rvec, self.tur_impacttime + 0.25);\r
818 #endif\r
819 }\r
820 \r
821 void turret_stdproc_fire()\r
822 {\r
823     dprint("^1Bang, ^3your dead^7 ",self.enemy.netname,"! ^1(turret with no real firefunc)\n");\r
824 }\r
825 \r
826 /*\r
827     When .used a turret switched team to activator.team.\r
828     If activator is world, the turrets goes inactive.\r
829 */\r
830 void turret_stdproc_use()\r
831 {\r
832     dprint("Turret ",self.netname, " used by ",activator.classname,"\n");\r
833 \r
834     self.team = activator.team;\r
835 \r
836     if(self.team == 0)\r
837         self.tur_active = 0;\r
838     else\r
839         self.tur_active = 1;\r
840 \r
841 }\r
842 \r
843 /*\r
844 * Standard turret initialization. use this!\r
845 * (unless you have a very good reason not to)\r
846 * Any special stuff like multiple cannon models should be done\r
847 * after this is proc called.\r
848 * if the return value is 0, the turret _must_ be removed.\r
849 */\r
850 float turret_stdproc_init (string cvar_base_name)\r
851 {\r
852         entity e,ee;\r
853 \r
854     // Are turrets allowed atm?\r
855     if (cvar("g_turrets") == 0)\r
856         return 0;\r
857 \r
858     // Better more then once then never.\r
859     // turret_gibs_precash();\r
860 \r
861     // Terrainbase spawnflag. This puts a enlongated model\r
862     // under the turret, so it looks ok on uneaven surfaces.\r
863     if (self.spawnflags & TSF_TERRAINBASE)\r
864     {\r
865         entity tb;\r
866         //precache_model("models/turrets/terrainbase.md3");\r
867         tb = spawn();\r
868         setmodel(tb,"models/turrets/terrainbase.md3");\r
869         setorigin(tb,self.origin);\r
870         tb.solid = SOLID_BBOX;\r
871         //makestatic(tb);\r
872     }\r
873 \r
874     self.cvar_basename = cvar_base_name;\r
875     load_unit_settings(self,self.cvar_basename,0);\r
876 \r
877     // Handle turret teams.\r
878     if (cvar("g_assult") != 0)\r
879     {\r
880         if (!self.team)\r
881             self.team = 14; // Assume turrets are on the defending side if not explicitly set otehrwize\r
882     }\r
883     else if (!teamplay)\r
884                 self.team = MAX_SHOT_DISTANCE; // Group all turrets into the same team iso they dont kill eachother.\r
885         else if(g_onslaught && self.targetname)\r
886         {\r
887                 e = find(world,target,self.targetname);\r
888                 if(e != world)\r
889                 {\r
890                         self.team = e.team;\r
891                         ee = e;\r
892                 }\r
893         }\r
894         else if(!self.team)\r
895                 self.team = MAX_SHOT_DISTANCE; // Group all turrets into the same team iso they dont kill eachother.\r
896 \r
897 \r
898 \r
899     /*\r
900     * Try to guess some reasonaly defaults\r
901     * for missing params and do sanety checks\r
902     * thise checks could produce some "interesting" results\r
903     * if it hits a glitch in my logic :P so try to set as mutch\r
904     * as possible beforehand.\r
905     */\r
906     if (self.turrcaps_flags & TFL_TURRCAPS_SUPPORT)\r
907         if (!self.ticrate) self.ticrate = 0.2;     // Support units generaly dont need to have a high speed ai-loop\r
908     else\r
909         if (!self.ticrate) self.ticrate = 0.1;     // 10 fps for normal turrets\r
910 \r
911     self.ticrate = bound(sys_ticrate,self.ticrate,60);  // keep it sane\r
912 \r
913 // General stuff\r
914     if (self.netname == "")\r
915         self.netname = self.classname;\r
916 \r
917     if (!self.respawntime)\r
918         self.respawntime = 60;\r
919     self.respawntime = max(-1,self.respawntime);\r
920 \r
921     if (!self.health)\r
922         self.health = 1000;\r
923     self.tur_health = max(1,self.health);\r
924 \r
925     if (!self.turrcaps_flags)\r
926         self.turrcaps_flags = TFL_TURRCAPS_RADIUSDMG | TFL_TURRCAPS_MEDPROJ | TFL_TURRCAPS_PLAYERKILL;\r
927 \r
928     if (!self.damage_flags)\r
929         self.damage_flags = TFL_DMG_YES | TFL_DMG_RETALIATE | TFL_DMG_AIMSHAKE;\r
930 \r
931 // Shot stuff.\r
932     if (!self.shot_refire)\r
933         self.shot_refire = 1;\r
934     self.shot_refire = bound(0.01,self.shot_refire,9999);\r
935 \r
936     if (!self.shot_dmg)\r
937         self.shot_dmg  = self.shot_refire * 50;\r
938     self.shot_dmg = max(1,self.shot_dmg);\r
939 \r
940     if (!self.shot_radius)\r
941         self.shot_radius = self.shot_dmg * 0.5;\r
942     self.shot_radius = max(1,self.shot_radius);\r
943 \r
944     if (!self.shot_speed)\r
945         self.shot_speed = 2500;\r
946     self.shot_speed = max(1,self.shot_speed);\r
947 \r
948     if (!self.shot_spread)\r
949         self.shot_spread = 0.0125;\r
950     self.shot_spread = bound(0.0001,self.shot_spread,500);\r
951 \r
952     if (!self.shot_force)\r
953         self.shot_force = self.shot_dmg * 0.5 + self.shot_radius * 0.5;\r
954     self.shot_force = bound(0.001,self.shot_force,MAX_SHOT_DISTANCE * 0.5);\r
955 \r
956     if (!self.shot_volly)\r
957         self.shot_volly = 1;\r
958     self.shot_volly = bound(1,self.shot_volly,floor(self.ammo_max / self.shot_dmg));\r
959 \r
960     if (!self.shot_volly_refire)\r
961         self.shot_volly_refire = self.shot_refire * self.shot_volly;\r
962     self.shot_volly_refire = bound(self.shot_refire,self.shot_volly_refire,60);\r
963 \r
964     if (!self.firecheck_flags)\r
965         self.firecheck_flags = TFL_FIRECHECK_WORLD | TFL_FIRECHECK_DEAD | TFL_FIRECHECK_DISTANCES |\r
966                                TFL_FIRECHECK_LOS | TFL_FIRECHECK_AIMDIST | TFL_FIRECHECK_TEAMCECK |\r
967                                TFL_FIRECHECK_OWM_AMMO | TFL_FIRECHECK_REFIRE | TFL_FIRECHECK_WORLD;\r
968 \r
969 // Range stuff.\r
970     if (!self.target_range)\r
971         self.target_range = self.shot_speed * 0.5;\r
972     self.target_range = bound(0,self.target_range,MAX_SHOT_DISTANCE);\r
973 \r
974     if (!self.target_range_min)\r
975         self.target_range_min = self.shot_radius * 2;\r
976     self.target_range_min = bound(0,self.target_range_min,MAX_SHOT_DISTANCE);\r
977 \r
978     if (!self.target_range_fire)\r
979         self.target_range_fire = self.target_range * 0.8;\r
980     self.target_range_fire = bound(0,self.target_range_fire,MAX_SHOT_DISTANCE);\r
981 \r
982     if (!self.target_range_optimal)\r
983         self.target_range_optimal = self.target_range_fire * 0.5;\r
984     self.target_range_optimal = bound(0,self.target_range_optimal,MAX_SHOT_DISTANCE);\r
985 \r
986 \r
987 // Aim stuff.\r
988     if (!self.aim_maxrot)\r
989         self.aim_maxrot = 90;\r
990     self.aim_maxrot = bound(0,self.aim_maxrot,360);\r
991 \r
992     if (!self.aim_maxpitch)\r
993         self.aim_maxpitch = 20;\r
994     self.aim_maxpitch = bound(0,self.aim_maxpitch,90);\r
995 \r
996     if (!self.aim_speed)\r
997         self.aim_speed = 36;\r
998     self.aim_speed  = bound(0.1,self.aim_speed, 1000);\r
999 \r
1000     if (!self.aim_firetolerance_dist)\r
1001         self.aim_firetolerance_dist  = 5 + (self.shot_radius * 2);\r
1002     self.aim_firetolerance_dist = bound(0.1,self.aim_firetolerance_dist,MAX_SHOT_DISTANCE);\r
1003 \r
1004     if (!self.aim_flags)\r
1005     {\r
1006         self.aim_flags = TFL_AIM_LEAD | TFL_AIM_SHOTTIMECOMPENSATE;\r
1007         if(self.turrcaps_flags & TFL_TURRCAPS_RADIUSDMG)\r
1008             self.aim_flags |= TFL_AIM_GROUND2;\r
1009     }\r
1010 \r
1011     // Sill the most tested (and aim-effective)\r
1012     if (!self.track_type) self.track_type = TFL_TRACKTYPE_STEPMOTOR;\r
1013 \r
1014     if (self.track_type != TFL_TRACKTYPE_STEPMOTOR)\r
1015     {\r
1016         // Fluid / Ineria mode. Looks mutch nicer, bit experimental &\r
1017         // Can inmapt aim preformance alot.\r
1018         // needs a bit diffrent aimspeed\r
1019 \r
1020         if (!self.aim_speed)\r
1021             self.aim_speed = 180;\r
1022         self.aim_speed = bound(0.1,self.aim_speed, 1000);\r
1023 \r
1024         if (!self.track_accel_pitch)\r
1025             self.track_accel_pitch = 0.5;\r
1026 \r
1027         if (!self.track_accel_rot)\r
1028             self.track_accel_rot   = 0.5;\r
1029 \r
1030         if (!self.track_blendrate)\r
1031             self.track_blendrate   = 0.35;\r
1032     }\r
1033 \r
1034     if (!self.track_flags)\r
1035         self.track_flags = TFL_TRACK_PITCH | TFL_TRACK_ROT;\r
1036 \r
1037 \r
1038 // Target selection stuff.\r
1039     if (!self.target_select_rangebias)\r
1040         self.target_select_rangebias = 1;\r
1041     self.target_select_rangebias = bound(-10,self.target_select_rangebias,10);\r
1042 \r
1043     if (!self.target_select_samebias)\r
1044         self.target_select_samebias = 1;\r
1045     self.target_select_samebias = bound(-10,self.target_select_samebias,10);\r
1046 \r
1047     if (!self.target_select_anglebias)\r
1048         self.target_select_anglebias = 1;\r
1049     self.target_select_anglebias = bound(-10,self.target_select_anglebias,10);\r
1050 \r
1051     if (!self.target_select_missilebias)\r
1052         self.target_select_missilebias = -10;\r
1053 \r
1054     self.target_select_missilebias = bound(-10,self.target_select_missilebias,10);\r
1055     self.target_select_playerbias = bound(-10,self.target_select_playerbias,10);\r
1056 \r
1057     if (!self.target_select_flags)\r
1058     {\r
1059             self.target_select_flags = TFL_TARGETSELECT_LOS | TFL_TARGETSELECT_TEAMCHECK\r
1060                                      | TFL_TARGETSELECT_RANGELIMTS | TFL_TARGETSELECT_ANGLELIMITS;\r
1061 \r
1062         if (self.turrcaps_flags & TFL_TURRCAPS_MISSILEKILL)\r
1063             self.target_select_flags |= TFL_TARGETSELECT_MISSILES;\r
1064 \r
1065         if (self.turrcaps_flags & TFL_TURRCAPS_PLAYERKILL)\r
1066             self.target_select_flags |= TFL_TARGETSELECT_PLAYERS;\r
1067         //else\r
1068         //    self.target_select_flags = TFL_TARGETSELECT_NO;\r
1069     }\r
1070 \r
1071     self.target_validate_flags = self.target_select_flags;\r
1072 \r
1073 \r
1074 // Ammo stuff\r
1075     if (!self.ammo_max)\r
1076         self.ammo_max = self.shot_dmg * 10;\r
1077     self.ammo_max = max(self.shot_dmg,self.ammo_max);\r
1078 \r
1079     if (!self.ammo)\r
1080         self.ammo = self.shot_dmg * 5;\r
1081     self.ammo = bound(0,self.ammo,self.ammo_max);\r
1082 \r
1083     if (!self.ammo_recharge)\r
1084         self.ammo_recharge = self.shot_dmg * 0.5;\r
1085     self.ammo_recharge = max(0,self.ammo_recharge);\r
1086 \r
1087     // Convert the recharge from X per sec to X per ticrate\r
1088     self.ammo_recharge = self.ammo_recharge * self.ticrate;\r
1089 \r
1090     if (!self.ammo_flags)\r
1091         self.ammo_flags = TFL_AMMO_ENERGY | TFL_AMMO_RECHARGE;\r
1092 \r
1093 // Damage stuff\r
1094     if(self.spawnflags & TSL_NO_RESPAWN)\r
1095         if not (self.damage_flags & TFL_DMG_DEATH_NORESPAWN)\r
1096             self.damage_flags |= TFL_DMG_DEATH_NORESPAWN;\r
1097 \r
1098 // Offsets & origins\r
1099     if (!self.tur_shotorg)   self.tur_shotorg = '50 0 50';\r
1100 \r
1101 // End of default & sanety checks, start building the turret.\r
1102 \r
1103 // Spawn extra bits\r
1104     self.tur_head         = spawn();\r
1105     self.tur_head.netname = self.tur_head.classname = "turret_head";\r
1106     self.tur_head.team    = self.team;\r
1107     self.tur_head.owner   = self;\r
1108 \r
1109     // Defend mode?\r
1110     if(!self.tur_defend)\r
1111     if (self.target != "")\r
1112     {\r
1113         self.tur_defend = find(world, targetname, self.target);\r
1114         if (self.tur_defend == world)\r
1115         {\r
1116             self.target = "";\r
1117             dprint("Turret has invalid defendpoint!\n");\r
1118         }\r
1119     }\r
1120 \r
1121 // Put pices in place\r
1122     if not (self.turrcaps_flags & TFL_TURRCAPS_HEADATTACHED)\r
1123         setorigin(self.tur_head,self.origin);\r
1124 \r
1125     // In target defend mode, aim on the spot to defend when idle.\r
1126     if(self.turrcaps_flags & TFL_TURRCAPS_HEADATTACHED)\r
1127     {\r
1128         if (self.tur_defend)\r
1129             self.idle_aim  = self.tur_head.angles + angleofs(self.tur_head,self.tur_defend);\r
1130         else\r
1131             self.idle_aim  = '0 0 0';\r
1132     }\r
1133     else\r
1134     {\r
1135         if (self.tur_defend)\r
1136             self.idle_aim  = self.tur_head.angles + angleofs(self.tur_head,self.tur_defend);\r
1137         else\r
1138             self.idle_aim  = self.angles;\r
1139     }\r
1140 \r
1141     if not (self.turrcaps_flags & TFL_TURRCAPS_HEADATTACHED)\r
1142         self.tur_head.angles    = self.idle_aim;\r
1143 \r
1144     if (!self.health)\r
1145         self.health = 150;\r
1146 \r
1147     self.tur_health      = self.health;\r
1148     self.tur_head.health = self.health;\r
1149 \r
1150     self.solid          = SOLID_BBOX;\r
1151     self.tur_head.solid = SOLID_BBOX;\r
1152 \r
1153     self.takedamage          = DAMAGE_AIM;\r
1154     self.tur_head.takedamage = DAMAGE_AIM;\r
1155 \r
1156     self.movetype            = MOVETYPE_NOCLIP;\r
1157     self.tur_head.movetype   = MOVETYPE_NOCLIP;\r
1158 \r
1159     // Team color\r
1160     if (self.team == COLOR_TEAM1) self.colormod = '1.4 0.8 0.8';\r
1161     if (self.team == COLOR_TEAM2) self.colormod = '0.8 0.8 1.4';\r
1162 \r
1163     // Attach stdprocs. override when and what needed\r
1164     if (self.turrcaps_flags & TFL_TURRCAPS_SUPPORT)\r
1165     {\r
1166         self.turret_score_target    = turret_stdproc_targetscore_support;\r
1167         self.turret_firecheckfunc   = turret_stdproc_firecheck;\r
1168         self.turret_firefunc        = turret_stdproc_fire;\r
1169         //self.turret_postthink       = turret_stdproc_nothing;\r
1170         self.event_damage           = turret_stdproc_damage;\r
1171         self.tur_head.event_damage  = turret_stdproc_damage;\r
1172     }\r
1173     else\r
1174     {\r
1175         self.turret_score_target    = turret_stdproc_targetscore_generic;\r
1176         self.turret_firecheckfunc   = turret_stdproc_firecheck;\r
1177         self.turret_firefunc        = turret_stdproc_fire;\r
1178         //self.turret_postthink       = turret_stdproc_nothing;\r
1179         self.event_damage           = turret_stdproc_damage;\r
1180         self.tur_head.event_damage  = turret_stdproc_damage;\r
1181         //self.turret_addtarget       = turret_stdproc_false;\r
1182     }\r
1183 \r
1184     self.use = turret_stdproc_use;\r
1185     self.bot_attack = TRUE;\r
1186 \r
1187     // Initiate the main AI loop\r
1188     self.think     = turret_think;\r
1189     self.nextthink = time + self.ticrate;\r
1190 \r
1191     self.tur_head.team = self.team;\r
1192     self.view_ofs = '0 0 0';\r
1193 \r
1194 #ifdef TURRET_DEBUG\r
1195     self.tur_dbg_start = self.nextthink;\r
1196     while (vlen(self.tur_dbg_rvec) < 2)\r
1197         self.tur_dbg_rvec  = randomvec() * 4;\r
1198 \r
1199     self.tur_dbg_rvec_x = fabs(self.tur_dbg_rvec_x);\r
1200     self.tur_dbg_rvec_y = fabs(self.tur_dbg_rvec_y);\r
1201     self.tur_dbg_rvec_z = fabs(self.tur_dbg_rvec_z);\r
1202 #endif\r
1203 \r
1204     // Its all good.\r
1205     self.classname = "turret_main";\r
1206 \r
1207     self.tur_active = 1;\r
1208 \r
1209     // In ONS mode, and linked to a ONS ent. need to call the use to set team.\r
1210     if (g_onslaught && ee)\r
1211     {\r
1212         activator = ee;\r
1213         self.use();\r
1214     }\r
1215 \r
1216     return 1;\r
1217 }\r
1218 \r
1219 \r