From 7f46f66dc8e88333da6826603aa1f45d028e965c Mon Sep 17 00:00:00 2001 From: Mario Date: Thu, 29 Aug 2013 02:26:43 +1000 Subject: [PATCH] Begin cleaning up most monster functions (still a bit buggy) --- qcsrc/client/Main.qc | 4 +- qcsrc/client/monsters.qc | 226 ++---------------- qcsrc/client/monsters.qh | 1 - qcsrc/client/progs.src | 5 +- .../monsters.qh => common/monsters/all.qh} | 8 - qcsrc/{server => common}/monsters/lib/defs.qh | 3 +- .../monsters/lib/monsters.qc | 158 +++++++----- qcsrc/common/monsters/lib/monsters_early.qh | 35 +++ .../{server => common}/monsters/lib/spawn.qc | 26 +- .../monsters/monster/animus.qc | 122 ++++++---- qcsrc/common/monsters/monster/bruiser.qc | 125 ++++++++++ .../monsters/monster/brute.qc | 120 ++++++---- .../monsters/monster/cerberus.qc | 130 +++++----- .../monsters/monster/knight.qc | 137 ++++++----- .../monsters/monster/mage.qc | 188 ++++++++------- .../monsters/monster/shambler.qc | 122 ++++++---- .../monsters/monster/slime.qc | 136 ++++++----- .../monsters/monster/spider.qc | 123 ++++++---- qcsrc/common/monsters/monster/stingray.qc | 112 +++++++++ .../monsters/monster/wyvern.qc | 128 +++++----- .../monsters/monster/zombie.qc | 124 ++++++---- qcsrc/common/monsters/monsters.qc | 54 +++++ qcsrc/common/monsters/monsters.qh | 87 +++++++ qcsrc/server/command/cmd.qc | 10 +- qcsrc/server/command/sv_cmd.qc | 1 + qcsrc/server/g_damage.qc | 2 +- qcsrc/server/g_world.qc | 2 + qcsrc/server/monsters/lib/monsters_early.qh | 90 ------- qcsrc/server/monsters/monster/bruiser.qc | 105 -------- qcsrc/server/monsters/monster/stingray.qc | 95 -------- qcsrc/server/mutators/gamemode_invasion.qc | 8 +- qcsrc/server/mutators/mutator_minstagib.qc | 2 +- qcsrc/server/progs.src | 5 +- 33 files changed, 1322 insertions(+), 1172 deletions(-) rename qcsrc/{server/monsters/monsters.qh => common/monsters/all.qh} (75%) rename qcsrc/{server => common}/monsters/lib/defs.qh (95%) rename qcsrc/{server => common}/monsters/lib/monsters.qc (94%) create mode 100644 qcsrc/common/monsters/lib/monsters_early.qh rename qcsrc/{server => common}/monsters/lib/spawn.qc (75%) rename qcsrc/{server => common}/monsters/monster/animus.qc (60%) create mode 100644 qcsrc/common/monsters/monster/bruiser.qc rename qcsrc/{server => common}/monsters/monster/brute.qc (80%) rename qcsrc/{server => common}/monsters/monster/cerberus.qc (52%) rename qcsrc/{server => common}/monsters/monster/knight.qc (82%) rename qcsrc/{server => common}/monsters/monster/mage.qc (83%) rename qcsrc/{server => common}/monsters/monster/shambler.qc (66%) rename qcsrc/{server => common}/monsters/monster/slime.qc (54%) rename qcsrc/{server => common}/monsters/monster/spider.qc (74%) create mode 100644 qcsrc/common/monsters/monster/stingray.qc rename qcsrc/{server => common}/monsters/monster/wyvern.qc (66%) rename qcsrc/{server => common}/monsters/monster/zombie.qc (71%) create mode 100644 qcsrc/common/monsters/monsters.qc create mode 100644 qcsrc/common/monsters/monsters.qh delete mode 100644 qcsrc/server/monsters/lib/monsters_early.qh delete mode 100644 qcsrc/server/monsters/monster/bruiser.qc delete mode 100644 qcsrc/server/monsters/monster/stingray.qc diff --git a/qcsrc/client/Main.qc b/qcsrc/client/Main.qc index 6eef5cc0d..81d224faa 100644 --- a/qcsrc/client/Main.qc +++ b/qcsrc/client/Main.qc @@ -104,6 +104,7 @@ void CSQC_Init(void) // needs to be done so early because of the constants they create CALL_ACCUMULATED_FUNCTION(RegisterWeapons); + CALL_ACCUMULATED_FUNCTION(RegisterMonsters); CALL_ACCUMULATED_FUNCTION(RegisterGametypes); CALL_ACCUMULATED_FUNCTION(RegisterNotifications); CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes); @@ -115,8 +116,7 @@ void CSQC_Init(void) precache_model("null"); precache_sound("misc/hit.wav"); precache_sound("misc/typehit.wav"); - - Monsters_Precache(); + generator_precache(); Projectile_Precache(); Hook_Precache(); diff --git a/qcsrc/client/monsters.qc b/qcsrc/client/monsters.qc index c3eef3c16..0dfbcf4c0 100644 --- a/qcsrc/client/monsters.qc +++ b/qcsrc/client/monsters.qc @@ -1,207 +1,3 @@ -string mid2info_model; -string mid2info_name; -vector mid2info_min; -vector mid2info_max; - -float monster_precached[MONSTER_LAST]; -void monster_mid2info(float _mid); - -void monster_precache(float _mid) -{ - monster_mid2info(_mid); - if(monster_precached[_mid]) - return; - - switch(_mid) - { - case MONSTER_ZOMBIE: - { - precache_model(ZOMBIE_MODEL); - break; - } - case MONSTER_BRUTE: - { - precache_model(BRUTE_MODEL); - break; - } - case MONSTER_ANIMUS: - { - precache_model(ANIMUS_MODEL); - break; - } - case MONSTER_SHAMBLER: - { - precache_model(SHAMBLER_MODEL); - break; - } - case MONSTER_BRUISER: - { - precache_model(BRUISER_MODEL); - break; - } - case MONSTER_WYVERN: - { - precache_model(WYVERN_MODEL); - break; - } - case MONSTER_CERBERUS: - { - precache_model(CERBERUS_MODEL); - break; - } - case MONSTER_SLIME: - { - precache_model(SLIME_MODEL); - precache_sound("weapons/rocket_impact.wav"); - break; - } - case MONSTER_KNIGHT: - { - precache_model(KNIGHT_MODEL); - break; - } - case MONSTER_STINGRAY: - { - precache_model(STINGRAY_MODEL); - break; - } - case MONSTER_MAGE: - { - precache_model(MAGE_MODEL); - break; - } - case MONSTER_SPIDER: - { - precache_model(SPIDER_MODEL); - - break; - } - } - - monster_precached[_mid] = TRUE; -} - -void Monsters_Precache() -{ - float i; - for(i = MONSTER_FIRST + 1; i < MONSTER_LAST; ++i) - monster_precache(i); -} - -void monster_mid2info(float _mid) -{ - switch(_mid) - { - case MONSTER_ZOMBIE: - { - mid2info_model = ZOMBIE_MODEL; - mid2info_name = "Zombie"; - mid2info_min = ZOMBIE_MIN; - mid2info_max = ZOMBIE_MAX; - break; - } - case MONSTER_BRUTE: - { - mid2info_model = BRUTE_MODEL; - mid2info_name = "Brute"; - mid2info_min = BRUTE_MIN; - mid2info_max = BRUTE_MAX; - break; - } - case MONSTER_ANIMUS: - { - mid2info_model = ANIMUS_MODEL; - mid2info_name = "Animus"; - mid2info_min = ANIMUS_MIN; - mid2info_max = ANIMUS_MAX; - if(self) self.scale = 1.3; - break; - } - case MONSTER_SHAMBLER: - { - mid2info_model = SHAMBLER_MODEL; - mid2info_name = "Shambler"; - mid2info_min = SHAMBLER_MIN; - mid2info_max = SHAMBLER_MAX; - if(self) self.scale = 1.3; - break; - } - case MONSTER_BRUISER: - { - mid2info_model = BRUISER_MODEL; - mid2info_name = "Bruiser"; - mid2info_min = BRUISER_MIN; - mid2info_max = BRUISER_MAX; - if(self) self.scale = 1.3; - break; - } - case MONSTER_WYVERN: - { - mid2info_model = WYVERN_MODEL; - mid2info_name = "Wyvern"; - mid2info_min = WYVERN_MIN; - mid2info_max = WYVERN_MAX; - if(self) self.scale = 1.3; - break; - } - case MONSTER_CERBERUS: - { - mid2info_model = CERBERUS_MODEL; - mid2info_name = "Cerberus"; - mid2info_min = CERBERUS_MIN; - mid2info_max = CERBERUS_MAX; - break; - } - case MONSTER_SLIME: - { - mid2info_model = SLIME_MODEL; - mid2info_name = "Slime"; - mid2info_min = SLIME_MIN; - mid2info_max = SLIME_MAX; - break; - } - case MONSTER_KNIGHT: - { - mid2info_model = KNIGHT_MODEL; - mid2info_name = "Knight"; - mid2info_min = KNIGHT_MIN; - mid2info_max = KNIGHT_MAX; - if(self) self.scale = 1.3; - break; - } - case MONSTER_STINGRAY: - { - mid2info_model = STINGRAY_MODEL; - mid2info_name = "Stingray"; - mid2info_min = STINGRAY_MIN; - mid2info_max = STINGRAY_MAX; - if(self) self.scale = 1.3; - break; - } - case MONSTER_MAGE: - { - mid2info_model = MAGE_MODEL; - mid2info_name = "Mage"; - mid2info_min = MAGE_MIN; - mid2info_max = MAGE_MAX; - break; - } - case MONSTER_SPIDER: - { - mid2info_model = SPIDER_MODEL; - mid2info_name = "Spider"; - mid2info_min = SPIDER_MIN; - mid2info_max = SPIDER_MAX; - break; - } - default: - { - dprint("WARNING: Unknown monster in CSQC\n"); - break; - } - } -} - .vector glowmod; void monster_changeteam() { @@ -216,8 +12,7 @@ void monster_changeteam() void monster_die() { - if(self.monsterid == MONSTER_SPIDER) - self.angles += '180 0 0'; + MON_ACTION(self.monsterid, MR_DEATH); self.solid = SOLID_CORPSE; } @@ -238,13 +33,21 @@ void monster_draw() } void monster_construct() -{ - monster_mid2info(self.monsterid); - self.netname = mid2info_name; +{ + vector min_s, max_s; + entity mon = get_monsterinfo(self.monsterid); + + min_s = mon.mins; + max_s = mon.maxs; + + if(mon.spawnflags & MONSTER_SIZE_BROKEN) + self.scale = 1.3; + + self.netname = M_NAME(self.monsterid); setorigin(self, self.origin); - setmodel(self, mid2info_model); - setsize(self, mid2info_min, mid2info_max); + setmodel(self, mon.model); + setsize(self, min_s, max_s); self.move_movetype = MOVETYPE_BOUNCE; self.health = 255; @@ -277,7 +80,6 @@ void ent_monster() self.skin = ReadByte(); self.team = ReadByte(); - monster_precache(self.monsterid); monster_construct(); monster_changeteam(); } diff --git a/qcsrc/client/monsters.qh b/qcsrc/client/monsters.qh index 83dac2956..aa6fb4126 100644 --- a/qcsrc/client/monsters.qh +++ b/qcsrc/client/monsters.qh @@ -1,2 +1 @@ void ent_monster(); -void Monsters_Precache(); diff --git a/qcsrc/client/progs.src b/qcsrc/client/progs.src index fd7003250..bc1ec35eb 100644 --- a/qcsrc/client/progs.src +++ b/qcsrc/client/progs.src @@ -27,6 +27,7 @@ Defs.qc ../common/command/shared_defs.qh ../common/urllib.qh ../common/animdecide.qh +../common/monsters/monsters.qh command/cl_cmd.qh autocvars.qh @@ -48,7 +49,7 @@ noise.qh tturrets.qh ../server/tturrets/include/turrets_early.qh monsters.qh -../server/monsters/lib/monsters_early.qh +../common/monsters/lib/monsters_early.qh ../server/movelib.qc ../server/generator.qh main.qh @@ -114,6 +115,7 @@ noise.qc ../server/w_all.qc ../common/explosion_equation.qc ../common/urllib.qc +../common/monsters/monsters.qc command/cl_cmd.qc ../warpzonelib/anglestransform.qc @@ -124,7 +126,6 @@ tturrets.qc ../server/generator.qc -../server/monsters/monsters.qh monsters.qc player_skeleton.qc diff --git a/qcsrc/server/monsters/monsters.qh b/qcsrc/common/monsters/all.qh similarity index 75% rename from qcsrc/server/monsters/monsters.qh rename to qcsrc/common/monsters/all.qh index 53b5a13ad..0c4f0af99 100644 --- a/qcsrc/server/monsters/monsters.qh +++ b/qcsrc/common/monsters/all.qh @@ -1,11 +1,3 @@ -// Lib -#ifdef SVQC -#include "lib/defs.qh" -#include "lib/monsters.qc" -#include "lib/spawn.qc" -#endif - -// Monsters #include "monster/brute.qc" #include "monster/animus.qc" #include "monster/shambler.qc" diff --git a/qcsrc/server/monsters/lib/defs.qh b/qcsrc/common/monsters/lib/defs.qh similarity index 95% rename from qcsrc/server/monsters/lib/defs.qh rename to qcsrc/common/monsters/lib/defs.qh index f5a75e3c8..1f5fe1293 100644 --- a/qcsrc/server/monsters/lib/defs.qh +++ b/qcsrc/common/monsters/lib/defs.qh @@ -11,7 +11,7 @@ const float MONSTER_ATTACK_RANGED = 2; .string oldtarget2; .float lastshielded; -const float MONSTER_RESPAWN_DEATHPOINT = 8; // re-spawn where we died +.vector oldangles; .float monster_respawned; // used to make sure we're not recounting respawned monster stats @@ -39,7 +39,6 @@ const float MONSTERFLAG_SPAWNED = 512; // flag for spawned monsters .string msound_pain; .void() monster_spawnfunc; -.void() monster_die; .float monster_movestate; // used to tell what the monster is currently doing const float MONSTER_MOVE_OWNER = 1; // monster will move to owner if in range, or stand still diff --git a/qcsrc/server/monsters/lib/monsters.qc b/qcsrc/common/monsters/lib/monsters.qc similarity index 94% rename from qcsrc/server/monsters/lib/monsters.qc rename to qcsrc/common/monsters/lib/monsters.qc index 7e013515a..4850dc1e1 100644 --- a/qcsrc/server/monsters/lib/monsters.qc +++ b/qcsrc/common/monsters/lib/monsters.qc @@ -500,7 +500,12 @@ void monster_move(float runspeed, float walkspeed, float stopspeed, float manim_ if(self.revive_progress >= 1) Unfreeze(self); // wait for next think before attacking - self.SendFlags |= MSF_MOVE; + // don't bother updating angles here? + if(self.origin != self.oldorigin) + { + self.oldorigin = self.origin; + self.SendFlags |= MSF_MOVE; + } return; // no moving while frozen } @@ -664,9 +669,18 @@ void monster_move(float runspeed, float walkspeed, float stopspeed, float manim_ } monster_checkattack(self, self.enemy); - - self.SendFlags |= MSF_ANG; - self.SendFlags |= MSF_MOVE; + + if(self.angles != self.oldangles) + { + self.oldangles = self.angles; + self.SendFlags |= MSF_ANG; + } + + if(self.origin != self.oldorigin) + { + self.oldorigin = self.origin; + self.SendFlags |= MSF_MOVE; + } } void monster_dead_think() @@ -809,6 +823,51 @@ void monsters_corpse_damage (entity inflictor, entity attacker, float damage, fl } } +void monster_die() +{ + self.think = monster_dead_think; + self.nextthink = self.ticrate; + self.ltime = time + 5; + + Monster_CheckDropCvars(self.netname); + + WaypointSprite_Kill(self.sprite); + + if(self.weaponentity) + { + remove(self.weaponentity); + self.weaponentity = world; + } + + monster_sound(self.msound_death, 0, FALSE); + + if(!(self.spawnflags & MONSTERFLAG_SPAWNED) && !self.monster_respawned) + monsters_killed += 1; + + if(self.candrop && self.weapon) + W_ThrowNewWeapon(self, self.weapon, 0, self.origin, randomvec() * 150 + '0 0 325'); + + if(IS_CLIENT(self.realowner)) + self.realowner.monstercount -= 1; + + self.event_damage = monsters_corpse_damage; + self.solid = SOLID_CORPSE; + self.takedamage = DAMAGE_AIM; + self.enemy = world; + self.movetype = MOVETYPE_TOSS; + self.moveto = self.origin; + self.touch = MonsterTouch; // reset incase monster was pouncing + + if not(self.flags & FL_FLY) + self.velocity = '0 0 0'; + + self.SendFlags |= MSF_MOVE; + + totalspawned -= 1; + + MON_ACTION(self.monsterid, MR_DEATH); +} + void monsters_damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) { if(self.frozen && deathtype != DEATH_KILL) @@ -864,7 +923,7 @@ void monsters_damage (entity inflictor, entity attacker, float damage, float dea SUB_UseTargets(); self.target2 = self.oldtarget2; // reset to original target on death, incase we respawn - self.monster_die(); + monster_die(); frag_attacker = attacker; frag_target = self; @@ -882,47 +941,18 @@ void monsters_damage (entity inflictor, entity attacker, float damage, float dea self.SendFlags |= MSF_STATUS; } -// post-death functions -void monster_hook_death() +void monster_think() { - WaypointSprite_Kill(self.sprite); - - if(self.weaponentity) - { - remove(self.weaponentity); - self.weaponentity = world; - } - - monster_sound(self.msound_death, 0, FALSE); - - if(!(self.spawnflags & MONSTERFLAG_SPAWNED) && !self.monster_respawned) - monsters_killed += 1; - - if(self.candrop && self.weapon) - W_ThrowNewWeapon(self, self.weapon, 0, self.origin, randomvec() * 150 + '0 0 325'); - - if(IS_CLIENT(self.realowner)) - self.realowner.monstercount -= 1; - - self.event_damage = monsters_corpse_damage; - self.solid = SOLID_CORPSE; - self.takedamage = DAMAGE_AIM; - self.enemy = world; - self.movetype = MOVETYPE_TOSS; - self.moveto = self.origin; - self.touch = MonsterTouch; // reset incase monster was pouncing + self.think = monster_think; + self.nextthink = self.ticrate; - if not(self.flags & FL_FLY) - self.velocity = '0 0 0'; - - self.SendFlags |= MSF_MOVE; - - totalspawned -= 1; + MON_ACTION(self.monsterid, MR_THINK); } -// post-spawn functions -void monster_hook_spawn() +void monster_spawn() { + MON_ACTION(self.monsterid, MR_SETUP); + if not(self.monster_respawned) Monster_CheckMinibossFlag(); @@ -942,6 +972,8 @@ void monster_hook_spawn() self.skin = rint(random() * 4); self.pos1 = self.origin; + + monster_setupsounds(self.netname); monster_precachesounds(self); @@ -950,7 +982,7 @@ void monster_hook_spawn() if(autocvar_g_monsters_healthbars) { - WaypointSprite_Spawn(strzone(strdecolorize(self.netname)), 0, 600, self, '0 0 1' * (self.maxs_z + 15), world, 0, self, sprite, FALSE, RADARICON_DANGER, ((self.team) ? Team_ColorRGB(self.team) : '1 0 0')); + WaypointSprite_Spawn(strzone(strdecolorize(self.monster_name)), 0, 600, self, '0 0 1' * (self.maxs_z + 15), world, 0, self, sprite, FALSE, RADARICON_DANGER, ((self.team) ? Team_ColorRGB(self.team) : '1 0 0')); WaypointSprite_UpdateMaxHealth(self.sprite, self.max_health); WaypointSprite_UpdateHealth(self.sprite, self.health); } @@ -959,19 +991,20 @@ void monster_hook_spawn() MUTATOR_CALLHOOK(MonsterSpawn); + self.think = monster_think; + self.nextthink = time + self.ticrate; + self.SendFlags = MSF_SETUP; } -float monster_initialize(string net_name, float mon_id, - vector min_s, - vector max_s, - float nodrop, - void() dieproc, - void() spawnproc) +float monster_initialize(float mon_id, float nodrop) { if not(autocvar_g_monsters) return FALSE; + vector min_s, max_s; + entity mon = get_monsterinfo(mon_id); + // support for quake style removing monsters based on skill if(monster_skill <= autocvar_g_monsters_skill_easy && (self.spawnflags & MONSTERSKILL_NOTEASY)) { return FALSE; } if(monster_skill == autocvar_g_monsters_skill_normal && (self.spawnflags & MONSTERSKILL_NOTMEDIUM)) { return FALSE; } @@ -979,8 +1012,8 @@ float monster_initialize(string net_name, float mon_id, if(monster_skill == autocvar_g_monsters_skill_insane && (self.spawnflags & MONSTERSKILL_NOTINSANE)) { return FALSE; } if(monster_skill >= autocvar_g_monsters_skill_nightmare && (self.spawnflags & MONSTERSKILL_NOTNIGHTMARE)) { return FALSE; } - if(self.netname == "") - self.netname = ((net_name == "") ? self.classname : net_name); + if(self.monster_name == "") + self.monster_name = M_NAME(mon_id); if(self.team && !teamplay) self.team = 0; @@ -990,6 +1023,11 @@ float monster_initialize(string net_name, float mon_id, if not(self.spawnflags & MONSTERFLAG_SPAWNED) // naturally spawned monster if not(self.monster_respawned) monsters_total += 1; + + min_s = mon.mins; + max_s = mon.maxs; + + self.netname = mon.netname; setsize(self, min_s, max_s); self.takedamage = DAMAGE_AIM; @@ -998,13 +1036,11 @@ float monster_initialize(string net_name, float mon_id, self.teleportable = TRUE; self.damagedbycontents = TRUE; self.monsterid = mon_id; - self.damageforcescale = 0.003; - self.monster_die = dieproc; + self.damageforcescale = 0; self.event_damage = monsters_damage; self.touch = MonsterTouch; self.use = monster_use; self.solid = SOLID_BBOX; - self.scale = 1; self.movetype = MOVETYPE_WALK; self.spawnshieldtime = time + autocvar_g_monsters_spawnshieldtime; monsters_spawned += 1; @@ -1016,12 +1052,24 @@ float monster_initialize(string net_name, float mon_id, self.candrop = TRUE; self.view_ofs = '0 0 1' * (self.maxs_z * 0.5); self.oldtarget2 = self.target2; - self.deadflag = DEAD_NO; // UNDEAD + self.deadflag = DEAD_NO; self.noalign = nodrop; self.spawn_time = time; self.gravity = 1; self.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_BOTCLIP | DPCONTENTS_MONSTERCLIP; + if(mon.spawnflags & MONSTER_TYPE_SWIM) + self.flags |= FL_SWIM; + + if(mon.spawnflags & MONSTER_TYPE_FLY) + { + self.flags |= FL_FLY; + self.movetype = MOVETYPE_FLY; + } + + if not(self.scale) + self.scale = 1; + if not(self.attack_range) self.attack_range = 120; @@ -1042,7 +1090,7 @@ float monster_initialize(string net_name, float mon_id, if not(self.monster_moveflags) self.monster_moveflags = MONSTER_MOVE_WANDER; - monster_link(spawnproc); + monster_link(monster_spawn); return TRUE; } diff --git a/qcsrc/common/monsters/lib/monsters_early.qh b/qcsrc/common/monsters/lib/monsters_early.qh new file mode 100644 index 000000000..f690cdc59 --- /dev/null +++ b/qcsrc/common/monsters/lib/monsters_early.qh @@ -0,0 +1,35 @@ +// for definitions used outside the monsters folder + +#ifdef SVQC +.string spawnmob; +.float monster_attack; + +float monster_skill; +float spawncode_first_load; // used to tell the player the monster database is loading (TODO: fix this?) + +.entity monster_owner; // new monster owner entity, fixes non-solid monsters +.float monstercount; // per player monster count + +.float stat_monsters_killed; // stats +.float stat_monsters_total; +float monsters_total; +float monsters_killed; +void monsters_setstatus(); // monsters.qc +.float monster_moveflags; // checks where to move when not attacking + +#endif // SVQC + +#ifndef MENUQC + +.float anim_start_time; + +float MSF_UPDATE = 2; +float MSF_STATUS = 4; +float MSF_SETUP = 8; +float MSF_ANG = 16; +float MSF_MOVE = 32; +float MSF_ANIM = 64; + +float MSF_FULL_UPDATE = 16777215; + +#endif // CSQC/SVQC diff --git a/qcsrc/server/monsters/lib/spawn.qc b/qcsrc/common/monsters/lib/spawn.qc similarity index 75% rename from qcsrc/server/monsters/lib/spawn.qc rename to qcsrc/common/monsters/lib/spawn.qc index b985c7f2c..95e0261ae 100644 --- a/qcsrc/server/monsters/lib/spawn.qc +++ b/qcsrc/common/monsters/lib/spawn.qc @@ -16,24 +16,32 @@ entity spawnmonster (string monster, float mnster, entity spawnedby, entity own, setorigin(e, orig); if(monster != "") - if not(monster_string2id(monster)) - monster = "bruiser"; + { + float i, found = 0; + entity mon; + for(i = MON_FIRST; i <= MON_LAST; ++i) + { + mon = get_monsterinfo(i); + if(mon.netname == monster) + { + found = TRUE; + break; + } + } + if not(found) + monster = (get_monsterinfo(MON_FIRST)).netname; + } if(monster == "") if(mnster) - monster = monster_id2string(mnster); + monster = (get_monsterinfo(mnster)).netname; e.realowner = spawnedby; if(moveflag) e.monster_moveflags = moveflag; - if (spawnedby.classname == "td_spawnpoint") - { - e.monster_owner = own; - e.team = spawnedby.team; - } - else if(IS_PLAYER(spawnedby)) + if(IS_PLAYER(spawnedby)) { if(teamplay && autocvar_g_monsters_teams) e.team = spawnedby.team; // colors handled in spawn code diff --git a/qcsrc/server/monsters/monster/animus.qc b/qcsrc/common/monsters/monster/animus.qc similarity index 60% rename from qcsrc/server/monsters/monster/animus.qc rename to qcsrc/common/monsters/monster/animus.qc index cfb2292b8..bd7639c09 100644 --- a/qcsrc/server/monsters/monster/animus.qc +++ b/qcsrc/common/monsters/monster/animus.qc @@ -1,8 +1,15 @@ -const vector ANIMUS_MIN = '-41 -41 -31'; -const vector ANIMUS_MAX = '41 41 31'; - -string ANIMUS_MODEL = "models/monsters/demon.mdl"; +#ifdef REGISTER_MONSTER +REGISTER_MONSTER( +/* MON_##id */ ANIMUS, +/* function */ m_animus, +/* spawnflags */ MONSTER_SIZE_BROKEN, +/* mins,maxs */ '-41 -41 -31', '41 41 31', +/* model */ "demon.mdl", +/* netname */ "animus", +/* fullname */ _("Animus") +); +#else #ifdef SVQC float autocvar_g_monster_animus; float autocvar_g_monster_animus_health; @@ -19,14 +26,6 @@ const float animus_anim_pain = 4; const float animus_anim_death = 5; const float animus_anim_attack = 6; -void animus_think() -{ - self.think = animus_think; - self.nextthink = time + self.ticrate; - - monster_move(autocvar_g_monster_animus_speed_run, autocvar_g_monster_animus_speed_walk, 100, animus_anim_run, animus_anim_walk, animus_anim_stand); -} - void animus_touch_jump() { if (self.health <= 0) @@ -68,60 +67,77 @@ float animus_attack(float attack_type) return FALSE; } -void animus_die() -{ - Monster_CheckDropCvars ("animus"); - - self.think = monster_dead_think; - self.nextthink = time + self.ticrate; - self.ltime = time + 5; - monsters_setframe(animus_anim_death); - - monster_hook_death(); // for post-death mods -} - -void animus_spawn() -{ - if not(self.health) - self.health = autocvar_g_monster_animus_health; - - self.damageforcescale = 0; - self.classname = "monster_animus"; - self.monster_attackfunc = animus_attack; - self.nextthink = time + random() * 0.5 + 0.1; - self.think = animus_think; - - monsters_setframe(animus_anim_stand); - - monster_setupsounds("animus"); - - monster_hook_spawn(); // for post-spawn mods -} - void spawnfunc_monster_animus() { if not(autocvar_g_monster_animus) { remove(self); return; } + self.classname = "monster_animus"; + self.monster_spawnfunc = spawnfunc_monster_animus; if(Monster_CheckAppearFlags(self)) return; - self.scale = 1.3; - - if not (monster_initialize( - "Animus", MONSTER_ANIMUS, - ANIMUS_MIN, ANIMUS_MAX, - FALSE, - animus_die, animus_spawn)) - { - remove(self); - return; - } + if not(monster_initialize(MON_ANIMUS, FALSE)) { remove(self); return; } } // compatibility with old spawns void spawnfunc_monster_demon1() { spawnfunc_monster_animus(); } void spawnfunc_monster_demon() { spawnfunc_monster_animus(); } +float m_animus(float req) +{ + switch(req) + { + case MR_THINK: + { + monster_move(autocvar_g_monster_animus_speed_run, autocvar_g_monster_animus_speed_walk, 100, animus_anim_run, animus_anim_walk, animus_anim_stand); + return TRUE; + } + case MR_DEATH: + { + monsters_setframe(animus_anim_death); + return TRUE; + } + case MR_SETUP: + { + if not(self.health) self.health = autocvar_g_monster_animus_health; + + self.monster_attackfunc = animus_attack; + monsters_setframe(animus_anim_stand); + + return TRUE; + } + case MR_INIT: + { + // nothing + return TRUE; + } + } + + return TRUE; +} + #endif // SVQC +#ifdef CSQC +float m_animus(float req) +{ + switch(req) + { + case MR_DEATH: + { + // nothing + return TRUE; + } + case MR_INIT: + { + precache_model ("models/monsters/demon.mdl"); + return TRUE; + } + } + + return TRUE; +} + +#endif // CSQC +#endif // REGISTER_MONSTER diff --git a/qcsrc/common/monsters/monster/bruiser.qc b/qcsrc/common/monsters/monster/bruiser.qc new file mode 100644 index 000000000..fe16f9216 --- /dev/null +++ b/qcsrc/common/monsters/monster/bruiser.qc @@ -0,0 +1,125 @@ +#ifdef REGISTER_MONSTER +REGISTER_MONSTER( +/* MON_##id */ BRUISER, +/* function */ m_bruiser, +/* spawnflags */ MONSTER_SIZE_BROKEN, +/* mins,maxs */ '-20 -20 -31', '20 20 53', +/* model */ "knight.mdl", +/* netname */ "bruiser", +/* fullname */ _("Bruiser") +); + +#else +#ifdef SVQC +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; + +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; + +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: + { + // no ranged attacks for bruiser + return FALSE; + } + } + + return FALSE; +} + +void spawnfunc_monster_bruiser() +{ + if not(autocvar_g_monster_bruiser) { remove(self); return; } + + self.classname = "monster_bruiser"; + + self.monster_spawnfunc = spawnfunc_monster_bruiser; + + if(Monster_CheckAppearFlags(self)) + return; + + if not(monster_initialize(MON_BRUISER, FALSE)) { remove(self); return; } +} + +float m_bruiser(float req) +{ + switch(req) + { + case MR_THINK: + { + monster_move(autocvar_g_monster_bruiser_speed_run, autocvar_g_monster_bruiser_speed_walk, 50, bruiser_anim_run, bruiser_anim_walk, bruiser_anim_stand); + return TRUE; + } + case MR_DEATH: + { + monsters_setframe((random() > 0.5) ? bruiser_anim_death1 : bruiser_anim_death2); + return TRUE; + } + case MR_SETUP: + { + if not(self.health) self.health = autocvar_g_monster_bruiser_health; + + self.monster_attackfunc = bruiser_attack; + monsters_setframe(bruiser_anim_stand); + + return TRUE; + } + case MR_INIT: + { + // nothing + return TRUE; + } + } + + return TRUE; +} + +#endif // SVQC +#ifdef CSQC +float m_bruiser(float req) +{ + switch(req) + { + case MR_DEATH: + { + // nothing + return TRUE; + } + case MR_INIT: + { + precache_model ("models/monsters/knight.mdl"); + return TRUE; + } + } + + return TRUE; +} + +#endif // CSQC +#endif // REGISTER_MONSTER diff --git a/qcsrc/server/monsters/monster/brute.qc b/qcsrc/common/monsters/monster/brute.qc similarity index 80% rename from qcsrc/server/monsters/monster/brute.qc rename to qcsrc/common/monsters/monster/brute.qc index 8952d5400..226e0d588 100644 --- a/qcsrc/server/monsters/monster/brute.qc +++ b/qcsrc/common/monsters/monster/brute.qc @@ -1,8 +1,15 @@ -const vector BRUTE_MIN = '-36 -36 -20'; -const vector BRUTE_MAX = '36 36 50'; - -string BRUTE_MODEL = "models/monsters/ogre.dpm"; - +#ifdef REGISTER_MONSTER +REGISTER_MONSTER( +/* MON_##id */ BRUTE, +/* function */ m_brute, +/* spawnflags */ 0, +/* mins,maxs */ '-36 -36 -20', '36 36 50', +/* model */ "ogre.dpm", +/* netname */ "brute", +/* fullname */ _("Brute") +); + +#else #ifdef SVQC float autocvar_g_monster_brute; float autocvar_g_monster_brute_health; @@ -27,14 +34,6 @@ const float brute_anim_die = 5; .float brute_cycles; -void brute_think() -{ - self.think = brute_think; - self.nextthink = time + self.ticrate; - - monster_move(autocvar_g_monster_brute_speed_run, autocvar_g_monster_brute_speed_walk, 300, brute_anim_run, brute_anim_walk, brute_anim_idle); -} - void brute_blade() { self.brute_cycles += 1; @@ -183,55 +182,74 @@ float brute_attack(float attack_type) return FALSE; } -void brute_die() -{ - Monster_CheckDropCvars ("brute"); - - self.think = monster_dead_think; - self.nextthink = time + self.ticrate; - self.ltime = time + 5; - monsters_setframe(brute_anim_die); - - monster_hook_death(); // for post-death mods -} - -void brute_spawn() -{ - if not(self.health) - self.health = autocvar_g_monster_brute_health; - - self.damageforcescale = 0.003; - self.classname = "monster_brute"; - self.monster_attackfunc = brute_attack; - self.nextthink = time + random() * 0.5 + 0.1; - self.think = brute_think; - self.weapon = WEP_GRENADE_LAUNCHER; - - monsters_setframe(brute_anim_idle); - - monster_setupsounds("brute"); - - monster_hook_spawn(); // for post-spawn mods -} - void spawnfunc_monster_brute() { if not(autocvar_g_monster_brute) { remove(self); return; } + self.classname = "monster_brute"; + self.monster_spawnfunc = spawnfunc_monster_brute; if(Monster_CheckAppearFlags(self)) return; - if not (monster_initialize( - "Brute", MONSTER_BRUTE, - BRUTE_MIN, BRUTE_MAX, - FALSE, - brute_die, brute_spawn)) + if not(monster_initialize(MON_BRUTE, FALSE)) { remove(self); return; } +} + +float m_brute(float req) +{ + switch(req) { - remove(self); - return; + case MR_THINK: + { + monster_move(autocvar_g_monster_brute_speed_run, autocvar_g_monster_brute_speed_walk, 300, brute_anim_run, brute_anim_walk, brute_anim_idle); + return TRUE; + } + case MR_DEATH: + { + monsters_setframe(brute_anim_die); + return TRUE; + } + case MR_SETUP: + { + if not(self.health) self.health = autocvar_g_monster_brute_health; + + self.monster_attackfunc = brute_attack; + monsters_setframe(brute_anim_idle); + self.weapon = WEP_GRENADE_LAUNCHER; + + return TRUE; + } + case MR_INIT: + { + // nothing + return TRUE; + } } + + return TRUE; } #endif // SVQC +#ifdef CSQC +float m_brute(float req) +{ + switch(req) + { + case MR_DEATH: + { + // nothing + return TRUE; + } + case MR_INIT: + { + precache_model ("models/monsters/ogre.dpm"); + return TRUE; + } + } + + return TRUE; +} + +#endif // CSQC +#endif // REGISTER_MONSTER diff --git a/qcsrc/server/monsters/monster/cerberus.qc b/qcsrc/common/monsters/monster/cerberus.qc similarity index 52% rename from qcsrc/server/monsters/monster/cerberus.qc rename to qcsrc/common/monsters/monster/cerberus.qc index 38b57e76c..907c07ffb 100644 --- a/qcsrc/server/monsters/monster/cerberus.qc +++ b/qcsrc/common/monsters/monster/cerberus.qc @@ -1,8 +1,15 @@ -const vector CERBERUS_MIN = '-16 -16 -24'; -const vector CERBERUS_MAX = '16 16 12'; - -string CERBERUS_MODEL = "models/monsters/dog.dpm"; +#ifdef REGISTER_MONSTER +REGISTER_MONSTER( +/* MON_##id */ CERBERUS, +/* function */ m_cerberus, +/* spawnflags */ 0, +/* mins,maxs */ '-16 -16 -24', '16 16 12', +/* model */ "dog.dpm", +/* netname */ "cerberus", +/* fullname */ _("Cerberus") +); +#else #ifdef SVQC float autocvar_g_monster_cerberus; float autocvar_g_monster_cerberus_health; @@ -11,20 +18,12 @@ float autocvar_g_monster_cerberus_attack_jump_damage; float autocvar_g_monster_cerberus_speed_walk; float autocvar_g_monster_cerberus_speed_run; -const float cerberus_anim_idle = 0; -const float cerberus_anim_walk = 1; -const float cerberus_anim_run = 2; +const float cerberus_anim_idle = 0; +const float cerberus_anim_walk = 1; +const float cerberus_anim_run = 2; const float cerberus_anim_attack = 3; -const float cerberus_anim_die = 4; -const float cerberus_anim_pain = 5; - -void cerberus_think() -{ - self.think = cerberus_think; - self.nextthink = time + self.ticrate; - - monster_move(autocvar_g_monster_cerberus_speed_run, autocvar_g_monster_cerberus_speed_walk, 50, cerberus_anim_run, cerberus_anim_walk, cerberus_anim_idle); -} +const float cerberus_anim_die = 4; +const float cerberus_anim_pain = 5; void cerberus_touch_jump() { @@ -62,57 +61,76 @@ float cerberus_attack(float attack_type) return FALSE; } -void cerberus_die() -{ - Monster_CheckDropCvars ("cerberus"); - - self.think = monster_dead_think; - self.nextthink = time + self.ticrate; - self.ltime = time + 5; - monsters_setframe(cerberus_anim_die); - - monster_hook_death(); // for post-death mods -} - -void cerberus_spawn() -{ - if not(self.health) - self.health = autocvar_g_monster_cerberus_health; - - self.damageforcescale = 0; - self.classname = "monster_cerberus"; - self.monster_attackfunc = cerberus_attack; - self.nextthink = time + random() * 0.5 + 0.1; - self.think = cerberus_think; - - monsters_setframe(cerberus_anim_idle); - - monster_setupsounds("cerberus"); - - monster_hook_spawn(); // for post-spawn mods -} - void spawnfunc_monster_cerberus() { if not(autocvar_g_monster_cerberus) { remove(self); return; } + self.classname = "monster_cerberus"; + self.monster_spawnfunc = spawnfunc_monster_cerberus; if(Monster_CheckAppearFlags(self)) return; - if not (monster_initialize( - "Cerberus", MONSTER_CERBERUS, - CERBERUS_MIN, CERBERUS_MAX, - FALSE, - cerberus_die, cerberus_spawn)) - { - remove(self); - return; - } + if not(monster_initialize(MON_CERBERUS, FALSE)) { remove(self); return; } } // compatibility with old spawns void spawnfunc_monster_dog() { spawnfunc_monster_cerberus(); } +float m_cerberus(float req) +{ + switch(req) + { + case MR_THINK: + { + monster_move(autocvar_g_monster_cerberus_speed_run, autocvar_g_monster_cerberus_speed_walk, 50, cerberus_anim_run, cerberus_anim_walk, cerberus_anim_idle); + return TRUE; + } + case MR_DEATH: + { + monsters_setframe(cerberus_anim_die); + return TRUE; + } + case MR_SETUP: + { + if not(self.health) self.health = autocvar_g_monster_cerberus_health; + + self.monster_attackfunc = cerberus_attack; + monsters_setframe(cerberus_anim_idle); + + return TRUE; + } + case MR_INIT: + { + // nothing + return TRUE; + } + } + + return TRUE; +} + #endif // SVQC +#ifdef CSQC +float m_cerberus(float req) +{ + switch(req) + { + case MR_DEATH: + { + // nothing + return TRUE; + } + case MR_INIT: + { + precache_model ("models/monsters/dog.dpm"); + return TRUE; + } + } + + return TRUE; +} + +#endif // CSQC +#endif // REGISTER_MONSTER \ No newline at end of file diff --git a/qcsrc/server/monsters/monster/knight.qc b/qcsrc/common/monsters/monster/knight.qc similarity index 82% rename from qcsrc/server/monsters/monster/knight.qc rename to qcsrc/common/monsters/monster/knight.qc index 816ac600f..bc2a0e950 100644 --- a/qcsrc/server/monsters/monster/knight.qc +++ b/qcsrc/common/monsters/monster/knight.qc @@ -1,8 +1,15 @@ -const vector KNIGHT_MIN = '-20 -20 -32'; -const vector KNIGHT_MAX = '20 20 41'; - -string KNIGHT_MODEL = "models/monsters/hknight.mdl"; +#ifdef REGISTER_MONSTER +REGISTER_MONSTER( +/* MON_##id */ KNIGHT, +/* function */ m_knight, +/* spawnflags */ MONSTER_SIZE_BROKEN, +/* mins,maxs */ '-20 -20 -32', '20 20 41', +/* model */ "hknight.mdl", +/* netname */ "knight", +/* fullname */ _("Knight") +); +#else #ifdef SVQC float autocvar_g_monster_knight; float autocvar_g_monster_knight_health; @@ -43,14 +50,6 @@ const float knight_anim_magic3 = 13; .float knight_cycles; -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, 100, knight_anim_run, knight_anim_walk, knight_anim_stand); -} - void knight_inferno() { if not(self.enemy) @@ -253,67 +252,83 @@ float knight_attack(float attack_type) return FALSE; } -void knight_die() -{ - float chance = random(); - 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); - - if(chance < 0.10 || self.flags & MONSTERFLAG_MINIBOSS) - if(self.candrop) - { - self.superweapons_finished = time + autocvar_g_balance_superweapons_time + 5; // give the player a few seconds to find the weapon - self.weapon = WEP_FIREBALL; - } - - 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.monster_attackfunc = 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.classname = "monster_knight"; + 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; - } + if not(monster_initialize(MON_KNIGHT, FALSE)) { remove(self); return; } } // compatibility with old spawns void spawnfunc_monster_hell_knight() { spawnfunc_monster_knight(); } +float m_knight(float req) +{ + switch(req) + { + case MR_THINK: + { + monster_move(autocvar_g_monster_knight_speed_run, autocvar_g_monster_knight_speed_walk, 100, knight_anim_run, knight_anim_walk, knight_anim_stand); + return TRUE; + } + case MR_DEATH: + { + float chance = random(); + monsters_setframe((random() > 0.5) ? knight_anim_death1 : knight_anim_death2); + if(chance < 0.10 || self.flags & MONSTERFLAG_MINIBOSS) + if(self.candrop) + { + self.superweapons_finished = time + autocvar_g_balance_superweapons_time + 5; // give the player a few seconds to find the weapon + self.weapon = WEP_FIREBALL; + } + return TRUE; + } + case MR_SETUP: + { + if not(self.health) self.health = autocvar_g_monster_knight_health; + + self.monster_attackfunc = knight_attack; + monsters_setframe(knight_anim_stand); + + return TRUE; + } + case MR_INIT: + { + precache_sound ("player/lava.wav"); + return TRUE; + } + } + + return TRUE; +} + #endif // SVQC +#ifdef CSQC +float m_knight(float req) +{ + switch(req) + { + case MR_DEATH: + { + // nothing + return TRUE; + } + case MR_INIT: + { + precache_model ("models/monsters/hknight.mdl"); + return TRUE; + } + } + + return TRUE; +} + +#endif // CSQC +#endif // REGISTER_MONSTER diff --git a/qcsrc/server/monsters/monster/mage.qc b/qcsrc/common/monsters/monster/mage.qc similarity index 83% rename from qcsrc/server/monsters/monster/mage.qc rename to qcsrc/common/monsters/monster/mage.qc index d30c20833..f62892f8d 100644 --- a/qcsrc/server/monsters/monster/mage.qc +++ b/qcsrc/common/monsters/monster/mage.qc @@ -1,8 +1,15 @@ -const vector MAGE_MIN = '-36 -36 -24'; -const vector MAGE_MAX = '36 36 50'; - -string MAGE_MODEL = "models/monsters/mage.dpm"; - +#ifdef REGISTER_MONSTER +REGISTER_MONSTER( +/* MON_##id */ MAGE, +/* function */ m_mage, +/* spawnflags */ 0, +/* mins,maxs */ '-36 -36 -24', '36 36 50', +/* model */ "mage.dpm", +/* netname */ "mage", +/* fullname */ _("Mage") +); + +#else #ifdef SVQC float autocvar_g_monster_mage; float autocvar_g_monster_mage_health; @@ -86,47 +93,6 @@ float friend_needshelp(entity e) return FALSE; } -void mage_think() -{ - entity head; - float need_help = FALSE; - - FOR_EACH_PLAYER(head) - if(friend_needshelp(head)) - { - need_help = TRUE; - break; // found 1 player near us who is low on health - } - if(!need_help) - FOR_EACH_MONSTER(head) - if(head != self) - if(friend_needshelp(head)) - { - need_help = TRUE; - break; // found 1 player near us who is low on health - } - - self.think = mage_think; - self.nextthink = time + self.ticrate; - - if(self.weaponentity) - if(time >= self.weaponentity.ltime) - mage_shield_die(); - - if(self.health < autocvar_g_monster_mage_heal_minhealth || need_help) - if(time >= self.attack_finished_single) - if(random() < 0.5) - mage_heal(); - - if(self.enemy) - if(self.health < self.max_health) - if(time >= self.lastshielded) - if(random() < 0.5) - mage_shield(); - - monster_move(autocvar_g_monster_mage_speed, autocvar_g_monster_mage_speed, 50, mage_anim_walk, mage_anim_run, mage_anim_idle); -} - void mageattack_melee() { monster_melee(self.enemy, autocvar_g_monster_mage_attack_melee_damage, 0.3, DEATH_MONSTER_MAGE, TRUE); @@ -375,57 +341,109 @@ float mage_attack(float attack_type) return FALSE; } -void mage_die() -{ - Monster_CheckDropCvars ("mage"); - - self.think = monster_dead_think; - self.nextthink = time + self.ticrate; - self.ltime = time + 5; - monsters_setframe(mage_anim_death); - - monster_hook_death(); // for post-death mods -} - -void mage_spawn() -{ - if not(self.health) - self.health = autocvar_g_monster_mage_health; - - self.damageforcescale = 0.003; - self.classname = "monster_mage"; - self.monster_attackfunc = mage_attack; - self.nextthink = time + random() * 0.5 + 0.1; - self.think = mage_think; - - monsters_setframe(mage_anim_walk); - - monster_setupsounds("mage"); - - monster_hook_spawn(); // for post-spawn mods -} - void spawnfunc_monster_mage() { if not(autocvar_g_monster_mage) { remove(self); return; } + self.classname = "monster_mage"; + self.monster_spawnfunc = spawnfunc_monster_mage; if(Monster_CheckAppearFlags(self)) return; - if not (monster_initialize( - "Mage", MONSTER_MAGE, - MAGE_MIN, MAGE_MAX, - FALSE, - mage_die, mage_spawn)) - { - remove(self); - return; - } + if not(monster_initialize(MON_MAGE, FALSE)) { remove(self); return; } } // compatibility with old spawns void spawnfunc_monster_shalrath() { spawnfunc_monster_mage(); } +float m_mage(float req) +{ + switch(req) + { + case MR_THINK: + { + entity head; + float need_help = FALSE; + + FOR_EACH_PLAYER(head) + if(friend_needshelp(head)) + { + need_help = TRUE; + break; // found 1 player near us who is low on health + } + if(!need_help) + FOR_EACH_MONSTER(head) + if(head != self) + if(friend_needshelp(head)) + { + need_help = TRUE; + break; // found 1 player near us who is low on health + } + + if(self.weaponentity) + if(time >= self.weaponentity.ltime) + mage_shield_die(); + + if(self.health < autocvar_g_monster_mage_heal_minhealth || need_help) + if(time >= self.attack_finished_single) + if(random() < 0.5) + mage_heal(); + + if(self.enemy) + if(self.health < self.max_health) + if(time >= self.lastshielded) + if(random() < 0.5) + mage_shield(); + + monster_move(autocvar_g_monster_mage_speed, autocvar_g_monster_mage_speed, 50, mage_anim_walk, mage_anim_run, mage_anim_idle); + return TRUE; + } + case MR_DEATH: + { + monsters_setframe(mage_anim_death); + return TRUE; + } + case MR_SETUP: + { + if not(self.health) self.health = autocvar_g_monster_mage_health; + + self.monster_attackfunc = mage_attack; + monsters_setframe(mage_anim_walk); + + return TRUE; + } + case MR_INIT: + { + // nothing + return TRUE; + } + } + + return TRUE; +} + #endif // SVQC +#ifdef CSQC +float m_mage(float req) +{ + switch(req) + { + case MR_DEATH: + { + // nothing + return TRUE; + } + case MR_INIT: + { + precache_model ("models/monsters/mage.dpm"); + return TRUE; + } + } + + return TRUE; +} + +#endif // CSQC +#endif // REGISTER_MONSTER diff --git a/qcsrc/server/monsters/monster/shambler.qc b/qcsrc/common/monsters/monster/shambler.qc similarity index 66% rename from qcsrc/server/monsters/monster/shambler.qc rename to qcsrc/common/monsters/monster/shambler.qc index ec782216c..54a6ec0c3 100644 --- a/qcsrc/server/monsters/monster/shambler.qc +++ b/qcsrc/common/monsters/monster/shambler.qc @@ -1,8 +1,15 @@ -const vector SHAMBLER_MIN = '-41 -41 -31'; -const vector SHAMBLER_MAX = '41 41 65'; - -string SHAMBLER_MODEL = "models/monsters/shambler.mdl"; - +#ifdef REGISTER_MONSTER +REGISTER_MONSTER( +/* MON_##id */ SHAMBLER, +/* function */ m_shambler, +/* spawnflags */ MONSTER_SIZE_BROKEN, +/* mins,maxs */ '-41 -41 -31', '41 41 65', +/* model */ "shambler.mdl", +/* netname */ "shambler", +/* fullname */ _("Shambler") +); + +#else #ifdef SVQC float autocvar_g_monster_shambler; float autocvar_g_monster_shambler_health; @@ -22,14 +29,6 @@ const float shambler_anim_magic = 6; const float shambler_anim_pain = 7; const float shambler_anim_death = 8; -void shambler_think() -{ - self.think = shambler_think; - self.nextthink = time + self.ticrate; - - monster_move(autocvar_g_monster_shambler_speed_run, autocvar_g_monster_shambler_speed_walk, 300, shambler_anim_run, shambler_anim_walk, shambler_anim_stand); -} - void shambler_smash() { monster_melee(self.enemy, autocvar_g_monster_shambler_damage, 0.3, DEATH_MONSTER_SHAMBLER_SMASH, TRUE); @@ -103,57 +102,74 @@ float shambler_attack(float attack_type) return FALSE; } -void shambler_die() -{ - Monster_CheckDropCvars ("shambler"); - - self.think = monster_dead_think; - self.nextthink = time + self.ticrate; - self.ltime = time + 5; - monsters_setframe(shambler_anim_death); - - monster_hook_death(); // for post-death mods -} - -void shambler_spawn() -{ - if not(self.health) - self.health = autocvar_g_monster_shambler_health; - - self.damageforcescale = 0.003; - self.classname = "monster_shambler"; - self.monster_attackfunc = shambler_attack; - self.nextthink = time + random() * 0.5 + 0.1; - self.think = shambler_think; - self.weapon = WEP_NEX; - - monsters_setframe(shambler_anim_stand); - - monster_setupsounds("shambler"); - - monster_hook_spawn(); // for post-spawn mods -} - void spawnfunc_monster_shambler() { if not(autocvar_g_monster_shambler) { remove(self); return; } + self.classname = "monster_shambler"; + self.monster_spawnfunc = spawnfunc_monster_shambler; if(Monster_CheckAppearFlags(self)) return; - self.scale = 1.3; - - if not (monster_initialize( - "Shambler", MONSTER_SHAMBLER, - SHAMBLER_MIN, SHAMBLER_MAX, - FALSE, - shambler_die, shambler_spawn)) + if not(monster_initialize(MON_SHAMBLER, FALSE)) { remove(self); return; } +} + +float m_shambler(float req) +{ + switch(req) { - remove(self); - return; + case MR_THINK: + { + monster_move(autocvar_g_monster_shambler_speed_run, autocvar_g_monster_shambler_speed_walk, 300, shambler_anim_run, shambler_anim_walk, shambler_anim_stand); + return TRUE; + } + case MR_DEATH: + { + monsters_setframe(shambler_anim_death); + return TRUE; + } + case MR_SETUP: + { + if not(self.health) self.health = autocvar_g_monster_shambler_health; + + self.monster_attackfunc = shambler_attack; + monsters_setframe(shambler_anim_stand); + self.weapon = WEP_NEX; + + return TRUE; + } + case MR_INIT: + { + // nothing + return TRUE; + } } + + return TRUE; } #endif // SVQC +#ifdef CSQC +float m_shambler(float req) +{ + switch(req) + { + case MR_DEATH: + { + // nothing + return TRUE; + } + case MR_INIT: + { + precache_model ("models/monsters/shambler.mdl"); + return TRUE; + } + } + + return TRUE; +} + +#endif // CSQC +#endif // REGISTER_MONSTER diff --git a/qcsrc/server/monsters/monster/slime.qc b/qcsrc/common/monsters/monster/slime.qc similarity index 54% rename from qcsrc/server/monsters/monster/slime.qc rename to qcsrc/common/monsters/monster/slime.qc index 8f73ceaea..5e206f227 100644 --- a/qcsrc/server/monsters/monster/slime.qc +++ b/qcsrc/common/monsters/monster/slime.qc @@ -1,8 +1,15 @@ -const vector SLIME_MIN = '-16 -16 -24'; -const vector SLIME_MAX = '16 16 16'; - -string SLIME_MODEL = "models/monsters/slime.dpm"; +#ifdef REGISTER_MONSTER +REGISTER_MONSTER( +/* MON_##id */ SLIME, +/* function */ m_slime, +/* spawnflags */ 0, +/* mins,maxs */ '-16 -16 -24', '16 16 16', +/* model */ "slime.dpm", +/* netname */ "slime", +/* fullname */ _("Slime") +); +#else #ifdef SVQC float autocvar_g_monster_slime; float autocvar_g_monster_slime_health; @@ -16,14 +23,6 @@ const float slime_anim_fly = 3; const float slime_anim_die = 4; const float slime_anim_pain = 5; -void slime_think() -{ - self.think = slime_think; - self.nextthink = time + self.ticrate; - - monster_move(autocvar_g_monster_slime_speed_run, autocvar_g_monster_slime_speed_walk, 20, slime_anim_walk, slime_anim_walk, slime_anim_idle); -} - void slime_touch_jump() { if(self.health > 0) @@ -73,69 +72,92 @@ void slime_dead() self.health = -100; // gibbed slime_explode(); - Monster_CheckDropCvars ("slime"); // drop items after exploding to prevent player picking up item before dying + Monster_CheckDropCvars ("slime"); // TODO: add a special function to drop items after death self.deadflag = DEAD_DEAD; self.think = Monster_Fade; self.nextthink = time + 0.1; - - monster_hook_death(); - - self.event_damage = func_null; // reset by monster_hook_death - self.takedamage = DAMAGE_NO; -} - -void slime_die() -{ - self.think = slime_dead; - self.nextthink = time; - self.event_damage = func_null; - self.movetype = MOVETYPE_NONE; - self.enemy = world; - self.health = 0; - - self.SendFlags |= MSF_MOVE | MSF_STATUS; -} - -void slime_spawn() -{ - if not(self.health) - self.health = autocvar_g_monster_slime_health; - - self.damageforcescale = 0.003; - self.classname = "monster_slime"; - self.monster_attackfunc = slime_attack; - self.nextthink = time + random() * 0.5 + 0.1; - self.think = slime_think; - - monsters_setframe(slime_anim_idle); - - monster_setupsounds("slime"); - - monster_hook_spawn(); // for post-spawn mods } void spawnfunc_monster_slime() { if not(autocvar_g_monster_slime) { remove(self); return; } + self.classname = "monster_slime"; + self.monster_spawnfunc = spawnfunc_monster_slime; if(Monster_CheckAppearFlags(self)) return; - if not (monster_initialize( - "Slime", MONSTER_SLIME, - SLIME_MIN, SLIME_MAX, - FALSE, - slime_die, slime_spawn)) - { - remove(self); - return; - } + if not(monster_initialize(MON_SLIME, FALSE)) { remove(self); return; } } // compatibility with old spawns void spawnfunc_monster_tarbaby() { spawnfunc_monster_slime(); } +float m_slime(float req) +{ + switch(req) + { + case MR_THINK: + { + monster_move(autocvar_g_monster_slime_speed_run, autocvar_g_monster_slime_speed_walk, 20, slime_anim_walk, slime_anim_walk, slime_anim_idle); + return TRUE; + } + case MR_DEATH: + { + self.think = slime_dead; + self.nextthink = time; + self.event_damage = func_null; + self.movetype = MOVETYPE_NONE; + self.takedamage = DAMAGE_NO; + self.enemy = world; + self.health = 0; + + self.SendFlags |= MSF_MOVE | MSF_STATUS; + + return TRUE; + } + case MR_SETUP: + { + if not(self.health) self.health = autocvar_g_monster_slime_health; + + self.monster_attackfunc = slime_attack; + monsters_setframe(slime_anim_idle); + + return TRUE; + } + case MR_INIT: + { + // nothing + return TRUE; + } + } + + return TRUE; +} + #endif // SVQC +#ifdef CSQC +float m_slime(float req) +{ + switch(req) + { + case MR_DEATH: + { + // nothing + return TRUE; + } + case MR_INIT: + { + precache_model ("models/monsters/slime.dpm"); + return TRUE; + } + } + + return TRUE; +} + +#endif // CSQC +#endif // REGISTER_MONSTER diff --git a/qcsrc/server/monsters/monster/spider.qc b/qcsrc/common/monsters/monster/spider.qc similarity index 74% rename from qcsrc/server/monsters/monster/spider.qc rename to qcsrc/common/monsters/monster/spider.qc index b72a857e7..f98ee8f94 100644 --- a/qcsrc/server/monsters/monster/spider.qc +++ b/qcsrc/common/monsters/monster/spider.qc @@ -1,8 +1,15 @@ -const vector SPIDER_MIN = '-18 -18 -25'; -const vector SPIDER_MAX = '18 18 30'; - -string SPIDER_MODEL = "models/monsters/spider.dpm"; - +#ifdef REGISTER_MONSTER +REGISTER_MONSTER( +/* MON_##id */ SPIDER, +/* function */ m_spider, +/* spawnflags */ 0, +/* mins,maxs */ '-18 -18 -25', '18 18 30', +/* model */ "spider.dpm", +/* netname */ "spider", +/* fullname */ _("Spider") +); + +#else #ifdef SVQC float autocvar_g_monster_spider; float autocvar_g_monster_spider_stopspeed; @@ -24,14 +31,6 @@ const float spider_anim_attack2 = 3; const float SPIDER_TYPE_ICE = 0; const float SPIDER_TYPE_FIRE = 1; -void spider_think() -{ - self.think = spider_think; - self.nextthink = time + self.ticrate; - - 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() { entity e; @@ -161,57 +160,75 @@ float spider_attack(float attack_type) return FALSE; } -void spider_die() -{ - Monster_CheckDropCvars ("spider"); - - self.think = monster_dead_think; - self.nextthink = time + self.ticrate; - self.ltime = time + 5; - monsters_setframe(spider_anim_attack); - self.angles += '180 0 0'; - - monster_hook_death(); // for post-death mods -} - -void spider_spawn() -{ - if not(self.health) - self.health = autocvar_g_monster_spider_health; - - self.classname = "monster_spider"; - self.nextthink = time + random() * 0.5 + 0.1; - self.monster_attackfunc = spider_attack; - self.think = spider_think; - - monsters_setframe(spider_anim_idle); - - monster_setupsounds("spider"); - - if not(self.spider_type) - self.spider_type = autocvar_g_monster_spider_attack_type; - - monster_hook_spawn(); // for post-spawn mods -} - void spawnfunc_monster_spider() { if not(autocvar_g_monster_spider) { remove(self); return; } + self.classname = "monster_spider"; + self.monster_spawnfunc = spawnfunc_monster_spider; if(Monster_CheckAppearFlags(self)) return; - if not (monster_initialize( - "Spider", MONSTER_SPIDER, - SPIDER_MIN, SPIDER_MAX, - FALSE, - spider_die, spider_spawn)) + if not(monster_initialize(MON_SPIDER, FALSE)) { remove(self); return; } +} + +float m_spider(float req) +{ + switch(req) { - remove(self); - return; + case MR_THINK: + { + 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 TRUE; + } + case MR_DEATH: + { + monsters_setframe(spider_anim_attack); + self.angles += '180 0 0'; + return TRUE; + } + case MR_SETUP: + { + if not(self.health) self.health = autocvar_g_monster_spider_health; + if not(self.spider_type) self.spider_type = autocvar_g_monster_spider_attack_type; + + self.monster_attackfunc = spider_attack; + monsters_setframe(spider_anim_idle); + + return TRUE; + } + case MR_INIT: + { + // nothing + return TRUE; + } } + + return TRUE; } #endif // SVQC +#ifdef CSQC +float m_spider(float req) +{ + switch(req) + { + case MR_DEATH: + { + self.angles += '180 0 0'; // TODO: use the server side angles instead? + return TRUE; + } + case MR_INIT: + { + precache_model ("models/monsters/spider.dpm"); + return TRUE; + } + } + + return TRUE; +} + +#endif // CSQC +#endif // REGISTER_MONSTER diff --git a/qcsrc/common/monsters/monster/stingray.qc b/qcsrc/common/monsters/monster/stingray.qc new file mode 100644 index 000000000..08c7635c3 --- /dev/null +++ b/qcsrc/common/monsters/monster/stingray.qc @@ -0,0 +1,112 @@ +#ifdef REGISTER_MONSTER +REGISTER_MONSTER( +/* MON_##id */ STINGRAY, +/* function */ m_stingray, +/* spawnflags */ MONSTER_TYPE_SWIM | MONSTER_SIZE_BROKEN, +/* mins,maxs */ '-20 -20 -31', '20 20 20', +/* model */ "fish.mdl", +/* netname */ "stingray", +/* fullname */ _("Stingray") +); + +#else +#ifdef SVQC +float autocvar_g_monster_stingray; +float autocvar_g_monster_stingray_health; +float autocvar_g_monster_stingray_damage; +float autocvar_g_monster_stingray_speed_walk; +float autocvar_g_monster_stingray_speed_run; + +const float stingray_anim_attack = 0; +const float stingray_anim_death = 1; +const float stingray_anim_swim = 2; +const float stingray_anim_pain = 3; + +float stingray_attack(float attack_type) +{ + switch(attack_type) + { + case MONSTER_ATTACK_MELEE: + { + monsters_setframe(stingray_anim_attack); + self.attack_finished_single = time + 0.5; + monster_melee(self.enemy, autocvar_g_monster_stingray_damage, 0.1, DEATH_MONSTER_STINGRAY, FALSE); + + return TRUE; + } + case MONSTER_ATTACK_RANGED: + } + + return FALSE; +} + +void spawnfunc_monster_stingray() +{ + if not(autocvar_g_monster_stingray) { remove(self); return; } + + self.classname = "monster_stingray"; + + self.monster_spawnfunc = spawnfunc_monster_stingray; + + if(Monster_CheckAppearFlags(self)) + return; + + if not(monster_initialize(MON_STINGRAY, TRUE)) { remove(self); return; } +} + +float m_stingray(float req) +{ + switch(req) + { + case MR_THINK: + { + monster_move(autocvar_g_monster_stingray_speed_run, autocvar_g_monster_stingray_speed_walk, 10, stingray_anim_swim, stingray_anim_swim, stingray_anim_swim); + return TRUE; + } + case MR_DEATH: + { + monsters_setframe(stingray_anim_swim); + return TRUE; + } + case MR_SETUP: + { + if not(self.health) self.health = autocvar_g_monster_stingray_health; + + self.monster_attackfunc = stingray_attack; + monsters_setframe(stingray_anim_death); + + return TRUE; + } + case MR_INIT: + { + // nothing + return TRUE; + } + } + + return TRUE; +} + +#endif // SVQC +#ifdef CSQC +float m_stingray(float req) +{ + switch(req) + { + case MR_DEATH: + { + // nothing + return TRUE; + } + case MR_INIT: + { + precache_model ("models/monsters/fish.mdl"); + return TRUE; + } + } + + return TRUE; +} + +#endif // CSQC +#endif // REGISTER_MONSTER diff --git a/qcsrc/server/monsters/monster/wyvern.qc b/qcsrc/common/monsters/monster/wyvern.qc similarity index 66% rename from qcsrc/server/monsters/monster/wyvern.qc rename to qcsrc/common/monsters/monster/wyvern.qc index e9eda6d6a..71e1236f4 100644 --- a/qcsrc/server/monsters/monster/wyvern.qc +++ b/qcsrc/common/monsters/monster/wyvern.qc @@ -1,8 +1,15 @@ -const vector WYVERN_MIN = '-20 -20 -58'; -const vector WYVERN_MAX = '20 20 20'; - -string WYVERN_MODEL = "models/monsters/wizard.mdl"; +#ifdef REGISTER_MONSTER +REGISTER_MONSTER( +/* MON_##id */ WYVERN, +/* function */ m_wyvern, +/* spawnflags */ MONSTER_TYPE_FLY | MONSTER_SIZE_BROKEN, +/* mins,maxs */ '-20 -20 -58', '20 20 20', +/* model */ "wizard.mdl", +/* netname */ "wyvern", +/* fullname */ _("Wyvern") +); +#else #ifdef SVQC float autocvar_g_monster_wyvern; float autocvar_g_monster_wyvern_health; @@ -21,14 +28,6 @@ const float wyvern_anim_magic = 2; const float wyvern_anim_pain = 3; const float wyvern_anim_death = 4; -void wyvern_think() -{ - self.think = wyvern_think; - self.nextthink = time + self.ticrate; - - monster_move(autocvar_g_monster_wyvern_speed_run, autocvar_g_monster_wyvern_speed_walk, 300, wyvern_anim_fly, wyvern_anim_hover, wyvern_anim_hover); -} - void wyvern_fireball_explode() { entity e; @@ -93,62 +92,79 @@ float wyvern_attack(float attack_type) return FALSE; } -void wyvern_die() -{ - Monster_CheckDropCvars ("wyvern"); - - self.think = monster_dead_think; - self.nextthink = time + self.ticrate; - self.ltime = time + 5; - self.velocity_x = -200 + 400 * random(); - self.velocity_y = -200 + 400 * random(); - self.velocity_z = 100 + 100 * random(); - - monsters_setframe(wyvern_anim_death); - - monster_hook_death(); // for post-death mods -} - -void wyvern_spawn() -{ - if not(self.health) - self.health = autocvar_g_monster_wyvern_health; - - self.classname = "monster_wyvern"; - self.monster_attackfunc = wyvern_attack; - self.nextthink = time + random() * 0.5 + 0.1; - self.movetype = MOVETYPE_FLY; - self.flags |= FL_FLY; - self.think = wyvern_think; - - monster_setupsounds("wyvern"); - - monster_hook_spawn(); // for post-spawn mods -} - void spawnfunc_monster_wyvern() { if not(autocvar_g_monster_wyvern) { remove(self); return; } + self.classname = "monster_wyvern"; + self.monster_spawnfunc = spawnfunc_monster_wyvern; if(Monster_CheckAppearFlags(self)) return; - self.scale = 1.3; - - if not (monster_initialize( - "Wyvern", MONSTER_WYVERN, - WYVERN_MIN, WYVERN_MAX, - TRUE, - wyvern_die, wyvern_spawn)) - { - remove(self); - return; - } + if not(monster_initialize(MON_WYVERN, TRUE)) { remove(self); return; } } // compatibility with old spawns void spawnfunc_monster_wizard() { spawnfunc_monster_wyvern(); } +float m_wyvern(float req) +{ + switch(req) + { + case MR_THINK: + { + monster_move(autocvar_g_monster_wyvern_speed_run, autocvar_g_monster_wyvern_speed_walk, 300, wyvern_anim_fly, wyvern_anim_hover, wyvern_anim_hover); + return TRUE; + } + case MR_DEATH: + { + monsters_setframe(wyvern_anim_death); + self.velocity_x = -200 + 400 * random(); + self.velocity_y = -200 + 400 * random(); + self.velocity_z = 100 + 100 * random(); + return TRUE; + } + case MR_SETUP: + { + if not(self.health) self.health = autocvar_g_monster_wyvern_health; + + self.monster_attackfunc = wyvern_attack; + monsters_setframe(wyvern_anim_hover); + + return TRUE; + } + case MR_INIT: + { + // nothing + return TRUE; + } + } + + return TRUE; +} + #endif // SVQC +#ifdef CSQC +float m_wyvern(float req) +{ + switch(req) + { + case MR_DEATH: + { + // nothing + return TRUE; + } + case MR_INIT: + { + precache_model ("models/monsters/knight.mdl"); + return TRUE; + } + } + + return TRUE; +} + +#endif // CSQC +#endif // REGISTER_MONSTER diff --git a/qcsrc/server/monsters/monster/zombie.qc b/qcsrc/common/monsters/monster/zombie.qc similarity index 71% rename from qcsrc/server/monsters/monster/zombie.qc rename to qcsrc/common/monsters/monster/zombie.qc index aa96920d7..9ddfbde58 100644 --- a/qcsrc/server/monsters/monster/zombie.qc +++ b/qcsrc/common/monsters/monster/zombie.qc @@ -1,8 +1,15 @@ -const vector ZOMBIE_MIN = '-18 -18 -25'; -const vector ZOMBIE_MAX = '18 18 47'; - -string ZOMBIE_MODEL = "models/monsters/zombie.dpm"; +#ifdef REGISTER_MONSTER +REGISTER_MONSTER( +/* MON_##id */ ZOMBIE, +/* function */ m_zombie, +/* spawnflags */ MONSTER_RESPAWN_DEATHPOINT, +/* mins,maxs */ '-18 -18 -25', '18 18 47', +/* model */ "zombie.dpm", +/* netname */ "zombie", +/* fullname */ _("Zombie") +); +#else #ifdef SVQC float autocvar_g_monster_zombie; float autocvar_g_monster_zombie_stopspeed; @@ -48,14 +55,6 @@ const float zombie_anim_runforwardleft = 28; const float zombie_anim_runforwardright = 29; const float zombie_anim_spawn = 30; -void zombie_think() -{ - self.think = zombie_think; - self.nextthink = time + self.ticrate; - - 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() { if (self.health <= 0) @@ -109,57 +108,76 @@ float zombie_attack(float attack_type) return FALSE; } -void zombie_die() -{ - Monster_CheckDropCvars ("zombie"); - - self.think = monster_dead_think; - self.nextthink = time + self.ticrate; - self.ltime = time + 5; - monsters_setframe((random() > 0.5) ? zombie_anim_deathback1 : zombie_anim_deathfront1); - - monster_hook_death(); // for post-death mods -} - -void zombie_spawn() -{ - if not(self.health) - self.health = autocvar_g_monster_zombie_health; - - self.classname = "monster_zombie"; - self.spawn_time = time + 2.1; - self.nextthink = time + random() * 0.5 + 0.1; - self.think = zombie_think; - self.monster_attackfunc = zombie_attack; - self.spawnshieldtime = self.spawn_time; - self.respawntime = 0.1; - self.spawnflags |= MONSTER_RESPAWN_DEATHPOINT; // always enabled for zombie - - monsters_setframe(zombie_anim_spawn); - - monster_setupsounds("zombie"); - - monster_hook_spawn(); // for post-spawn mods -} - void spawnfunc_monster_zombie() { if not(autocvar_g_monster_zombie) { remove(self); return; } + self.classname = "monster_zombie"; + self.monster_spawnfunc = spawnfunc_monster_zombie; if(Monster_CheckAppearFlags(self)) return; - if not (monster_initialize( - "Zombie", MONSTER_ZOMBIE, - ZOMBIE_MIN, ZOMBIE_MAX, - FALSE, - zombie_die, zombie_spawn)) + if not(monster_initialize(MON_ZOMBIE, FALSE)) { remove(self); return; } +} + +float m_zombie(float req) +{ + switch(req) { - remove(self); - return; + case MR_THINK: + { + 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); + return TRUE; + } + case MR_DEATH: + { + monsters_setframe((random() > 0.5) ? zombie_anim_deathback1 : zombie_anim_deathfront1); + return TRUE; + } + case MR_SETUP: + { + if not(self.health) self.health = autocvar_g_monster_zombie_health; + + self.monster_attackfunc = zombie_attack; + monsters_setframe(zombie_anim_spawn); + self.spawn_time = time + 2.1; + self.spawnshieldtime = self.spawn_time; + self.respawntime = 0.1; + + return TRUE; + } + case MR_INIT: + { + // nothing + return TRUE; + } + } + + return TRUE; +} + +#endif // SVQC +#ifdef CSQC +float m_zombie(float req) +{ + switch(req) + { + case MR_DEATH: + { + // nothing + return TRUE; + } + case MR_INIT: + { + precache_model ("models/monsters/zombie.dpm"); + return TRUE; + } } + + return TRUE; } -#endif //SVQC +#endif // CSQC +#endif // REGISTER_MONSTER diff --git a/qcsrc/common/monsters/monsters.qc b/qcsrc/common/monsters/monsters.qc new file mode 100644 index 000000000..706bf5526 --- /dev/null +++ b/qcsrc/common/monsters/monsters.qc @@ -0,0 +1,54 @@ +#ifdef SVQC +#include "lib/defs.qh" +#include "lib/monsters.qc" +#include "lib/spawn.qc" +#endif + +#include "all.qh" + +// MONSTER PLUGIN SYSTEM +entity monster_info[MON_MAXCOUNT]; +entity dummy_monster_info; + +void register_monster(float id, float(float) func, float monstertype, vector min_s, vector max_s, string modelname, string shortname, string mname) +{ + entity e; + monster_info[id - 1] = e = spawn(); + e.classname = "monster_info"; + e.monsterid = id; + e.netname = shortname; + e.monster_name = mname; + e.monster_func = func; + e.mdl = modelname; + e.mins = min_s; + e.maxs = max_s; + e.model = strzone(strcat("models/monsters/", modelname)); + e.spawnflags = monstertype; + + func(MR_INIT); +} +float m_null(float dummy) { return 0; } +void register_monsters_done() +{ + dummy_monster_info = spawn(); + dummy_monster_info.classname = "monster_info"; + dummy_monster_info.monsterid = 0; // you can recognize dummies by this + dummy_monster_info.netname = ""; + dummy_monster_info.monster_name = "Monster"; + dummy_monster_info.monster_func = m_null; + dummy_monster_info.mdl = ""; + dummy_monster_info.mins = '-0 -0 -0'; + dummy_monster_info.maxs = '0 0 0'; + dummy_monster_info.model = ""; + dummy_monster_info.spawnflags = 0; +} +entity get_monsterinfo(float id) +{ + entity m; + if(id < MON_FIRST || id > MON_LAST) + return dummy_monster_info; + m = monster_info[id - 1]; + if(m) + return m; + return dummy_monster_info; +} diff --git a/qcsrc/common/monsters/monsters.qh b/qcsrc/common/monsters/monsters.qh new file mode 100644 index 000000000..5124e4528 --- /dev/null +++ b/qcsrc/common/monsters/monsters.qh @@ -0,0 +1,87 @@ +// monster requests +#define MR_SETUP 1 // (SERVER) setup monster data +#define MR_THINK 2 // (SERVER) logic to run every frame +#define MR_DEATH 3 // (BOTH) called when monster dies +#define MR_INIT 4 // (BOTH) precaches models/sounds used by this monster +#define MR_CONFIG 5 // (ALL) + +// functions: +entity get_monsterinfo(float id); + +// entity properties of monsterinfo: +.float monsterid; // MON_... +.string netname; // short name +.string monster_name; // human readable name +.float(float) monster_func; // m_... +.string mdl; // currently a copy of the model +.string model; // full name of model +.float spawnflags; + +// other useful macros +#define MON_ACTION(monstertype,mrequest) (get_monsterinfo(monstertype)).monster_func(mrequest) +#define M_NAME(monstertype) (get_monsterinfo(monstertype)).monster_name + +// ===================== +// Monster Registration +// ===================== + +float m_null(float dummy); +void register_monster(float id, float(float) func, float monstertype, vector min_s, vector max_s, string modelname, string shortname, string mname); +void register_monsters_done(); + +// special spawn flags +const float MONSTER_RESPAWN_DEATHPOINT = 699; // re-spawn where we died +const float MONSTER_TYPE_FLY = 700; +const float MONSTER_TYPE_SWIM = 701; +const float MONSTER_SIZE_BROKEN = 702; // TODO: remove when bad models are replaced + +const float MON_MAXCOUNT = 24; +#define MON_FIRST 1 +float MON_COUNT; +float MON_LAST; + +#define REGISTER_MONSTER_2(id,func,monstertype,min_s,max_s,modelname,shortname,mname) \ + float id; \ + float func(float); \ + void RegisterMonsters_##id() \ + { \ + MON_LAST = (id = MON_FIRST + MON_COUNT); \ + ++MON_COUNT; \ + register_monster(id,func,monstertype,min_s,max_s,modelname,shortname,mname); \ + } \ + ACCUMULATE_FUNCTION(RegisterMonsters, RegisterMonsters_##id) +#define REGISTER_MONSTER(id,func,monstertype,min_s,max_s,modelname,shortname,mname) \ + REGISTER_MONSTER_2(MON_##id,func,monstertype,min_s,max_s,modelname,shortname,mname) + +#define MON_DUPECHECK(dupecheck,cvar) \ + #ifndef dupecheck \ + #define dupecheck \ + float cvar; \ + #else \ + #error DUPLICATE MONSTER CVAR: cvar \ + #endif + +#define MON_ADD_CVAR(monster,name) \ + MON_DUPECHECK(MON_CVAR_##monster##_##name, autocvar_g_monster_##monster##_##name) + +#define MON_CVAR(monster,name) autocvar_g_balance_##monster##_##name + +#define MON_ADD_PROP(monster,prop,name) \ + .float ##prop; \ + MON_DUPECHECK(MON_CVAR_##monster##_##name, autocvar_g_monster_##monster##_##name) + +#define MON_SET_PROP(wepid,monster,prop,name) get_monsterinfo(##wepid).##prop = autocvar_g_monster_##monster##_##name; + +#define MON_SET_PROPS(monsettings,wepid) \ + #define MON_ADD_CVAR(monster,mode,name) \ + #define MON_ADD_PROP(monster,prop,name) MON_SET_PROP(wepid,monster,prop,name) \ + monsettings \ + #undef MON_ADD_CVAR \ + #undef MON_ADD_PROP + +#include "all.qh" + +#undef MON_ADD_CVAR +#undef MON_ADD_PROP +#undef REGISTER_MONSTER +ACCUMULATE_FUNCTION(RegisterMonsters, register_monsters_done) diff --git a/qcsrc/server/command/cmd.qc b/qcsrc/server/command/cmd.qc index a12fc3f14..ce049adf3 100644 --- a/qcsrc/server/command/cmd.qc +++ b/qcsrc/server/command/cmd.qc @@ -197,7 +197,7 @@ void ClientCommand_mobedit(float request, float argc) switch(argv(1)) { case "name": trace_ent.netname = strzone(strdecolorize(argv(2))); if(trace_ent.sprite) WaypointSprite_UpdateSprites(trace_ent.sprite, trace_ent.netname, "", ""); return; - case "skin": if(trace_ent.monsterid != MONSTER_MAGE) { trace_ent.skin = stof(argv(2)); trace_ent.SendFlags |= MSF_STATUS; } return; + case "skin": if(trace_ent.monsterid != MON_MAGE) { trace_ent.skin = stof(argv(2)); trace_ent.SendFlags |= MSF_STATUS; } return; case "movetarget": trace_ent.monster_moveflags = stof(argv(2)); return; } } @@ -268,8 +268,8 @@ void ClientCommand_mobspawn(float request, float argc) float i; string list = "Available monsters:"; - for(i = MONSTER_FIRST + 1; i < MONSTER_LAST; ++i) - list = strcat(list, " ", monster_id2string(i)); + for(i = MON_FIRST; i <= MON_LAST; ++i) + list = strcat(list, " ", (get_monsterinfo(i)).netname); sprint(self, strcat(list, "\n")); @@ -295,9 +295,9 @@ void ClientCommand_mobspawn(float request, float argc) //WarpZone_TraceLine(self.origin + self.view_ofs, self.origin + self.view_ofs + v_forward * 150, MOVE_NORMAL, self); e = spawnmonster(tospawn, 0, self, self, trace_endpos, FALSE, moveflag); - if(mname) e.netname = strzone(mname); + if(mname) e.monster_name = strzone(mname); - sprint(self, strcat("Spawned ", e.netname, "\n")); + sprint(self, strcat("Spawned ", e.monster_name, "\n")); } return; diff --git a/qcsrc/server/command/sv_cmd.qc b/qcsrc/server/command/sv_cmd.qc index 34a8a84f5..2175ceb42 100644 --- a/qcsrc/server/command/sv_cmd.qc +++ b/qcsrc/server/command/sv_cmd.qc @@ -146,6 +146,7 @@ void GameCommand_butcher(float request) case CMD_REQUEST_COMMAND: { if(autocvar_g_campaign) { print("This command doesn't work in campaign mode.\n"); return; } + if(g_invasion) { print("This command doesn't work during an invasion.\n"); return; } float removed_count = 0; entity montokill, head; diff --git a/qcsrc/server/g_damage.qc b/qcsrc/server/g_damage.qc index ecc9c9e50..2e100f2ce 100644 --- a/qcsrc/server/g_damage.qc +++ b/qcsrc/server/g_damage.qc @@ -734,7 +734,7 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, float mirrorforce *= g_weaponforcefactor; } - if(((targ.frozen == 2 && attacker.monsterid != MONSTER_SPIDER) || (targ.frozen == 1)) && deathtype != DEATH_HURTTRIGGER) + if(((targ.frozen == 2 && attacker.monsterid != MON_SPIDER) || (targ.frozen == 1)) && deathtype != DEATH_HURTTRIGGER) { damage = 0; force *= 0.2; diff --git a/qcsrc/server/g_world.qc b/qcsrc/server/g_world.qc index 23f51f54a..c9e24123a 100644 --- a/qcsrc/server/g_world.qc +++ b/qcsrc/server/g_world.qc @@ -546,6 +546,7 @@ void spawnfunc___init_dedicated_server(void) // needs to be done so early because of the constants they create CALL_ACCUMULATED_FUNCTION(RegisterWeapons); + CALL_ACCUMULATED_FUNCTION(RegisterMonsters); CALL_ACCUMULATED_FUNCTION(RegisterGametypes); CALL_ACCUMULATED_FUNCTION(RegisterNotifications); CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes); @@ -594,6 +595,7 @@ void spawnfunc_worldspawn (void) // needs to be done so early because of the constants they create CALL_ACCUMULATED_FUNCTION(RegisterWeapons); + CALL_ACCUMULATED_FUNCTION(RegisterMonsters); CALL_ACCUMULATED_FUNCTION(RegisterGametypes); CALL_ACCUMULATED_FUNCTION(RegisterNotifications); CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes); diff --git a/qcsrc/server/monsters/lib/monsters_early.qh b/qcsrc/server/monsters/lib/monsters_early.qh deleted file mode 100644 index 9c7fc1e75..000000000 --- a/qcsrc/server/monsters/lib/monsters_early.qh +++ /dev/null @@ -1,90 +0,0 @@ -// for definitions used outside the monsters folder - -#ifdef SVQC -.string spawnmob; -.float monster_attack; - -float monster_skill; -float spawncode_first_load; // used to tell the player the monster database is loading (TODO: fix this?) - -.entity monster_owner; // new monster owner entity, fixes non-solid monsters -.float monstercount; // per player monster count - -.float stat_monsters_killed; // stats -.float stat_monsters_total; -float monsters_total; -float monsters_killed; -void monsters_setstatus(); // monsters.qc -.float monster_moveflags; // checks where to move when not attacking -#endif // SVQC - -#ifndef MENUQC -.float monsterid; -// Monster IDs -float MONSTER_FIRST = 1; -float MONSTER_ZOMBIE = 2; -float MONSTER_BRUTE = 3; -float MONSTER_ANIMUS = 4; -float MONSTER_SHAMBLER = 5; -float MONSTER_BRUISER = 6; -float MONSTER_WYVERN = 7; -float MONSTER_CERBERUS = 8; -float MONSTER_SLIME = 9; -float MONSTER_KNIGHT = 10; -float MONSTER_STINGRAY = 11; -float MONSTER_MAGE = 12; -float MONSTER_SPIDER = 13; -float MONSTER_LAST = 14; - -// id-string converters (TODO: remove these!) -string monster_id2string(float mnster) -{ - switch(mnster) - { - case MONSTER_ZOMBIE: return "zombie"; - case MONSTER_BRUTE: return "brute"; - case MONSTER_ANIMUS: return "animus"; - case MONSTER_SHAMBLER: return "shambler"; - case MONSTER_BRUISER: return "bruiser"; - case MONSTER_WYVERN: return "wyvern"; - case MONSTER_CERBERUS: return "cerberus"; - case MONSTER_SLIME: return "slime"; - case MONSTER_KNIGHT: return "knight"; - case MONSTER_STINGRAY: return "stingray"; - case MONSTER_MAGE: return "mage"; - case MONSTER_SPIDER: return "spider"; - default: return ""; - } -} -float monster_string2id(string monster) -{ - switch(monster) - { - case "zombie": return MONSTER_ZOMBIE; - case "brute": return MONSTER_BRUTE; - case "animus": return MONSTER_ANIMUS; - case "shambler": return MONSTER_SHAMBLER; - case "bruiser": return MONSTER_BRUISER; - case "wyvern": return MONSTER_WYVERN; - case "cerberus": return MONSTER_CERBERUS; - case "slime": return MONSTER_SLIME; - case "knight": return MONSTER_KNIGHT; - case "stingray": return MONSTER_STINGRAY; - case "mage": return MONSTER_MAGE; - case "spider": return MONSTER_SPIDER; - default: return 0; - } -} - -.float anim_start_time; - -float MSF_UPDATE = 2; -float MSF_STATUS = 4; -float MSF_SETUP = 8; -float MSF_ANG = 16; -float MSF_MOVE = 32; -float MSF_ANIM = 64; - -float MSF_FULL_UPDATE = 16777215; - -#endif // CSQC/SVQC diff --git a/qcsrc/server/monsters/monster/bruiser.qc b/qcsrc/server/monsters/monster/bruiser.qc deleted file mode 100644 index e19066bba..000000000 --- a/qcsrc/server/monsters/monster/bruiser.qc +++ /dev/null @@ -1,105 +0,0 @@ -const vector BRUISER_MIN = '-20 -20 -31'; -const vector BRUISER_MAX = '20 20 53'; - -string BRUISER_MODEL = "models/monsters/knight.mdl"; - -#ifdef SVQC -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; - -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/stingray.qc b/qcsrc/server/monsters/monster/stingray.qc deleted file mode 100644 index 61dccfbd6..000000000 --- a/qcsrc/server/monsters/monster/stingray.qc +++ /dev/null @@ -1,95 +0,0 @@ -const vector STINGRAY_MIN = '-20 -20 -31'; -const vector STINGRAY_MAX = '20 20 20'; - -string STINGRAY_MODEL = "models/monsters/fish.mdl"; - -#ifdef SVQC -float autocvar_g_monster_stingray; -float autocvar_g_monster_stingray_health; -float autocvar_g_monster_stingray_damage; -float autocvar_g_monster_stingray_speed_walk; -float autocvar_g_monster_stingray_speed_run; - -const float stingray_anim_attack = 0; -const float stingray_anim_death = 1; -const float stingray_anim_swim = 2; -const float stingray_anim_pain = 3; - -void stingray_think() -{ - self.think = stingray_think; - self.nextthink = time + self.ticrate; - - monster_move(autocvar_g_monster_stingray_speed_run, autocvar_g_monster_stingray_speed_walk, 10, stingray_anim_swim, stingray_anim_swim, stingray_anim_swim); -} - -float stingray_attack(float attack_type) -{ - switch(attack_type) - { - case MONSTER_ATTACK_MELEE: - { - monsters_setframe(stingray_anim_attack); - self.attack_finished_single = time + 0.5; - monster_melee(self.enemy, autocvar_g_monster_stingray_damage, 0.1, DEATH_MONSTER_STINGRAY, FALSE); - - return TRUE; - } - case MONSTER_ATTACK_RANGED: - } - - return FALSE; -} - -void stingray_die() -{ - Monster_CheckDropCvars ("stingray"); - - self.think = monster_dead_think; - self.nextthink = time + self.ticrate; - self.ltime = time + 5; - monsters_setframe(stingray_anim_death); - - monster_hook_death(); // for post-death mods -} - -void stingray_spawn() -{ - if not(self.health) - self.health = autocvar_g_monster_stingray_health; - - self.damageforcescale = 0.5; - self.classname = "monster_stingray"; - self.monster_attackfunc = stingray_attack; - self.flags |= FL_SWIM; - self.nextthink = time + random() * 0.5 + 0.1; - self.think = stingray_think; - - monster_setupsounds("stingray"); - - monster_hook_spawn(); // for post-spawn mods -} - -void spawnfunc_monster_stingray() -{ - if not(autocvar_g_monster_stingray) { remove(self); return; } - - self.monster_spawnfunc = spawnfunc_monster_stingray; - - if(Monster_CheckAppearFlags(self)) - return; - - self.scale = 1.3; - - if not (monster_initialize( - "Stingray", MONSTER_STINGRAY, - STINGRAY_MIN, STINGRAY_MAX, - TRUE, - stingray_die, stingray_spawn)) - { - remove(self); - return; - } -} - -#endif // SVQC diff --git a/qcsrc/server/mutators/gamemode_invasion.qc b/qcsrc/server/mutators/gamemode_invasion.qc index 7b82f8127..47af8e78d 100644 --- a/qcsrc/server/mutators/gamemode_invasion.qc +++ b/qcsrc/server/mutators/gamemode_invasion.qc @@ -8,15 +8,15 @@ void invasion_spawnpoint() float invasion_PickMonster(float have_shamblers) { if(autocvar_g_invasion_zombies_only) - return MONSTER_ZOMBIE; + return MON_ZOMBIE; float i; RandomSelection_Init(); - for(i = MONSTER_FIRST + 1; i < MONSTER_LAST; ++i) + for(i = MON_FIRST; i <= MON_LAST; ++i) { - if(i == MONSTER_STINGRAY || i == MONSTER_WYVERN || (i == MONSTER_SHAMBLER && have_shamblers >= 1)) + if(i == MON_STINGRAY || i == MON_WYVERN || (i == MON_SHAMBLER && have_shamblers >= 1)) continue; // flying/swimming monsters not yet supported RandomSelection_Add(world, i, "", 1, 1); @@ -88,7 +88,7 @@ float Invasion_CheckWinner() FOR_EACH_MONSTER(head) if(head.health > 0) { - if(head.monsterid == MONSTER_SHAMBLER) + if(head.monsterid == MON_SHAMBLER) ++shamblers; ++total_alive_monsters; } diff --git a/qcsrc/server/mutators/mutator_minstagib.qc b/qcsrc/server/mutators/mutator_minstagib.qc index d438faa62..5fae3a0e1 100644 --- a/qcsrc/server/mutators/mutator_minstagib.qc +++ b/qcsrc/server/mutators/mutator_minstagib.qc @@ -119,7 +119,7 @@ MUTATOR_HOOKFUNCTION(minstagib_MonsterLoot) MUTATOR_HOOKFUNCTION(minstagib_MonsterSpawn) { // always refill ammo - if(self.monsterid == MONSTER_MAGE) + if(self.monsterid == MON_MAGE) self.skin = 1; return FALSE; diff --git a/qcsrc/server/progs.src b/qcsrc/server/progs.src index d446d1bd3..7de6565c3 100644 --- a/qcsrc/server/progs.src +++ b/qcsrc/server/progs.src @@ -26,6 +26,7 @@ sys-post.qh ../common/command/shared_defs.qh ../common/net_notice.qh ../common/animdecide.qh +../common/monsters/monsters.qh autocvars.qh constants.qh @@ -53,7 +54,7 @@ mutators/mutator_nades.qh tturrets/include/turrets_early.qh vehicles/vehicles_def.qh -monsters/lib/monsters_early.qh +../common/monsters/lib/monsters_early.qh generator.qh @@ -233,7 +234,7 @@ round_handler.qc ../common/explosion_equation.qc -monsters/monsters.qh +../common/monsters/monsters.qc mutators/base.qc mutators/gamemode_assault.qc -- 2.39.2