5 #define ANIM_STRAFE_L 4
6 #define ANIM_STRAFE_R 5
17 #define WALKER_MIN '-70 -70 0'
18 #define WALKER_MAX '70 70 95'
20 #define WALKER_PATH(s,e) pathlib_astar(s,e)
22 float walker_meele_dmg;
23 float walker_meele_force;
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;
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;
38 void walker_loadcvars()
40 walker_meele_dmg = autocvar_g_turrets_unit_walker_std_meele_dmg;
41 walker_meele_force = autocvar_g_turrets_unit_walker_std_meele_force;
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;
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;
60 float walker_firecheck()
62 if (self.animflag == ANIM_MEELE)
65 return turret_stdproc_firecheck();
68 void walker_meele_do_dmg()
72 makevectors(self.angles);
73 where = self.origin + v_forward * 128;
75 //w_deathtypestring = "tried to hug the cute spider thingy.";
76 e = findradius(where,32);
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);
86 void walker_setnoanim()
89 self.animflag = self.owner.frame;
90 dprint("walker_setnoanim\n");
94 void walker_dly_meele_do_dmg()
96 walker_meele_do_dmg();
97 dprint("walker_dly_meele_do_dmg\n");
101 void walker_animate()
106 real_angle = vectoangles(self.steerto) - self.angles;
107 vz = self.velocity_z;
109 if (self.tur_head.frame != 0)
110 self.tur_head.frame = self.tur_head.frame + 1;
112 if (self.tur_head.frame > 12)
113 self.tur_head.frame = 0;
115 if(self.frame != self.animflag)
117 self.SendFlags |= TNSF_ANIM;
118 self.anim_start_time = time;
121 switch (self.animflag)
126 movelib_beak_simple(walker_speed_stop);
131 if ((self.frame < 5) || (self.frame > 25))
134 self.frame = self.frame -1;
135 movelib_move_simple(v_forward * -1, walker_speed_walk, 0.6);
144 self.frame = ANIM_TURN;
145 self.angles_y += bound(-15, shortangle_f(real_angle_y, self.angles_y), 15);
146 movelib_beak_simple(walker_speed_stop);
150 self.frame = ANIM_WALK;
151 self.angles_y += bound(-10, shortangle_f(real_angle_y, self.angles_y), 10);
152 movelib_move_simple(v_forward, walker_speed_walk, 0.6);
156 self.frame = ANIM_RUN;
157 self.angles_y += bound(-5, shortangle_f(real_angle_y, self.angles_y), 5);
158 movelib_move_simple(v_forward, walker_speed_run, 0.6);
162 self.frame = ANIM_STRAFE_L;
163 self.angles_y += bound(-2.5, shortangle_f(real_angle_y, self.angles_y), 2.5);
164 movelib_move_simple(v_right * -1, walker_speed_walk, 0.8);
168 self.frame = ANIM_STRAFE_R;
169 self.angles_y += bound(-2.5, shortangle_f(real_angle_y, self.angles_y), 2.5);
170 movelib_move_simple(v_right, walker_speed_walk, 0.8);
174 self.frame = ANIM_JUMP;
175 self.velocity += '0 0 1' * walker_speed_jump;
179 self.frame = ANIM_LAND;
183 if(self.frame != ANIM_PAIN)
184 defer(0.25,walker_setnoanim);
186 self.frame = ANIM_PAIN;
191 if(self.frame != ANIM_MEELE)
193 defer(0.41, walker_setnoanim);
194 defer(0.21, walker_dly_meele_do_dmg);
197 self.frame = ANIM_MEELE;
198 movelib_beak_simple(walker_speed_stop);
202 self.frame = ANIM_SWIM;
203 self.angles_y += bound(-10, shortangle_f(real_angle_y, self.angles_y), 10);
204 self.angles_x += bound(-10, shortangle_f(real_angle_x, self.angles_x), 10);
205 movelib_move_simple(v_forward, walker_speed_swim, 0.3);
206 vz = self.velocity_z + sin(time * 4) * 8;
210 self.frame = ANIM_ROAM;
211 self.angles_y += bound(-5, shortangle_f(real_angle_y, self.angles_y), 5);
212 movelib_move_simple(v_forward ,walker_speed_roam, 0.5);
217 self.velocity_z = vz;
219 if (self.flags & FL_ONGROUND)
220 movelib_groundalign4point(300, 100, 0.25);
225 void walker_rocket_explode()
229 if (self.event_damage != SUB_Null)
231 self.event_damage = SUB_Null;
232 self.think = walker_rocket_explode;
233 self.nextthink = time;
237 sound (self, CHAN_PROJECTILE, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM);
238 org2 = findbetterlocation (self.origin, 16);
240 pointparticles(particleeffectnum("rocket_explode"), org2, '0 0 0', 1);
241 RadiusDamage (self, self.owner, walker_std_rocket_dmg, 0, walker_std_rocket_radius, world,walker_std_rocket_force, DEATH_TURRET, world);
246 void walker_rocket_damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector vforce)
248 self.health = self.health - damage;
249 self.velocity = self.velocity + vforce;
250 if (self.health <= 0)
251 walker_rocket_explode();
254 #define WALKER_ROCKET_MOVE movelib_move_simple(newdir, walker_std_rocket_speed, walker_std_rocket_turnrate); UpdateCSQCProjectile(self)
255 void walker_rocket_loop();
256 void walker_rocket_think()
263 self.nextthink = time;
265 edist = vlen(self.enemy.origin - self.origin);
267 // Simulate crude guidance
271 self.tur_shotorg = randomvec() * min(edist,64);
273 self.tur_shotorg = randomvec() * min(edist,256);
275 self.cnt = time + 0.5;
279 self.tur_shotorg = '0 0 0';
282 if (self.tur_health < time)
284 self.think = walker_rocket_explode;
285 self.nextthink = time;
289 if (self.shot_dmg != 1337)
292 walker_rocket_loop();
296 m_speed = vlen(self.velocity);
298 // Enemy dead? just keep on the current heading then.
299 if ((self.enemy == world) || (self.enemy.deadflag != DEAD_NO))
301 // Make sure we dont return to tracking a respawned entity
307 itime = max(edist / m_speed,1);
308 newdir = steerlib_pull(self.enemy.origin + self.tur_shotorg);
312 newdir = normalize(self.velocity);
318 void walker_rocket_loop3()
321 self.nextthink = time;
323 if (self.tur_health < time)
325 self.think = walker_rocket_explode;
329 if (vlen(self.origin - self.tur_shotorg) < 128 )
331 self.think = walker_rocket_think;
335 newdir = steerlib_pull(self.tur_shotorg);
338 self.angles = vectoangles(self.velocity);
341 void walker_rocket_loop2()
345 self.nextthink = time;
347 if (self.tur_health < time)
349 self.think = walker_rocket_explode;
353 if (vlen(self.origin - self.tur_shotorg) < 128 )
355 self.tur_shotorg = self.origin - '0 0 200';
356 self.think = walker_rocket_loop3;
360 newdir = steerlib_pull(self.tur_shotorg);
364 void walker_rocket_loop()
366 self.nextthink = time;
367 self.tur_shotorg = self.origin + '0 0 400';
368 self.think = walker_rocket_loop2;
369 self.shot_dmg = 1337;
372 void walker_fire_rocket(vector org)
378 //self.angles_x *= -1;
379 fixedmakevectors(self.angles);
380 //self.angles_x *= -1;
385 setorigin(rocket, org);
387 sound (self, CHAN_WEAPON, "weapons/hagar_fire.wav", VOL_BASE, ATTN_NORM);
388 setsize (rocket, '-3 -3 -3', '3 3 3'); // give it some size so it can be shot
390 rocket.classname = "walker_rocket";
393 rocket.bot_dodge = TRUE;
394 rocket.bot_dodgerating = 50;
396 rocket.takedamage = DAMAGE_YES;
398 rocket.damageforcescale = 2;
400 rocket.tur_shotorg = randomvec() * 512;
401 rocket.cnt = time + 1;
402 rocket.enemy = self.enemy;
405 rocket.think = walker_rocket_loop;
407 rocket.think = walker_rocket_think;
409 rocket.event_damage = walker_rocket_damage;
411 rocket.nextthink = time;// + 0.25;
412 rocket.movetype = MOVETYPE_FLY;
413 rocket.velocity = normalize((v_forward + v_up * 0.5) + (randomvec() * 0.2)) * walker_std_rocket_speed;
414 rocket.angles = vectoangles(rocket.velocity);
415 rocket.touch = walker_rocket_explode;
416 rocket.flags = FL_PROJECTILE;
417 rocket.solid = SOLID_BBOX;
418 rocket.tur_health = time + 9;
420 CSQCProjectile(rocket, FALSE, PROJECTILE_ROCKET, FALSE); // no culling, has fly sound
429 if (self.owner.deadflag != DEAD_NO)
435 self.cnt = self.cnt -1;
444 f = gettagindex(self.owner,"tag_rocket01");
446 f = gettagindex(self.owner,"tag_rocket02");
448 org = gettaginfo(self.owner,f);
450 self.nextthink = time + 0.2;
453 walker_fire_rocket(org);
457 void walker_move_path()
459 // Are we close enougth to a path node to switch to the next?
460 if (vlen(self.origin - self.pathcurrent.origin) < 64)
461 if (self.pathcurrent.path_next == world)
463 // Path endpoint reached
464 pathlib_deletepath(self.pathcurrent.owner);
465 self.pathcurrent = world;
469 if (self.pathgoal.use)
472 if (self.pathgoal.enemy)
474 self.pathcurrent = WALKER_PATH(self.pathgoal.origin,self.pathgoal.enemy.origin);
475 self.pathgoal = self.pathgoal.enemy;
479 self.pathgoal = world;
482 self.pathcurrent = self.pathcurrent.path_next;
484 switch (self.waterlevel)
487 self.animflag = ANIM_WALK;
490 if (self.animflag == ANIM_WALK)
491 self.animflag = ANIM_WALK;
493 self.animflag = ANIM_SWIM;
496 self.animflag = ANIM_SWIM;
499 self.moveto = self.pathcurrent.origin;
500 self.steerto = steerlib_attract2(self.moveto,0.5,500,0.95);
504 void walker_move_enemy()
506 switch (self.waterlevel)
509 if (self.tur_dist_enemy > 500)
510 self.animflag = ANIM_RUN;
512 self.animflag = ANIM_WALK;
515 if (self.animflag != ANIM_SWIM)
516 self.animflag = ANIM_WALK;
518 self.animflag = ANIM_SWIM;
521 self.animflag = ANIM_SWIM;
524 self.moveto = self.enemy.origin;
525 self.steerto = steerlib_attract2(self.moveto,0.5,500,0.95);
529 void walker_move_idle_pause()
531 self.moveto = self.origin;
532 self.steerto = v_forward;
533 self.animflag = ANIM_NO;
536 void walker_move_idle_roam()
540 void walker_move_idle()
544 float walker_attack_meele()
550 if (self.animflag == ANIM_SWIM || self.animflag == ANIM_MEELE)
553 wish_angle = angleofs(self,self.enemy);
555 if (self.tur_dist_enemy > autocvar_g_turrets_unit_walker_std_meele_range)
558 if (fabs(wish_angle_y) > 15)
561 self.moveto = self.enemy.origin;
562 self.steerto = steerlib_attract2(self.moveto,0.5,500,0.95);
563 self.animflag = ANIM_MEELE;
568 float walker_attack_rockets()
570 if (self.tur_head.attack_finished_single > time)
573 if (self.tur_dist_enemy < autocvar_g_turrets_unit_walker_std_rockets_range_min)
576 if (self.tur_dist_enemy > autocvar_g_turrets_unit_walker_std_rockets_range)
587 self.tur_head.attack_finished_single = time + autocvar_g_turrets_unit_walker_std_rocket_refire;
592 void walker_postthink()
595 //self.angles_x *= -1;
596 fixedmakevectors(self.angles);
597 //self.angles_x *= -1;
599 if ((self.spawnflags & TSF_NO_PATHBREAK) && self.pathcurrent)
601 else if (self.enemy == world)
606 walker_move_idle_pause();
610 if not (self.animflag == ANIM_MEELE)
611 if not (walker_attack_rockets())
612 walker_attack_meele();
614 if not (self.animflag == ANIM_MEELE)
620 //if(vlen(self.velocity))
621 self.SendFlags |= TNSF_MOVE;
627 sound (self, CHAN_WEAPON, "weapons/uzi_fire.wav", VOL_BASE, ATTN_NORM);
628 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);
629 endFireBallisticBullet();
630 if (self.misc_bulletcounter == 2)
634 setattachment(self.muzzle_flash, self.tur_head, "tag_fire");
636 self.misc_bulletcounter = 0;
639 self.misc_bulletcounter = self.misc_bulletcounter + 1;
640 self.tur_head.frame = self.tur_head.frame + 1;
644 void walker_respawnhook()
649 // Respawn is called & first spawn to, to set team. need to make sure we do not move the initial spawn.
650 if(self.movetype != MOVETYPE_WALK)
653 setorigin(self, self.wkr_spawn.origin);
655 self.angles = self.wkr_spawn.angles;
656 vtmp = self.wkr_spawn.origin;
657 vtmp_z += self.wkr_spawn.maxs_z;
658 setorigin(self,vtmp);
660 if (self.target != "")
662 e = find(world,targetname,self.target);
665 dprint("Warning! initital waypoint for Walker does NOT exsist!\n");
669 if (e.classname != "turret_checkpoint")
670 dprint("Warning: not a turrret path\n");
673 self.pathcurrent = WALKER_PATH(self.origin,e.origin);
679 void walker_diehook()
681 //turret_trowgib2(self.origin, self.velocity + v_up * 200, '-0.6 -0.2 -02', self,time + random() * 1);
682 //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);
684 if (self.pathcurrent)
685 pathlib_deletepath(self.pathcurrent.owner);
687 self.pathcurrent = world;
689 if (self.damage_flags & TFL_DMG_DEATH_NORESPAWN)
690 remove(self.wkr_spawn);
694 void turret_walker_dinit()
699 if (self.netname == "") self.netname = "Walker Turret";
700 self.wkr_spawn = spawn();
702 self.ammo_flags = TFL_AMMO_BULLETS | TFL_AMMO_RECHARGE | TFL_AMMO_RECIVE;
703 self.turrcaps_flags = TFL_TURRCAPS_PLAYERKILL | TFL_TURRCAPS_MOVE ;
704 self.aim_flags = TFL_AIM_LEAD;
706 if (autocvar_g_antilag_bullets)
707 self.turrcaps_flags |= TFL_TURRCAPS_HITSCAN;
709 self.aim_flags |= TFL_AIM_SHOTTIMECOMPENSATE;
712 self.turret_respawnhook = walker_respawnhook;
713 self.turret_diehook = walker_diehook;
716 if (turret_stdproc_init("walker_std", "models/turrets/walker_body.md3", "models/turrets/walker_head_minigun.md3", TID_WALKER) == 0)
722 self.damage_flags |= TFL_DMG_DEATH_NOGIBS;
723 self.target_select_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_RANGELIMTS | TFL_TARGETSELECT_TEAMCHECK | TFL_TARGETSELECT_LOS;
724 self.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_RANGELIMTS | TFL_TARGETSELECT_TEAMCHECK | TFL_TARGETSELECT_LOS;
726 self.iscreature = TRUE;
727 self.movetype = MOVETYPE_WALK;
728 self.solid = SOLID_SLIDEBOX;
729 self.takedamage = DAMAGE_AIM;
731 setmodel(self.wkr_spawn,"models/turrets/walker_spawn.md3");
733 self.wkr_spawn.angles = self.angles;
734 self.wkr_spawn.solid = SOLID_NOT;
736 setsize(self, WALKER_MIN, WALKER_MAX);
738 setorigin(self,self.origin);
739 //traceline(self.origin + '0 0 128', self.origin - '0 0 10000', MOVE_NORMAL, self);
740 tracebox(self.origin + '0 0 128', self.mins,self.maxs,self.origin - '0 0 10000', MOVE_NORMAL, self);
742 setorigin(self.wkr_spawn, trace_endpos + '0 0 4');
743 setorigin(self, self.wkr_spawn.origin);
745 self.idle_aim = '0 0 0';
746 self.turret_firecheckfunc = walker_firecheck;
747 self.turret_firefunc = walker_attack;
748 self.turret_postthink = walker_postthink;
750 if (self.target != "")
752 e = find(world,targetname,self.target);
755 dprint("Initital waypoint for walker does NOT exsist, fix your map!\n");
759 if (e.classname != "turret_checkpoint")
760 dprint("Warning: not a turrret path\n");
763 self.pathcurrent = WALKER_PATH(self.origin,e.origin);
770 void spawnfunc_turret_walker()
774 g_turrets_common_precash();
776 precache_model ("models/turrets/walker_head_minigun.md3");
777 precache_model ("models/turrets/walker_body.md3");
778 precache_model ("models/turrets/walker_props.md3");
779 precache_model ("models/turrets/walker_spawn.md3");
780 precache_model ( "models/turrets/rocket.md3");
781 precache_sound ( "weapons/rocket_impact.wav" );
783 self.think = turret_walker_dinit;
784 self.nextthink = time + 0.5;