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 switch (self.animflag)
120 movelib_beak_simple(walker_speed_stop);
125 if ((self.frame < 5) || (self.frame > 25))
128 self.frame = self.frame -1;
129 movelib_move_simple(v_forward * -1, walker_speed_walk, 0.6);
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);
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);
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);
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);
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);
168 self.frame = ANIM_JUMP;
169 self.velocity += '0 0 1' * walker_speed_jump;
173 self.frame = ANIM_LAND;
177 if(self.frame != ANIM_PAIN)
178 defer(0.25,walker_setnoanim);
180 self.frame = ANIM_PAIN;
185 if(self.frame != ANIM_MEELE)
187 defer(0.41, walker_setnoanim);
188 defer(0.21, walker_dly_meele_do_dmg);
191 self.frame = ANIM_MEELE;
192 movelib_beak_simple(walker_speed_stop);
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;
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);
211 self.velocity_z = vz;
213 if (self.flags & FL_ONGROUND)
214 movelib_groundalign4point(300, 100, 0.25);
219 void walker_rocket_explode()
223 if (self.event_damage != SUB_Null)
225 self.event_damage = SUB_Null;
226 self.think = walker_rocket_explode;
227 self.nextthink = time;
231 sound (self, CHAN_PROJECTILE, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM);
232 org2 = findbetterlocation (self.origin, 16);
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);
240 void walker_rocket_damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector vforce)
242 self.health = self.health - damage;
243 self.velocity = self.velocity + vforce;
244 if (self.health <= 0)
245 walker_rocket_explode();
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()
257 self.nextthink = time;
259 edist = vlen(self.enemy.origin - self.origin);
261 // Simulate crude guidance
265 self.tur_shotorg = randomvec() * min(edist,64);
267 self.tur_shotorg = randomvec() * min(edist,256);
269 self.cnt = time + 0.5;
273 self.tur_shotorg = '0 0 0';
276 if (self.tur_health < time)
278 self.think = walker_rocket_explode;
279 self.nextthink = time;
283 if (self.shot_dmg != 1337)
286 walker_rocket_loop();
290 m_speed = vlen(self.velocity);
292 // Enemy dead? just keep on the current heading then.
293 if ((self.enemy == world) || (self.enemy.deadflag != DEAD_NO))
295 // Make sure we dont return to tracking a respawned entity
301 itime = max(edist / m_speed,1);
302 newdir = steerlib_pull(self.enemy.origin + self.tur_shotorg);
306 newdir = normalize(self.velocity);
312 void walker_rocket_loop3()
315 self.nextthink = time;
317 if (self.tur_health < time)
319 self.think = walker_rocket_explode;
323 if (vlen(self.origin - self.tur_shotorg) < 128 )
325 self.think = walker_rocket_think;
329 newdir = steerlib_pull(self.tur_shotorg);
332 self.angles = vectoangles(self.velocity);
335 void walker_rocket_loop2()
339 self.nextthink = time;
341 if (self.tur_health < time)
343 self.think = walker_rocket_explode;
347 if (vlen(self.origin - self.tur_shotorg) < 128 )
349 self.tur_shotorg = self.origin - '0 0 200';
350 self.think = walker_rocket_loop3;
354 newdir = steerlib_pull(self.tur_shotorg);
358 void walker_rocket_loop()
360 self.nextthink = time;
361 self.tur_shotorg = self.origin + '0 0 400';
362 self.think = walker_rocket_loop2;
363 self.shot_dmg = 1337;
366 void walker_fire_rocket(vector org)
372 //self.angles_x *= -1;
373 fixedmakevectors(self.angles);
374 //self.angles_x *= -1;
379 setorigin(rocket, org);
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
384 rocket.classname = "walker_rocket";
387 rocket.bot_dodge = TRUE;
388 rocket.bot_dodgerating = 50;
390 rocket.takedamage = DAMAGE_YES;
392 rocket.damageforcescale = 2;
394 rocket.tur_shotorg = randomvec() * 512;
395 rocket.cnt = time + 1;
396 rocket.enemy = self.enemy;
399 rocket.think = walker_rocket_loop;
401 rocket.think = walker_rocket_think;
403 rocket.event_damage = walker_rocket_damage;
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;
414 CSQCProjectile(rocket, FALSE, PROJECTILE_ROCKET, FALSE); // no culling, has fly sound
423 if (self.owner.deadflag != DEAD_NO)
429 self.cnt = self.cnt -1;
438 f = gettagindex(self.owner,"tag_rocket01");
440 f = gettagindex(self.owner,"tag_rocket02");
442 org = gettaginfo(self.owner,f);
444 self.nextthink = time + 0.2;
447 walker_fire_rocket(org);
451 void walker_move_path()
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)
457 // Path endpoint reached
458 pathlib_deletepath(self.pathcurrent.owner);
459 self.pathcurrent = world;
463 if (self.pathgoal.use)
466 if (self.pathgoal.enemy)
468 self.pathcurrent = WALKER_PATH(self.pathgoal.origin,self.pathgoal.enemy.origin);
469 self.pathgoal = self.pathgoal.enemy;
473 self.pathgoal = world;
476 self.pathcurrent = self.pathcurrent.path_next;
478 switch (self.waterlevel)
481 self.animflag = ANIM_WALK;
484 if (self.animflag == ANIM_WALK)
485 self.animflag = ANIM_WALK;
487 self.animflag = ANIM_SWIM;
490 self.animflag = ANIM_SWIM;
493 self.moveto = self.pathcurrent.origin;
494 self.steerto = steerlib_attract2(self.moveto,0.5,500,0.95);
498 void walker_move_enemy()
500 switch (self.waterlevel)
503 if (self.tur_dist_enemy > 500)
504 self.animflag = ANIM_RUN;
506 self.animflag = ANIM_WALK;
509 if (self.animflag != ANIM_SWIM)
510 self.animflag = ANIM_WALK;
512 self.animflag = ANIM_SWIM;
515 self.animflag = ANIM_SWIM;
518 self.moveto = self.enemy.origin;
519 self.steerto = steerlib_attract2(self.moveto,0.5,500,0.95);
523 void walker_move_idle_pause()
525 self.moveto = self.origin;
526 self.steerto = v_forward;
527 self.animflag = ANIM_NO;
530 void walker_move_idle_roam()
534 void walker_move_idle()
538 float walker_attack_meele()
544 if (self.animflag == ANIM_SWIM || self.animflag == ANIM_MEELE)
547 wish_angle = angleofs(self,self.enemy);
549 if (self.tur_dist_enemy > autocvar_g_turrets_unit_walker_std_meele_range)
552 if (fabs(wish_angle_y) > 15)
555 self.moveto = self.enemy.origin;
556 self.steerto = steerlib_attract2(self.moveto,0.5,500,0.95);
557 self.animflag = ANIM_MEELE;
562 float walker_attack_rockets()
564 if (self.tur_head.attack_finished_single > time)
567 if (self.tur_dist_enemy < autocvar_g_turrets_unit_walker_std_rockets_range_min)
570 if (self.tur_dist_enemy > autocvar_g_turrets_unit_walker_std_rockets_range)
581 self.tur_head.attack_finished_single = time + autocvar_g_turrets_unit_walker_std_rocket_refire;
586 void walker_postthink()
589 //self.angles_x *= -1;
590 fixedmakevectors(self.angles);
591 //self.angles_x *= -1;
593 if ((self.spawnflags & TSF_NO_PATHBREAK) && self.pathcurrent)
595 else if (self.enemy == world)
600 walker_move_idle_pause();
604 if not (self.animflag == ANIM_MEELE)
605 if not (walker_attack_rockets())
606 walker_attack_meele();
608 if not (self.animflag == ANIM_MEELE)
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)
625 setattachment(self.muzzle_flash, self.tur_head, "tag_fire");
627 self.uzi_bulletcounter = 0;
630 self.uzi_bulletcounter = self.uzi_bulletcounter + 1;
631 self.tur_head.frame = self.tur_head.frame + 1;
635 void walker_respawnhook()
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)
644 setorigin(self, self.wkr_spawn.origin);
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);
651 if (self.target != "")
653 e = find(world,targetname,self.target);
656 dprint("Warning! initital waypoint for Walker does NOT exsist!\n");
660 if (e.classname != "turret_checkpoint")
661 dprint("Warning: not a turrret path\n");
664 self.pathcurrent = WALKER_PATH(self.origin,e.origin);
670 void walker_diehook()
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);
675 if (self.pathcurrent)
676 pathlib_deletepath(self.pathcurrent.owner);
678 self.pathcurrent = world;
680 if (self.damage_flags & TFL_DMG_DEATH_NORESPAWN)
681 remove(self.wkr_spawn);
685 void turret_walker_dinit()
690 if (self.netname == "") self.netname = "Walker Turret";
691 self.wkr_spawn = spawn();
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;
697 if (autocvar_g_antilag_bullets)
698 self.turrcaps_flags |= TFL_TURRCAPS_HITSCAN;
700 self.aim_flags |= TFL_AIM_SHOTTIMECOMPENSATE;
703 self.turret_respawnhook = walker_respawnhook;
704 self.turret_diehook = walker_diehook;
707 if (turret_stdproc_init("walker_std",FALSE,"models/turrets/walker_body.md3","models/turrets/walker_head_minigun.md3") == 0)
713 if (!turret_tag_fire_update())
714 dprint("Warning: Turret ",self.classname, " faild to initialize md3 tags\n");
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;
720 self.iscreature = TRUE;
721 self.movetype = MOVETYPE_WALK;
722 self.solid = SOLID_SLIDEBOX;
723 self.takedamage = DAMAGE_AIM;
725 setmodel(self.wkr_spawn,"models/turrets/walker_spawn.md3");
727 self.wkr_spawn.angles = self.angles;
728 self.wkr_spawn.solid = SOLID_NOT;
730 setsize(self, WALKER_MIN, WALKER_MAX);
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);
736 setorigin(self.wkr_spawn, trace_endpos + '0 0 4');
737 setorigin(self, self.wkr_spawn.origin);
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;
744 if (self.target != "")
746 e = find(world,targetname,self.target);
749 dprint("Initital waypoint for walker does NOT exsist, fix your map!\n");
753 if (e.classname != "turret_checkpoint")
754 dprint("Warning: not a turrret path\n");
757 self.pathcurrent = WALKER_PATH(self.origin,e.origin);
764 void spawnfunc_turret_walker()
768 g_turrets_common_precash();
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" );
777 self.think = turret_walker_dinit;
778 self.nextthink = time + 0.5;