-//#define MONSTES_ENABLED\r
-#ifdef MONSTES_ENABLED\r
-\r
-#define zombie_anim_attackleap 0\r
-#define zombie_anim_attackrun1 1\r
-#define zombie_anim_attackrun2 2\r
-#define zombie_anim_attackrun3 3\r
-#define zombie_anim_attackstanding1 4\r
-#define zombie_anim_attackstanding2 5\r
-#define zombie_anim_attackstanding3 6\r
-#define zombie_anim_blockend 7\r
-#define zombie_anim_blockstart 8\r
-#define zombie_anim_deathback1 9\r
-#define zombie_anim_deathback2 10\r
-#define zombie_anim_deathback3 11\r
-#define zombie_anim_deathfront1 12\r
-#define zombie_anim_deathfront2 13\r
-#define zombie_anim_deathfront3 14\r
-#define zombie_anim_deathleft1 15\r
-#define zombie_anim_deathleft2 16\r
-#define zombie_anim_deathright1 17\r
-#define zombie_anim_deathright2 18\r
-#define zombie_anim_idle 19\r
-#define zombie_anim_painback1 20\r
-#define zombie_anim_painback2 21\r
-#define zombie_anim_painfront1 22\r
-#define zombie_anim_painfront2 23\r
-#define zombie_anim_runbackwards 24\r
-#define zombie_anim_runbackwardsleft 25\r
-#define zombie_anim_runbackwardsright 26\r
-#define zombie_anim_runforward 27\r
-#define zombie_anim_runforwardleft 28\r
-#define zombie_anim_runforwardright 29\r
-#define zombie_anim_spawn 30\r
-\r
-#define ZOMBIE_MIN '-18 -18 -25'\r
-#define ZOMBIE_MAX '18 18 47'\r
-\r
-#define ZV_IDLE 10\r
-\r
-#define ZV_PATH 100\r
-#define ZV_HUNT 200\r
-\r
-#define ZV_ATTACK_FIND 10\r
-#define ZV_ATTACK_RUN 20\r
-#define ZV_ATTACK_STAND 30\r
-\r
-#define ZV_PATH2 10000\r
-\r
-//.entity verbs_idle;\r
-//.entity verbs_attack;\r
-//.entity verbs_move;\r
-\r
-//.float state_timeout;\r
-//.void() monster_state;\r
-#define MONSTERFLAG_NORESPAWN 2\r
-\r
-void zombie_spawn();\r
-\r
-float zombie_scoretarget(entity trg)\r
-{\r
- float tmp;\r
- vector ang1;\r
-\r
- if (trg.takedamage == DAMAGE_AIM)\r
- if not (trg.flags & FL_NOTARGET)\r
- if (trg.deadflag == DEAD_NO)\r
- if (trg.team != self.team)\r
- {\r
- if((self.origin_z - trg.origin_z) < 128)\r
- {\r
- ang1 = normalize(self.origin - trg.origin);\r
- tmp = vlen(ang1 - v_forward);\r
- if(tmp > 1.5)\r
- {\r
- traceline(self.origin + '0 0 47',trg.origin + '0 0 32',MOVE_NORMAL,self);\r
- if(trace_ent != trg)\r
- return 0;\r
-\r
- return (cvar("g_monster_zombie_targetrange") - vlen(self.origin - trg.origin)) * tmp;\r
- }\r
- else if(self.enemy == trg)\r
- return (cvar("g_monster_zombie_targetrange") - vlen(self.origin - trg.origin)) * tmp;\r
- }\r
- }\r
-\r
- return 0;\r
-}\r
-\r
-void zombie_corpse_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)\r
-{\r
- //dprint("zombie_corpse_damage\n");\r
- Violence_GibSplash_At(hitloc, force, 2, bound(0, damage, 200) / 16, self, attacker);\r
-\r
- self.health -= damage;\r
-\r
- if(self.health < 0)\r
- {\r
- Violence_GibSplash(self, 1, 1, attacker);\r
- remove(self);\r
- }\r
-}\r
-\r
-void zombie_die(vector dir)\r
-{\r
- vector v;\r
- float f;\r
-\r
- entity dummy;\r
-\r
- dummy = spawn();\r
- setmodel(dummy,"models/monsters/zombie.dpm");\r
- setorigin(dummy, self.origin);\r
- dummy.velocity = self.velocity;\r
- dummy.movetype = MOVETYPE_BOUNCE;\r
- dummy.think = SUB_Remove;\r
- dummy.nextthink = time + 3;\r
- dummy.health = 50;\r
- dummy.takedamage = DAMAGE_YES;\r
- dummy.event_damage = zombie_corpse_damage;\r
- dummy.solid = SOLID_CORPSE;\r
- setsize(dummy,self.mins,self.maxs);\r
-\r
- SUB_SetFade(dummy,time + 5,2);\r
-\r
-\r
- v = normalize(self.origin - dir);\r
- f = vlen(v_forward - v) - 1;\r
- if(f > 0.5)\r
- dummy.frame = zombie_anim_deathfront1 + rint(random() * 2);\r
- else if(f < 0.5)\r
- dummy.frame = zombie_anim_deathback1 + rint(random() * 2);\r
- else\r
- {\r
- f = vlen(v_right - v) - 1;\r
- if(f > 0.5)\r
- dummy.frame = zombie_anim_deathright1 + rint(random() * 2);\r
- else if(f < 0.5)\r
- dummy.frame = zombie_anim_deathleft1 + rint(random() * 2);\r
- }\r
-\r
-\r
- if(self.spawnflags & MONSTERFLAG_NORESPAWN)\r
- {\r
- self.think = SUB_Remove;\r
- self.nextthink = time;\r
- return;\r
- }\r
-\r
- setmodel(self,"");\r
- self.solid = SOLID_NOT;\r
- self.takedamage = DAMAGE_NO;\r
- self.event_damage = SUB_Null;\r
- self.enemy = world;\r
- self.think = zombie_spawn;\r
- self.nextthink = time + cvar("g_monster_zombie_respawntime");\r
- self.pain_finished = self.nextthink;\r
-}\r
-\r
-void zombie_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)\r
-{\r
-\r
- vector v;\r
- float f;\r
-\r
- v = normalize(self.origin - hitloc);\r
- f = vlen(v_forward - v) - 1;\r
-\r
-\r
- self.health -= damage;\r
- self.velocity = self.velocity + force;\r
- if(self.health <= 0)\r
- {\r
- zombie_die(hitloc);\r
- return;\r
- }\r
-\r
- Violence_GibSplash_At(hitloc, force, 2, bound(0, damage, 200) / 16, self, attacker);\r
-\r
- if (damage > 50)\r
- Violence_GibSplash_At(hitloc, force * -0.1, 3, 1, self, attacker);\r
- if (damage > 100)\r
- Violence_GibSplash_At(hitloc, force * -0.2, 3, 1, self, attacker);\r
-\r
- if (time > self.pain_finished)\r
- {\r
- if(f < 0.5)\r
- {\r
- if(random() < 0.5)\r
- self.frame = zombie_anim_painback1;\r
- else\r
- self.frame = zombie_anim_painback2;\r
- }\r
- else\r
- {\r
- if(random() < 0.5)\r
- self.frame = zombie_anim_painfront1;\r
- else\r
- self.frame = zombie_anim_painfront2;\r
- }\r
-\r
- self.pain_finished = time + 0.36;\r
- }\r
-}\r
-\r
-.vector bvec;\r
-.float bvec_time;\r
-\r
-void zombie_move()\r
-{\r
- vector real_angle;\r
- float vz, tdiff, tspeed;\r
-\r
- tdiff = time - self.zoomstate;\r
- tspeed = tdiff * cvar("g_monster_zombie_turnspeed");\r
- vz = self.velocity_z;\r
- self.zoomstate = time;\r
-\r
- if(self.bvec_time < time)\r
- {\r
- self.bvec_time = time + 0.2;\r
- self.bvec = steerlib_beamsteer(steerlib_attract2(self.moveto,0.5,500,0.95),512,32,34,64);\r
- }\r
-\r
- if(self.enemy)\r
- self.moveto = self.enemy.origin;\r
- else\r
- self.moveto = self.origin + v_forward;\r
-\r
- self.steerto = normalize(steerlib_attract2(self.moveto,0.5,500,0.95) + self.bvec);\r
-\r
- self.angles_y = safeangle(self.angles_y);\r
- real_angle = vectoangles(self.steerto) - self.angles;\r
- self.angles_y += bound(-10, real_angle_y, 10);\r
-\r
- if(vlen(self.origin - self.moveto) > 64)\r
- {\r
- movelib_move_simple(v_forward ,cvar("g_monster_zombie_movespeed"),0.6);\r
- if(time > self.pain_finished)\r
- if(self.attack_finished_single < time)\r
- self.frame = zombie_anim_runforward;\r
- }\r
- else\r
- {\r
- movelib_beak_simple(cvar("g_monster_zombie_stopspeed"));\r
- if(time > self.pain_finished)\r
- if(self.attack_finished_single < time)\r
- self.frame = zombie_anim_idle;\r
- }\r
-\r
- self.velocity_z = vz;\r
- self.steerto = self.origin;\r
-}\r
-\r
-float zombie_verb_idle_roam(float eval)\r
-{\r
- switch (eval)\r
- {\r
- case VCM_EVAL:\r
-\r
- if(self.enemy)\r
- return VS_CALL_NO;\r
-\r
- return verb.verb_static_value;\r
-\r
- case VCM_DO:\r
-\r
- self.moveto = v_forward * 128;\r
- self.steerto = v_forward; //steerlib_beamsteer(v_forward,512,32,34,64);\r
-\r
- return VS_CALL_YES_DOING;\r
- }\r
-\r
- return VS_CALL_YES_DONE;\r
-}\r
-\r
-float zombie_verb_idle_stand(float eval)\r
-{\r
- switch (eval)\r
- {\r
- case VCM_EVAL:\r
-\r
- if(self.enemy)\r
- return VS_CALL_NO;\r
-\r
- return verb.verb_static_value;\r
-\r
- case VCM_DO:\r
-\r
- self.moveto = self.origin;\r
- self.frame = zombie_anim_idle;\r
- self.velocity = '0 0 0';\r
-\r
- return VS_CALL_YES_DOING;\r
- }\r
-\r
- return VS_CALL_YES_DONE;\r
-}\r
-\r
-float zombie_verb_idle(float eval)\r
-{\r
- switch (eval)\r
- {\r
- case VCM_EVAL:\r
-\r
- if(self.enemy)\r
- return VS_CALL_NO;\r
-\r
- return verb.verb_static_value;\r
-\r
- case VCM_DO:\r
- float t;\r
-\r
- t = cvar("g_monster_zombie_idle_timer_max") - cvar("g_monster_zombie_idle_timer_min");\r
- t = cvar("g_monster_zombie_idle_timer_min") + (random() * t);\r
-\r
- if(random() < 0.5)\r
- verbstack_push(self.verbs_idle, zombie_verb_idle_roam, ZV_IDLE + 1, t, self);\r
- else\r
- verbstack_push(self.verbs_idle, zombie_verb_idle_stand, ZV_IDLE + 1, 0.1, self);\r
-\r
- return VS_CALL_YES_DOING;\r
- }\r
-\r
- return VS_CALL_YES_DONE;\r
-}\r
-\r
-float zombie_verb_attack_findtarget(float eval)\r
-{\r
- switch (eval)\r
- {\r
- case VCM_EVAL:\r
- if(self.enemy)\r
- return VS_CALL_NO;\r
-\r
- return verb.verb_static_value;\r
-\r
- case VCM_DO:\r
-\r
- entity trg, best_trg;\r
- float trg_score, best_trg_score;\r
-\r
- trg = findradius(self.origin,cvar("g_monster_zombie_targetrange"));\r
- while(trg)\r
- {\r
- trg_score = zombie_scoretarget(trg);\r
- if(trg_score > best_trg_score)\r
- {\r
- best_trg = trg;\r
- best_trg_score = trg_score;\r
- }\r
-\r
- trg = trg.chain;\r
- }\r
-\r
- if(best_trg)\r
- {\r
- self.enemy = best_trg;\r
- dprint("Selected: ",best_trg.netname, " as target.\n");\r
- }\r
-\r
- return VS_CALL_YES_DOING;\r
- }\r
-\r
- return VS_CALL_YES_DONE;\r
-}\r
-\r
-void zombie_runattack_damage()\r
-{\r
- entity oldself;\r
- oldself = self;\r
- self = self.owner;\r
-\r
- if(vlen(self.origin - self.enemy.origin) > cvar("g_monster_zombie_attack_run_hitrange"))\r
- return;\r
-\r
- if(vlen(normalize(self.origin - self.enemy.origin) - v_forward) < 1.6)\r
- return;\r
-\r
- Damage(self.enemy, self, self, cvar("g_monster_zombie_attack_run_damage"), DEATH_TURRET, self.enemy.origin, normalize(self.enemy.origin - self.origin) * cvar("g_monster_zombie_attack_run_force"));\r
-\r
- self = oldself;\r
- self.think = SUB_Remove;\r
- self.nextthink = time;\r
-}\r
-\r
-float zombie_verb_attack_run(float eval)\r
-{\r
- switch (eval)\r
- {\r
- case VCM_EVAL:\r
- if not (self.enemy)\r
- return VS_CALL_NO;\r
-\r
- if(self.attack_finished_single > time)\r
- return VS_CALL_NO;\r
-\r
- if(vlen(self.origin - self.enemy.origin) > cvar("g_monster_zombie_attack_run_range"))\r
- return VS_CALL_NO;\r
-\r
- if(vlen(normalize(self.origin - self.enemy.origin) - v_forward) < 1.6)\r
- return VS_CALL_NO;\r
-\r
- return verb.verb_static_value;\r
-\r
- case VCM_DO:\r
- entity pain;\r
- pain = spawn();\r
- pain.owner = self;\r
- pain.think = zombie_runattack_damage;\r
- pain.nextthink = time + cvar("g_monster_zombie_attack_run_delay");\r
-\r
- self.attack_finished_single = time + 0.7;\r
- self.frame = zombie_anim_attackrun1 + rint(random() * 2);\r
-\r
- return VS_CALL_YES_DOING;\r
- }\r
-\r
- return VS_CALL_YES_DONE;\r
-}\r
-\r
-void zombie_standattack_damage()\r
-{\r
- //entity oldself;\r
- //oldself = self;\r
- //self = self.owner;\r
-\r
- setorigin(self,self.owner.origin + v_forward * 32);\r
- RadiusDamage(self, self.owner, cvar("g_monster_zombie_attack_stand_damage"),cvar("g_monster_zombie_attack_stand_damage"),16,self, cvar("g_monster_zombie_attack_stand_force"),DEATH_TURRET,world);\r
- //float RadiusDamage (entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity ignore, float forceintensity, float deathtype, entity directhitentity)\r
-\r
-\r
- //self = oldself;\r
- self.think = SUB_Remove;\r
- self.nextthink = time;\r
-}\r
-\r
-float zombie_verb_attack_stand(float eval)\r
-{\r
- switch (eval)\r
- {\r
- case VCM_EVAL:\r
- if not (self.enemy)\r
- return VS_CALL_NO;\r
-\r
- if(self.attack_finished_single > time)\r
- return VS_CALL_NO;\r
-\r
- if(vlen(self.origin - self.enemy.origin) > cvar("g_monster_zombie_attack_stand_range"))\r
- return VS_CALL_NO;\r
-\r
- if(vlen(normalize(self.origin - self.enemy.origin) - v_forward) < 1.8)\r
- return VS_CALL_NO;\r
-\r
- return verb.verb_static_value;\r
-\r
- case VCM_DO:\r
- entity pain;\r
- pain = spawn();\r
- pain.owner = self;\r
- pain.think = zombie_runattack_damage;\r
- pain.nextthink = time + cvar("g_monster_zombie_attack_stand_delay");\r
-\r
- self.attack_finished_single = time + 0.7;\r
- self.frame = zombie_anim_attackstanding1 + rint(random() * 1);\r
- dprint("frame:",ftos(self.frame),"\n");\r
-\r
- return VS_CALL_YES_DOING;\r
- }\r
-\r
- return VS_CALL_YES_DONE;\r
-}\r
-\r
-void zombie_think()\r
-{\r
- self.angles_x *= -1;\r
- makevectors(self.angles);\r
- self.angles_x *= -1;\r
-\r
- if (zombie_scoretarget(self.enemy) == 0)\r
- self.enemy = world;\r
-\r
- verbstack_pop(self.verbs_attack);\r
- //verbstack_pop(self.verbs_move);\r
-\r
- if not (self.enemy)\r
- verbstack_pop(self.verbs_idle);\r
-\r
- zombie_move();\r
-\r
- if(self.enemy)\r
- self.nextthink = time;\r
- else\r
- self.nextthink = time + 0.2;\r
-}\r
-\r
-void zombie_spawn()\r
-{\r
- setmodel(self,"models/monsters/zombie.dpm");\r
-\r
- self.solid = SOLID_BBOX;\r
- self.takedamage = DAMAGE_AIM;\r
- self.event_damage = zombie_damage;\r
- self.enemy = world;\r
- self.frame = zombie_anim_spawn;\r
- self.think = zombie_think;\r
- self.nextthink = time + 2.1;\r
- self.pain_finished = self.nextthink;\r
- self.movetype = MOVETYPE_WALK;\r
- self.health = cvar("g_monster_zombie_health");\r
- self.velocity = '0 0 0';\r
- self.angles = self.pos2;\r
- self.moveto = self.origin;\r
- self.flags = FL_MONSTER;\r
-\r
- setorigin(self,self.pos1);\r
- setsize(self,ZOMBIE_MIN,ZOMBIE_MAX);\r
-}\r
-\r
-\r
-void spawnfunc_monster_zombie()\r
-{\r
- if not(cvar("g_monsters"))\r
- {\r
- remove(self);\r
- return;\r
- }\r
-\r
- precache_model("models/monsters/zombie.dpm");\r
-\r
-\r
- self.verbs_idle = spawn();\r
- self.verbs_attack = spawn();\r
-\r
- self.verbs_idle.owner = self;\r
- self.verbs_attack.owner = self;\r
-\r
- self.think = zombie_spawn;\r
- self.nextthink = time + 2;\r
-\r
- traceline(self.origin + '0 0 10', self.origin - '0 0 32', MOVE_WORLDONLY, self);\r
-\r
- self.pos1 = trace_endpos;\r
- self.pos2 = self.angles;\r
- self.team = MAX_SHOT_DISTANCE -1;\r
-\r
- verbstack_push(self.verbs_idle, zombie_verb_idle, ZV_IDLE,0 , self);\r
-\r
- verbstack_push(self.verbs_attack, zombie_verb_attack_findtarget, ZV_ATTACK_FIND,0 , self);\r
- verbstack_push(self.verbs_attack, zombie_verb_attack_run, ZV_ATTACK_RUN,0 , self);\r
- verbstack_push(self.verbs_attack, zombie_verb_attack_stand, ZV_ATTACK_STAND,0 , self);\r
-\r
-}\r
-\r
-#endif // MONSTES_ENABLED\r
+//#define MONSTES_ENABLED
+#ifdef MONSTES_ENABLED
+
+#define zombie_anim_attackleap 0
+#define zombie_anim_attackrun1 1
+#define zombie_anim_attackrun2 2
+#define zombie_anim_attackrun3 3
+#define zombie_anim_attackstanding1 4
+#define zombie_anim_attackstanding2 5
+#define zombie_anim_attackstanding3 6
+#define zombie_anim_blockend 7
+#define zombie_anim_blockstart 8
+#define zombie_anim_deathback1 9
+#define zombie_anim_deathback2 10
+#define zombie_anim_deathback3 11
+#define zombie_anim_deathfront1 12
+#define zombie_anim_deathfront2 13
+#define zombie_anim_deathfront3 14
+#define zombie_anim_deathleft1 15
+#define zombie_anim_deathleft2 16
+#define zombie_anim_deathright1 17
+#define zombie_anim_deathright2 18
+#define zombie_anim_idle 19
+#define zombie_anim_painback1 20
+#define zombie_anim_painback2 21
+#define zombie_anim_painfront1 22
+#define zombie_anim_painfront2 23
+#define zombie_anim_runbackwards 24
+#define zombie_anim_runbackwardsleft 25
+#define zombie_anim_runbackwardsright 26
+#define zombie_anim_runforward 27
+#define zombie_anim_runforwardleft 28
+#define zombie_anim_runforwardright 29
+#define zombie_anim_spawn 30
+
+#define ZOMBIE_MIN '-18 -18 -25'
+#define ZOMBIE_MAX '18 18 47'
+
+#define ZV_IDLE 10
+
+#define ZV_PATH 100
+#define ZV_HUNT 200
+
+#define ZV_ATTACK_FIND 10
+#define ZV_ATTACK_RUN 20
+#define ZV_ATTACK_STAND 30
+
+#define ZV_PATH2 10000
+
+//.entity verbs_idle;
+//.entity verbs_attack;
+//.entity verbs_move;
+
+//.float state_timeout;
+//.void() monster_state;
+#define MONSTERFLAG_NORESPAWN 2
+
+void zombie_spawn();
+
+float zombie_scoretarget(entity trg)
+{
+ float tmp;
+ vector ang1;
+
+ if (trg.takedamage == DAMAGE_AIM)
+ if not (trg.flags & FL_NOTARGET)
+ if (trg.deadflag == DEAD_NO)
+ if (trg.team != self.team)
+ {
+ if((self.origin_z - trg.origin_z) < 128)
+ {
+ ang1 = normalize(self.origin - trg.origin);
+ tmp = vlen(ang1 - v_forward);
+ if(tmp > 1.5)
+ {
+ traceline(self.origin + '0 0 47',trg.origin + '0 0 32',MOVE_NORMAL,self);
+ if(trace_ent != trg)
+ return 0;
+
+ return (cvar("g_monster_zombie_targetrange") - vlen(self.origin - trg.origin)) * tmp;
+ }
+ else if(self.enemy == trg)
+ return (cvar("g_monster_zombie_targetrange") - vlen(self.origin - trg.origin)) * tmp;
+ }
+ }
+
+ return 0;
+}
+
+void zombie_corpse_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+{
+ //dprint("zombie_corpse_damage\n");
+ Violence_GibSplash_At(hitloc, force, 2, bound(0, damage, 200) / 16, self, attacker);
+
+ self.health -= damage;
+
+ if(self.health < 0)
+ {
+ Violence_GibSplash(self, 1, 1, attacker);
+ remove(self);
+ }
+}
+
+void zombie_die(vector dir)
+{
+ vector v;
+ float f;
+
+ entity dummy;
+
+ dummy = spawn();
+ setmodel(dummy,"models/monsters/zombie.dpm");
+ setorigin(dummy, self.origin);
+ dummy.velocity = self.velocity;
+ dummy.movetype = MOVETYPE_BOUNCE;
+ dummy.think = SUB_Remove;
+ dummy.nextthink = time + 3;
+ dummy.health = 50;
+ dummy.takedamage = DAMAGE_YES;
+ dummy.event_damage = zombie_corpse_damage;
+ dummy.solid = SOLID_CORPSE;
+ setsize(dummy,self.mins,self.maxs);
+
+ SUB_SetFade(dummy,time + 5,2);
+
+
+ v = normalize(self.origin - dir);
+ f = vlen(v_forward - v) - 1;
+ if(f > 0.5)
+ dummy.frame = zombie_anim_deathfront1 + rint(random() * 2);
+ else if(f < 0.5)
+ dummy.frame = zombie_anim_deathback1 + rint(random() * 2);
+ else
+ {
+ f = vlen(v_right - v) - 1;
+ if(f > 0.5)
+ dummy.frame = zombie_anim_deathright1 + rint(random() * 2);
+ else if(f < 0.5)
+ dummy.frame = zombie_anim_deathleft1 + rint(random() * 2);
+ }
+
+
+ if(self.spawnflags & MONSTERFLAG_NORESPAWN)
+ {
+ self.think = SUB_Remove;
+ self.nextthink = time;
+ return;
+ }
+
+ setmodel(self,"");
+ self.solid = SOLID_NOT;
+ self.takedamage = DAMAGE_NO;
+ self.event_damage = SUB_Null;
+ self.enemy = world;
+ self.think = zombie_spawn;
+ self.nextthink = time + cvar("g_monster_zombie_respawntime");
+ self.pain_finished = self.nextthink;
+}
+
+void zombie_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+{
+
+ vector v;
+ float f;
+
+ v = normalize(self.origin - hitloc);
+ f = vlen(v_forward - v) - 1;
+
+
+ self.health -= damage;
+ self.velocity = self.velocity + force;
+ if(self.health <= 0)
+ {
+ zombie_die(hitloc);
+ return;
+ }
+
+ Violence_GibSplash_At(hitloc, force, 2, bound(0, damage, 200) / 16, self, attacker);
+
+ if (damage > 50)
+ Violence_GibSplash_At(hitloc, force * -0.1, 3, 1, self, attacker);
+ if (damage > 100)
+ Violence_GibSplash_At(hitloc, force * -0.2, 3, 1, self, attacker);
+
+ if (time > self.pain_finished)
+ {
+ if(f < 0.5)
+ {
+ if(random() < 0.5)
+ self.frame = zombie_anim_painback1;
+ else
+ self.frame = zombie_anim_painback2;
+ }
+ else
+ {
+ if(random() < 0.5)
+ self.frame = zombie_anim_painfront1;
+ else
+ self.frame = zombie_anim_painfront2;
+ }
+
+ self.pain_finished = time + 0.36;
+ }
+}
+
+.vector bvec;
+.float bvec_time;
+
+void zombie_move()
+{
+ vector real_angle;
+ float vz, tdiff, tspeed;
+
+ tdiff = time - self.zoomstate;
+ tspeed = tdiff * cvar("g_monster_zombie_turnspeed");
+ vz = self.velocity_z;
+ self.zoomstate = time;
+
+ if(self.bvec_time < time)
+ {
+ self.bvec_time = time + 0.2;
+ self.bvec = steerlib_beamsteer(steerlib_attract2(self.moveto,0.5,500,0.95),512,32,34,64);
+ }
+
+ if(self.enemy)
+ self.moveto = self.enemy.origin;
+ else
+ self.moveto = self.origin + v_forward;
+
+ self.steerto = normalize(steerlib_attract2(self.moveto,0.5,500,0.95) + self.bvec);
+
+ self.angles_y = safeangle(self.angles_y);
+ real_angle = vectoangles(self.steerto) - self.angles;
+ self.angles_y += bound(-10, real_angle_y, 10);
+
+ if(vlen(self.origin - self.moveto) > 64)
+ {
+ movelib_move_simple(v_forward ,cvar("g_monster_zombie_movespeed"),0.6);
+ if(time > self.pain_finished)
+ if(self.attack_finished_single < time)
+ self.frame = zombie_anim_runforward;
+ }
+ else
+ {
+ movelib_beak_simple(cvar("g_monster_zombie_stopspeed"));
+ if(time > self.pain_finished)
+ if(self.attack_finished_single < time)
+ self.frame = zombie_anim_idle;
+ }
+
+ self.velocity_z = vz;
+ self.steerto = self.origin;
+}
+
+float zombie_verb_idle_roam(float eval)
+{
+ switch (eval)
+ {
+ case VCM_EVAL:
+
+ if(self.enemy)
+ return VS_CALL_NO;
+
+ return verb.verb_static_value;
+
+ case VCM_DO:
+
+ self.moveto = v_forward * 128;
+ self.steerto = v_forward; //steerlib_beamsteer(v_forward,512,32,34,64);
+
+ return VS_CALL_YES_DOING;
+ }
+
+ return VS_CALL_YES_DONE;
+}
+
+float zombie_verb_idle_stand(float eval)
+{
+ switch (eval)
+ {
+ case VCM_EVAL:
+
+ if(self.enemy)
+ return VS_CALL_NO;
+
+ return verb.verb_static_value;
+
+ case VCM_DO:
+
+ self.moveto = self.origin;
+ self.frame = zombie_anim_idle;
+ self.velocity = '0 0 0';
+
+ return VS_CALL_YES_DOING;
+ }
+
+ return VS_CALL_YES_DONE;
+}
+
+float zombie_verb_idle(float eval)
+{
+ switch (eval)
+ {
+ case VCM_EVAL:
+
+ if(self.enemy)
+ return VS_CALL_NO;
+
+ return verb.verb_static_value;
+
+ case VCM_DO:
+ float t;
+
+ t = cvar("g_monster_zombie_idle_timer_max") - cvar("g_monster_zombie_idle_timer_min");
+ t = cvar("g_monster_zombie_idle_timer_min") + (random() * t);
+
+ if(random() < 0.5)
+ verbstack_push(self.verbs_idle, zombie_verb_idle_roam, ZV_IDLE + 1, t, self);
+ else
+ verbstack_push(self.verbs_idle, zombie_verb_idle_stand, ZV_IDLE + 1, 0.1, self);
+
+ return VS_CALL_YES_DOING;
+ }
+
+ return VS_CALL_YES_DONE;
+}
+
+float zombie_verb_attack_findtarget(float eval)
+{
+ switch (eval)
+ {
+ case VCM_EVAL:
+ if(self.enemy)
+ return VS_CALL_NO;
+
+ return verb.verb_static_value;
+
+ case VCM_DO:
+
+ entity trg, best_trg;
+ float trg_score, best_trg_score;
+
+ trg = findradius(self.origin,cvar("g_monster_zombie_targetrange"));
+ while(trg)
+ {
+ trg_score = zombie_scoretarget(trg);
+ if(trg_score > best_trg_score)
+ {
+ best_trg = trg;
+ best_trg_score = trg_score;
+ }
+
+ trg = trg.chain;
+ }
+
+ if(best_trg)
+ {
+ self.enemy = best_trg;
+ dprint("Selected: ",best_trg.netname, " as target.\n");
+ }
+
+ return VS_CALL_YES_DOING;
+ }
+
+ return VS_CALL_YES_DONE;
+}
+
+void zombie_runattack_damage()
+{
+ entity oldself;
+ oldself = self;
+ self = self.owner;
+
+ if(vlen(self.origin - self.enemy.origin) > cvar("g_monster_zombie_attack_run_hitrange"))
+ return;
+
+ if(vlen(normalize(self.origin - self.enemy.origin) - v_forward) < 1.6)
+ return;
+
+ Damage(self.enemy, self, self, cvar("g_monster_zombie_attack_run_damage"), DEATH_TURRET, self.enemy.origin, normalize(self.enemy.origin - self.origin) * cvar("g_monster_zombie_attack_run_force"));
+
+ self = oldself;
+ self.think = SUB_Remove;
+ self.nextthink = time;
+}
+
+float zombie_verb_attack_run(float eval)
+{
+ switch (eval)
+ {
+ case VCM_EVAL:
+ if not (self.enemy)
+ return VS_CALL_NO;
+
+ if(self.attack_finished_single > time)
+ return VS_CALL_NO;
+
+ if(vlen(self.origin - self.enemy.origin) > cvar("g_monster_zombie_attack_run_range"))
+ return VS_CALL_NO;
+
+ if(vlen(normalize(self.origin - self.enemy.origin) - v_forward) < 1.6)
+ return VS_CALL_NO;
+
+ return verb.verb_static_value;
+
+ case VCM_DO:
+ entity pain;
+ pain = spawn();
+ pain.owner = self;
+ pain.think = zombie_runattack_damage;
+ pain.nextthink = time + cvar("g_monster_zombie_attack_run_delay");
+
+ self.attack_finished_single = time + 0.7;
+ self.frame = zombie_anim_attackrun1 + rint(random() * 2);
+
+ return VS_CALL_YES_DOING;
+ }
+
+ return VS_CALL_YES_DONE;
+}
+
+void zombie_standattack_damage()
+{
+ //entity oldself;
+ //oldself = self;
+ //self = self.owner;
+
+ setorigin(self,self.owner.origin + v_forward * 32);
+ RadiusDamage(self, self.owner, cvar("g_monster_zombie_attack_stand_damage"),cvar("g_monster_zombie_attack_stand_damage"),16,self, cvar("g_monster_zombie_attack_stand_force"),DEATH_TURRET,world);
+ //float RadiusDamage (entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity ignore, float forceintensity, float deathtype, entity directhitentity)
+
+
+ //self = oldself;
+ self.think = SUB_Remove;
+ self.nextthink = time;
+}
+
+float zombie_verb_attack_stand(float eval)
+{
+ switch (eval)
+ {
+ case VCM_EVAL:
+ if not (self.enemy)
+ return VS_CALL_NO;
+
+ if(self.attack_finished_single > time)
+ return VS_CALL_NO;
+
+ if(vlen(self.origin - self.enemy.origin) > cvar("g_monster_zombie_attack_stand_range"))
+ return VS_CALL_NO;
+
+ if(vlen(normalize(self.origin - self.enemy.origin) - v_forward) < 1.8)
+ return VS_CALL_NO;
+
+ return verb.verb_static_value;
+
+ case VCM_DO:
+ entity pain;
+ pain = spawn();
+ pain.owner = self;
+ pain.think = zombie_runattack_damage;
+ pain.nextthink = time + cvar("g_monster_zombie_attack_stand_delay");
+
+ self.attack_finished_single = time + 0.7;
+ self.frame = zombie_anim_attackstanding1 + rint(random() * 1);
+ dprint("frame:",ftos(self.frame),"\n");
+
+ return VS_CALL_YES_DOING;
+ }
+
+ return VS_CALL_YES_DONE;
+}
+
+void zombie_think()
+{
+ self.angles_x *= -1;
+ makevectors(self.angles);
+ self.angles_x *= -1;
+
+ if (zombie_scoretarget(self.enemy) == 0)
+ self.enemy = world;
+
+ verbstack_pop(self.verbs_attack);
+ //verbstack_pop(self.verbs_move);
+
+ if not (self.enemy)
+ verbstack_pop(self.verbs_idle);
+
+ zombie_move();
+
+ if(self.enemy)
+ self.nextthink = time;
+ else
+ self.nextthink = time + 0.2;
+}
+
+void zombie_spawn()
+{
+ setmodel(self,"models/monsters/zombie.dpm");
+
+ self.solid = SOLID_BBOX;
+ self.takedamage = DAMAGE_AIM;
+ self.event_damage = zombie_damage;
+ self.enemy = world;
+ self.frame = zombie_anim_spawn;
+ self.think = zombie_think;
+ self.nextthink = time + 2.1;
+ self.pain_finished = self.nextthink;
+ self.movetype = MOVETYPE_WALK;
+ self.health = cvar("g_monster_zombie_health");
+ self.velocity = '0 0 0';
+ self.angles = self.pos2;
+ self.moveto = self.origin;
+ self.flags = FL_MONSTER;
+
+ setorigin(self,self.pos1);
+ setsize(self,ZOMBIE_MIN,ZOMBIE_MAX);
+}
+
+
+void spawnfunc_monster_zombie()
+{
+ if not(cvar("g_monsters"))
+ {
+ remove(self);
+ return;
+ }
+
+ precache_model("models/monsters/zombie.dpm");
+
+
+ self.verbs_idle = spawn();
+ self.verbs_attack = spawn();
+
+ self.verbs_idle.owner = self;
+ self.verbs_attack.owner = self;
+
+ self.think = zombie_spawn;
+ self.nextthink = time + 2;
+
+ traceline(self.origin + '0 0 10', self.origin - '0 0 32', MOVE_WORLDONLY, self);
+
+ self.pos1 = trace_endpos;
+ self.pos2 = self.angles;
+ self.team = MAX_SHOT_DISTANCE -1;
+
+ verbstack_push(self.verbs_idle, zombie_verb_idle, ZV_IDLE,0 , self);
+
+ verbstack_push(self.verbs_attack, zombie_verb_attack_findtarget, ZV_ATTACK_FIND,0 , self);
+ verbstack_push(self.verbs_attack, zombie_verb_attack_run, ZV_ATTACK_RUN,0 , self);
+ verbstack_push(self.verbs_attack, zombie_verb_attack_stand, ZV_ATTACK_STAND,0 , self);
+
+}
+
+#endif // MONSTES_ENABLED