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