set g_monsters_skill_hard 5 "Monster hard skill level (used for skill based functions)"
set g_monsters_skill_insane 7 "Monster insane skill level (used for skill based functions)"
set g_monsters_skill_nightmare 10 "Monster nightmare skill level (used for skill based functions)"
-set g_monsters_spawn_list "ogre demon shambler knight marine scrag dog slime hellknight fish mage zombie spider" "monsters not listed here will spawn as knights"
+set g_monsters_spawn_list "ogre demon shambler bruiser marine scrag dog slime hellknight fish mage zombie spider" "monsters not listed here will spawn as bruisers"
// Ogre
set g_monster_ogre 1 "Enable Ogres"
set g_monster_shambler_speed_walk 100 "Shambler walk speed"
set g_monster_shambler_speed_run 150 "Shambler run speed"
-// Knight
-set g_monster_knight 1 "Enable Knights"
-set g_monster_knight_health 75 "Knight Health"
-set g_monster_knight_drop armor "Knight drops this item on death"
-set g_monster_knight_drop_size medium "Size of the item Knights drop. Possible values are: small, medium, large"
-set g_monster_knight_melee_damage 20 "Knight melee attack damage"
-set g_monster_knight_melee_side_damage 10 "Knight melee attack side damage"
-set g_monster_knight_speed_walk 40 "Knight walk speed"
-set g_monster_knight_speed_run 70 "Knight run speed"
+// Bruiser
+set g_monster_bruiser 1 "Enable Bruisers"
+set g_monster_bruiser_health 75 "Bruiser Health"
+set g_monster_bruiser_drop armor "Bruiser drops this item on death"
+set g_monster_bruiser_drop_size medium "Size of the item Bruisers drop. Possible values are: small, medium, large"
+set g_monster_bruiser_melee_damage 20 "Bruiser melee attack damage"
+set g_monster_bruiser_melee_side_damage 10 "Bruiser melee attack side damage"
+set g_monster_bruiser_speed_walk 40 "Bruiser walk speed"
+set g_monster_bruiser_speed_run 70 "Bruiser run speed"
// Grunt
set g_monster_soldier 1 "Enable Grunts"
precache_model(SHAMBLER_MODEL);
break;
}
- case MONSTER_KNIGHT:
+ case MONSTER_BRUISER:
{
- precache_model(KNIGHT_MODEL);
+ precache_model(BRUISER_MODEL);
break;
}
case MONSTER_MARINE:
if(self) self.scale = 1.3;
break;
}
- case MONSTER_KNIGHT:
+ case MONSTER_BRUISER:
{
- mid2info_model = KNIGHT_MODEL;
- mid2info_name = "Knight";
- mid2info_min = KNIGHT_MIN;
- mid2info_max = KNIGHT_MAX;
+ mid2info_model = BRUISER_MODEL;
+ mid2info_name = "Bruiser";
+ mid2info_min = BRUISER_MIN;
+ mid2info_max = BRUISER_MAX;
if(self) self.scale = 1.3;
break;
}
DEATHTYPE(DEATH_MONSTER_HKNIGHT_INFERNO,DEATH_SELF_MON_HKNIGHT_INFERNO, NO_MSG, NORMAL_POS) \
DEATHTYPE(DEATH_MONSTER_HKNIGHT_MELEE, DEATH_SELF_MON_HKNIGHT_MELEE, NO_MSG, NORMAL_POS) \
DEATHTYPE(DEATH_MONSTER_HKNIGHT_SPIKE, DEATH_SELF_MON_HKNIGHT_SPIKE, NO_MSG, NORMAL_POS) \
- DEATHTYPE(DEATH_MONSTER_KNIGHT, DEATH_SELF_MON_KNIGHT, NO_MSG, NORMAL_POS) \
+ DEATHTYPE(DEATH_MONSTER_BRUISER, DEATH_SELF_MON_BRUISER, NO_MSG, NORMAL_POS) \
DEATHTYPE(DEATH_MONSTER_OGRE_CHAINSAW, DEATH_SELF_MON_OGRE_CHAINSAW, NO_MSG, NORMAL_POS) \
DEATHTYPE(DEATH_MONSTER_OGRE_GRENADE, DEATH_SELF_MON_OGRE_GRENADE, NO_MSG, NORMAL_POS) \
DEATHTYPE(DEATH_MONSTER_OGRE_UZI, DEATH_SELF_MON_OGRE_UZI, NO_MSG, NORMAL_POS) \
MSG_INFO_NOTIF(1, INFO_DEATH_SELF_MON_HKNIGHT_INFERNO, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was burned to death by a Hell-Knight%s%s\n"), "") \
MSG_INFO_NOTIF(1, INFO_DEATH_SELF_MON_HKNIGHT_MELEE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was slain by a Hell-Knight%s%s\n"), "") \
MSG_INFO_NOTIF(1, INFO_DEATH_SELF_MON_HKNIGHT_SPIKE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was cursed by a Hell-Knight%s%s\n"), "") \
- MSG_INFO_NOTIF(1, INFO_DEATH_SELF_MON_KNIGHT, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was sliced up by a Knight%s%s\n"), "") \
+ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_MON_BRUISER, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was beaten in a fistfight by a Bruiser%s%s\n"), "") \
MSG_INFO_NOTIF(1, INFO_DEATH_SELF_MON_OGRE_CHAINSAW, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was cut down by an Ogre%s%s\n"), "") \
MSG_INFO_NOTIF(1, INFO_DEATH_SELF_MON_OGRE_GRENADE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 almost dodged the Ogre grenade%s%s\n"), "") \
MSG_INFO_NOTIF(1, INFO_DEATH_SELF_MON_OGRE_UZI, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was nailed by an Ogre%s%s\n"), "") \
MSG_MULTI_NOTIF(1, DEATH_SELF_MON_HKNIGHT_INFERNO, NO_MSG, INFO_DEATH_SELF_MON_HKNIGHT_INFERNO, CENTER_DEATH_SELF_MONSTER) \
MSG_MULTI_NOTIF(1, DEATH_SELF_MON_HKNIGHT_MELEE, NO_MSG, INFO_DEATH_SELF_MON_HKNIGHT_MELEE, CENTER_DEATH_SELF_MONSTER) \
MSG_MULTI_NOTIF(1, DEATH_SELF_MON_HKNIGHT_SPIKE, NO_MSG, INFO_DEATH_SELF_MON_HKNIGHT_SPIKE, CENTER_DEATH_SELF_MONSTER) \
- MSG_MULTI_NOTIF(1, DEATH_SELF_MON_KNIGHT, NO_MSG, INFO_DEATH_SELF_MON_KNIGHT, CENTER_DEATH_SELF_MONSTER) \
+ MSG_MULTI_NOTIF(1, DEATH_SELF_MON_BRUISER, NO_MSG, INFO_DEATH_SELF_MON_BRUISER, CENTER_DEATH_SELF_MONSTER) \
MSG_MULTI_NOTIF(1, DEATH_SELF_MON_OGRE_CHAINSAW, NO_MSG, INFO_DEATH_SELF_MON_OGRE_CHAINSAW, CENTER_DEATH_SELF_MONSTER) \
MSG_MULTI_NOTIF(1, DEATH_SELF_MON_OGRE_GRENADE, NO_MSG, INFO_DEATH_SELF_MON_OGRE_GRENADE, CENTER_DEATH_SELF_MONSTER) \
MSG_MULTI_NOTIF(1, DEATH_SELF_MON_OGRE_UZI, NO_MSG, INFO_DEATH_SELF_MON_OGRE_UZI, CENTER_DEATH_SELF_MONSTER) \
-.float() attack_melee;
-.float() attack_ranged;
.float() checkattack;
+.float(float attack_type) monster_attackfunc;
+const float MONSTER_ATTACK_MELEE = 1;
+const float MONSTER_ATTACK_RANGED = 2;
+
.float candrop;
.float spawn_time; // stop monster from moving around right after spawning
if (time < self.attack_finished_single)
return FALSE;
- if(self.attack_melee)
+ if not(self.monster_attackfunc)
+ return FALSE; // doesn't have an attack function?!
+
if(vlen(self.enemy.origin - self.origin) <= 100)
{
monster_sound(self.msound_attack_melee, 0, FALSE); // no delay for attack sounds
- self.attack_melee(); // don't wait for nextthink - too slow
- return TRUE;
+ if(self.monster_attackfunc(MONSTER_ATTACK_MELEE))
+ return TRUE;
}
-
- // monster doesn't have a ranged attack function, so stop here
- if not(self.attack_ranged)
- return FALSE;
// see if any entities are in the way of the shot
if not(findtrajectorywithleading(self.origin, '0 0 0', '0 0 0', self.enemy, 800, 0, 2.5, 0, self))
return FALSE;
- if(self.attack_ranged())
+ if(self.monster_attackfunc(MONSTER_ATTACK_RANGED))
{
monster_sound(self.msound_attack_ranged, 0, FALSE); // no delay for attack sounds
return TRUE;
self.touch = MonsterTouch;
self.use = monster_use;
self.solid = SOLID_BBOX;
+ self.checkattack = GenericCheckAttack;
self.scale = 1;
self.movetype = MOVETYPE_WALK;
self.delay = -1; // used in attack delay code
float MONSTER_OGRE = 3;
float MONSTER_DEMON = 4;
float MONSTER_SHAMBLER = 5;
-float MONSTER_KNIGHT = 6;
+float MONSTER_BRUISER = 6;
float MONSTER_MARINE = 7;
float MONSTER_SCRAG = 8;
float MONSTER_DOG = 9;
setorigin(e, orig);
if not(spawnmonster_checkinlist(monster, autocvar_g_monsters_spawn_list))
- monster = "knight";
+ monster = "bruiser";
e.realowner = spawnedby;
--- /dev/null
+// size
+const vector BRUISER_MIN = '-20 -20 -31';
+const vector BRUISER_MAX = '20 20 53';
+
+// model
+string BRUISER_MODEL = "models/monsters/knight.mdl";
+
+#ifdef SVQC
+// cvars
+float autocvar_g_monster_bruiser;
+float autocvar_g_monster_bruiser_health;
+float autocvar_g_monster_bruiser_melee_damage;
+float autocvar_g_monster_bruiser_speed_walk;
+float autocvar_g_monster_bruiser_speed_run;
+
+// animations
+const float bruiser_anim_stand = 0;
+const float bruiser_anim_run = 1;
+const float bruiser_anim_runattack = 2;
+const float bruiser_anim_pain1 = 3;
+const float bruiser_anim_pain2 = 4;
+const float bruiser_anim_attack = 5;
+const float bruiser_anim_walk = 6;
+const float bruiser_anim_kneel = 7;
+const float bruiser_anim_standing = 8;
+const float bruiser_anim_death1 = 9;
+const float bruiser_anim_death2 = 10;
+
+void bruiser_think ()
+{
+ self.think = bruiser_think;
+ self.nextthink = time + self.ticrate;
+
+ monster_move(autocvar_g_monster_bruiser_speed_run, autocvar_g_monster_bruiser_speed_walk, 50, bruiser_anim_run, bruiser_anim_walk, bruiser_anim_stand);
+}
+
+float bruiser_attack(float attack_type)
+{
+ switch(attack_type)
+ {
+ case MONSTER_ATTACK_MELEE:
+ {
+ float len = vlen(self.velocity);
+ monsters_setframe((len < 50) ? bruiser_anim_attack : bruiser_anim_runattack);
+ self.attack_finished_single = time + 1.25;
+
+ monster_melee(self.enemy, autocvar_g_monster_bruiser_melee_damage, 0.3, DEATH_MONSTER_BRUISER, FALSE);
+
+ return TRUE;
+ }
+ case MONSTER_ATTACK_RANGED:
+ }
+
+ return FALSE;
+}
+
+void bruiser_die ()
+{
+ Monster_CheckDropCvars ("bruiser");
+
+ self.think = monster_dead_think;
+ self.nextthink = time + self.ticrate;
+ self.ltime = time + 5;
+ monsters_setframe((random() > 0.5) ? bruiser_anim_death1 : bruiser_anim_death2);
+
+ monster_hook_death(); // for post-death mods
+}
+
+void bruiser_spawn ()
+{
+ if not(self.health)
+ self.health = autocvar_g_monster_bruiser_health;
+
+ self.damageforcescale = 0.003;
+ self.classname = "monster_bruiser";
+ self.monster_attackfunc = bruiser_attack;
+ self.nextthink = time + random() * 0.5 + 0.1;
+ self.think = bruiser_think;
+
+ monsters_setframe(bruiser_anim_stand);
+
+ monster_setupsounds("bruiser");
+
+ monster_hook_spawn(); // for post-spawn mods
+}
+
+void spawnfunc_monster_bruiser ()
+{
+ if not(autocvar_g_monster_bruiser) { remove(self); return; }
+
+ self.monster_spawnfunc = spawnfunc_monster_bruiser;
+
+ if(Monster_CheckAppearFlags(self))
+ return;
+
+ self.scale = 1.3;
+
+ if not (monster_initialize(
+ "Bruiser", MONSTER_BRUISER,
+ BRUISER_MIN, BRUISER_MAX,
+ FALSE,
+ bruiser_die, bruiser_spawn))
+ {
+ remove(self);
+ return;
+ }
+}
+
+#endif // SVQC
monster_move(autocvar_g_monster_demon_speed_run, autocvar_g_monster_demon_speed_walk, 100, demon_anim_run, demon_anim_walk, demon_anim_stand);
}
-float demon_attack_melee ()
-{
- monsters_setframe(demon_anim_attack);
- self.attack_finished_single = time + 1;
-
- monster_melee(self.enemy, autocvar_g_monster_demon_damage, 0.3, DEATH_MONSTER_FIEND, TRUE);
-
- return TRUE;
-}
-
void Demon_JumpTouch ()
{
if (self.health <= 0)
self.touch = MonsterTouch;
}
-float demon_jump ()
+float demon_attack(float attack_type)
{
- makevectors(self.angles);
- if(monster_leap(demon_anim_leap, Demon_JumpTouch, v_forward * 700 + '0 0 300', 0.8))
- return TRUE;
-
+ switch(attack_type)
+ {
+ case MONSTER_ATTACK_MELEE:
+ {
+ monsters_setframe(demon_anim_attack);
+ self.attack_finished_single = time + 1;
+ monster_melee(self.enemy, autocvar_g_monster_demon_damage, 0.3, DEATH_MONSTER_FIEND, TRUE);
+
+ return TRUE;
+ }
+ case MONSTER_ATTACK_RANGED:
+ {
+ makevectors(self.angles);
+ if(monster_leap(demon_anim_leap, Demon_JumpTouch, v_forward * 700 + '0 0 300', 0.8))
+ return TRUE;
+ }
+ }
+
return FALSE;
}
self.damageforcescale = 0;
self.classname = "monster_demon";
- self.checkattack = GenericCheckAttack;
- self.attack_melee = demon_attack_melee;
- self.attack_ranged = demon_jump;
+ self.monster_attackfunc = demon_attack;
self.nextthink = time + random() * 0.5 + 0.1;
self.think = demon_think;
const float dog_anim_die = 4;
const float dog_anim_pain = 5;
+void dog_think ()
+{
+ self.think = dog_think;
+ self.nextthink = time + self.ticrate;
+
+ monster_move(autocvar_g_monster_dog_speed_run, autocvar_g_monster_dog_speed_walk, 50, dog_anim_run, dog_anim_walk, dog_anim_idle);
+}
+
void Dog_JumpTouch ()
{
if (self.health <= 0)
self.touch = MonsterTouch;
}
-void dog_think ()
-{
- self.think = dog_think;
- self.nextthink = time + self.ticrate;
-
- monster_move(autocvar_g_monster_dog_speed_run, autocvar_g_monster_dog_speed_walk, 50, dog_anim_run, dog_anim_walk, dog_anim_idle);
-}
-
-float dog_attack ()
+float cerberus_attack(float attack_type)
{
- monsters_setframe(dog_anim_attack);
- self.attack_finished_single = time + 0.7;
-
- monster_melee(self.enemy, autocvar_g_monster_dog_bite_damage, 0.2, DEATH_MONSTER_DOG_BITE, TRUE);
+ switch(attack_type)
+ {
+ case MONSTER_ATTACK_MELEE:
+ {
+ monsters_setframe(dog_anim_attack);
+ self.attack_finished_single = time + 0.7;
+ monster_melee(self.enemy, autocvar_g_monster_dog_bite_damage, 0.2, DEATH_MONSTER_DOG_BITE, TRUE);
+
+ return TRUE;
+ }
+ case MONSTER_ATTACK_RANGED:
+ {
+ makevectors(self.angles);
+ if(monster_leap(dog_anim_attack, Dog_JumpTouch, v_forward * 300 + '0 0 200', 0.8))
+ return TRUE;
+ }
+ }
- return TRUE;
-}
-
-float dog_jump ()
-{
- makevectors(self.angles);
- if(monster_leap(dog_anim_attack, Dog_JumpTouch, v_forward * 300 + '0 0 200', 0.8))
- return TRUE;
-
return FALSE;
}
self.damageforcescale = 0;
self.classname = "monster_dog";
- self.attack_melee = dog_attack;
- self.attack_ranged = dog_jump;
- self.checkattack = GenericCheckAttack;
+ self.monster_attackfunc = cerberus_attack;
self.nextthink = time + random() * 0.5 + 0.1;
self.think = dog_think;
monster_move(autocvar_g_monster_fish_speed_run, autocvar_g_monster_fish_speed_walk, 10, fish_anim_swim, fish_anim_swim, fish_anim_swim);
}
-float fish_attack ()
+float fish_attack(float attack_type)
{
- monsters_setframe(fish_anim_attack);
- self.attack_finished_single = time + 0.5;
-
- monster_melee(self.enemy, autocvar_g_monster_fish_damage, 0.1, DEATH_MONSTER_FISH, FALSE);
+ switch(attack_type)
+ {
+ case MONSTER_ATTACK_MELEE:
+ {
+ monsters_setframe(fish_anim_attack);
+ self.attack_finished_single = time + 0.5;
+ monster_melee(self.enemy, autocvar_g_monster_fish_damage, 0.1, DEATH_MONSTER_FISH, FALSE);
+
+ return TRUE;
+ }
+ case MONSTER_ATTACK_RANGED:
+ }
- return TRUE;
+ return FALSE;
}
void fish_die ()
self.damageforcescale = 0.5;
self.classname = "monster_fish";
- self.checkattack = GenericCheckAttack;
- self.attack_melee = fish_attack;
+ self.monster_attackfunc = fish_attack;
self.flags |= FL_SWIM;
self.nextthink = time + random() * 0.5 + 0.1;
self.think = fish_think;
const float hellknight_anim_wattack = 12;
const float hellknight_anim_magic3 = 13;
+void hellknight_think()
+{
+ self.think = hellknight_think;
+ self.nextthink = time + self.ticrate;
+
+ monster_move(autocvar_g_monster_hellknight_speed_run, autocvar_g_monster_hellknight_speed_walk, 100, hellknight_anim_run, hellknight_anim_walk, hellknight_anim_stand);
+}
+
void hknight_spike_think()
{
if(self)
hknight_inferno();
}
-float() hknight_magic;
-float hknight_checkmagic ()
-{
- local vector v1 = '0 0 0', v2 = '0 0 0';
- local float dot = 0;
-
- // use magic to kill zombies as they heal too fast for sword
- if (self.enemy.monsterid == MONSTER_ZOMBIE)
- {
- traceline((self.absmin + self.absmax) * 0.5, (self.enemy.absmin + self.enemy.absmax) * 0.5, FALSE, self);
- if (trace_ent == self.enemy)
- {
- hknight_magic();
- return TRUE;
- }
- }
-
- if (random() < 0.25)
- return FALSE; // 25% of the time it won't do anything
- v1 = normalize(self.enemy.velocity);
- v2 = normalize(self.enemy.origin - self.origin);
- dot = v1 * v2;
- if (dot >= 0.7) // moving away
- if (vlen(self.enemy.velocity) >= 150) // walking/running away
- return hknight_magic();
- return FALSE;
-}
-
-void() hellknight_charge;
-void CheckForCharge ()
-{
- // check for mad charge
- if (time < self.attack_finished_single)
- return;
- if (fabs(self.origin_z - self.enemy.origin_z) > 20)
- return; // too much height change
- if (vlen (self.origin - self.enemy.origin) < 80)
- return; // use regular attack
- if (hknight_checkmagic())
- return; // chose magic
-
- // charge
- hellknight_charge();
-}
-
-void CheckContinueCharge ()
-{
- if(hknight_checkmagic())
- return; // chose magic
- if(time >= self.attack_finished_single)
- {
- hellknight_think();
- return; // done charging
- }
-}
-
-void hellknight_think ()
-{
- self.think = hellknight_think;
- self.nextthink = time + self.ticrate;
-
- monster_move(autocvar_g_monster_hellknight_speed_run, autocvar_g_monster_hellknight_speed_walk, 100, hellknight_anim_run, hellknight_anim_walk, hellknight_anim_stand);
-}
-
.float hknight_cycles;
void hellknight_magic ()
{
self.delay = time + 0.4;
}
-void hellknight_charge ()
-{
- monsters_setframe(hellknight_anim_charge1);
- self.attack_finished_single = time + 0.5;
-
- hknight_checkmagic();
- monster_melee(self.enemy, autocvar_g_monster_hellknight_melee_damage, 0.3, DEATH_MONSTER_HKNIGHT_MELEE, FALSE);
- hknight_checkmagic();
-}
-
-void hellknight_charge2 ()
-{
- monsters_setframe(hellknight_anim_charge2);
- self.attack_finished_single = time + 0.5;
-
- CheckContinueCharge ();
- monster_melee(self.enemy, autocvar_g_monster_hellknight_melee_damage, 0.3, DEATH_MONSTER_HKNIGHT_MELEE, FALSE);
-}
-
-void hellknight_slice ()
-{
- monsters_setframe(hellknight_anim_slice);
- self.attack_finished_single = time + 0.7;
- monster_melee(self.enemy, autocvar_g_monster_hellknight_melee_damage, 0.3, DEATH_MONSTER_HKNIGHT_MELEE, FALSE);
-}
-
-void hellknight_smash ()
-{
- monsters_setframe(hellknight_anim_smash);
- self.attack_finished_single = time + 0.7;
- monster_melee(self.enemy, autocvar_g_monster_hellknight_melee_damage, 0.3, DEATH_MONSTER_HKNIGHT_MELEE, TRUE);
-}
-
-void hellknight_weapon_attack ()
-{
- monsters_setframe(hellknight_anim_wattack);
- self.attack_finished_single = time + 0.7;
- monster_melee(self.enemy, autocvar_g_monster_hellknight_melee_damage, 0.3, DEATH_MONSTER_HKNIGHT_MELEE, TRUE);
-}
-
-float hknight_type;
-float hknight_melee ()
-{
- hknight_type += 1;
-
- if (hknight_type == 1)
- hellknight_slice();
- else if (hknight_type == 2)
- hellknight_smash();
- else
- {
- hellknight_weapon_attack();
- hknight_type = 0;
- }
-
- return TRUE;
-}
-
-float hknight_magic ()
+float hknight_magic()
{
if not(self.flags & FL_ONGROUND)
return FALSE;
}
return FALSE;
}
- default:
- return FALSE;
}
- // never get here
+
+ return FALSE;
+}
+
+float knight_attack(float attack_type)
+{
+ switch(attack_type)
+ {
+ case MONSTER_ATTACK_MELEE:
+ {
+ float anim;
+ if(random() < 0.3)
+ anim = hellknight_anim_slice;
+ else if(random() < 0.6)
+ anim = hellknight_anim_smash;
+ else
+ anim = hellknight_anim_wattack;
+
+ monsters_setframe(anim);
+ self.attack_finished_single = time + 0.7;
+ monster_melee(self.enemy, autocvar_g_monster_hellknight_melee_damage, 0.3, DEATH_MONSTER_HKNIGHT_MELEE, TRUE);
+
+ return TRUE;
+ }
+ case MONSTER_ATTACK_RANGED:
+ {
+ if(hknight_magic())
+ return TRUE;
+ }
+ }
+
+ return FALSE;
}
void hellknight_die ()
self.damageforcescale = 0.003;
self.classname = "monster_hellknight";
- self.checkattack = GenericCheckAttack;
- self.attack_melee = hknight_melee;
- self.attack_ranged = hknight_magic;
+ self.monster_attackfunc = knight_attack;
self.nextthink = time + random() * 0.5 + 0.1;
self.think = hellknight_think;
+++ /dev/null
-// size
-const vector KNIGHT_MIN = '-20 -20 -31';
-const vector KNIGHT_MAX = '20 20 53';
-
-// model
-string KNIGHT_MODEL = "models/monsters/knight.mdl";
-
-#ifdef SVQC
-// cvars
-float autocvar_g_monster_knight;
-float autocvar_g_monster_knight_health;
-float autocvar_g_monster_knight_melee_damage;
-float autocvar_g_monster_knight_speed_walk;
-float autocvar_g_monster_knight_speed_run;
-
-// animations
-const float knight_anim_stand = 0;
-const float knight_anim_run = 1;
-const float knight_anim_runattack = 2;
-const float knight_anim_pain1 = 3;
-const float knight_anim_pain2 = 4;
-const float knight_anim_attack = 5;
-const float knight_anim_walk = 6;
-const float knight_anim_kneel = 7;
-const float knight_anim_standing = 8;
-const float knight_anim_death1 = 9;
-const float knight_anim_death2 = 10;
-
-void knight_think ()
-{
- self.think = knight_think;
- self.nextthink = time + self.ticrate;
-
- monster_move(autocvar_g_monster_knight_speed_run, autocvar_g_monster_knight_speed_walk, 50, knight_anim_run, knight_anim_walk, knight_anim_stand);
-}
-
-float knight_attack ()
-{
- float len = vlen(self.velocity);
-
- monsters_setframe((len < 50) ? knight_anim_attack : knight_anim_runattack);
-
- self.attack_finished_single = time + 1.25;
-
- monster_melee(self.enemy, autocvar_g_monster_knight_melee_damage, 0.3, DEATH_MONSTER_KNIGHT, FALSE);
-
- return TRUE;
-}
-
-void knight_die ()
-{
- Monster_CheckDropCvars ("knight");
-
- self.think = monster_dead_think;
- self.nextthink = time + self.ticrate;
- self.ltime = time + 5;
- monsters_setframe((random() > 0.5) ? knight_anim_death1 : knight_anim_death2);
-
- monster_hook_death(); // for post-death mods
-}
-
-void knight_spawn ()
-{
- if not(self.health)
- self.health = autocvar_g_monster_knight_health;
-
- self.damageforcescale = 0.003;
- self.classname = "monster_knight";
- self.checkattack = GenericCheckAttack;
- self.attack_melee = knight_attack;
- self.nextthink = time + random() * 0.5 + 0.1;
- self.think = knight_think;
-
- monsters_setframe(knight_anim_stand);
-
- monster_setupsounds("knight");
-
- monster_hook_spawn(); // for post-spawn mods
-}
-
-void spawnfunc_monster_knight ()
-{
- if not(autocvar_g_monster_knight) { remove(self); return; }
-
- self.monster_spawnfunc = spawnfunc_monster_knight;
-
- if(Monster_CheckAppearFlags(self))
- return;
-
- self.scale = 1.3;
-
- if not (monster_initialize(
- "Knight", MONSTER_KNIGHT,
- KNIGHT_MIN, KNIGHT_MAX,
- FALSE,
- knight_die, knight_spawn))
- {
- remove(self);
- return;
- }
-}
-
-#endif // SVQC
void ogre_swing()
{
self.ogre_cycles += 1;
- monsters_setframe(ogre_anim_swing);
- if(self.ogre_cycles == 1)
- self.attack_finished_single = time + 1.3;
self.angles_y = self.angles_y + random()* 25;
self.delay = time + 0.2;
self.monster_delayedattack = ogre_swing;
self.monster_delayedattack = ogre_uzi_fire;
}
-void ogre_uzi()
-{
- monsters_setframe(ogre_anim_pain);
- self.attack_finished_single = time + 0.8;
- self.delay = time + 0.1;
- self.monster_delayedattack = ogre_uzi_fire;
-}
-
void ogre_grenade_explode()
{
pointparticles(particleeffectnum("grenade_explode"), self.origin, '0 0 0', 1);
void ogre_gl()
{
entity gren;
-
- monster_makevectors(self.enemy);
W_SetupShot_ProjectileSize (self, '-3 -3 -3', '3 3 3', FALSE, 4, "weapons/grenade_fire.wav", CH_WEAPON_A, autocvar_g_monster_ogre_attack_grenade_damage);
w_shotdir = v_forward; // no TrueAim for grenades please
gren.flags = FL_PROJECTILE;
CSQCProjectile(gren, TRUE, PROJECTILE_GRENADE, TRUE);
-
-
- monsters_setframe(ogre_anim_pain);
- self.attack_finished_single = time + 1.2;
}
-float ogre_missile()
+float ogre_attack(float attack_type)
{
- self.ogre_cycles = 0;
- if (random() <= autocvar_g_monster_ogre_attack_uzi_chance)
- {
- ogre_uzi();
- return TRUE;
- }
- else
+ switch(attack_type)
{
- ogre_gl();
- return TRUE;
+ case MONSTER_ATTACK_MELEE:
+ {
+ self.ogre_cycles = 0;
+ monsters_setframe(ogre_anim_swing);
+ self.attack_finished_single = time + 1.3;
+ ogre_swing();
+
+ return TRUE;
+ }
+ case MONSTER_ATTACK_RANGED:
+ {
+ self.ogre_cycles = 0;
+ if(random() <= autocvar_g_monster_ogre_attack_uzi_chance)
+ {
+ monsters_setframe(ogre_anim_pain);
+ self.attack_finished_single = time + 0.8;
+ self.delay = time + 0.1;
+ self.monster_delayedattack = ogre_uzi_fire;
+ }
+ else
+ {
+ monster_makevectors(self.enemy);
+ ogre_gl();
+ monsters_setframe(ogre_anim_pain);
+ self.attack_finished_single = time + 1.2;
+ }
+
+ return TRUE;
+ }
}
-}
-
-float ogre_melee()
-{
- self.ogre_cycles = 0;
- ogre_swing();
- return TRUE;
+
+ return FALSE;
}
void ogre_die()
self.damageforcescale = 0.003;
self.classname = "monster_ogre";
- self.checkattack = GenericCheckAttack;
- self.attack_melee = ogre_melee;
- self.attack_ranged = ogre_missile;
+ self.monster_attackfunc = ogre_attack;
self.nextthink = time + random() * 0.5 + 0.1;
self.think = ogre_think;
self.weapon = WEP_GRENADE_LAUNCHER;
const float shalrath_anim_run = 5;
void() ShalMissile;
-float() shal_missile;
void() shalrath_heal;
void() shalrath_shield;
void() shalrath_shield_die;
monster_move(autocvar_g_monster_shalrath_speed, autocvar_g_monster_shalrath_speed, 50, shalrath_anim_walk, shalrath_anim_run, shalrath_anim_idle);
}
-void shalrath_attack()
-{
- monsters_setframe(shalrath_anim_attack);
- self.delay = time + 0.2;
- self.attack_finished_single = time + autocvar_g_monster_shalrath_attack_spike_delay;
- self.monster_delayedattack = ShalMissile;
-}
-
void shalrathattack_melee()
{
monster_melee(self.enemy, autocvar_g_monster_shalrath_attack_melee_damage, 0.3, DEATH_MONSTER_MAGE, TRUE);
self.monster_delayedattack = func_null;
}
-float shalrath_attack_melee()
-{
- self.monster_delayedattack = shalrathattack_melee;
- self.delay = time + 0.2;
- monsters_setframe(shalrath_anim_attack);
- self.attack_finished_single = time + autocvar_g_monster_shalrath_attack_melee_delay;
-
- return TRUE;
-}
-
void shalrath_grenade_explode()
{
pointparticles(particleeffectnum("explosion_small"), self.origin, '0 0 0', 1);
self.attack_finished_single = time + 1.5;
}
-float shal_missile()
-{
- if(random() < autocvar_g_monster_shalrath_attack_grenade_chance / 100)
- {
- shalrath_throw_itemgrenade();
- return TRUE;
- }
-
- shalrath_attack();
-
- return TRUE;
-}
-
void ShalHome()
{
local vector dir = '0 0 0', vtemp = self.enemy.origin + '0 0 10';
if(time < self.attack_finished_single)
return FALSE;
+
+ if not(self.monster_attackfunc)
+ return FALSE; // no attack function?!
if (vlen(self.enemy.origin - self.origin) <= 120)
- { // melee attack
- if (self.attack_melee)
+ {
+ if(self.monster_attackfunc(MONSTER_ATTACK_MELEE))
{
monster_sound(self.msound_attack_melee, 0, FALSE); // no delay for attack sounds
- self.attack_melee();
return TRUE;
}
}
//if (trace_inopen && trace_inwater)
// return FALSE; // sight line crossed contents
- if (self.attack_ranged())
+ if (self.monster_attackfunc(MONSTER_ATTACK_RANGED))
return TRUE;
return FALSE;
self.armorvalue = autocvar_g_monster_shalrath_shield_blockpercent / 100;
}
+float mage_attack(float attack_type)
+{
+ switch(attack_type)
+ {
+ case MONSTER_ATTACK_MELEE:
+ {
+ self.monster_delayedattack = shalrathattack_melee;
+ self.delay = time + 0.2;
+ monsters_setframe(shalrath_anim_attack);
+ self.attack_finished_single = time + autocvar_g_monster_shalrath_attack_melee_delay;
+
+ return TRUE;
+ }
+ case MONSTER_ATTACK_RANGED:
+ {
+ if(random() < autocvar_g_monster_shalrath_attack_grenade_chance / 100)
+ {
+ shalrath_throw_itemgrenade();
+ return TRUE;
+ }
+
+ monsters_setframe(shalrath_anim_attack);
+ self.delay = time + 0.2;
+ self.attack_finished_single = time + autocvar_g_monster_shalrath_attack_spike_delay;
+ self.monster_delayedattack = ShalMissile;
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
void shalrath_die()
{
Monster_CheckDropCvars ("shalrath");
self.damageforcescale = 0.003;
self.classname = "monster_shalrath";
self.checkattack = ShalrathCheckAttack;
- self.attack_ranged = shal_missile;
- self.attack_melee = shalrath_attack_melee;
+ self.monster_attackfunc = mage_attack;
self.nextthink = time + random() * 0.5 + 0.1;
self.think = shalrath_think;
}
}
-float sham_melee ()
-{
- local float chance = random();
-
- if (chance > 0.6)
- shambler_delayedsmash();
- else if (chance > 0.3)
- shambler_swing_right ();
- else
- shambler_swing_left ();
-
- return TRUE;
-}
-
void CastLightning ()
{
self.monster_delayedattack = func_null;
WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3"), org, v);
}
-void shambler_magic ()
+float shambler_attack(float attack_type)
{
- monsters_setframe(shambler_anim_magic);
- self.attack_finished_single = time + 1.1;
- self.monster_delayedattack = CastLightning;
- self.delay = time + 0.6;
-}
+ switch(attack_type)
+ {
+ case MONSTER_ATTACK_MELEE:
+ {
+ float chance = random();
+
+ if(chance > 0.6)
+ shambler_delayedsmash();
+ else if(chance > 0.3)
+ shambler_swing_right();
+ else
+ shambler_swing_left();
+
+ return TRUE;
+ }
+ case MONSTER_ATTACK_RANGED:
+ {
+ monsters_setframe(shambler_anim_magic);
+ self.attack_finished_single = time + 1.1;
+ self.monster_delayedattack = CastLightning;
+ self.delay = time + 0.6;
+
+ return TRUE;
+ }
+ }
-float sham_lightning ()
-{
- shambler_magic();
- return TRUE;
+ return FALSE;
}
void shambler_die ()
self.damageforcescale = 0.003;
self.classname = "monster_shambler";
- self.attack_melee = sham_melee;
- self.checkattack = GenericCheckAttack;
- self.attack_ranged = sham_lightning;
+ self.monster_attackfunc = shambler_attack;
self.nextthink = time + random() * 0.5 + 0.1;
self.think = shambler_think;
self.weapon = WEP_NEX;
}
}
-float slime_attack()
+float slime_attack(float attack_type)
{
- makevectors(self.angles);
- if(monster_leap(slime_anim_jump, slime_touch_jump, v_forward * 600 + '0 0 200', 0.5))
- return TRUE;
+ switch(attack_type)
+ {
+ case MONSTER_ATTACK_MELEE:
+ case MONSTER_ATTACK_RANGED:
+ {
+ makevectors(self.angles);
+ if(monster_leap(slime_anim_jump, slime_touch_jump, v_forward * 600 + '0 0 200', 0.5))
+ return TRUE;
+ }
+ }
return FALSE;
}
self.damageforcescale = 0.003;
self.classname = "monster_slime";
- self.checkattack = GenericCheckAttack;
- self.attack_ranged = slime_attack;
- self.attack_melee = self.attack_ranged;
+ self.monster_attackfunc = slime_attack;
self.nextthink = time + random() * 0.5 + 0.1;
self.think = slime_think;
CSQCProjectile(missile, TRUE, PROJECTILE_LASER, TRUE);
}
-float soldier_attack()
+float marine_attack(float attack_type)
{
- monsters_setframe(soldier_anim_shoot);
-
- monster_makevectors(self.enemy);
-
- if(self.currentammo <= 0)
+ switch(attack_type)
{
- soldier_reload();
- return FALSE;
- }
-
- self.grunt_cycles = 0;
-
- switch(self.weapon)
- {
- case WEP_ROCKET_LAUNCHER:
- {
- self.currentammo -= 1;
- self.attack_finished_single = time + 0.8;
- soldier_rocket_fire();
- return TRUE;
- }
- case WEP_SHOTGUN:
- {
- self.currentammo -= 1;
- self.attack_finished_single = time + 0.8;
- soldier_shotgun_fire();
- return TRUE;
- }
- case WEP_UZI:
+ case MONSTER_ATTACK_MELEE:
{
+ monsters_setframe(soldier_anim_shoot);
self.attack_finished_single = time + 0.8;
- self.delay = time + 0.1;
- self.monster_delayedattack = soldier_uzi_fire;
+ monster_melee(self.enemy, autocvar_g_monster_soldier_melee_damage, 0.3, DEATH_MONSTER_MARINE_SLAP, TRUE);
+
return TRUE;
}
- case WEP_LASER:
+ case MONSTER_ATTACK_RANGED:
{
- self.attack_finished_single = time + 0.8;
- soldier_laser_fire();
- return TRUE;
+ if(self.currentammo <= 0)
+ {
+ soldier_reload();
+
+ return FALSE;
+ }
+
+ monsters_setframe(soldier_anim_shoot);
+ monster_makevectors(self.enemy);
+ self.grunt_cycles = 0;
+
+ switch(self.weapon)
+ {
+ case WEP_ROCKET_LAUNCHER:
+ {
+ self.currentammo -= 1;
+ self.attack_finished_single = time + 0.8;
+ soldier_rocket_fire();
+
+ return TRUE;
+ }
+ case WEP_SHOTGUN:
+ {
+ self.currentammo -= 1;
+ self.attack_finished_single = time + 0.8;
+ soldier_shotgun_fire();
+
+ return TRUE;
+ }
+ case WEP_UZI:
+ {
+ self.attack_finished_single = time + 0.8;
+ self.delay = time + 0.1;
+ self.monster_delayedattack = soldier_uzi_fire;
+
+ return TRUE;
+ }
+ case WEP_LASER:
+ {
+ self.attack_finished_single = time + 0.8;
+ soldier_laser_fire();
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
}
- default:
- return FALSE; // no weapon?
}
-}
-
-float soldier_melee ()
-{
- monsters_setframe(soldier_anim_shoot);
- self.attack_finished_single = time + 0.8;
- monster_melee(self.enemy, autocvar_g_monster_soldier_melee_damage, 0.3, DEATH_MONSTER_MARINE_SLAP, TRUE);
- return TRUE;
+ return FALSE;
}
void soldier_die()
self.damageforcescale = 0.003;
self.classname = "monster_soldier";
- self.checkattack = GenericCheckAttack;
- self.attack_melee = soldier_melee;
- self.attack_ranged = soldier_attack;
+ self.monster_attackfunc = marine_attack;
self.nextthink = time + random() * 0.5 + 0.1;
self.think = soldier_think;
self.currentammo = 3;
const float SPIDER_TYPE_ICE = 0;
const float SPIDER_TYPE_FIRE = 1;
-float spider_attack_standing()
-{
- monster_melee(self.enemy, autocvar_g_monster_spider_attack_stand_damage, 0.3, DEATH_MONSTER_SPIDER, TRUE);
-
- monsters_setframe((random() > 0.5) ? spider_anim_attack : spider_anim_attack2);
-
- self.attack_finished_single = time + autocvar_g_monster_spider_attack_stand_delay;
+void spider_think()
+{
+ self.think = spider_think;
+ self.nextthink = time + self.ticrate;
- return TRUE;
+ monster_move(autocvar_g_monster_spider_speed_run, autocvar_g_monster_spider_speed_walk, autocvar_g_monster_spider_stopspeed, spider_anim_walk, spider_anim_walk, spider_anim_idle);
}
void spider_web_explode ()
proj.bouncestop = 0.05;
proj.missile_flags = MIF_SPLASH | MIF_ARC;
- CSQCProjectile(proj, TRUE, p, FALSE); // no culling, it has sound
+ CSQCProjectile(proj, TRUE, p, TRUE);
}
-void spider_attack_leap()
+float spider_attack(float attack_type)
{
- vector angles_face = vectoangles(self.enemy.origin - self.origin);
-
- // face the enemy
- monsters_setframe(spider_anim_attack2);
- self.angles_y = angles_face_y ;
- self.attack_finished_single = time + autocvar_g_monster_spider_attack_leap_delay;
-
- monster_makevectors(self.enemy);
-
- spider_shootweb(self.spider_type);
-}
-
-float spider_attack_ranged()
-{
- if(self.enemy.frozen)
- return FALSE;
-
- spider_attack_leap();
- return TRUE;
-}
-
-void spider_think()
-{
- self.think = spider_think;
- self.nextthink = time + self.ticrate;
+ switch(attack_type)
+ {
+ case MONSTER_ATTACK_MELEE:
+ {
+ monster_melee(self.enemy, autocvar_g_monster_spider_attack_stand_damage, 0.3, DEATH_MONSTER_SPIDER, TRUE);
+ monsters_setframe((random() > 0.5) ? spider_anim_attack : spider_anim_attack2);
+ self.attack_finished_single = time + autocvar_g_monster_spider_attack_stand_delay;
+
+ return TRUE;
+ }
+ case MONSTER_ATTACK_RANGED:
+ {
+ if(self.enemy.frozen)
+ return FALSE;
+
+ monsters_setframe(spider_anim_attack2);
+ self.attack_finished_single = time + autocvar_g_monster_spider_attack_leap_delay;
+ monster_makevectors(self.enemy);
+ spider_shootweb(self.spider_type);
+
+ return TRUE;
+ }
+ }
- monster_move(autocvar_g_monster_spider_speed_run, autocvar_g_monster_spider_speed_walk, autocvar_g_monster_spider_stopspeed, spider_anim_walk, spider_anim_walk, spider_anim_idle);
+ return FALSE;
}
void spider_die ()
self.classname = "monster_spider";
self.nextthink = time + random() * 0.5 + 0.1;
- self.checkattack = GenericCheckAttack;
- self.attack_melee = spider_attack_standing;
- self.attack_ranged = spider_attack_ranged;
+ self.monster_attackfunc = spider_attack;
self.think = spider_think;
monsters_setframe(spider_anim_idle);
const float wizard_anim_pain = 3;
const float wizard_anim_death = 4;
+void wizard_think ()
+{
+ self.think = wizard_think;
+ self.nextthink = time + self.ticrate;
+
+ monster_move(autocvar_g_monster_wizard_speed_run, autocvar_g_monster_wizard_speed_walk, 300, wizard_anim_fly, wizard_anim_hover, wizard_anim_hover);
+}
+
void Wiz_FastExplode()
{
self.event_damage = func_null;
CSQCProjectile(missile, TRUE, PROJECTILE_CRYLINK, TRUE);
}
-void wizard_think ()
+float wyvern_attack(float attack_type)
{
- self.think = wizard_think;
- self.nextthink = time + self.ticrate;
+ switch(attack_type)
+ {
+ case MONSTER_ATTACK_MELEE:
+ case MONSTER_ATTACK_RANGED:
+ {
+ Wiz_StartFast();
+
+ return TRUE;
+ }
+ }
- monster_move(autocvar_g_monster_wizard_speed_run, autocvar_g_monster_wizard_speed_walk, 300, wizard_anim_fly, wizard_anim_hover, wizard_anim_hover);
-}
-
-void wizard_fastattack ()
-{
- Wiz_StartFast();
+ return FALSE;
}
void wizard_die ()
monster_hook_death(); // for post-death mods
}
-float Wiz_Missile ()
-{
- wizard_fastattack();
- return TRUE;
-}
-
void wizard_spawn ()
{
if not(self.health)
self.health = autocvar_g_monster_wizard_health;
self.classname = "monster_wizard";
- self.checkattack = GenericCheckAttack;
- self.attack_ranged = Wiz_Missile;
+ self.monster_attackfunc = wyvern_attack;
self.nextthink = time + random() * 0.5 + 0.1;
self.movetype = MOVETYPE_FLY; // TODO: make it fly up/down
self.flags |= FL_FLY;
const float zombie_anim_runforwardright = 29;
const float zombie_anim_spawn = 30;
-float zombie_attack_standing()
+void zombie_think()
{
- float rand = random(), chosen_anim;
-
- if (rand < 0.33)
- chosen_anim = zombie_anim_attackstanding1;
- else if (rand < 0.66)
- chosen_anim = zombie_anim_attackstanding2;
- else
- chosen_anim = zombie_anim_attackstanding3;
-
- monsters_setframe(chosen_anim);
+ self.think = zombie_think;
+ self.nextthink = time + self.ticrate;
- self.attack_finished_single = time + autocvar_g_monster_zombie_attack_stand_delay;
-
- monster_melee(self.enemy, autocvar_g_monster_zombie_attack_stand_damage, 0.3, DEATH_MONSTER_ZOMBIE_MELEE, TRUE);
-
- return TRUE;
+ monster_move(autocvar_g_monster_zombie_speed_run, autocvar_g_monster_zombie_speed_walk, autocvar_g_monster_zombie_stopspeed, zombie_anim_runforward, zombie_anim_runforward, zombie_anim_idle);
}
void zombie_attack_leap_touch ()
vector angles_face;
- if (monster_isvalidtarget(other, self))
+ if(other.takedamage)
{
angles_face = vectoangles(self.moveto - self.origin);
angles_face = normalize(angles_face) * autocvar_g_monster_zombie_attack_leap_force;
self.touch = MonsterTouch; // instantly turn it off to stop damage spam
}
- if(self.flags & FL_ONGROUND)
+ if (trace_dphitcontents)
self.touch = MonsterTouch;
}
-float zombie_attack_ranged()
+float zombie_attack(float attack_type)
{
- makevectors(self.angles);
- if(monster_leap(zombie_anim_attackleap, zombie_attack_leap_touch, v_forward * autocvar_g_monster_zombie_attack_leap_speed + '0 0 200', autocvar_g_monster_zombie_attack_leap_delay))
- return TRUE;
+ switch(attack_type)
+ {
+ case MONSTER_ATTACK_MELEE:
+ {
+ float rand = random(), chosen_anim;
- return FALSE;
-}
-
-void zombie_think()
-{
- self.think = zombie_think;
- self.nextthink = time + self.ticrate;
+ if(rand < 0.33)
+ chosen_anim = zombie_anim_attackstanding1;
+ else if(rand < 0.66)
+ chosen_anim = zombie_anim_attackstanding2;
+ else
+ chosen_anim = zombie_anim_attackstanding3;
+
+ monsters_setframe(chosen_anim);
- monster_move(autocvar_g_monster_zombie_speed_run, autocvar_g_monster_zombie_speed_walk, autocvar_g_monster_zombie_stopspeed, zombie_anim_runforward, zombie_anim_runforward, zombie_anim_idle);
+ self.attack_finished_single = time + autocvar_g_monster_zombie_attack_stand_delay;
+
+ monster_melee(self.enemy, autocvar_g_monster_zombie_attack_stand_damage, 0.3, DEATH_MONSTER_ZOMBIE_MELEE, TRUE);
+
+ return TRUE;
+ }
+ case MONSTER_ATTACK_RANGED:
+ {
+ makevectors(self.angles);
+ if(monster_leap(zombie_anim_attackleap, zombie_attack_leap_touch, v_forward * autocvar_g_monster_zombie_attack_leap_speed + '0 0 200', autocvar_g_monster_zombie_attack_leap_delay))
+ return TRUE;
+ }
+ }
+
+ return FALSE;
}
void zombie_die ()
self.spawn_time = time + 2.1;
self.nextthink = time + random() * 0.5 + 0.1;
self.think = zombie_think;
- self.checkattack = GenericCheckAttack;
- self.attack_melee = zombie_attack_standing;
- self.attack_ranged = zombie_attack_ranged;
+ self.monster_attackfunc = zombie_attack;
self.respawntime = 0.1;
self.spawnflags |= MONSTER_RESPAWN_DEATHPOINT; // always enabled for zombie
#include "monster/ogre.qc"
#include "monster/demon.qc"
#include "monster/shambler.qc"
-#include "monster/knight.qc"
+#include "monster/bruiser.qc"
#include "monster/soldier.qc"
#include "monster/wizard.qc"
#include "monster/dog.qc"
switch(mnster)
{
default:
- case MONSTER_KNIGHT:
+ case MONSTER_BRUISER:
case MONSTER_MARINE:
case MONSTER_ZOMBIE:
case MONSTER_SPIDER:
case MONSTER_OGRE: return "ogre";
case MONSTER_DEMON: return "demon";
case MONSTER_SHAMBLER: return "shambler";
- case MONSTER_KNIGHT: return "knight";
+ case MONSTER_BRUISER: return "bruiser";
case MONSTER_MARINE: return "marine";
case MONSTER_SCRAG: return "scrag";
case MONSTER_DOG: return "dog";
switch(mnster)
{
default:
- case MONSTER_KNIGHT:
+ case MONSTER_BRUISER:
case MONSTER_MARINE:
case MONSTER_ZOMBIE:
case MONSTER_SPIDER:
if(n_spiders) RandomSelection_Add(world, MONSTER_SPIDER, "", 1, 1);
if(n_ogres) RandomSelection_Add(world, MONSTER_OGRE, "", 1, 1);
if(n_dogs) RandomSelection_Add(world, MONSTER_DOG, "", 1, 1);
- if(n_knights) RandomSelection_Add(world, MONSTER_KNIGHT, "", 1, 1);
+ if(n_bruisers) RandomSelection_Add(world, MONSTER_BRUISER, "", 1, 1);
if(n_shamblers) RandomSelection_Add(world, MONSTER_SHAMBLER, "", 0.2, 0.2);
if(n_slimes) RandomSelection_Add(world, MONSTER_SLIME, "", 0.2, 0.2);
if(n_wizards && flyspawns_count) RandomSelection_Add(world, MONSTER_SCRAG, "", 1, 1);
n_demons = DistributeEvenly_Get(1);
n_ogres = DistributeEvenly_Get(1);
n_dogs = DistributeEvenly_Get(1);
- n_knights = DistributeEvenly_Get(1);
+ n_bruisers = DistributeEvenly_Get(1);
n_shalraths = DistributeEvenly_Get(1);
n_soldiers = DistributeEvenly_Get(1);
n_hknights = DistributeEvenly_Get(1);
case MONSTER_OGRE: n_ogres -= 1; break;
case MONSTER_DEMON: n_demons -= 1; break;
case MONSTER_SHAMBLER: n_shamblers -= 1; break;
- case MONSTER_KNIGHT: n_knights -= 1; break;
+ case MONSTER_BRUISER: n_bruisers -= 1; break;
case MONSTER_MARINE: n_soldiers -= 1; break;
case MONSTER_SCRAG: n_wizards -= 1; break;
case MONSTER_DOG: n_dogs -= 1; break;
// Counters
float monster_count, totalmonsters;
-float n_knights, n_dogs, n_ogres, n_shamblers, n_wizards, n_shalraths, n_soldiers, n_hknights, n_demons, n_zombies, n_slimes, n_fish, n_spiders;
+float n_bruisers, n_dogs, n_ogres, n_shamblers, n_wizards, n_shalraths, n_soldiers, n_hknights, n_demons, n_zombies, n_slimes, n_fish, n_spiders;
float current_monsters;
float waterspawns_count, flyspawns_count;
float wave_count, max_waves;