From: Mario Date: Sat, 27 Apr 2013 20:12:59 +0000 (+1000) Subject: Rewrite monster attacks as a single function & rename knight to bruiser X-Git-Tag: xonotic-v0.8.0~241^2^2~273 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=a7a0b46ef0bc4b3102f5c6f4d4670056494fe296;p=xonotic%2Fxonotic-data.pk3dir.git Rewrite monster attacks as a single function & rename knight to bruiser --- diff --git a/monsters.cfg b/monsters.cfg index ad9e36703..4b6611276 100644 --- a/monsters.cfg +++ b/monsters.cfg @@ -25,7 +25,7 @@ set g_monsters_skill_normal 4 "Monster normal skill level (used for skill based 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" @@ -65,15 +65,15 @@ set g_monster_shambler_drop_size large "Size of the item Shamblers drop. Possibl 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" diff --git a/qcsrc/client/monsters.qc b/qcsrc/client/monsters.qc index e8b8d990f..68ff59610 100644 --- a/qcsrc/client/monsters.qc +++ b/qcsrc/client/monsters.qc @@ -34,9 +34,9 @@ void monster_precache(float _mid) precache_model(SHAMBLER_MODEL); break; } - case MONSTER_KNIGHT: + case MONSTER_BRUISER: { - precache_model(KNIGHT_MODEL); + precache_model(BRUISER_MODEL); break; } case MONSTER_MARINE: @@ -135,12 +135,12 @@ void monster_mid2info(float _mid) 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; } diff --git a/qcsrc/common/deathtypes.qh b/qcsrc/common/deathtypes.qh index 81a53e7f1..506cb9cac 100644 --- a/qcsrc/common/deathtypes.qh +++ b/qcsrc/common/deathtypes.qh @@ -24,7 +24,7 @@ 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) \ diff --git a/qcsrc/common/notifications.qh b/qcsrc/common/notifications.qh index d081e1e65..9e0d60f51 100644 --- a/qcsrc/common/notifications.qh +++ b/qcsrc/common/notifications.qh @@ -296,7 +296,7 @@ void Send_Notification_WOVA( 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"), "") \ @@ -652,7 +652,7 @@ void Send_Notification_WOVA( 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) \ diff --git a/qcsrc/server/monsters/lib/defs.qh b/qcsrc/server/monsters/lib/defs.qh index fbeadc634..4169c0d91 100644 --- a/qcsrc/server/monsters/lib/defs.qh +++ b/qcsrc/server/monsters/lib/defs.qh @@ -1,7 +1,9 @@ -.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 diff --git a/qcsrc/server/monsters/lib/monsters.qc b/qcsrc/server/monsters/lib/monsters.qc index 181aa8d8d..ad2924478 100644 --- a/qcsrc/server/monsters/lib/monsters.qc +++ b/qcsrc/server/monsters/lib/monsters.qc @@ -372,23 +372,21 @@ float GenericCheckAttack () 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; @@ -1003,6 +1001,7 @@ float monster_initialize(string net_name, float mon_id, 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 diff --git a/qcsrc/server/monsters/lib/monsters_early.qh b/qcsrc/server/monsters/lib/monsters_early.qh index 0c0cdfcd0..b0d3fb932 100644 --- a/qcsrc/server/monsters/lib/monsters_early.qh +++ b/qcsrc/server/monsters/lib/monsters_early.qh @@ -26,7 +26,7 @@ float MONSTER_ZOMBIE = 2; 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; diff --git a/qcsrc/server/monsters/lib/spawn.qc b/qcsrc/server/monsters/lib/spawn.qc index 40c2b7f6c..2912f0ad7 100644 --- a/qcsrc/server/monsters/lib/spawn.qc +++ b/qcsrc/server/monsters/lib/spawn.qc @@ -26,7 +26,7 @@ entity spawnmonster (string monster, entity spawnedby, entity own, vector orig, setorigin(e, orig); if not(spawnmonster_checkinlist(monster, autocvar_g_monsters_spawn_list)) - monster = "knight"; + monster = "bruiser"; e.realowner = spawnedby; diff --git a/qcsrc/server/monsters/monster/bruiser.qc b/qcsrc/server/monsters/monster/bruiser.qc new file mode 100644 index 000000000..bf2983735 --- /dev/null +++ b/qcsrc/server/monsters/monster/bruiser.qc @@ -0,0 +1,109 @@ +// 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 diff --git a/qcsrc/server/monsters/monster/demon.qc b/qcsrc/server/monsters/monster/demon.qc index 634bdfc1b..28e97b6c4 100644 --- a/qcsrc/server/monsters/monster/demon.qc +++ b/qcsrc/server/monsters/monster/demon.qc @@ -31,16 +31,6 @@ void demon_think () 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) @@ -59,12 +49,26 @@ void Demon_JumpTouch () 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; } @@ -87,9 +91,7 @@ void demon_spawn () 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; diff --git a/qcsrc/server/monsters/monster/dog.qc b/qcsrc/server/monsters/monster/dog.qc index 99288ae8c..0846b7b64 100644 --- a/qcsrc/server/monsters/monster/dog.qc +++ b/qcsrc/server/monsters/monster/dog.qc @@ -22,6 +22,14 @@ const float dog_anim_attack = 3; 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) @@ -37,30 +45,26 @@ void Dog_JumpTouch () 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; } @@ -83,9 +87,7 @@ void dog_spawn () 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; diff --git a/qcsrc/server/monsters/monster/fish.qc b/qcsrc/server/monsters/monster/fish.qc index 4d490745a..1f19da0d1 100644 --- a/qcsrc/server/monsters/monster/fish.qc +++ b/qcsrc/server/monsters/monster/fish.qc @@ -27,14 +27,22 @@ void fish_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 () @@ -56,8 +64,7 @@ void fish_spawn () 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; diff --git a/qcsrc/server/monsters/monster/hknight.qc b/qcsrc/server/monsters/monster/hknight.qc index f16cb1593..1de3ba525 100644 --- a/qcsrc/server/monsters/monster/hknight.qc +++ b/qcsrc/server/monsters/monster/hknight.qc @@ -45,6 +45,14 @@ const float hellknight_anim_smash = 11; 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) @@ -118,70 +126,6 @@ void hknight_infernowarning () 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 () { @@ -269,65 +213,7 @@ void hellknight_magic3 () 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; @@ -386,10 +272,39 @@ float hknight_magic () } 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 () @@ -419,9 +334,7 @@ void hellknight_spawn () 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; diff --git a/qcsrc/server/monsters/monster/knight.qc b/qcsrc/server/monsters/monster/knight.qc deleted file mode 100644 index 78226208f..000000000 --- a/qcsrc/server/monsters/monster/knight.qc +++ /dev/null @@ -1,103 +0,0 @@ -// 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 diff --git a/qcsrc/server/monsters/monster/ogre.qc b/qcsrc/server/monsters/monster/ogre.qc index 7b051a96d..238526ba1 100644 --- a/qcsrc/server/monsters/monster/ogre.qc +++ b/qcsrc/server/monsters/monster/ogre.qc @@ -41,9 +41,6 @@ void ogre_think() 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; @@ -78,14 +75,6 @@ void ogre_uzi_fire() 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); @@ -137,8 +126,6 @@ void ogre_grenade_think() 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 @@ -172,32 +159,44 @@ void ogre_gl() 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() @@ -219,9 +218,7 @@ void ogre_spawn() 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; diff --git a/qcsrc/server/monsters/monster/shalrath.qc b/qcsrc/server/monsters/monster/shalrath.qc index 44f52acdd..fbbccc9d1 100644 --- a/qcsrc/server/monsters/monster/shalrath.qc +++ b/qcsrc/server/monsters/monster/shalrath.qc @@ -39,7 +39,6 @@ const float shalrath_anim_death = 4; const float shalrath_anim_run = 5; void() ShalMissile; -float() shal_missile; void() shalrath_heal; void() shalrath_shield; void() shalrath_shield_die; @@ -94,14 +93,6 @@ void shalrath_think() 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); @@ -110,16 +101,6 @@ void shalrathattack_melee() 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); @@ -171,19 +152,6 @@ void shalrath_throw_itemgrenade() 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'; @@ -278,13 +246,15 @@ float ShalrathCheckAttack() 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; } } @@ -301,7 +271,7 @@ float ShalrathCheckAttack() //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; @@ -388,6 +358,39 @@ void shalrath_shield() 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"); @@ -408,8 +411,7 @@ void shalrath_spawn() 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; diff --git a/qcsrc/server/monsters/monster/shambler.qc b/qcsrc/server/monsters/monster/shambler.qc index f139d72a2..2ec7f6d6f 100644 --- a/qcsrc/server/monsters/monster/shambler.qc +++ b/qcsrc/server/monsters/monster/shambler.qc @@ -79,20 +79,6 @@ void shambler_swing_right () } } -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; @@ -117,18 +103,35 @@ void CastLightning () 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 () @@ -150,9 +153,7 @@ void shambler_spawn () 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; diff --git a/qcsrc/server/monsters/monster/slime.qc b/qcsrc/server/monsters/monster/slime.qc index 57821556a..dd8fdae30 100644 --- a/qcsrc/server/monsters/monster/slime.qc +++ b/qcsrc/server/monsters/monster/slime.qc @@ -49,11 +49,18 @@ void slime_touch_jump() } } -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; } @@ -102,9 +109,7 @@ void slime_spawn() 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; diff --git a/qcsrc/server/monsters/monster/soldier.qc b/qcsrc/server/monsters/monster/soldier.qc index 4a85f8492..dfe7de825 100644 --- a/qcsrc/server/monsters/monster/soldier.qc +++ b/qcsrc/server/monsters/monster/soldier.qc @@ -237,61 +237,71 @@ void soldier_laser_fire() 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() @@ -313,9 +323,7 @@ void soldier_spawn () 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; diff --git a/qcsrc/server/monsters/monster/spider.qc b/qcsrc/server/monsters/monster/spider.qc index 3867894bf..4487ba726 100644 --- a/qcsrc/server/monsters/monster/spider.qc +++ b/qcsrc/server/monsters/monster/spider.qc @@ -28,15 +28,12 @@ const float spider_anim_attack2 = 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 () @@ -130,38 +127,36 @@ void spider_shootweb(float ptype) 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 () @@ -184,9 +179,7 @@ void spider_spawn() 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); diff --git a/qcsrc/server/monsters/monster/wizard.qc b/qcsrc/server/monsters/monster/wizard.qc index 04880534c..03813dd14 100644 --- a/qcsrc/server/monsters/monster/wizard.qc +++ b/qcsrc/server/monsters/monster/wizard.qc @@ -23,6 +23,14 @@ const float wizard_anim_magic = 2; 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; @@ -84,17 +92,20 @@ void Wiz_StartFast () 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 () @@ -113,20 +124,13 @@ 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; diff --git a/qcsrc/server/monsters/monster/zombie.qc b/qcsrc/server/monsters/monster/zombie.qc index d9c45d9ff..a1d0b5395 100644 --- a/qcsrc/server/monsters/monster/zombie.qc +++ b/qcsrc/server/monsters/monster/zombie.qc @@ -52,24 +52,12 @@ const float zombie_anim_runforwardleft = 28; 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 () @@ -79,7 +67,7 @@ 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; @@ -87,25 +75,42 @@ void zombie_attack_leap_touch () 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 () @@ -129,9 +134,7 @@ void zombie_spawn() 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 diff --git a/qcsrc/server/monsters/monsters.qh b/qcsrc/server/monsters/monsters.qh index d1ff2db38..0d5c260a3 100644 --- a/qcsrc/server/monsters/monsters.qh +++ b/qcsrc/server/monsters/monsters.qh @@ -9,7 +9,7 @@ #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" diff --git a/qcsrc/server/mutators/gamemode_towerdefense.qc b/qcsrc/server/mutators/gamemode_towerdefense.qc index dcc79b82c..bd43d4218 100644 --- a/qcsrc/server/mutators/gamemode_towerdefense.qc +++ b/qcsrc/server/mutators/gamemode_towerdefense.qc @@ -379,7 +379,7 @@ float Monster_GetStrength(float mnster) switch(mnster) { default: - case MONSTER_KNIGHT: + case MONSTER_BRUISER: case MONSTER_MARINE: case MONSTER_ZOMBIE: case MONSTER_SPIDER: @@ -406,7 +406,7 @@ string monster_type2string(float mnster) 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"; @@ -424,7 +424,7 @@ float Monster_GetType(float mnster) switch(mnster) { default: - case MONSTER_KNIGHT: + case MONSTER_BRUISER: case MONSTER_MARINE: case MONSTER_ZOMBIE: case MONSTER_SPIDER: @@ -455,7 +455,7 @@ float RandomMonster() 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); @@ -505,7 +505,7 @@ void queue_monsters(float maxmonsters) 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); @@ -842,7 +842,7 @@ MUTATOR_HOOKFUNCTION(td_MonsterSpawn) 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; diff --git a/qcsrc/server/mutators/gamemode_towerdefense.qh b/qcsrc/server/mutators/gamemode_towerdefense.qh index dd78d14cc..35847d182 100644 --- a/qcsrc/server/mutators/gamemode_towerdefense.qh +++ b/qcsrc/server/mutators/gamemode_towerdefense.qh @@ -1,6 +1,6 @@ // 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;