Merge branch 'master' into Mario/turrets
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / turrets / unit / walker.qc
1 #ifdef REGISTER_TURRET
2 REGISTER_TURRET(
3 /* TUR_##id   */ WALKER,
4 /* function   */ t_walker,
5 /* spawnflags */ TUR_FLAG_PLAYER | TUR_FLAG_MOVE,
6 /* mins,maxs  */ '-70 -70 0', '70 70 95',
7 /* model          */ "walker_body.md3",
8 /* head_model */ "walker_head_minigun.md3",
9 /* netname        */ "walker",
10 /* fullname   */ _("Walker Turret")
11 );
12 #else
13 #ifdef SVQC
14 float autocvar_g_turrets_unit_walker_melee_damage;
15 float autocvar_g_turrets_unit_walker_melee_force;
16 float autocvar_g_turrets_unit_walker_melee_range;
17 float autocvar_g_turrets_unit_walker_rocket_damage;
18 float autocvar_g_turrets_unit_walker_rocket_radius;
19 float autocvar_g_turrets_unit_walker_rocket_force;
20 float autocvar_g_turrets_unit_walker_rocket_speed;
21 float autocvar_g_turrets_unit_walker_rocket_range;
22 float autocvar_g_turrets_unit_walker_rocket_range_min;
23 float autocvar_g_turrets_unit_walker_rocket_refire;
24 float autocvar_g_turrets_unit_walker_rocket_turnrate;
25 float autocvar_g_turrets_unit_walker_speed_stop;
26 float autocvar_g_turrets_unit_walker_speed_walk;
27 float autocvar_g_turrets_unit_walker_speed_run;
28 float autocvar_g_turrets_unit_walker_speed_jump;
29 float autocvar_g_turrets_unit_walker_speed_swim;
30 float autocvar_g_turrets_unit_walker_speed_roam;
31 float autocvar_g_turrets_unit_walker_turn;
32 float autocvar_g_turrets_unit_walker_turn_walk;
33 float autocvar_g_turrets_unit_walker_turn_strafe;
34 float autocvar_g_turrets_unit_walker_turn_swim;
35 float autocvar_g_turrets_unit_walker_turn_run;
36
37 #define ANIM_NO         0
38 #define ANIM_TURN       1
39 #define ANIM_WALK       2
40 #define ANIM_RUN        3
41 #define ANIM_STRAFE_L   4
42 #define ANIM_STRAFE_R   5
43 #define ANIM_JUMP       6
44 #define ANIM_LAND       7
45 #define ANIM_PAIN       8
46 #define ANIM_MELEE      9
47 #define ANIM_SWIM       10
48 #define ANIM_ROAM       11
49
50 .float animflag;
51 .float idletime;
52
53 #define WALKER_PATH(s,e) pathlib_astar(s,e)
54
55 float walker_firecheck()
56 {
57         if (self.animflag == ANIM_MELEE)
58                 return 0;
59
60         return turret_firecheck();
61 }
62
63 void walker_melee_do_dmg()
64 {
65         vector where;
66         entity e;
67
68         makevectors(self.angles);
69         where = self.origin + v_forward * 128;
70
71         e = findradius(where,32);
72         while (e)
73         {
74                 if (turret_validate_target(self, e, self.target_validate_flags))
75                         if (e != self && e.owner != self)
76                                 Damage(e, self, self, (autocvar_g_turrets_unit_walker_melee_damage), DEATH_TURRET_WALK_MELEE, '0 0 0', v_forward * (autocvar_g_turrets_unit_walker_melee_force));
77
78                 e = e.chain;
79         }
80 }
81
82 void walker_setnoanim()
83 {
84         turrets_setframe(ANIM_NO, false);
85         self.animflag = self.frame;
86 }
87 void walker_rocket_explode()
88 {
89         RadiusDamage (self, self.owner, (autocvar_g_turrets_unit_walker_rocket_damage), 0, (autocvar_g_turrets_unit_walker_rocket_radius), self, world, (autocvar_g_turrets_unit_walker_rocket_force), DEATH_TURRET_WALK_ROCKET, world);
90         remove (self);
91 }
92
93 void walker_rocket_damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector vforce)
94 {
95         self.health = self.health - damage;
96         self.velocity = self.velocity + vforce;
97
98         if (self.health <= 0)
99                 W_PrepareExplosionByDamage(self.owner, walker_rocket_explode);
100 }
101
102 #define WALKER_ROCKET_MOVE movelib_move_simple(newdir, (autocvar_g_turrets_unit_walker_rocket_speed), (autocvar_g_turrets_unit_walker_rocket_turnrate)); UpdateCSQCProjectile(self)
103 void walker_rocket_loop();
104 void walker_rocket_think()
105 {
106         vector newdir;
107         float edist;
108         float itime;
109         float m_speed;
110
111         self.nextthink = time;
112
113         edist = vlen(self.enemy.origin - self.origin);
114
115         // Simulate crude guidance
116         if (self.cnt < time)
117         {
118                 if (edist < 1000)
119                         self.tur_shotorg = randomvec() * min(edist, 64);
120                 else
121                         self.tur_shotorg = randomvec() * min(edist, 256);
122
123                 self.cnt = time + 0.5;
124         }
125
126         if (edist < 128)
127                 self.tur_shotorg = '0 0 0';
128
129         if (self.max_health < time)
130         {
131                 self.think        = walker_rocket_explode;
132                 self.nextthink  = time;
133                 return;
134         }
135
136         if (self.shot_dmg != 1337 && random() < 0.01)
137         {
138                 walker_rocket_loop();
139                 return;
140         }
141
142         m_speed = vlen(self.velocity);
143
144         // Enemy dead? just keep on the current heading then.
145         if (self.enemy == world || self.enemy.deadflag != DEAD_NO)
146                 self.enemy = world;
147
148         if (self.enemy)
149         {
150                 itime = max(edist / m_speed, 1);
151                 newdir = steerlib_pull(self.enemy.origin + self.tur_shotorg);
152         }
153         else
154                 newdir  = normalize(self.velocity);
155
156         WALKER_ROCKET_MOVE;
157 }
158
159 void walker_rocket_loop3()
160 {
161         vector newdir;
162         self.nextthink = time;
163
164         if (self.max_health < time)
165         {
166                 self.think = walker_rocket_explode;
167                 return;
168         }
169
170         if (vlen(self.origin - self.tur_shotorg) < 100 )
171         {
172                 self.think = walker_rocket_think;
173                 return;
174         }
175
176         newdir = steerlib_pull(self.tur_shotorg);
177         WALKER_ROCKET_MOVE;
178
179         self.angles = vectoangles(self.velocity);
180 }
181
182 void walker_rocket_loop2()
183 {
184         vector newdir;
185
186         self.nextthink = time;
187
188         if (self.max_health < time)
189         {
190                 self.think = walker_rocket_explode;
191                 return;
192         }
193
194         if (vlen(self.origin - self.tur_shotorg) < 100 )
195         {
196                 self.tur_shotorg = self.origin - '0 0 200';
197                 self.think = walker_rocket_loop3;
198                 return;
199         }
200
201         newdir = steerlib_pull(self.tur_shotorg);
202         WALKER_ROCKET_MOVE;
203 }
204
205 void walker_rocket_loop()
206 {
207         self.nextthink = time;
208         self.tur_shotorg = self.origin + '0 0 300';
209         self.think = walker_rocket_loop2;
210         self.shot_dmg = 1337;
211 }
212
213 void walker_fire_rocket(vector org)
214 {
215         entity rocket;
216
217         fixedmakevectors(self.angles);
218
219         te_explosion (org);
220
221         rocket = spawn ();
222         setorigin(rocket, org);
223
224         sound (self, CH_WEAPON_A, "weapons/hagar_fire.wav", VOL_BASE, ATTEN_NORM);
225         setsize (rocket, '-3 -3 -3', '3 3 3'); // give it some size so it can be shot
226
227         rocket.classname                  = "walker_rocket";
228         rocket.owner                      = self;
229         rocket.bot_dodge                  = true;
230         rocket.bot_dodgerating  = 50;
231         rocket.takedamage                = DAMAGE_YES;
232         rocket.damageforcescale   = 2;
233         rocket.health                    = 25;
234         rocket.tur_shotorg              = randomvec() * 512;
235         rocket.cnt                              = time + 1;
236         rocket.enemy                      = self.enemy;
237
238         if (random() < 0.01)
239                 rocket.think              = walker_rocket_loop;
240         else
241                 rocket.think              = walker_rocket_think;
242
243         rocket.event_damage        = walker_rocket_damage;
244
245         rocket.nextthink                  = time;
246         rocket.movetype            = MOVETYPE_FLY;
247         rocket.velocity            = normalize((v_forward + v_up * 0.5) + (randomvec() * 0.2)) * (autocvar_g_turrets_unit_walker_rocket_speed);
248         rocket.angles                    = vectoangles(rocket.velocity);
249         rocket.touch                      = walker_rocket_explode;
250         rocket.flags                      = FL_PROJECTILE;
251         rocket.solid                      = SOLID_BBOX;
252         rocket.max_health                = time + 9;
253         rocket.missile_flags = MIF_SPLASH | MIF_PROXY | MIF_GUIDED_HEAT;
254
255         CSQCProjectile(rocket, false, PROJECTILE_ROCKET, false); // no culling, has fly sound
256 }
257
258 .vector enemy_last_loc;
259 .float enemy_last_time;
260 void walker_move_to(vector _target, float _dist)
261 {
262         switch (self.waterlevel)
263         {
264                 case WATERLEVEL_NONE:
265                         if (_dist > 500)
266                                 self.animflag = ANIM_RUN;
267                         else
268                                 self.animflag = ANIM_WALK;
269                 case WATERLEVEL_WETFEET:
270                 case WATERLEVEL_SWIMMING:
271                         if (self.animflag != ANIM_SWIM)
272                                 self.animflag = ANIM_WALK;
273                         else
274                                 self.animflag = ANIM_SWIM;
275                         break;
276                 case WATERLEVEL_SUBMERGED:
277                         self.animflag = ANIM_SWIM;
278         }
279
280         self.moveto = _target;
281         self.steerto = steerlib_attract2(self.moveto, 0.5, 500, 0.95);
282
283         if(self.enemy)
284         {
285                 self.enemy_last_loc = _target;
286                 self.enemy_last_time = time;
287         }
288 }
289
290 //#define WALKER_FANCYPATHING
291
292 void walker_move_path()
293 {
294 #ifdef WALKER_FANCYPATHING
295         // Are we close enougth to a path node to switch to the next?
296         if (vlen(self.origin  - self.pathcurrent.origin) < 64)
297                 if (self.pathcurrent.path_next == world)
298                 {
299                         // Path endpoint reached
300                         pathlib_deletepath(self.pathcurrent.owner);
301                         self.pathcurrent = world;
302
303                         if (self.pathgoal)
304                         {
305                                 if (self.pathgoal.use)
306                                         self.pathgoal.use();
307
308                                 if (self.pathgoal.enemy)
309                                 {
310                                         self.pathcurrent = WALKER_PATH(self.pathgoal.origin,self.pathgoal.enemy.origin);
311                                         self.pathgoal = self.pathgoal.enemy;
312                                 }
313                         }
314                         else
315                                 self.pathgoal = world;
316                 }
317                 else
318                         self.pathcurrent = self.pathcurrent.path_next;
319
320         self.moveto = self.pathcurrent.origin;
321         self.steerto = steerlib_attract2(self.moveto,0.5,500,0.95);
322         walker_move_to(self.moveto, 0);
323
324 #else
325         if (vlen(self.origin - self.pathcurrent.origin) < 64)
326                 self.pathcurrent = self.pathcurrent.enemy;
327
328         if(!self.pathcurrent)
329                 return;
330
331         self.moveto = self.pathcurrent.origin;
332         self.steerto = steerlib_attract2(self.moveto, 0.5, 500, 0.95);
333         walker_move_to(self.moveto, 0);
334 #endif
335 }
336
337 void spawnfunc_turret_walker() { if(!turret_initialize(TUR_WALKER)) remove(self); }
338
339 float t_walker(float req)
340 {
341         switch(req)
342         {
343                 case TR_ATTACK:
344                 {
345                         sound (self, CH_WEAPON_A, "weapons/uzi_fire.wav", VOL_BASE, ATTEN_NORM);
346                         fireBullet (self.tur_shotorg, self.tur_shotdir_updated, self.shot_spread, 0, self.shot_dmg, self.shot_force, DEATH_TURRET_WALK_GUN, 0);
347                         pointparticles(particleeffectnum("laser_muzzleflash"), self.tur_shotorg, self.tur_shotdir_updated * 1000, 1);
348
349                         return true;
350                 }
351                 case TR_THINK:
352                 {
353                         fixedmakevectors(self.angles);
354
355                         if (self.spawnflags & TSF_NO_PATHBREAK && self.pathcurrent)
356                                 walker_move_path();
357                         else if (self.enemy == world)
358                         {
359                                 if(self.pathcurrent)
360                                         walker_move_path();
361                                 else
362                                 {
363                                         if(self.enemy_last_time != 0)
364                                         {
365                                                 if(vlen(self.origin - self.enemy_last_loc) < 128 || time - self.enemy_last_time > 10)
366                                                         self.enemy_last_time = 0;
367                                                 else
368                                                         walker_move_to(self.enemy_last_loc, 0);
369                                         }
370                                         else
371                                         {
372                                                 if(self.animflag != ANIM_NO)
373                                                 {
374                                                         traceline(self.origin + '0 0 64', self.origin + '0 0 64' + v_forward * 128, MOVE_NORMAL, self);
375
376                                                         if(trace_fraction != 1.0)
377                                                                 self.tur_head.idletime = -1337;
378                                                         else
379                                                         {
380                                                                 traceline(trace_endpos, trace_endpos - '0 0 256', MOVE_NORMAL, self);
381                                                                 if(trace_fraction == 1.0)
382                                                                         self.tur_head.idletime = -1337;
383                                                         }
384
385                                                         if(self.tur_head.idletime == -1337)
386                                                         {
387                                                                 self.moveto = self.origin + randomvec() * 256;
388                                                                 self.tur_head.idletime = 0;
389                                                         }
390
391                                                         self.moveto = self.moveto * 0.9 + ((self.origin + v_forward * 500) + randomvec() * 400) * 0.1;
392                                                         self.moveto_z = self.origin_z + 64;
393                                                         walker_move_to(self.moveto, 0);
394                                                 }
395
396                                                 if(self.idletime < time)
397                                                 {
398                                                         if(random() < 0.5 || !(self.spawnflags & TSL_ROAM))
399                                                         {
400                                                                 self.idletime = time + 1 + random() * 5;
401                                                                 self.moveto = self.origin;
402                                                                 self.animflag = ANIM_NO;
403                                                         }
404                                                         else
405                                                         {
406                                                                 self.animflag = ANIM_WALK;
407                                                                 self.idletime = time + 4 + random() * 2;
408                                                                 self.moveto = self.origin + randomvec() * 256;
409                                                                 self.tur_head.moveto = self.moveto;
410                                                                 self.tur_head.idletime = 0;
411                                                         }
412                                                 }
413                                         }
414                                 }
415                         }
416                         else
417                         {
418                                 if (self.tur_dist_enemy < (autocvar_g_turrets_unit_walker_melee_range) && self.animflag != ANIM_MELEE)
419                                 {
420                                         vector wish_angle;
421
422                                         wish_angle = angleofs(self, self.enemy);
423                                         if (self.animflag != ANIM_SWIM)
424                                         if (fabs(wish_angle_y) < 15)
425                                         {
426                                                 self.moveto   = self.enemy.origin;
427                                                 self.steerto  = steerlib_attract2(self.moveto, 0.5, 500, 0.95);
428                                                 self.animflag = ANIM_MELEE;
429                                         }
430                                 }
431                                 else if (self.tur_head.attack_finished_single < time)
432                                 {
433                                         if(self.tur_head.shot_volly)
434                                         {
435                                                 self.animflag = ANIM_NO;
436
437                                                 self.tur_head.shot_volly = self.tur_head.shot_volly -1;
438                                                 if(self.tur_head.shot_volly == 0)
439                                                         self.tur_head.attack_finished_single = time + (autocvar_g_turrets_unit_walker_rocket_refire);
440                                                 else
441                                                         self.tur_head.attack_finished_single = time + 0.2;
442
443                                                 if(self.tur_head.shot_volly > 1)
444                                                         walker_fire_rocket(gettaginfo(self, gettagindex(self, "tag_rocket01")));
445                                                 else
446                                                         walker_fire_rocket(gettaginfo(self, gettagindex(self, "tag_rocket02")));
447                                         }
448                                         else
449                                         {
450                                                 if (self.tur_dist_enemy > (autocvar_g_turrets_unit_walker_rocket_range_min))
451                                                 if (self.tur_dist_enemy < (autocvar_g_turrets_unit_walker_rocket_range))
452                                                         self.tur_head.shot_volly = 4;
453                                         }
454                                 }
455                                 else
456                                 {
457                                         if (self.animflag != ANIM_MELEE)
458                                                 walker_move_to(self.enemy.origin, self.tur_dist_enemy);
459                                 }
460                         }
461                         
462                         {
463                                 vector real_angle;
464                                 float turny = 0, turnx = 0;
465                                 float vz;
466
467                                 real_angle = vectoangles(self.steerto) - self.angles;
468                                 vz = self.velocity_z;
469
470                                 switch (self.animflag)
471                                 {
472                                         case ANIM_NO:
473                                                 movelib_beak_simple((autocvar_g_turrets_unit_walker_speed_stop));
474                                                 break;
475
476                                         case ANIM_TURN:
477                                                 turny = (autocvar_g_turrets_unit_walker_turn);
478                                                 movelib_beak_simple((autocvar_g_turrets_unit_walker_speed_stop));
479                                                 break;
480
481                                         case ANIM_WALK:
482                                                 turny = (autocvar_g_turrets_unit_walker_turn_walk);
483                                                 movelib_move_simple(v_forward, (autocvar_g_turrets_unit_walker_speed_walk), 0.6);
484                                                 break;
485
486                                         case ANIM_RUN:
487                                                 turny = (autocvar_g_turrets_unit_walker_turn_run);
488                                                 movelib_move_simple(v_forward, (autocvar_g_turrets_unit_walker_speed_run), 0.6);
489                                                 break;
490
491                                         case ANIM_STRAFE_L:
492                                                 turny = (autocvar_g_turrets_unit_walker_turn_strafe);
493                                                 movelib_move_simple(v_right * -1, (autocvar_g_turrets_unit_walker_speed_walk), 0.8);
494                                                 break;
495
496                                         case ANIM_STRAFE_R:
497                                                 turny = (autocvar_g_turrets_unit_walker_turn_strafe);
498                                                 movelib_move_simple(v_right, (autocvar_g_turrets_unit_walker_speed_walk), 0.8);
499                                                 break;
500
501                                         case ANIM_JUMP:
502                                                 self.velocity += '0 0 1' * (autocvar_g_turrets_unit_walker_speed_jump);
503                                                 break;
504
505                                         case ANIM_LAND:
506                                                 break;
507
508                                         case ANIM_PAIN:
509                                                 if(self.frame != ANIM_PAIN)
510                                                         defer(0.25, walker_setnoanim);
511
512                                                 break;
513
514                                         case ANIM_MELEE:
515                                                 if(self.frame != ANIM_MELEE)
516                                                 {
517                                                         defer(0.41, walker_setnoanim);
518                                                         defer(0.21, walker_melee_do_dmg);
519                                                 }
520
521                                                 movelib_beak_simple((autocvar_g_turrets_unit_walker_speed_stop));
522                                                 break;
523
524                                         case ANIM_SWIM:
525                                                 turny = (autocvar_g_turrets_unit_walker_turn_swim);
526                                                 turnx = (autocvar_g_turrets_unit_walker_turn_swim);
527
528                                                 self.angles_x += bound(-10, shortangle_f(real_angle_x, self.angles_x), 10);
529                                                 movelib_move_simple(v_forward, (autocvar_g_turrets_unit_walker_speed_swim), 0.3);
530                                                 vz = self.velocity_z + sin(time * 4) * 8;
531                                                 break;
532
533                                         case ANIM_ROAM:
534                                                 turny = (autocvar_g_turrets_unit_walker_turn_walk);
535                                                 movelib_move_simple(v_forward ,(autocvar_g_turrets_unit_walker_speed_roam), 0.5);
536                                                 break;
537                                 }
538
539                                 if(turny)
540                                 {
541                                         turny = bound( turny * -1, shortangle_f(real_angle_y, self.angles_y), turny );
542                                         self.angles_y += turny;
543                                 }
544
545                                 if(turnx)
546                                 {
547                                         turnx = bound( turnx * -1, shortangle_f(real_angle_x, self.angles_x), turnx );
548                                         self.angles_x += turnx;
549                                 }
550
551                                 self.velocity_z = vz;
552                         }
553
554
555                         if(self.origin != self.oldorigin)
556                                 self.SendFlags |= TNSF_MOVE;
557
558                         self.oldorigin = self.origin;
559                         turrets_setframe(self.animflag, false);
560
561                         return true;
562                 }
563                 case TR_DEATH:
564                 {
565 #ifdef WALKER_FANCYPATHING
566                         if (self.pathcurrent)
567                                 pathlib_deletepath(self.pathcurrent.owner);
568 #endif
569                         self.pathcurrent = world;
570                 
571                         return true;
572                 }
573                 case TR_SETUP:
574                 {
575                         self.ticrate = 0.05;
576                         
577                         entity e;
578
579                         // Respawn is called & first spawn to, to set team. need to make sure we do not move the initial spawn.
580                         if(self.movetype == MOVETYPE_WALK)
581                         {
582                                 if(self.pos1)
583                                         setorigin(self, self.pos1);
584                                 if(self.pos2)
585                                         self.angles = self.pos2;
586                         }
587                         
588                         self.ammo_flags = TFL_AMMO_BULLETS | TFL_AMMO_RECHARGE | TFL_AMMO_RECIEVE;
589                         self.aim_flags = TFL_AIM_LEAD;
590                         self.turret_flags |= TUR_FLAG_HITSCAN;
591                                 
592                         self.target_select_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK | TFL_TARGETSELECT_LOS;
593                         self.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK | TFL_TARGETSELECT_LOS;
594                         self.iscreature = true;
595                         self.teleportable = TELEPORT_NORMAL;
596                         self.damagedbycontents = true;
597                         self.solid = SOLID_SLIDEBOX;
598                         self.takedamage = DAMAGE_AIM;
599                         if(self.movetype != MOVETYPE_WALK)
600                         {
601                                 setorigin(self, self.origin);
602                                 tracebox(self.origin + '0 0 128', self.mins, self.maxs, self.origin - '0 0 10000', MOVE_NORMAL, self);
603                                 setorigin(self, trace_endpos + '0 0 4');
604                                 self.pos1 = self.origin;
605                                 self.pos2 = self.angles;
606                         }
607                         self.movetype = MOVETYPE_WALK;
608                         self.idle_aim = '0 0 0';
609                         self.turret_firecheckfunc = walker_firecheck;
610                         
611                         if (self.target != "")
612                         {
613                                 e = find(world, targetname, self.target);
614                                 if (!e)
615                                 {
616                                         dprint("Initital waypoint for walker does NOT exsist, fix your map!\n");
617                                         self.target = "";
618                                 }
619
620                                 if (e.classname != "turret_checkpoint")
621                                         dprint("Warning: not a turrret path\n");
622                                 else
623                                 {
624 #ifdef WALKER_FANCYPATHING
625                                         self.pathcurrent = WALKER_PATH(self.origin, e.origin);
626                                         self.pathgoal = e;
627 #else
628                                         self.pathcurrent = e;
629 #endif
630                                 }
631                         }
632
633                         return true;
634                 }
635                 case TR_PRECACHE:
636                 {
637                         precache_model ("models/turrets/walker_body.md3");
638                         precache_model ("models/turrets/walker_head_minigun.md3");
639                         precache_model ("models/turrets/rocket.md3");
640                         precache_sound ("weapons/rocket_impact.wav");
641                         return true;
642                 }
643         }
644
645         return true;
646 }
647
648 #endif // SVQC
649 #ifdef CSQC
650
651 #include "../../../server/movelib.qh"
652
653 void walker_draw()
654 {
655         float dt;
656
657         dt = time - self.move_time;
658         self.move_time = time;
659         if(dt <= 0)
660                 return;
661
662         fixedmakevectors(self.angles);
663         movelib_groundalign4point(300, 100, 0.25, 45);
664         setorigin(self, self.origin + self.velocity * dt);
665         self.tur_head.angles += dt * self.tur_head.move_avelocity;
666         self.angles_y = self.move_angles_y;
667
668         if (self.health < 127)
669         if(random() < 0.15)
670                 te_spark(self.origin + '0 0 40', randomvec() * 256 + '0 0 256', 16);
671 }
672
673 float t_walker(float req)
674 {
675         switch(req)
676         {
677                 case TR_SETUP:
678                 {
679                         self.gravity            = 1;
680                         self.movetype           = MOVETYPE_BOUNCE;
681                         self.move_movetype      = MOVETYPE_BOUNCE;
682                         self.move_origin        = self.origin;
683                         self.move_time          = time;
684                         self.draw                       = walker_draw;
685                         
686                         return true;
687                 }
688                 case TR_PRECACHE:
689                 {
690                         return true;
691                 }
692         }
693
694         return true;
695 }
696
697 #endif // CSQC
698 #endif // REGISTER_TURRET