1 //#define MONSTES_ENABLED
4 float autocvar_g_monster_zombie_attack_run_damage;
5 float autocvar_g_monster_zombie_attack_run_delay;
6 float autocvar_g_monster_zombie_attack_run_force;
7 float autocvar_g_monster_zombie_attack_run_hitrange;
8 float autocvar_g_monster_zombie_attack_run_range;
9 float autocvar_g_monster_zombie_attack_stand_damage;
10 float autocvar_g_monster_zombie_attack_stand_delay;
11 float autocvar_g_monster_zombie_attack_stand_force;
12 float autocvar_g_monster_zombie_attack_stand_range;
13 float autocvar_g_monster_zombie_health;
14 float autocvar_g_monster_zombie_idle_timer_max;
15 float autocvar_g_monster_zombie_idle_timer_min;
16 float autocvar_g_monster_zombie_movespeed;
17 float autocvar_g_monster_zombie_respawntime;
18 float autocvar_g_monster_zombie_stopspeed;
19 float autocvar_g_monster_zombie_targetrange;
20 float autocvar_g_monster_zombie_turnspeed;
21 float autocvar_g_monsters;
24 #define zombie_anim_attackleap 0
25 #define zombie_anim_attackrun1 1
26 #define zombie_anim_attackrun2 2
27 #define zombie_anim_attackrun3 3
28 #define zombie_anim_attackstanding1 4
29 #define zombie_anim_attackstanding2 5
30 #define zombie_anim_attackstanding3 6
31 #define zombie_anim_blockend 7
32 #define zombie_anim_blockstart 8
33 #define zombie_anim_deathback1 9
34 #define zombie_anim_deathback2 10
35 #define zombie_anim_deathback3 11
36 #define zombie_anim_deathfront1 12
37 #define zombie_anim_deathfront2 13
38 #define zombie_anim_deathfront3 14
39 #define zombie_anim_deathleft1 15
40 #define zombie_anim_deathleft2 16
41 #define zombie_anim_deathright1 17
42 #define zombie_anim_deathright2 18
43 #define zombie_anim_idle 19
44 #define zombie_anim_painback1 20
45 #define zombie_anim_painback2 21
46 #define zombie_anim_painfront1 22
47 #define zombie_anim_painfront2 23
48 #define zombie_anim_runbackwards 24
49 #define zombie_anim_runbackwardsleft 25
50 #define zombie_anim_runbackwardsright 26
51 #define zombie_anim_runforward 27
52 #define zombie_anim_runforwardleft 28
53 #define zombie_anim_runforwardright 29
54 #define zombie_anim_spawn 30
56 #define ZOMBIE_MIN '-18 -18 -25'
57 #define ZOMBIE_MAX '18 18 47'
64 #define ZV_ATTACK_FIND 10
65 #define ZV_ATTACK_RUN 20
66 #define ZV_ATTACK_STAND 30
68 #define ZV_PATH2 10000
71 //.entity verbs_attack;
74 //.float state_timeout;
75 //.void() monster_state;
76 #define MONSTERFLAG_NORESPAWN 2
80 float zombie_scoretarget(entity trg)
85 if (trg.takedamage == DAMAGE_AIM)
86 if not (trg.flags & FL_NOTARGET)
87 if (trg.deadflag == DEAD_NO)
88 if (trg.team != self.team)
90 if((self.origin_z - trg.origin_z) < 128)
92 ang1 = normalize(self.origin - trg.origin);
93 tmp = vlen(ang1 - v_forward);
96 traceline(self.origin + '0 0 47',trg.origin + '0 0 32',MOVE_NORMAL,self);
100 return (autocvar_g_monster_zombie_targetrange - vlen(self.origin - trg.origin)) * tmp;
102 else if(self.enemy == trg)
103 return (autocvar_g_monster_zombie_targetrange - vlen(self.origin - trg.origin)) * tmp;
110 void zombie_corpse_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
112 //dprint("zombie_corpse_damage\n");
113 Violence_GibSplash_At(hitloc, force, 2, bound(0, damage, 200) / 16, self, attacker);
115 self.health -= damage;
119 Violence_GibSplash(self, 1, 1, attacker);
124 void zombie_die(vector dir)
132 setmodel(dummy,"models/monsters/zombie.dpm");
133 setorigin(dummy, self.origin);
134 dummy.velocity = self.velocity;
135 dummy.movetype = MOVETYPE_BOUNCE;
136 dummy.think = SUB_Remove;
137 dummy.nextthink = time + 3;
139 dummy.takedamage = DAMAGE_YES;
140 dummy.event_damage = zombie_corpse_damage;
141 dummy.solid = SOLID_CORPSE;
142 setsize(dummy,self.mins,self.maxs);
144 SUB_SetFade(dummy,time + 5,2);
147 v = normalize(self.origin - dir);
148 f = vlen(v_forward - v) - 1;
150 dummy.frame = zombie_anim_deathfront1 + rint(random() * 2);
152 dummy.frame = zombie_anim_deathback1 + rint(random() * 2);
155 f = vlen(v_right - v) - 1;
157 dummy.frame = zombie_anim_deathright1 + rint(random() * 2);
159 dummy.frame = zombie_anim_deathleft1 + rint(random() * 2);
163 if(self.spawnflags & MONSTERFLAG_NORESPAWN)
165 self.think = SUB_Remove;
166 self.nextthink = time;
171 self.solid = SOLID_NOT;
172 self.takedamage = DAMAGE_NO;
173 self.event_damage = SUB_Null;
175 self.think = zombie_spawn;
176 self.nextthink = time + autocvar_g_monster_zombie_respawntime;
177 self.pain_finished = self.nextthink;
180 void zombie_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
186 v = normalize(self.origin - hitloc);
187 f = vlen(v_forward - v) - 1;
190 self.health -= damage;
191 self.velocity = self.velocity + force;
198 Violence_GibSplash_At(hitloc, force, 2, bound(0, damage, 200) / 16, self, attacker);
201 Violence_GibSplash_At(hitloc, force * -0.1, 3, 1, self, attacker);
203 Violence_GibSplash_At(hitloc, force * -0.2, 3, 1, self, attacker);
205 if (time > self.pain_finished)
210 self.frame = zombie_anim_painback1;
212 self.frame = zombie_anim_painback2;
217 self.frame = zombie_anim_painfront1;
219 self.frame = zombie_anim_painfront2;
222 self.pain_finished = time + 0.36;
232 float vz, tdiff, tspeed;
234 tdiff = time - self.zoomstate;
235 tspeed = tdiff * autocvar_g_monster_zombie_turnspeed;
236 vz = self.velocity_z;
237 self.zoomstate = time;
239 if(self.bvec_time < time)
241 self.bvec_time = time + 0.2;
242 self.bvec = steerlib_beamsteer(steerlib_attract2(self.moveto,0.5,500,0.95),512,32,34,64);
246 self.moveto = self.enemy.origin;
248 self.moveto = self.origin + v_forward;
250 self.steerto = normalize(steerlib_attract2(self.moveto,0.5,500,0.95) + self.bvec);
252 self.angles_y = safeangle(self.angles_y);
253 real_angle = vectoangles(self.steerto) - self.angles;
254 self.angles_y += bound(-10, real_angle_y, 10);
256 if(vlen(self.origin - self.moveto) > 64)
258 movelib_move_simple(v_forward ,autocvar_g_monster_zombie_movespeed,0.6);
259 if(time > self.pain_finished)
260 if(self.attack_finished_single < time)
261 self.frame = zombie_anim_runforward;
265 movelib_beak_simple(autocvar_g_monster_zombie_stopspeed);
266 if(time > self.pain_finished)
267 if(self.attack_finished_single < time)
268 self.frame = zombie_anim_idle;
271 self.velocity_z = vz;
272 self.steerto = self.origin;
275 float zombie_verb_idle_roam(float eval)
284 return verb.verb_static_value;
288 self.moveto = v_forward * 128;
289 self.steerto = v_forward; //steerlib_beamsteer(v_forward,512,32,34,64);
291 return VS_CALL_YES_DOING;
294 return VS_CALL_YES_DONE;
297 float zombie_verb_idle_stand(float eval)
306 return verb.verb_static_value;
310 self.moveto = self.origin;
311 self.frame = zombie_anim_idle;
312 self.velocity = '0 0 0';
314 return VS_CALL_YES_DOING;
317 return VS_CALL_YES_DONE;
320 float zombie_verb_idle(float eval)
329 return verb.verb_static_value;
334 t = autocvar_g_monster_zombie_idle_timer_max - autocvar_g_monster_zombie_idle_timer_min;
335 t = autocvar_g_monster_zombie_idle_timer_min + (random() * t);
338 verbstack_push(self.verbs_idle, zombie_verb_idle_roam, ZV_IDLE + 1, t, self);
340 verbstack_push(self.verbs_idle, zombie_verb_idle_stand, ZV_IDLE + 1, 0.1, self);
342 return VS_CALL_YES_DOING;
345 return VS_CALL_YES_DONE;
348 float zombie_verb_attack_findtarget(float eval)
356 return verb.verb_static_value;
360 entity trg, best_trg;
361 float trg_score, best_trg_score;
363 trg = findradius(self.origin,autocvar_g_monster_zombie_targetrange);
366 trg_score = zombie_scoretarget(trg);
367 if(trg_score > best_trg_score)
370 best_trg_score = trg_score;
378 self.enemy = best_trg;
379 dprint("Selected: ",best_trg.netname, " as target.\n");
382 return VS_CALL_YES_DOING;
385 return VS_CALL_YES_DONE;
388 void zombie_runattack_damage()
394 if(vlen(self.origin - self.enemy.origin) > autocvar_g_monster_zombie_attack_run_hitrange)
397 if(vlen(normalize(self.origin - self.enemy.origin) - v_forward) < 1.6)
400 Damage(self.enemy, self, self, autocvar_g_monster_zombie_attack_run_damage, DEATH_TURRET, self.enemy.origin, normalize(self.enemy.origin - self.origin) * autocvar_g_monster_zombie_attack_run_force);
403 self.think = SUB_Remove;
404 self.nextthink = time;
407 float zombie_verb_attack_run(float eval)
415 if(self.attack_finished_single > time)
418 if(vlen(self.origin - self.enemy.origin) > autocvar_g_monster_zombie_attack_run_range)
421 if(vlen(normalize(self.origin - self.enemy.origin) - v_forward) < 1.6)
424 return verb.verb_static_value;
430 pain.think = zombie_runattack_damage;
431 pain.nextthink = time + autocvar_g_monster_zombie_attack_run_delay;
433 self.attack_finished_single = time + 0.7;
434 self.frame = zombie_anim_attackrun1 + rint(random() * 2);
436 return VS_CALL_YES_DOING;
439 return VS_CALL_YES_DONE;
442 void zombie_standattack_damage()
448 setorigin(self,self.owner.origin + v_forward * 32);
449 RadiusDamage(self, self.owner, autocvar_g_monster_zombie_attack_stand_damage,autocvar_g_monster_zombie_attack_stand_damage,16,self, autocvar_g_monster_zombie_attack_stand_force,DEATH_TURRET,world);
450 //float RadiusDamage (entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity ignore, float forceintensity, float deathtype, entity directhitentity)
454 self.think = SUB_Remove;
455 self.nextthink = time;
458 float zombie_verb_attack_stand(float eval)
466 if(self.attack_finished_single > time)
469 if(vlen(self.origin - self.enemy.origin) > autocvar_g_monster_zombie_attack_stand_range)
472 if(vlen(normalize(self.origin - self.enemy.origin) - v_forward) < 1.8)
475 return verb.verb_static_value;
481 pain.think = zombie_runattack_damage;
482 pain.nextthink = time + autocvar_g_monster_zombie_attack_stand_delay;
484 self.attack_finished_single = time + 0.7;
485 self.frame = zombie_anim_attackstanding1 + rint(random() * 1);
486 dprint("frame:",ftos(self.frame),"\n");
488 return VS_CALL_YES_DOING;
491 return VS_CALL_YES_DONE;
497 makevectors(self.angles);
500 if (zombie_scoretarget(self.enemy) == 0)
503 verbstack_pop(self.verbs_attack);
504 //verbstack_pop(self.verbs_move);
507 verbstack_pop(self.verbs_idle);
512 self.nextthink = time;
514 self.nextthink = time + 0.2;
519 setmodel(self,"models/monsters/zombie.dpm");
521 self.solid = SOLID_BBOX;
522 self.takedamage = DAMAGE_AIM;
523 self.event_damage = zombie_damage;
525 self.frame = zombie_anim_spawn;
526 self.think = zombie_think;
527 self.nextthink = time + 2.1;
528 self.pain_finished = self.nextthink;
529 self.movetype = MOVETYPE_WALK;
530 self.health = autocvar_g_monster_zombie_health;
531 self.velocity = '0 0 0';
532 self.angles = self.pos2;
533 self.moveto = self.origin;
534 self.flags = FL_MONSTER;
536 setorigin(self,self.pos1);
537 setsize(self,ZOMBIE_MIN,ZOMBIE_MAX);
541 void spawnfunc_monster_zombie()
543 if not(autocvar_g_monsters)
549 precache_model("models/monsters/zombie.dpm");
552 self.verbs_idle = spawn();
553 self.verbs_attack = spawn();
555 self.verbs_idle.owner = self;
556 self.verbs_attack.owner = self;
558 self.think = zombie_spawn;
559 self.nextthink = time + 2;
561 traceline(self.origin + '0 0 10', self.origin - '0 0 32', MOVE_WORLDONLY, self);
563 self.pos1 = trace_endpos;
564 self.pos2 = self.angles;
565 self.team = MAX_SHOT_DISTANCE -1;
567 verbstack_push(self.verbs_idle, zombie_verb_idle, ZV_IDLE,0 , self);
569 verbstack_push(self.verbs_attack, zombie_verb_attack_findtarget, ZV_ATTACK_FIND,0 , self);
570 verbstack_push(self.verbs_attack, zombie_verb_attack_run, ZV_ATTACK_RUN,0 , self);
571 verbstack_push(self.verbs_attack, zombie_verb_attack_stand, ZV_ATTACK_STAND,0 , self);
575 #endif // MONSTES_ENABLED