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