]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/tturrets/units/unit_walker.qc
Merge branch 'terencehill/newpanelhud' into terencehill/speedpanel
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / tturrets / units / unit_walker.qc
1 #define ANIM_NO         0
2 #define ANIM_TURN       1
3 #define ANIM_WALK       2
4 #define ANIM_RUN        3
5 #define ANIM_STRAFE_L   4
6 #define ANIM_STRAFE_R   5
7 #define ANIM_JUMP       6
8 #define ANIM_LAND       7
9 #define ANIM_PAIN       8
10 #define ANIM_MEELE      9
11 #define ANIM_SWIM       10
12 #define ANIM_ROAM       11
13
14 .float animflag;
15 .entity wkr_spawn;
16
17 #define WALKER_MIN '-70 -70 0'
18 #define WALKER_MAX '70 70 95'
19
20 #define WALKER_PATH(s,e) pathlib_astar(s,e)
21
22 float walker_meele_dmg;
23 float walker_meele_force;
24
25 float walker_speed_stop;
26 float walker_speed_walk;
27 float walker_speed_run;
28 float walker_speed_jump;
29 float walker_speed_roam;
30 float walker_speed_swim;
31
32 float walker_std_rocket_dmg;
33 float walker_std_rocket_radius;
34 float walker_std_rocket_force;
35 float walker_std_rocket_speed;
36 float walker_std_rocket_turnrate;
37
38 void walker_loadcvars()
39 {
40     walker_meele_dmg    = autocvar_g_turrets_unit_walker_std_meele_dmg;
41     walker_meele_force  = autocvar_g_turrets_unit_walker_std_meele_force;
42
43     walker_speed_stop   = autocvar_g_turrets_unit_walker_speed_stop;
44     walker_speed_walk   = autocvar_g_turrets_unit_walker_speed_walk;
45     walker_speed_run    = autocvar_g_turrets_unit_walker_speed_run;
46     walker_speed_jump   = autocvar_g_turrets_unit_walker_speed_jump;
47     walker_speed_roam   = autocvar_g_turrets_unit_walker_speed_roam;
48     walker_speed_swim   = autocvar_g_turrets_unit_walker_speed_swim;
49
50     walker_std_rocket_dmg       = autocvar_g_turrets_unit_walker_std_rocket_dmg;
51     walker_std_rocket_radius    = autocvar_g_turrets_unit_walker_std_rocket_radius;
52     walker_std_rocket_force     = autocvar_g_turrets_unit_walker_std_rocket_force;
53     walker_std_rocket_speed     = autocvar_g_turrets_unit_walker_std_rocket_speed;
54     walker_std_rocket_turnrate  = autocvar_g_turrets_unit_walker_std_rocket_turnrate;
55
56 }
57
58
59
60 float walker_firecheck()
61 {
62     if (self.animflag == ANIM_MEELE)
63         return 0;
64
65     return turret_stdproc_firecheck();
66 }
67
68 void walker_meele_do_dmg()
69 {
70     vector where;
71     entity e;
72     makevectors(self.angles);
73     where = self.origin + v_forward * 128;
74
75     //w_deathtypestring = "tried to hug the cute spider thingy.";
76     e = findradius(where,32);
77     while (e)
78     {
79         if (turret_validate_target(self,e,self.target_validate_flags))
80             if (e != self && e.owner != self)
81                 Damage(e, self, self, walker_meele_dmg ,DEATH_TURRET,'0 0 0', v_forward * walker_meele_force);
82
83         e = e.chain;
84     }
85 }
86 void walker_setnoanim()
87 {
88     self.frame = ANIM_NO;
89     self.animflag = self.owner.frame;
90     dprint("walker_setnoanim\n");
91
92 }
93
94 void walker_dly_meele_do_dmg()
95 {
96     walker_meele_do_dmg();
97     dprint("walker_dly_meele_do_dmg\n");
98
99 }
100
101 void walker_animate()
102 {
103     vector real_angle;
104     float  vz;
105
106     real_angle = vectoangles(self.steerto) - self.angles;
107     vz         = self.velocity_z;
108
109     if (self.tur_head.frame != 0)
110         self.tur_head.frame = self.tur_head.frame +1;
111
112     if (self.tur_head.frame > 12)
113         self.tur_head.frame = 0;
114
115     switch (self.animflag)
116     {
117
118     case ANIM_NO:
119         self.frame = 0;
120         movelib_beak_simple(walker_speed_stop);
121         break;
122
123     /*
124     case ANIM_REVERSE:
125         if ((self.frame < 5) || (self.frame > 25))
126             self.frame = 25;
127
128         self.frame = self.frame -1;
129         movelib_move_simple(v_forward * -1, walker_speed_walk, 0.6);
130
131         if (self.frame < 5)
132             self.frame = 25;
133
134         break;
135     */
136
137     case ANIM_TURN:
138         self.frame = ANIM_TURN;
139         self.angles_y += bound(-15, shortangle_f(real_angle_y, self.angles_y), 15);
140         movelib_beak_simple(walker_speed_stop);
141         break;
142
143     case ANIM_WALK:
144         self.frame = ANIM_WALK;
145         self.angles_y += bound(-10, shortangle_f(real_angle_y, self.angles_y), 10);
146         movelib_move_simple(v_forward, walker_speed_walk, 0.6);
147         break;
148
149     case ANIM_RUN:
150         self.frame = ANIM_RUN;
151         self.angles_y += bound(-5, shortangle_f(real_angle_y, self.angles_y), 5);
152         movelib_move_simple(v_forward, walker_speed_run, 0.6);
153         break;
154
155     case ANIM_STRAFE_L:
156         self.frame = ANIM_STRAFE_L;
157         self.angles_y += bound(-2.5, shortangle_f(real_angle_y, self.angles_y), 2.5);
158         movelib_move_simple(v_right * -1, walker_speed_walk, 0.8);
159         break;
160
161     case ANIM_STRAFE_R:
162         self.frame = ANIM_STRAFE_R;
163         self.angles_y += bound(-2.5, shortangle_f(real_angle_y, self.angles_y), 2.5);
164         movelib_move_simple(v_right, walker_speed_walk, 0.8);
165         break;
166
167     case ANIM_JUMP:
168         self.frame = ANIM_JUMP;
169         self.velocity += '0 0 1' * walker_speed_jump;
170         break;
171
172     case ANIM_LAND:
173         self.frame = ANIM_LAND;
174         break;
175
176     case ANIM_PAIN:
177         if(self.frame != ANIM_PAIN)
178             defer(0.25,walker_setnoanim);
179
180         self.frame = ANIM_PAIN;
181
182         break;
183
184     case ANIM_MEELE:
185         if(self.frame != ANIM_MEELE)
186         {
187             defer(0.41, walker_setnoanim);
188             defer(0.21, walker_dly_meele_do_dmg);
189         }
190
191         self.frame = ANIM_MEELE;
192         movelib_beak_simple(walker_speed_stop);
193         break;
194
195     case ANIM_SWIM:
196         self.frame = ANIM_SWIM;
197         self.angles_y += bound(-10, shortangle_f(real_angle_y, self.angles_y), 10);
198         self.angles_x += bound(-10, shortangle_f(real_angle_x, self.angles_x), 10);
199         movelib_move_simple(v_forward, walker_speed_swim, 0.3);
200         vz = self.velocity_z + sin(time * 4) * 8;
201         break;
202
203     case ANIM_ROAM:
204         self.frame = ANIM_ROAM;
205         self.angles_y += bound(-5, shortangle_f(real_angle_y, self.angles_y), 5);
206         movelib_move_simple(v_forward ,walker_speed_roam, 0.5);
207         break;
208
209     }
210
211     self.velocity_z = vz;
212
213     if (self.flags & FL_ONGROUND)
214         movelib_groundalign4point(300, 100, 0.25);
215
216 }
217
218
219 void walker_rocket_explode()
220 {
221     vector org2;
222
223     if (self.event_damage != SUB_Null)
224     {
225         self.event_damage = SUB_Null;
226         self.think = walker_rocket_explode;
227         self.nextthink = time;
228         return;
229     }
230
231     sound (self, CHAN_PROJECTILE, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM);
232     org2 = findbetterlocation (self.origin, 16);
233
234     pointparticles(particleeffectnum("rocket_explode"), org2, '0 0 0', 1);
235     RadiusDamage (self, self.owner, walker_std_rocket_dmg, 0, walker_std_rocket_radius, world,walker_std_rocket_force, DEATH_TURRET, world);
236
237     remove (self);
238 }
239
240 void walker_rocket_damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector vforce)
241 {
242     self.health = self.health - damage;
243     self.velocity = self.velocity + vforce;
244     if (self.health <= 0)
245         walker_rocket_explode();
246 }
247
248 #define WALKER_ROCKET_MOVE movelib_move_simple(newdir, walker_std_rocket_speed, walker_std_rocket_turnrate); UpdateCSQCProjectile(self)
249 void walker_rocket_loop();
250 void walker_rocket_think()
251 {
252     vector newdir;
253     float edist;
254     float itime;
255     float m_speed;
256
257     self.nextthink = time;
258
259     edist = vlen(self.enemy.origin - self.origin);
260
261     // Simulate crude guidance
262     if (self.cnt < time)
263     {
264         if (edist < 1000)
265             self.tur_shotorg = randomvec() * min(edist,64);
266         else
267             self.tur_shotorg = randomvec() * min(edist,256);
268
269         self.cnt = time + 0.5;
270     }
271
272     if (edist < 256)
273         self.tur_shotorg = '0 0 0';
274
275
276     if (self.tur_health < time)
277     {
278         self.think = walker_rocket_explode;
279         self.nextthink = time;
280         return;
281     }
282
283     if (self.shot_dmg != 1337)
284         if (random() < 0.01)
285         {
286             walker_rocket_loop();
287             return;
288         }
289
290     m_speed = vlen(self.velocity);
291
292     // Enemy dead? just keep on the current heading then.
293     if ((self.enemy == world) || (self.enemy.deadflag != DEAD_NO))
294     {
295         // Make sure we dont return to tracking a respawned entity
296         self.enemy = world;
297     }
298
299     if (self.enemy)
300     {
301         itime = max(edist / m_speed,1);
302         newdir = steerlib_pull(self.enemy.origin + self.tur_shotorg);
303     }
304     else
305     {
306         newdir  = normalize(self.velocity);
307     }
308
309     WALKER_ROCKET_MOVE;
310 }
311
312 void walker_rocket_loop3()
313 {
314     vector newdir;
315     self.nextthink = time;
316
317     if (self.tur_health < time)
318     {
319         self.think = walker_rocket_explode;
320         return;
321     }
322
323     if (vlen(self.origin - self.tur_shotorg) < 128 )
324     {
325         self.think = walker_rocket_think;
326         return;
327     }
328
329     newdir = steerlib_pull(self.tur_shotorg);
330     WALKER_ROCKET_MOVE;
331
332     self.angles = vectoangles(self.velocity);
333 }
334
335 void walker_rocket_loop2()
336 {
337     vector newdir;
338
339     self.nextthink = time;
340
341     if (self.tur_health < time)
342     {
343         self.think = walker_rocket_explode;
344         return;
345     }
346
347     if (vlen(self.origin - self.tur_shotorg) < 128 )
348     {
349         self.tur_shotorg = self.origin - '0 0 200';
350         self.think = walker_rocket_loop3;
351         return;
352     }
353
354     newdir = steerlib_pull(self.tur_shotorg);
355     WALKER_ROCKET_MOVE;
356 }
357
358 void walker_rocket_loop()
359 {
360     self.nextthink = time;
361     self.tur_shotorg = self.origin + '0 0 400';
362     self.think = walker_rocket_loop2;
363     self.shot_dmg = 1337;
364 }
365
366 void walker_fire_rocket(vector org)
367 {
368
369     entity rocket;
370
371
372     //self.angles_x *= -1;
373     fixedmakevectors(self.angles);
374     //self.angles_x *= -1;
375
376     te_explosion (org);
377
378     rocket = spawn ();
379     setorigin(rocket, org);
380
381     sound (self, CHAN_WEAPON, "weapons/hagar_fire.wav", VOL_BASE, ATTN_NORM);
382     setsize (rocket, '-3 -3 -3', '3 3 3'); // give it some size so it can be shot
383
384     rocket.classname          = "walker_rocket";
385     rocket.owner              = self;
386
387     rocket.bot_dodge          = TRUE;
388     rocket.bot_dodgerating    = 50;
389
390     rocket.takedamage         = DAMAGE_YES;
391
392     rocket.damageforcescale   = 2;
393     rocket.health             = 25;
394     rocket.tur_shotorg        = randomvec() * 512;
395     rocket.cnt                = time + 1;
396     rocket.enemy              = self.enemy;
397
398     if (random() < 0.01)
399         rocket.think          = walker_rocket_loop;
400     else
401         rocket.think          = walker_rocket_think;
402
403     rocket.event_damage       = walker_rocket_damage;
404
405     rocket.nextthink          = time;// + 0.25;
406     rocket.movetype           = MOVETYPE_FLY;
407     rocket.velocity           = normalize((v_forward + v_up * 0.5) + (randomvec() * 0.2)) * walker_std_rocket_speed;
408     rocket.angles             = vectoangles(rocket.velocity);
409     rocket.touch              = walker_rocket_explode;
410     rocket.flags              = FL_PROJECTILE;
411     rocket.solid              = SOLID_BBOX;
412     rocket.tur_health         = time + 9;
413
414     CSQCProjectile(rocket, FALSE, PROJECTILE_ROCKET, FALSE); // no culling, has fly sound
415 }
416
417 void rv_think()
418 {
419     float f;
420     vector org;
421     entity oldself;
422
423     if (self.owner.deadflag != DEAD_NO)
424     {
425         remove(self);
426         return;
427     }
428
429     self.cnt = self.cnt -1;
430
431     if (self.cnt < 0)
432     {
433         remove(self);
434         return;
435     }
436
437     if (self.cnt > 1)
438         f = gettagindex(self.owner,"tag_rocket01");
439     else
440         f = gettagindex(self.owner,"tag_rocket02");
441
442     org = gettaginfo(self.owner,f);
443
444     self.nextthink = time + 0.2;
445     oldself = self;
446     self = self.owner;
447     walker_fire_rocket(org);
448     self = oldself;
449 }
450
451 void walker_move_path()
452 {
453     // Are we close enougth to a path node to switch to the next?
454     if (vlen(self.origin  - self.pathcurrent.origin) < 64)
455         if (self.pathcurrent.path_next == world)
456         {
457             // Path endpoint reached
458             pathlib_deletepath(self.pathcurrent.owner);
459             self.pathcurrent = world;
460
461             if (self.pathgoal)
462             {
463                 if (self.pathgoal.use)
464                     self.pathgoal.use();
465
466                 if (self.pathgoal.enemy)
467                 {
468                     self.pathcurrent = WALKER_PATH(self.pathgoal.origin,self.pathgoal.enemy.origin);
469                     self.pathgoal = self.pathgoal.enemy;
470                 }
471             }
472             else
473                 self.pathgoal = world;
474         }
475         else
476             self.pathcurrent = self.pathcurrent.path_next;
477
478     switch (self.waterlevel)
479     {
480     case 0:
481         self.animflag = ANIM_WALK;
482     case 1:
483     case 2:
484         if (self.animflag == ANIM_WALK)
485             self.animflag = ANIM_WALK;
486         else
487             self.animflag = ANIM_SWIM;
488         break;
489     case 3:
490         self.animflag = ANIM_SWIM;
491     }
492
493     self.moveto = self.pathcurrent.origin;
494     self.steerto = steerlib_attract2(self.moveto,0.5,500,0.95);
495
496 }
497
498 void walker_move_enemy()
499 {
500     switch (self.waterlevel)
501     {
502     case 0:
503         if (self.tur_dist_enemy > 500)
504             self.animflag = ANIM_RUN;
505         else
506             self.animflag = ANIM_WALK;
507     case 1:
508     case 2:
509         if (self.animflag != ANIM_SWIM)
510             self.animflag = ANIM_WALK;
511         else
512             self.animflag = ANIM_SWIM;
513         break;
514     case 3:
515         self.animflag = ANIM_SWIM;
516     }
517
518     self.moveto = self.enemy.origin;
519     self.steerto = steerlib_attract2(self.moveto,0.5,500,0.95);
520
521 }
522
523 void walker_move_idle_pause()
524 {
525     self.moveto   = self.origin;
526     self.steerto  = v_forward;
527     self.animflag = ANIM_NO;
528 }
529
530 void walker_move_idle_roam()
531 {
532 }
533
534 void walker_move_idle()
535 {
536 }
537
538 float walker_attack_meele()
539 {
540
541     vector wish_angle;
542
543
544     if (self.animflag == ANIM_SWIM || self.animflag == ANIM_MEELE)
545         return 0;
546
547     wish_angle = angleofs(self,self.enemy);
548
549     if (self.tur_dist_enemy > autocvar_g_turrets_unit_walker_std_meele_range)
550         return 0;
551     else
552         if (fabs(wish_angle_y) > 15)
553             return 0;
554
555     self.moveto   = self.enemy.origin;
556     self.steerto  = steerlib_attract2(self.moveto,0.5,500,0.95);
557     self.animflag = ANIM_MEELE;
558
559     return 1;
560 }
561
562 float walker_attack_rockets()
563 {
564     if (self.tur_head.attack_finished_single > time)
565         return 0;
566
567     if (self.tur_dist_enemy < autocvar_g_turrets_unit_walker_std_rockets_range_min)
568         return 0;
569
570     if (self.tur_dist_enemy > autocvar_g_turrets_unit_walker_std_rockets_range)
571         return 0;
572
573     entity rv;
574
575     rv           = spawn();
576     rv.think     = rv_think;
577     rv.nextthink = time;
578     rv.cnt       = 4;
579     rv.owner     = self;
580
581     self.tur_head.attack_finished_single = time + autocvar_g_turrets_unit_walker_std_rocket_refire;
582
583     return 1;
584 }
585
586 void walker_postthink()
587 {
588
589     //self.angles_x *= -1;
590     fixedmakevectors(self.angles);
591     //self.angles_x *= -1;
592
593     if ((self.spawnflags & TSF_NO_PATHBREAK) && self.pathcurrent)
594         walker_move_path();
595     else if (self.enemy == world)
596     {
597         if(self.pathcurrent)
598             walker_move_path();
599         else
600             walker_move_idle_pause();
601     }
602     else
603     {
604         if not (self.animflag == ANIM_MEELE)
605             if not (walker_attack_rockets())
606                 walker_attack_meele();
607
608         if not (self.animflag == ANIM_MEELE)
609             walker_move_enemy();
610     }
611
612
613     walker_animate();
614 }
615
616 void walker_attack()
617 {
618     sound (self, CHAN_WEAPON, "weapons/uzi_fire.wav", VOL_BASE, ATTN_NORM);
619     fireBallisticBullet (self.tur_shotorg, self.tur_shotdir_updated,self.shot_spread, self.shot_speed, 5, self.shot_dmg, 0, self.shot_force, DEATH_TURRET, 0, 1, autocvar_g_balance_uzi_bulletconstant);
620     endFireBallisticBullet();
621     if (self.uzi_bulletcounter == 2)
622     {
623
624                 UziFlash();
625                 setattachment(self.muzzle_flash, self.tur_head, "tag_fire");
626
627         self.uzi_bulletcounter = 0;
628     }
629
630     self.uzi_bulletcounter = self.uzi_bulletcounter + 1;
631     self.tur_head.frame    = self.tur_head.frame + 1;
632 }
633
634
635 void walker_respawnhook()
636 {
637     vector vtmp;
638     entity e;
639
640     // Respawn is called & first spawn to, to set team. need to make sure we do not move the initial spawn.
641     if(self.movetype  != MOVETYPE_WALK)
642                 return;
643                 
644     setorigin(self, self.wkr_spawn.origin);
645
646     self.angles = self.wkr_spawn.angles;
647     vtmp = self.wkr_spawn.origin;
648     vtmp_z += self.wkr_spawn.maxs_z;
649     setorigin(self,vtmp);
650
651     if (self.target != "")
652     {
653         e = find(world,targetname,self.target);
654         if (!e)
655         {
656             dprint("Warning! initital waypoint for Walker does NOT exsist!\n");
657             self.target = "";
658         }
659
660         if (e.classname != "turret_checkpoint")
661             dprint("Warning: not a turrret path\n");
662         else
663         {
664             self.pathcurrent = WALKER_PATH(self.origin,e.origin);
665             self.pathgoal = e;
666         }
667     }
668 }
669
670 void walker_diehook()
671 {
672     turret_trowgib2(self.origin, self.velocity + v_up * 200, '-0.6 -0.2 -02', self,time + random() * 1);
673     turret_trowgib2(self.origin + '0 0 64', self.velocity + v_forward * 150 + v_up * 150, '-0.2 -0.2 -02', self.tur_head, 3 + time + random() * 2);
674
675     if (self.pathcurrent)
676         pathlib_deletepath(self.pathcurrent.owner);
677
678     self.pathcurrent = world;
679
680     if (self.damage_flags & TFL_DMG_DEATH_NORESPAWN)
681         remove(self.wkr_spawn);
682
683 }
684
685 void turret_walker_dinit()
686 {
687
688     entity e;
689
690     if (self.netname == "")      self.netname     = "Walker Turret";
691     self.wkr_spawn = spawn();
692
693     self.ammo_flags = TFL_AMMO_BULLETS | TFL_AMMO_RECHARGE | TFL_AMMO_RECIVE;
694     self.turrcaps_flags = TFL_TURRCAPS_PLAYERKILL | TFL_TURRCAPS_MOVE ;
695     self.aim_flags = TFL_AIM_LEAD;
696
697     if (autocvar_g_antilag_bullets)
698         self.turrcaps_flags |= TFL_TURRCAPS_HITSCAN;
699     else
700         self.aim_flags      |= TFL_AIM_SHOTTIMECOMPENSATE;
701
702
703     self.turret_respawnhook = walker_respawnhook;
704     self.turret_diehook = walker_diehook;
705
706     self.ticrate = 0.05;
707     if (turret_stdproc_init("walker_std",FALSE,"models/turrets/walker_body.md3","models/turrets/walker_head_minigun.md3") == 0)
708     {
709         remove(self);
710         return;
711     }
712
713     if (!turret_tag_fire_update())
714         dprint("Warning: Turret ",self.classname, " faild to initialize md3 tags\n");
715
716     self.damage_flags |= TFL_DMG_DEATH_NOGIBS;
717     self.target_select_flags   = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_RANGELIMTS | TFL_TARGETSELECT_TEAMCHECK | TFL_TARGETSELECT_LOS;
718     self.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_RANGELIMTS | TFL_TARGETSELECT_TEAMCHECK | TFL_TARGETSELECT_LOS;
719
720     self.iscreature = TRUE;
721     self.movetype   = MOVETYPE_WALK;
722     self.solid      = SOLID_SLIDEBOX;
723     self.takedamage = DAMAGE_AIM;
724
725     setmodel(self.wkr_spawn,"models/turrets/walker_spawn.md3");
726
727     self.wkr_spawn.angles   = self.angles;
728     self.wkr_spawn.solid    = SOLID_NOT;
729
730     setsize(self, WALKER_MIN, WALKER_MAX);
731
732     setorigin(self,self.origin);
733     //traceline(self.origin + '0 0 128', self.origin - '0 0 10000', MOVE_NORMAL, self);
734     tracebox(self.origin + '0 0 128', self.mins,self.maxs,self.origin - '0 0 10000', MOVE_NORMAL, self);
735
736     setorigin(self.wkr_spawn, trace_endpos + '0 0 4');
737     setorigin(self, self.wkr_spawn.origin);
738
739     self.idle_aim = '0 0 0';
740     self.turret_firecheckfunc = walker_firecheck;
741     self.turret_firefunc      = walker_attack;
742     self.turret_postthink     = walker_postthink;
743
744     if (self.target != "")
745     {
746         e = find(world,targetname,self.target);
747         if (!e)
748         {
749             dprint("Initital waypoint for walker does NOT exsist, fix your map!\n");
750             self.target = "";
751         }
752
753         if (e.classname != "turret_checkpoint")
754             dprint("Warning: not a turrret path\n");
755         else
756         {
757             self.pathcurrent = WALKER_PATH(self.origin,e.origin);
758             self.pathgoal = e;
759         }
760     }
761 }
762
763
764 void spawnfunc_turret_walker()
765 {
766     walker_loadcvars();
767
768     g_turrets_common_precash();
769
770     precache_model ("models/turrets/walker_head_minigun.md3");
771     precache_model ("models/turrets/walker_body.md3");
772     precache_model ("models/turrets/walker_props.md3");
773     precache_model ("models/turrets/walker_spawn.md3");
774     precache_model ( "models/turrets/rocket.md3");
775     precache_sound ( "weapons/rocket_impact.wav" );
776
777     self.think = turret_walker_dinit;
778     self.nextthink = time + 0.5;
779 }