5 #define ANIM_STRAFE_L 4
6 #define ANIM_STRAFE_R 5
15 #define WVM_IDLE_UP 25
19 #define WVM_ENEMY 2000
21 #define WVM_DODGE 4000
22 #define WVM_PANIC 10000
23 #define walker_verbs_move verbs_move
25 #define WVA_MINIGUN 100
26 #define WVA_ROCKET 500
27 #define WVA_MEELE 1000
28 #define walker_verbs_attack verbs_attack
32 #define walker_verbs_idle verbs_idle
37 #define WALKER_MIN '-70 -70 5'
38 #define WALKER_MAX '70 70 70'
40 #define WALKER_PATH(s,e) pathlib_astar(s,e)
42 float walker_firecheck()
44 if (self.animflag == ANIM_MEELE)
47 return turret_stdproc_firecheck();
50 void walker_meele_do_dmg()
54 makevectors(self.angles);
55 where = self.origin + v_forward * 128;
57 //w_deathtypestring = "tried to hug the cute spider thingy.";
58 e = findradius(where,64);
61 if (turret_validate_target(self,e,self.target_validate_flags))
62 if (e != self && e.owner != self)
63 Damage(e,self,self,cvar("g_turrets_unit_walker_std_meele_dmg"),DEATH_TURRET,'0 0 0', v_forward * cvar("g_turrets_unit_walker_std_meele_force") );
74 real_angle = vectoangles(self.steerto) - self.angles;
77 if (self.tur_head.frame != 0)
78 self.tur_head.frame = self.tur_head.frame +1;
80 if (self.tur_head.frame > 12)
81 self.tur_head.frame = 0;
83 switch (self.animflag)
90 movelib_beak_simple(cvar("g_turrets_unit_walker_speed_stop"));
95 if ((self.frame < 5) || (self.frame > 25))
98 self.frame = self.frame -1;
99 movelib_move_simple(v_forward * -1 ,cvar("g_turrets_unit_walker_speed_walk"),0.6);
108 if ((self.frame < 30) || (self.frame > 55))
111 self.frame = self.frame + 1;
113 self.angles_y += bound(-15,shortangle_f(real_angle_y,self.angles_y),15);
115 movelib_beak_simple(cvar("g_turrets_unit_walker_speed_stop"));
123 if ((self.frame < 5) || (self.frame > 25))
126 self.frame = self.frame +1;
127 self.angles_y += bound(-10,shortangle_f(real_angle_y,self.angles_y),10);
128 movelib_move_simple(v_forward ,cvar("g_turrets_unit_walker_speed_walk"),0.6);
136 if ((self.frame < 5) || (self.frame > 25))
139 self.frame = self.frame +1;
141 self.angles_y += bound(-5,shortangle_f(real_angle_y,self.angles_y),5);
143 movelib_move_simple(v_forward ,cvar("g_turrets_unit_walker_speed_roam"),0.5);
151 if ((self.frame < 142) || (self.frame > 151))
154 self.frame = self.frame +1;
156 self.angles_y += bound(-10,shortangle_f(real_angle_y,self.angles_y),10);
157 self.angles_x += bound(-10,shortangle_f(real_angle_x,self.angles_x),10);
159 movelib_move_simple(v_forward, cvar("g_turrets_unit_walker_speed_swim"),0.3);
160 vz = self.velocity_z + sin(time * 4) * 8;
162 if (self.frame > 151)
169 if ((self.frame < 5) || (self.frame > 25))
172 self.angles_y += bound(-5,shortangle_f(real_angle_y,self.angles_y),5);
173 movelib_move_simple(v_forward, cvar("g_turrets_unit_walker_speed_run"),0.6);
181 if ((self.frame < 30) || (self.frame > 55))
184 self.frame = self.frame + 1;
185 self.angles_y += bound(-2.5,shortangle_f(real_angle_y,self.angles_y),2.5);
186 movelib_move_simple(v_right * -1, cvar("g_turrets_unit_walker_speed_walk"),0.8);
193 if ((self.frame < 60) || (self.frame > 65))
196 self.frame = self.frame + 1;
197 self.angles_y += bound(-2.5,shortangle_f(real_angle_y,self.angles_y),2.5);
198 movelib_move_simple(v_right, cvar("g_turrets_unit_walker_speed_walk"),0.8);
206 if ((self.frame < 95) || (self.frame > 100))
209 self.velocity += '0 0 1' * cvar("g_turrets_unit_walker_speed_jump");
211 if (self.frame > 100)
212 self.frame = self.frame + 1;
217 if ((self.frame < 100) || (self.frame > 107))
220 self.frame = self.frame + 1;
222 if (self.frame > 107)
223 self.animflag = ANIM_NO;
228 if ((self.frame < 60) || (self.frame > 95))
231 self.frame = self.frame + 1;
234 self.animflag = ANIM_NO;
239 if ((self.frame < 123) || (self.frame > 140))
242 movelib_beak_simple(cvar("g_turrets_unit_walker_speed_stop"));
244 self.frame = self.frame + 2;
246 if (self.frame == 133)
247 walker_meele_do_dmg();
249 if (self.frame > 140)
251 self.animflag = ANIM_NO;
256 self.velocity_z = vz;
258 if (self.flags & FL_ONGROUND)
259 movelib_groundalign4point(300,100,0.25);
264 void walker_rocket_explode()
268 if (self.event_damage != SUB_Null)
270 self.event_damage = SUB_Null;
271 self.think = walker_rocket_explode;
272 self.nextthink = time;
276 sound (self, CHAN_PROJECTILE, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM);
277 org2 = findbetterlocation (self.origin, 16);
279 pointparticles(particleeffectnum("rocket_explode"), org2, '0 0 0', 1);
280 //w_deathtypestring = "got blasted to oblivion";
281 RadiusDamage (self, self.owner, cvar("g_turrets_unit_walker_std_rocket_dmg"), 0, cvar("g_turrets_unit_walker_std_rocket_radius"), world, cvar("g_turrets_unit_walker_std_rocket_force"), DEATH_TURRET, world);
286 void walker_rocket_damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector vforce)
288 self.health = self.health - damage;
289 self.velocity = self.velocity + vforce;
290 if (self.health <= 0)
291 walker_rocket_explode();
294 #define WALKER_ROCKET_MOVE movelib_move_simple(newdir,cvar("g_turrets_unit_walker_std_rocket_speed"),cvar("g_turrets_unit_walker_std_rocket_tunrate")); UpdateCSQCProjectile(self)
295 void walker_rocket_loop();
296 void walker_rocket_think()
303 self.nextthink = time;
305 edist = vlen(self.enemy.origin - self.origin);
307 // Simulate crude guidance
311 self.tur_shotorg = randomvec() * min(edist,64);
313 self.tur_shotorg = randomvec() * min(edist,256);
315 self.cnt = time + 0.5;
319 self.tur_shotorg = '0 0 0';
322 if (self.tur_health < time)
324 self.think = walker_rocket_explode;
325 self.nextthink = time;
329 if (self.shot_dmg != 1337)
332 walker_rocket_loop();
336 m_speed = vlen(self.velocity) + cvar("g_turrets_unit_walker_std_rocket_speed_add");
338 // Enemy dead? just keep on the current heading then.
339 if ((self.enemy == world) || (self.enemy.deadflag != DEAD_NO))
341 // Make sure we dont return to tracking a respawned player
347 itime = max(edist / m_speed,1);
348 newdir = steerlib_pull(self.enemy.origin + self.tur_shotorg);
352 newdir = normalize(self.velocity);
358 void walker_rocket_loop3()
361 self.nextthink = time;
363 if (self.tur_health < time)
365 self.think = walker_rocket_explode;
369 if (vlen(self.origin - self.tur_shotorg) < 128 )
371 self.think = walker_rocket_think;
375 newdir = steerlib_pull(self.tur_shotorg);
378 self.angles = vectoangles(self.velocity);
381 void walker_rocket_loop2()
385 self.nextthink = time;
387 if (self.tur_health < time)
389 self.think = walker_rocket_explode;
393 if (vlen(self.origin - self.tur_shotorg) < 128 )
395 self.tur_shotorg = self.origin - '0 0 200';
396 self.think = walker_rocket_loop3;
400 newdir = steerlib_pull(self.tur_shotorg);
404 void walker_rocket_loop()
406 self.nextthink = time;
407 self.tur_shotorg = self.origin + '0 0 400';
408 self.think = walker_rocket_loop2;
409 self.shot_dmg = 1337;
412 void walker_fire_rocket(vector org)
419 makevectors(self.angles);
425 setorigin(rocket, org);
427 sound (self, CHAN_WEAPON, "weapons/hagar_fire.wav", VOL_BASE, ATTN_NORM);
428 setsize (rocket, '-3 -3 -3', '3 3 3'); // give it some size so it can be shot
430 rocket.classname = "walker_rocket";
433 rocket.bot_dodge = TRUE;
434 rocket.bot_dodgerating = 50;
436 rocket.takedamage = DAMAGE_YES;
438 rocket.damageforcescale = 2;
440 rocket.tur_shotorg = randomvec() * 512;
441 rocket.cnt = time + 1;
442 rocket.enemy = self.enemy;
445 rocket.think = walker_rocket_loop;
447 rocket.think = walker_rocket_think;
449 rocket.event_damage = walker_rocket_damage;
451 rocket.nextthink = time;// + 0.25;
452 rocket.movetype = MOVETYPE_FLY;
453 rocket.velocity = normalize((v_forward + v_up * 0.5) + (randomvec() * 0.2)) * cvar("g_turrets_unit_walker_std_rocket_speed");
454 rocket.angles = vectoangles(rocket.velocity);
455 rocket.touch = walker_rocket_explode;
456 rocket.flags = FL_PROJECTILE;
457 rocket.solid = SOLID_BBOX;
458 rocket.tur_health = time + 9;
460 CSQCProjectile(rocket, FALSE, PROJECTILE_ROCKET, FALSE); // no culling, has fly sound
469 if (self.owner.deadflag != DEAD_NO)
475 self.cnt = self.cnt -1;
484 f = gettagindex(self.owner,"tag_rocket01");
486 f = gettagindex(self.owner,"tag_rocket02");
488 org = gettaginfo(self.owner,f);
490 self.nextthink = time + 0.2;
493 walker_fire_rocket(org);
497 float walker_moveverb_path(float eval)
503 if (self.animflag == ANIM_MEELE)
506 if (self.pathcurrent)
507 return verb.verb_static_value;
512 // Do we have a path?
513 if not(self.pathcurrent)
519 // Are we close enougth to a path node to switch to the next?
520 if (vlen(self.origin - self.pathcurrent.origin) < 64)
521 if (self.pathcurrent.path_next == world)
523 // Path endpoint reached
524 pathlib_deletepath(self.pathcurrent.owner);
525 self.pathcurrent = world;
529 if (self.pathgoal.use)
532 if (self.pathgoal.enemy)
534 self.pathcurrent = WALKER_PATH(self.pathgoal.origin,self.pathgoal.enemy.origin);
535 self.pathgoal = self.pathgoal.enemy;
539 self.pathgoal = world;
542 self.pathcurrent = self.pathcurrent.path_next;
546 if (self.pathcurrent)
548 switch (self.waterlevel)
551 self.animflag = ANIM_WALK;
554 if (self.animflag == ANIM_WALK)
555 self.animflag = ANIM_WALK;
557 self.animflag = ANIM_SWIM;
560 self.animflag = ANIM_SWIM;
563 self.moveto = self.pathcurrent.origin;
564 self.steerto = steerlib_attract2(self.moveto,0.5,500,0.95);
566 return VS_CALL_YES_DOING;
569 return VS_CALL_YES_DONE;
573 if (self.pathcurrent)
574 pathlib_deletepath(self.pathcurrent.owner);
576 self.pathcurrent = world;
578 return VS_CALL_YES_DONE;
581 return VS_CALL_YES_DONE;
584 float walker_moveverb_enemy(float eval)
591 if (self.spawnflags & TSF_NO_PATHBREAK)
592 if (self.pathcurrent)
595 if (self.animflag == ANIM_MEELE)
598 if (self.enemy == world)
601 //if (tracewalk(self.enemy, self.origin, self.mins, self.maxs, self.enemy.origin, MOVE_NORMAL))
602 return verb.verb_static_value;
607 switch (self.waterlevel)
610 if (self.tur_dist_enemy > 500)
611 self.animflag = ANIM_RUN;
613 self.animflag = ANIM_WALK;
616 if (self.animflag != ANIM_SWIM)
617 self.animflag = ANIM_WALK;
619 self.animflag = ANIM_SWIM;
622 self.animflag = ANIM_SWIM;
625 self.moveto = self.enemy.origin;
626 self.steerto = steerlib_attract2(self.moveto,0.5,500,0.95);
628 return VS_CALL_YES_DOING;
631 return VS_CALL_YES_DONE;
634 float walker_moveverb_idle_pause(float eval)
640 if (self.animflag == ANIM_MEELE)
643 return verb.verb_static_value;
647 self.moveto = self.origin;
648 self.steerto = v_forward;
649 self.animflag = ANIM_NO;
651 return VS_CALL_YES_DOING;
654 return VS_CALL_YES_DONE;
657 float walker_moveverb_idle_roam(float eval)
663 if (self.animflag == ANIM_MEELE)
666 return verb.verb_static_value;
672 while(trace_fraction != 1.0)
674 self.moveto = self.origin + (v_forward * 256);
675 self.moveto += v_right * (random() * 256);
676 self.moveto -= v_right * (random() * 256);
678 tracebox(self.origin+'0 0 64',self.mins,self.maxs,self.moveto + '0 0 64',MOVE_NORMAL,self);
680 verb.wait = time + 10;
684 if(verb.wait - time < 9)
685 if(vlen(self.moveto - self.origin) < 32)
687 verbstack_push(self.walker_verbs_move, walker_moveverb_idle_pause, WVM_IDLE + WVM_IDLE_UP, random() * (verb.wait - time), self);
688 self.animflag = ANIM_NO;
689 return VS_CALL_REMOVE;
693 self.steerto = steerlib_attract(self.moveto,256);
694 te_lightning1(self,self.origin + '0 0 64',self.moveto + '0 0 64');
698 switch (self.waterlevel)
701 self.animflag = ANIM_ROAM;
704 if (self.animflag != ANIM_SWIM)
705 self.animflag = ANIM_ROAM;
709 self.animflag = ANIM_SWIM;
712 return VS_CALL_YES_DOING;
715 return VS_CALL_YES_DONE;
718 float walker_moveverb_idle(float eval)
724 if (self.animflag == ANIM_MEELE)
727 return verb.verb_static_value;
731 //if (random() < 0.5)
732 verbstack_push(self.walker_verbs_move, walker_moveverb_idle_pause, WVM_IDLE + WVM_IDLE_UP, random() * 5, self);
734 // verbstack_push(self.walker_verbs_move, walker_moveverb_idle_roam, WVM_IDLE + WVM_IDLE_UP, random() * 15);
736 return VS_CALL_YES_DOING;
739 return VS_CALL_YES_DONE;
742 float walker_attackverb_meele(float eval)
750 if (cvar("g_turrets_nofire"))
753 if (self.animflag == ANIM_SWIM || self.animflag == ANIM_MEELE)
759 wish_angle = angleofs(self,self.enemy);
761 if (self.tur_dist_enemy < cvar("g_turrets_unit_walker_std_meele_range"))
762 if (fabs(wish_angle_y) < 15)
763 return verb.verb_static_value;
769 self.moveto = self.enemy.origin;
770 self.steerto = steerlib_attract2(self.moveto,0.5,500,0.95);
771 self.animflag = ANIM_MEELE;
773 return VS_CALL_YES_DOING;
776 return VS_CALL_YES_DONE;
779 float walker_attackverb_rockets(float eval)
784 if (self.tur_head.attack_finished_single > time)
790 if (cvar("g_turrets_nofire"))
793 if (self.tur_dist_enemy < cvar("g_turrets_unit_walker_std_rockets_range_min"))
796 if (self.tur_dist_enemy > cvar("g_turrets_unit_walker_std_rockets_range"))
799 return verb.verb_static_value;
811 self.tur_head.attack_finished_single = time + cvar("g_turrets_unit_walker_std_rocket_refire");
813 return VS_CALL_YES_DONE;
816 return VS_CALL_YES_DONE;
819 void walker_postthink()
823 makevectors(self.angles);
826 verbstack_pop(self.walker_verbs_attack);
827 verbstack_pop(self.walker_verbs_move);
836 //w_deathtypestring = "was miniguned";
837 sound (self, CHAN_WEAPON, "weapons/uzi_fire.wav", VOL_BASE, ATTN_NORM);
838 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, cvar("g_balance_uzi_bulletconstant"));
839 if (self.uzi_bulletcounter == 2)
844 setmodel(flash, "models/uziflash.md3");
845 setattachment(flash, self.tur_head, "tag_fire");
848 flash.think = W_Uzi_Flash_Go;
849 flash.nextthink = time + 0.02;
851 flash.angles_z = flash.v_angle_z + random() * 180;
853 flash.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION;
855 self.uzi_bulletcounter = self.uzi_bulletcounter = 0;
858 self.uzi_bulletcounter = self.uzi_bulletcounter + 1;
859 self.tur_head.frame = self.tur_head.frame + 1;
863 void walker_respawnhook()
868 self.origin = self.wkr_spawn.origin;
869 //self.wkr_props.solid = SOLID_BBOX;
870 //self.wkr_props.alpha = 1;
872 self.angles = self.wkr_spawn.angles;
873 vtmp = self.wkr_spawn.origin;
874 vtmp_z += self.wkr_spawn.maxs_z;
875 setorigin(self,vtmp);
877 if (self.target != "")
879 e = find(world,targetname,self.target);
882 dprint("Warning! initital waypoint for Walker does NOT exsist!\n");
886 if (e.classname != "turret_checkpoint")
887 dprint("Warning: not a turrret path\n");
890 self.pathcurrent = WALKER_PATH(self.origin,e.origin);
895 void walker_diehook()
897 turret_trowgib2(self.origin,self.velocity + v_up * 200,'-0.6 -0.2 -02',self,time + random() * 1);
898 turret_trowgib2(self.origin + '0 0 64',self.velocity + v_forward * 150 + v_up * 150,'-0.2 -0.2 -02',self.tur_head,time + random() * 2 + 3);
900 if (self.pathcurrent)
901 pathlib_deletepath(self.pathcurrent.owner);
903 self.pathcurrent = world;
905 if (self.damage_flags & TFL_DMG_DEATH_NORESPAWN)
907 remove(self.wkr_spawn);
909 verbstack_flush(self.walker_verbs_move);
910 verbstack_flush(self.walker_verbs_attack);
911 verbstack_flush(self.walker_verbs_idle);
913 remove(self.walker_verbs_move);
914 remove(self.walker_verbs_attack);
915 remove(self.walker_verbs_idle);
920 void turret_walker_dinit()
925 if (self.netname == "") self.netname = "Walker Turret";
926 self.wkr_spawn = spawn();
928 self.ammo_flags = TFL_AMMO_BULLETS | TFL_AMMO_RECHARGE | TFL_AMMO_RECIVE;
929 self.turrcaps_flags = TFL_TURRCAPS_PLAYERKILL | TFL_TURRCAPS_MOVE | TFL_TURRCAPS_HEADATTACHED;
930 self.aim_flags = TFL_AIM_LEAD;
932 if (cvar("g_antilag_bullets"))
933 self.turrcaps_flags |= TFL_TURRCAPS_HITSCAN;
935 self.aim_flags |= TFL_AIM_SHOTTIMECOMPENSATE;
938 self.turret_respawnhook = walker_respawnhook;
939 self.turret_diehook = walker_diehook;
942 if (turret_stdproc_init("walker_std",0) == 0)
948 self.walker_verbs_move = spawn();
949 self.walker_verbs_attack = spawn();
950 self.walker_verbs_idle = spawn();
952 verbstack_push(self.walker_verbs_move, walker_moveverb_idle, WVM_IDLE, 0, self);
953 verbstack_push(self.walker_verbs_move, walker_moveverb_enemy, WVM_ENEMY, 0, self);
954 verbstack_push(self.walker_verbs_move, walker_moveverb_path, WVM_PATH, 0, self);
956 verbstack_push(self.walker_verbs_attack, walker_attackverb_meele, WVA_MEELE, 0, self);
957 verbstack_push(self.walker_verbs_attack, walker_attackverb_rockets, WVA_ROCKET, 0, self);
959 self.damage_flags |= TFL_DMG_DEATH_NOGIBS;
961 self.target_select_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_RANGELIMTS | TFL_TARGETSELECT_TEAMCHECK | TFL_TARGETSELECT_LOS;
962 self.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_RANGELIMTS | TFL_TARGETSELECT_TEAMCHECK | TFL_TARGETSELECT_LOS;
964 self.iscreature = TRUE;
965 self.movetype = MOVETYPE_WALK;
966 self.solid = SOLID_SLIDEBOX;
967 self.takedamage = DAMAGE_AIM;
969 setmodel(self,"models/turrets/walker_body.md3");
970 setmodel(self.tur_head,"models/turrets/walker_head_minigun.md3");
971 setmodel(self.wkr_spawn,"models/turrets/walker_spawn.md3");
973 setattachment(self.tur_head,self,"tag_head");
975 self.wkr_spawn.angles = self.angles;
976 self.wkr_spawn.solid = SOLID_NOT;
978 traceline(self.origin + '0 0 16', self.origin - '0 0 10000', MOVE_WORLDONLY, self);
979 setorigin(self.wkr_spawn,trace_endpos + '0 0 4');
980 setorigin(self,self.wkr_spawn.origin);
982 setsize(self,WALKER_MIN,WALKER_MAX);
984 self.idle_aim = '0 0 0';
985 self.turret_firecheckfunc = walker_firecheck;
986 self.turret_firefunc = walker_attack;
987 self.turret_postthink = walker_postthink;
989 if (self.target != "")
991 e = find(world,targetname,self.target);
994 dprint("Initital waypoint for walker does NOT exsist, fix your map!\n");
998 if (e.classname != "turret_checkpoint")
999 dprint("Warning: not a turrret path\n");
1002 self.pathcurrent = WALKER_PATH(self.origin,e.origin);
1009 void spawnfunc_turret_walker()
1011 g_turrets_common_precash();
1013 precache_model ("models/turrets/walker_head_minigun.md3");
1014 precache_model ("models/turrets/walker_body.md3");
1015 precache_model ("models/turrets/walker_props.md3");
1016 precache_model ("models/turrets/walker_spawn.md3");
1017 precache_model ( "models/turrets/rocket.md3");
1018 precache_sound ( "weapons/rocket_impact.wav" );
1020 self.think = turret_walker_dinit;
1021 self.nextthink = time + 0.5;