1 //#define rocket_rack tur_head.enemy
\r
6 #define ANIM_STRAFE_L 2
\r
7 #define ANIM_STRAFE_R 3
\r
12 #define ANIM_MEELE 7
\r
19 #define WALKER_MIN '-70 -70 5'
\r
20 #define WALKER_MAX '70 70 70'
\r
23 .entity goalcurrent, goalstack01, goalstack02, goalstack03;
\r
24 .entity goalstack04, goalstack05, goalstack06, goalstack07;
\r
25 .entity goalstack08, goalstack09, goalstack10, goalstack11;
\r
26 .entity goalstack12, goalstack13, goalstack14, goalstack15;
\r
27 .entity goalstack16, goalstack17, goalstack18, goalstack19;
\r
28 .entity goalstack20, goalstack21, goalstack22, goalstack23;
\r
29 .entity goalstack24, goalstack25, goalstack26, goalstack27;
\r
30 .entity goalstack28, goalstack29, goalstack30, goalstack31;
\r
34 float walker_firecheck()
\r
36 return turret_stdproc_firecheck();
\r
39 void walker_meele_do_dmg()
\r
43 makevectors(self.angles);
\r
44 where = self.origin + v_forward * 128;
\r
46 e = findradius(where,128);
\r
49 if (turret_validate_target(self,e,self.target_validate_flags))
\r
51 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") );
\r
57 void walker_animate()
\r
60 switch (self.animflag)
\r
68 self.frame = self.frame + 1;
\r
69 if (self.frame > 25)
\r
75 self.frame = self.frame + 2;
\r
76 if (self.frame > 25)
\r
81 if (self.frame < 35) self.frame = 35;
\r
82 self.frame = self.frame + 1;
\r
83 if (self.frame > 55) self.frame = 35;
\r
87 if (self.frame < 65) self.frame = 65;
\r
88 self.frame = self.frame + 1;
\r
89 if (self.frame > 85) self.frame = 65;
\r
93 if (self.frame < 95) self.frame = 95;
\r
94 if (self.frame > 100)
\r
95 self.frame = self.frame + 1;
\r
100 if (self.frame < 100) self.frame = 100;
\r
101 self.frame = self.frame + 1;
\r
102 if (self.frame > 107)
\r
103 self.animflag = ANIM_NO;
\r
107 if (self.frame < 60) self.frame = 90;
\r
108 self.frame = self.frame + 1;
\r
109 if (self.frame > 95)
\r
110 self.animflag = ANIM_NO;
\r
114 if (self.frame < 123) self.frame = 123;
\r
115 self.frame = self.frame + 1;
\r
117 if (self.frame == 133)
\r
118 walker_meele_do_dmg();
\r
120 if (self.frame > 140)
\r
121 self.animflag = ANIM_NO;
\r
127 void walker_rocket_explode()
\r
131 if(self.event_damage != SUB_Null)
\r
133 self.event_damage = SUB_Null;
\r
134 self.think = walker_rocket_explode;
\r
135 self.nextthink = time;
\r
139 sound (self, CHAN_PROJECTILE, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM);
\r
140 org2 = findbetterlocation (self.origin, 16);
\r
142 pointparticles(particleeffectnum("rocket_explode"), org2, '0 0 0', 1);
\r
144 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);
\r
149 void walker_rocket_damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector vforce)
\r
151 self.health = self.health - damage;
\r
152 self.velocity = self.velocity + vforce;
\r
153 if (self.health <= 0)
\r
154 walker_rocket_explode();
\r
157 //#define WALKER_ROCKET_MOVE movelib_move(newdir * 275,900,0.1,10)
\r
158 #define WALKER_ROCKET_MOVE movelib_move_simple(newdir,1000,cvar("g_turrets_unit_walker_std_rocket_tunrate")); UpdateCSQCProjectile(self)
\r
159 void walker_rocket_loop();
\r
160 void walker_rocket_think()
\r
167 self.nextthink = time;
\r
169 edist = vlen(self.enemy.origin - self.origin);
\r
171 // Simulate crude guidance
\r
172 if (self.cnt < time)
\r
175 self.tur_shotorg = randomvec() * min(edist,64);
\r
177 self.tur_shotorg = randomvec() * min(edist,256);
\r
179 self.cnt = time + 0.5;
\r
183 self.tur_shotorg = '0 0 0';
\r
186 if (self.tur_health < time)
\r
188 self.think = walker_rocket_explode;
\r
189 self.nextthink = time;
\r
193 if (self.shot_dmg != 1337)
\r
194 if (random() < 0.01)
\r
196 walker_rocket_loop();
\r
200 m_speed = vlen(self.velocity) + cvar("g_turrets_unit_walker_std_rocket_speed_add");
\r
202 // Enemy dead? just keep on the current heading then.
\r
203 if ((self.enemy == world) || (self.enemy.deadflag != DEAD_NO))
\r
206 // Make sure we dont return to tracking a respawned player
\r
207 self.enemy = world;
\r
210 self.angles = vectoangles(self.velocity);
\r
215 itime = max(edist / m_speed,1);
\r
216 newdir = steerlib_pull(self.enemy.origin + self.tur_shotorg);
\r
220 newdir = normalize(self.velocity);
\r
224 self.angles = vectoangles(self.velocity);
\r
227 WALKER_ROCKET_MOVE;
\r
228 //UpdateCSQCProjectile(self);
\r
231 void walker_rocket_loop3()
\r
234 self.nextthink = time;
\r
236 if (self.tur_health < time)
\r
238 self.think = walker_rocket_explode;
\r
242 if (vlen(self.origin - self.tur_shotorg) < 128 )
\r
244 self.think = walker_rocket_think;
\r
249 newdir = steerlib_pull(self.tur_shotorg);
\r
250 WALKER_ROCKET_MOVE;
\r
252 self.angles = vectoangles(self.velocity);
\r
255 void walker_rocket_loop2()
\r
259 self.nextthink = time;
\r
261 if (self.tur_health < time)
\r
263 self.think = walker_rocket_explode;
\r
267 if (vlen(self.origin - self.tur_shotorg) < 128 )
\r
269 self.tur_shotorg = self.origin - '0 0 200';
\r
270 self.think = walker_rocket_loop3;
\r
274 self.angles = vectoangles(self.velocity);
\r
275 newdir = steerlib_pull(self.tur_shotorg);
\r
276 WALKER_ROCKET_MOVE;
\r
279 void walker_rocket_loop()
\r
281 self.nextthink = time;
\r
282 self.tur_shotorg = self.origin + '0 0 400';
\r
283 self.think = walker_rocket_loop2;
\r
284 self.shot_dmg = 1337;
\r
287 void walker_fire_rocket(vector org)
\r
293 //self.angles_x *= -1;
\r
294 makevectors(self.angles);
\r
295 //self.angles_x *= -1;
\r
297 te_explosion (org);
\r
300 setorigin(rocket, org);
\r
302 sound (self, CHAN_WEAPON, "weapons/hagar_fire.wav", VOL_BASE, ATTN_NORM);
\r
303 setsize (rocket, '-3 -3 -3', '3 3 3'); // give it some size so it can be shot
\r
305 rocket.classname = "walker_rocket";
\r
306 rocket.owner = self;
\r
308 rocket.bot_dodge = TRUE;
\r
309 rocket.bot_dodgerating = 50;
\r
311 rocket.takedamage = DAMAGE_YES;
\r
313 rocket.damageforcescale = 2;
\r
314 rocket.health = 25;
\r
315 rocket.tur_shotorg = randomvec() * 512;
\r
316 rocket.cnt = time + 1;
\r
317 rocket.enemy = self.enemy;
\r
319 if (random() < 0.01)
\r
320 rocket.think = walker_rocket_loop;
\r
322 rocket.think = walker_rocket_think;
\r
324 rocket.event_damage = walker_rocket_damage;
\r
326 rocket.nextthink = time;// + 0.25;
\r
327 rocket.movetype = MOVETYPE_FLY;
\r
328 rocket.velocity = normalize((v_forward + v_up * 0.25) + (randomvec() * 0.1)) * cvar("g_turrets_unit_walker_std_rocket_speed");
\r
329 rocket.angles = vectoangles(rocket.velocity);
\r
330 rocket.touch = walker_rocket_explode;
\r
331 rocket.flags = FL_PROJECTILE;
\r
332 rocket.solid = SOLID_BBOX;
\r
333 rocket.tur_health = time + 9;
\r
335 CSQCProjectile(rocket, FALSE, PROJECTILE_ROCKET, FALSE); // no culling, has fly sound
\r
343 #define s_accel2 16
\r
353 if(self.owner.deadflag != DEAD_NO)
\r
359 self.cnt = self.cnt -1;
\r
368 f = gettagindex(self.owner,"tag_rocket01");
\r
370 f = gettagindex(self.owner,"tag_rocket02");
\r
372 org = self.owner.origin + gettaginfo(self.owner,f);
\r
374 self.nextthink = time + 0.2;
\r
377 walker_fire_rocket(org);
\r
385 animation_set(self,5,25,40,AF_ENDCALLBACK,5);
\r
390 animation_set(self,5,25,20,AF_ENDCALLBACK,5);
\r
397 void set_acb(void() acb_func)
\r
399 self.animator_callback = acb_func;
\r
400 if(animation_query(self) != AS_RUNNING)
\r
402 bprint("Not running\n");
\r
407 if not(self.animator.anim_flags & AF_ENDCALLBACK)
\r
408 self.animator.anim_flags = self.animator.anim_flags | AF_ENDCALLBACK;
\r
413 void walker_postthink()
\r
420 //if (self.flags & FL_ONGROUND)
\r
421 //if (self.animflag != ANIM_MEELE)
\r
422 // self.animflag = ANIM_NO;
\r
424 if (self.tur_head.attack_finished_single < time)
\r
430 rv.think = rv_think;
\r
431 rv.nextthink = time;
\r
435 self.tur_head.attack_finished_single = time + cvar("g_turrets_unit_walker_std_rocket_refire");
\r
438 // Do we have a path?
\r
439 if (self.pathcurrent)
\r
441 //set_acb(acb_walk);
\r
442 self.animflag = ANIM_WALK;
\r
444 // Are we close enougth to a path node to switch to the next?
\r
445 if (vlen(self.origin - self.pathcurrent.origin) < 64)
\r
446 if (self.pathcurrent.path_next == world)
\r
448 // Path endpoint reached
\r
449 pathlib_deletepath(self.pathcurrent.owner);
\r
450 self.pathcurrent = world;
\r
454 if(self.pathgoal.use)
\r
455 self.pathgoal.use();
\r
457 if(self.pathgoal.enemy)
\r
459 self.pathcurrent = pathlib_makepath(self.pathgoal.origin,self.pathgoal.enemy.origin,PFL_GROUNDSNAP,1500,2,PT_QUICKBOX);
\r
460 self.pathgoal = self.pathgoal.enemy;
\r
464 self.pathgoal = world;
\r
467 self.pathcurrent = self.pathcurrent.path_next;
\r
469 steer = steerlib_attract2(self.pathcurrent.origin,0.5,2000,0.95);
\r
472 else // Roaming mode
\r
476 wish_angle = angleofs(self,self.enemy);
\r
477 steer = steerlib_pull(self.enemy.origin);
\r
479 if (self.tur_dist_aimpos < cvar("g_turrets_unit_walker_std_meele_range"))
\r
481 if (fabs(wish_angle_y) < 15)
\r
484 //set_acb(acb_meele);
\r
485 //walker_do_meele();
\r
486 self.animflag = ANIM_MEELE;
\r
492 if (fabs(wish_angle_y) < 15)
\r
494 //set_acb(acb_run);
\r
495 self.animflag = ANIM_RUN;
\r
498 else if (fabs(wish_angle_y) < 30)
\r
500 //set_acb(acb_walk);
\r
501 self.animflag = ANIM_WALK;
\r
506 //set_acb(acb_walk);
\r
507 self.animflag = ANIM_WALK;
\r
516 if(self.animflag != ANIM_MEELE)
\r
517 self.animflag = ANIM_NO;
\r
521 // Align the walker to the ground
\r
523 self.angles_x = self.angles_x * -1;
\r
524 makevectors(self.angles);
\r
525 self.angles_x = self.angles_x * -1;
\r
527 traceline(self.origin + '0 0 15', self.origin - '0 0 150' ,MOVE_WORLDONLY,self);
\r
528 wish_angle = (trace_endpos);
\r
529 traceline(self.origin + v_forward * 10 + '0 0 15', self.origin + v_forward * 10 - '0 0 150' ,MOVE_WORLDONLY,self);
\r
530 real_angle = vectoangles(normalize( trace_endpos - wish_angle));
\r
532 self.angles_x = real_angle_x;
\r
533 self.angles_z = real_angle_z;
\r
537 self.velocity = '0 0 0';
\r
538 //animator_remove(self);
\r
542 steer = steer * 0.5 + steerlib_traceavoid(0.3,256);
\r
544 vz = self.velocity_z;
\r
545 movelib_move_simple(steer * 200,vel,0.5);
\r
546 self.velocity_z = vz;
\r
548 wish_angle = vectoangles(self.velocity);
\r
550 real_angle = wish_angle - self.angles;
\r
552 real_angle_y = shortangle_f(real_angle_y,self.angles_y);
\r
554 self.angles_y = self.angles_y + bound(-5,real_angle_y,5);
\r
558 if (self.tur_head.frame != 0)
\r
559 self.tur_head.frame = self.tur_head.frame +1;
\r
561 if (self.tur_head.frame > 12)
\r
562 self.tur_head.frame = 0;
\r
567 void walker_attack()
\r
571 //turret_do_updates(self);
\r
573 self.tur_head.frame = self.tur_head.frame + 1;
\r
575 sound (self, CHAN_WEAPON, "weapons/uzi_fire.wav", VOL_BASE, ATTN_NORM);
\r
577 fireBallisticBullet (self.tur_shotorg_updated, 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"));
\r
578 te_smallflash(self.tur_shotorg_updated);
\r
580 if (!(self.uzi_bulletcounter & 3))
\r
583 trailparticles(self,particleeffectnum("EF_MGTURRETTRAIL"),self.tur_shotorg_updated,trace_endpos);
\r
584 // te_lightning1(self,self.tur_shotorg_updated,trace_endpos);
\r
586 setmodel(flash, "models/uziflash.md3"); // precision set below
\r
587 setattachment(flash, self.tur_head, "tag_fire");
\r
589 flash.think = W_Uzi_Flash_Go;
\r
590 flash.nextthink = time + 0.02;
\r
592 flash.angles_z = flash.v_angle_z + random() * 180;
\r
594 flash.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION;
\r
597 self.uzi_bulletcounter = self.uzi_bulletcounter + 1;
\r
601 void walker_respawnhook()
\r
606 //load_unit_settings(self.rocket_rack,"walker_std_rocket",1);
\r
608 self.origin = self.wkr_spawn.origin;
\r
609 self.wkr_props.solid = SOLID_BBOX;
\r
610 self.wkr_props.alpha = 1;
\r
612 self.angles = self.wkr_spawn.angles;
\r
613 vtmp = self.origin;
\r
614 vtmp_z +=self.wkr_spawn.origin_z + self.wkr_spawn.maxs_z;
\r
615 setorigin(self,vtmp);
\r
617 if (self.target != "")
\r
619 e = find(world,targetname,self.target);
\r
622 bprint("Warning! initital waypoint for Walker does NOT exsist!\n");
\r
626 if (e.classname != "turret_checkpoint")
\r
627 dprint("Warning: not a turrret path\n");
\r
630 self.pathcurrent = pathlib_makepath(self.origin,e.origin,PFL_GROUNDSNAP,500,2,PT_QUICKBOX);
\r
635 void walker_diehook()
\r
637 //animator_remove(self);
\r
639 if(self.pathcurrent)
\r
640 pathlib_deletepath(self.pathcurrent.owner);
\r
642 self.pathcurrent = world;
\r
644 self.wkr_props.solid = SOLID_NOT;
\r
645 self.wkr_props.alpha = -1;
\r
647 if(self.damage_flags & TFL_DMG_DEATH_NORESPAWN)
\r
650 remove(self.wkr_props);
\r
651 //remove(self.rocket_rack);
\r
652 remove(self.wkr_spawn);
\r
657 //.string target_start;
\r
658 void turret_walker_dinit()
\r
663 if (self.netname == "") self.netname = "Walker Turret";
\r
666 self.wkr_props = spawn();
\r
667 self.wkr_spawn = spawn();
\r
669 self.ammo_flags = TFL_AMMO_BULLETS | TFL_AMMO_RECHARGE | TFL_AMMO_RECIVE;
\r
670 self.turrcaps_flags = TFL_TURRCAPS_PLAYERKILL | TFL_TURRCAPS_MOVE | TFL_TURRCAPS_ROAM | TFL_TURRCAPS_LINKED;
\r
671 self.aim_flags = TFL_AIM_LEAD | TFL_AIM_ZEASE | TFL_AIM_SHOTTIMECOMPENSATE;
\r
673 self.turret_respawnhook = walker_respawnhook;
\r
674 self.turret_diehook = walker_diehook;
\r
676 self.ticrate = 0.05;
\r
677 if (turret_stdproc_init("walker_std") == 0)
\r
682 self.damage_flags |= RFL_DMG_DEATH_NOGIBS;
\r
684 self.target_select_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_RANGELIMTS | TFL_TARGETSELECT_TEAMCHECK | TFL_TARGETSELECT_LOS;
\r
685 self.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_RANGELIMTS | TFL_TARGETSELECT_TEAMCHECK;// | TFL_TARGETSELECT_LOS;
\r
687 //self.flags = FL_CLIENT;
\r
688 self.iscreature = TRUE;
\r
689 self.movetype = MOVETYPE_WALK;
\r
690 self.solid = SOLID_SLIDEBOX;
\r
691 self.takedamage = DAMAGE_AIM;
\r
693 setmodel(self.wkr_props,"models/turrets/walker_props.md3");
\r
694 setmodel(self.wkr_spawn,"models/turrets/walker_spawn.md3");
\r
695 setorigin(self.wkr_spawn,self.origin);
\r
697 self.wkr_spawn.angles = self.angles;
\r
698 self.wkr_spawn.solid = SOLID_NOT;
\r
701 traceline(self.wkr_spawn.origin + '0 0 16', self.wkr_spawn.origin - '0 0 10000', MOVE_NOMONSTERS, self);
\r
702 setorigin(self.wkr_spawn,trace_endpos + '0 0 4');
\r
703 setorigin(self,self.wkr_spawn.origin);
\r
705 setmodel(self,"models/turrets/walker_body.md3");
\r
706 setmodel(self.tur_head,"models/turrets/walker_head_minigun.md3");
\r
708 setattachment(self.tur_head,self,"tag_head");
\r
709 setattachment(self.wkr_props,self,"tag_head");
\r
713 f = gettagindex(self.tur_head,"tag_fire");
\r
714 v = gettaginfo(self.tur_head,f);
\r
717 setsize(self,WALKER_MIN,WALKER_MAX);
\r
718 //setsize(self,'-70 -70 0','70 70 55');
\r
720 self.tur_shotorg = v;
\r
721 self.tur_aimorg = v;// + '0 0 10';
\r
723 self.idle_aim = '0 0 0';
\r
725 // self.v_home = self.origin;
\r
727 self.turret_firecheckfunc = walker_firecheck;
\r
729 // Our fire routine
\r
730 self.turret_firefunc = walker_attack;
\r
732 self.turret_postthink = walker_postthink;
\r
734 if (self.target != "")
\r
736 e = find(world,targetname,self.target);
\r
739 dprint("Initital waypoint for walker does NOT exsist, fix your map!\n");
\r
743 if (e.classname != "turret_checkpoint")
\r
744 dprint("Warning: not a turrret path\n");
\r
747 self.pathcurrent = pathlib_makepath(self.origin,e.origin,PFL_GROUNDSNAP,500,2,PT_QUICKBOX);
\r
752 //self.solid = SOLID_NOT;
\r
757 void spawnfunc_turret_walker()
\r
759 precache_model ("models/turrets/walker_head_minigun.md3");
\r
760 precache_model ("models/turrets/walker_body.md3");
\r
761 precache_model ("models/turrets/walker_props.md3");
\r
762 precache_model ("models/turrets/walker_spawn.md3");
\r
763 precache_model ( "models/turrets/rocket.md3");
\r
765 self.think = turret_walker_dinit;
\r
766 self.nextthink = time + 0.5;
\r