#if defined(CSQC)
#elif defined(MENUQC)
#elif defined(SVQC)
- #include "../../dpdefs/progsdefs.qh"
- #include "../../dpdefs/dpextensions.qh"
- #include "../../warpzonelib/common.qh"
+ #include <lib/warpzone/common.qh>
#include "../constants.qh"
#include "../teams.qh"
#include "../util.qh"
#include "all.qh"
#include "sv_monsters.qh"
+ #include "../physics/movelib.qh"
#include "../weapons/all.qh"
- #include "../../server/autocvars.qh"
- #include "../../server/defs.qh"
- #include "../deathtypes.qh"
- #include "../../server/mutators/mutators_include.qh"
- #include "../../server/steerlib.qh"
+ #include <server/autocvars.qh>
+ #include <server/defs.qh>
+ #include "../deathtypes/all.qh"
+ #include <server/mutators/all.qh>
+ #include <server/steerlib.qh>
#include "../turrets/sv_turrets.qh"
#include "../turrets/util.qh"
#include "../vehicles/all.qh"
- #include "../../server/campaign.qh"
- #include "../../server/command/common.qh"
- #include "../../server/command/cmd.qh"
+ #include <server/campaign.qh>
+ #include <server/command/common.qh>
+ #include <server/command/cmd.qh>
#include "../triggers/triggers.qh"
- #include "../../csqcmodellib/sv_model.qh"
- #include "../../server/round_handler.qh"
+ #include <lib/csqcmodel/sv_model.qh>
+ #include <server/round_handler.qh>
#endif
void monsters_setstatus()
return;
vector org = self.origin + ((self.mins + self.maxs) * 0.5);
- entity e = spawn();
+ entity e = new(droppedweapon); // use weapon handling to remove it on touch
+ e.spawnfunc_checked = true;
e.monster_loot = self.monster_loot;
{
setself(e);
e.noalign = true;
- e.monster_loot();
+ e.monster_loot(e);
e.gravity = 1;
e.movetype = MOVETYPE_TOSS;
e.reset = SUB_Remove;
setorigin(e, org);
e.velocity = randomvec() * 175 + '0 0 325';
e.item_spawnshieldtime = time + 0.7;
- e.classname = "droppedweapon"; // use weapon handling to remove it on touch
SUB_SetFade(e, time + autocvar_g_monsters_drop_time, 1);
setself(this);
}
|| (player.takedamage == DAMAGE_NO)
|| (player.items & IT_INVISIBILITY)
|| (IS_SPEC(player) || IS_OBSERVER(player)) // don't attack spectators
- || (!IS_VEHICLE(player) && (player.deadflag != DEAD_NO || mon.deadflag != DEAD_NO || player.health <= 0 || mon.health <= 0))
+ || (!IS_VEHICLE(player) && (IS_DEAD(player) || IS_DEAD(mon) || player.health <= 0 || mon.health <= 0))
|| (mon.monster_follow == player || player.monster_follow == mon)
|| (!IS_VEHICLE(player) && (player.flags & FL_NOTARGET))
|| (!autocvar_g_monsters_typefrag && player.BUTTON_CHAT)
|| (SAME_TEAM(player, mon))
- || (player.frozen)
+ || (STAT(FROZEN, player))
|| (player.alpha != 0 && player.alpha < 0.5)
)
{
}
else
{
- oldself.think = SUB_Remove;
+ oldself.think = SUB_Remove_self;
oldself.nextthink = time;
}
}
void Monster_Sounds_Precache()
{SELFPARAM();
- string m = (get_monsterinfo(self.monsterid)).model;
+ string m = (get_monsterinfo(self.monsterid)).m_model.model_str();
float globhandle, n, i;
string f;
if(delaytoo)
if(time < self.msound_delay)
return; // too early
- GlobalSound(self.(samplefield), chan, VOICETYPE_PLAYERSOUND);
+ GlobalSound_string(self, self.(samplefield), chan, VOICETYPE_PLAYERSOUND);
self.msound_delay = time + sound_delay;
}
setanim(self, anim, false, true, false);
if(self.animstate_endtime > time && (self.flags & FL_MONSTER))
- self.attack_finished_single = self.anim_finished = self.animstate_endtime;
+ self.attack_finished_single[0] = self.anim_finished = self.animstate_endtime;
else
- self.attack_finished_single = self.anim_finished = time + animtime;
+ self.attack_finished_single[0] = self.anim_finished = time + animtime;
monster_makevectors(targ);
{SELFPARAM();
if(self.state && (self.flags & FL_MONSTER))
return false; // already attacking
- if(!(self.flags & FL_ONGROUND))
+ if(!(IS_ONGROUND(self)))
return false; // not on the ground
if(self.health <= 0)
return false; // called when dead?
- if(time < self.attack_finished_single)
+ if(time < self.attack_finished_single[0])
return false; // still attacking
vector old = self.velocity;
setanim(self, anm, false, true, false);
if(self.animstate_endtime > time && (self.flags & FL_MONSTER))
- self.attack_finished_single = self.anim_finished = self.animstate_endtime;
+ self.attack_finished_single[0] = self.anim_finished = self.animstate_endtime;
else
- self.attack_finished_single = self.anim_finished = time + animtime;
+ self.attack_finished_single[0] = self.anim_finished = time + animtime;
if(self.flags & FL_MONSTER)
self.state = MONSTER_ATTACK_RANGED;
self.touch = touchfunc;
self.origin_z += 1;
self.velocity = vel;
- self.flags &= ~FL_ONGROUND;
+ UNSET_ONGROUND(self);
return true;
}
{
if((e == world || targ == world)
|| (!e.monster_attackfunc)
- || (time < e.attack_finished_single)
+ || (time < e.attack_finished_single[0])
) { return; }
float targ_vlen = vlen(targ.origin - e.origin);
if(targ_vlen <= e.attack_range)
{
- float attack_success = e.monster_attackfunc(MONSTER_ATTACK_MELEE);
+ float attack_success = e.monster_attackfunc(MONSTER_ATTACK_MELEE, targ);
if(attack_success == 1)
Monster_Sound(monstersound_melee, 0, false, CH_VOICE);
else if(attack_success > 0)
if(targ_vlen > e.attack_range)
{
- float attack_success = e.monster_attackfunc(MONSTER_ATTACK_RANGED);
+ float attack_success = e.monster_attackfunc(MONSTER_ATTACK_RANGED, targ);
if(attack_success == 1)
Monster_Sound(monstersound_melee, 0, false, CH_VOICE);
else if(attack_success > 0)
self.anim_die2 = animfixfps(self, '9 1 0.01', '0 0 0');*/
// then get the real values
- MON_ACTION(self.monsterid, MR_ANIM);
+ Monster mon = get_monsterinfo(self.monsterid);
+ mon.mr_anim(mon);
}
void Monster_Touch()
WarpZone_TraceLine(self.origin, targ_origin, MOVE_NOMONSTERS, self);
if((self.enemy == world)
- || (self.enemy.deadflag != DEAD_NO || self.enemy.health < 1)
- || (self.enemy.frozen)
+ || (IS_DEAD(self.enemy) || self.enemy.health < 1)
+ || (STAT(FROZEN, self.enemy))
|| (self.enemy.flags & FL_NOTARGET)
|| (self.enemy.alpha < 0.5 && self.enemy.alpha != 0)
|| (self.enemy.takedamage == DAMAGE_NO)
|| (vlen(self.origin - targ_origin) > self.target_range)
|| ((trace_fraction < 1) && (trace_ent != self.enemy)))
- //|| (time > self.ctf_droptime + autocvar_g_ctf_pass_timelimit)) // TODO: chase timelimit?
{
self.enemy = world;
self.pass_distance = 0;
entity targ;
- if(self.frozen == 2)
+ if(STAT(FROZEN, self) == 2)
{
self.revive_progress = bound(0, self.revive_progress + self.ticrate * self.revive_speed, 1);
self.health = max(1, self.revive_progress * self.max_health);
if(!(self.spawnflags & MONSTERFLAG_INVINCIBLE) && self.sprite)
WaypointSprite_UpdateHealth(self.sprite, self.health);
- movelib_beak_simple(stpspeed);
+ movelib_brake_simple(stpspeed);
setanim(self, self.anim_idle, true, false, false);
self.enemy = world;
return;
}
- else if(self.frozen == 3)
+ else if(STAT(FROZEN, self) == 3)
{
self.revive_progress = bound(0, self.revive_progress - self.ticrate * self.revive_speed, 1);
self.health = max(0, autocvar_g_nades_ice_health + (self.max_health-autocvar_g_nades_ice_health) * self.revive_progress );
if(!(self.spawnflags & MONSTERFLAG_INVINCIBLE) && self.sprite)
WaypointSprite_UpdateHealth(self.sprite, self.health);
- movelib_beak_simple(stpspeed);
+ movelib_brake_simple(stpspeed);
setanim(self, self.anim_idle, true, false, false);
self.enemy = world;
Unfreeze(self);
self.health = 0;
if(self.event_damage)
- self.event_damage(self, self.frozen_by, 1, DEATH_NADE_ICE_FREEZE, self.origin, '0 0 0');
+ self.event_damage(self, self.frozen_by, 1, DEATH_NADE_ICE_FREEZE.m_id, self.origin, '0 0 0');
}
else if ( self.revive_progress <= 0 )
{
self.last_trace = time + 0.4;
- Damage (self, world, world, 2, DEATH_DROWN, self.origin, '0 0 0');
+ Damage (self, world, world, 2, DEATH_DROWN.m_id, self.origin, '0 0 0');
self.angles = '90 90 0';
if(random() < 0.5)
{
runspeed = walkspeed = 0;
if(time >= self.spawn_time)
setanim(self, self.anim_idle, true, false, false);
- movelib_beak_simple(stpspeed);
+ movelib_brake_simple(stpspeed);
return;
}
runspeed = bound(0, monster_speed_run * MONSTER_SKILLMOD(self), runspeed * 2.5); // limit maxspeed to prevent craziness
walkspeed = bound(0, monster_speed_walk * MONSTER_SKILLMOD(self), walkspeed * 2.5); // limit maxspeed to prevent craziness
- if(time < self.spider_slowness)
- {
- runspeed *= 0.5;
- walkspeed *= 0.5;
- }
-
if(teamplay)
if(autocvar_g_monsters_teams)
if(DIFF_TEAM(self.monster_follow, self))
self.last_enemycheck = time + 1; // check for enemies every second
}
- if(self.state == MONSTER_ATTACK_RANGED && (self.flags & FL_ONGROUND))
+ if(self.state == MONSTER_ATTACK_RANGED && (IS_ONGROUND(self)))
{
self.state = 0;
self.touch = Monster_Touch;
}
- if(self.state && time >= self.attack_finished_single)
+ if(self.state && time >= self.attack_finished_single[0])
self.state = 0; // attack is over
if(self.state != MONSTER_ATTACK_MELEE) // don't move if set
if(vlen(self.origin - self.moveto) > 100)
{
float do_run = (self.enemy || self.monster_moveto);
- if((self.flags & FL_ONGROUND) || ((self.flags & FL_FLY) || (self.flags & FL_SWIM)))
+ if((IS_ONGROUND(self)) || ((self.flags & FL_FLY) || (self.flags & FL_SWIM)))
Monster_CalculateVelocity(self, self.moveto, self.origin, true, ((do_run) ? runspeed : walkspeed));
if(time > self.pain_finished) // TODO: use anim_finished instead!
else if(e.target)
self.target2 = e.target;
- movelib_beak_simple(stpspeed);
+ movelib_brake_simple(stpspeed);
if(time > self.anim_finished)
if(time > self.pain_finished)
if(!self.state)
void Monster_Remove(entity mon)
{
+ .entity weaponentity = weaponentities[0];
if(!mon) { return; }
if(!MUTATOR_CALLHOOK(MonsterRemove, mon))
Send_Effect(EFFECT_ITEM_PICKUP, mon.origin, '0 0 0', 1);
- if(mon.weaponentity) { remove(mon.weaponentity); }
+ if(mon.(weaponentity)) { remove(mon.(weaponentity)); }
if(mon.iceblock) { remove(mon.iceblock); }
WaypointSprite_Kill(mon.sprite);
remove(mon);
return true;
}
-void Monster_Reset()
-{SELFPARAM();
- setorigin(self, self.pos1);
- self.angles = self.pos2;
+void Monster_Reset(entity this)
+{
+ setorigin(this, this.pos1);
+ this.angles = this.pos2;
- Unfreeze(self); // remove any icy remains
+ Unfreeze(this); // remove any icy remains
- self.health = self.max_health;
- self.velocity = '0 0 0';
- self.enemy = world;
- self.goalentity = world;
- self.attack_finished_single = 0;
- self.moveto = self.origin;
+ this.health = this.max_health;
+ this.velocity = '0 0 0';
+ this.enemy = world;
+ this.goalentity = world;
+ this.attack_finished_single[0] = 0;
+ this.moveto = this.origin;
}
void Monster_Dead_Damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
// number of monsters spawned with mobspawn command
totalspawned -= 1;
- self.think = SUB_Remove;
+ self.think = SUB_Remove_self;
self.nextthink = time + 0.1;
self.event_damage = func_null;
}
self.nextthink = time;
self.monster_lifetime = time + 5;
- if(self.frozen)
+ if(STAT(FROZEN, self))
{
Unfreeze(self); // remove any icy remains
self.health = 0; // reset by Unfreeze
self.touch = Monster_Touch; // reset incase monster was pouncing
self.reset = func_null;
self.state = 0;
- self.attack_finished_single = 0;
+ self.attack_finished_single[0] = 0;
self.effects = 0;
if(!((self.flags & FL_FLY) || (self.flags & FL_SWIM)))
self.velocity = '0 0 0';
- CSQCModel_UnlinkEntity();
+ CSQCModel_UnlinkEntity(self);
- MON_ACTION(self.monsterid, MR_DEATH);
+ Monster mon = get_monsterinfo(self.monsterid);
+ mon.mr_death(mon);
if(self.candrop && self.weapon)
W_ThrowNewWeapon(self, self.weapon, 0, self.origin, randomvec() * 150 + '0 0 325');
void Monster_Damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
{SELFPARAM();
- if((self.spawnflags & MONSTERFLAG_INVINCIBLE) && deathtype != DEATH_KILL)
+ if((self.spawnflags & MONSTERFLAG_INVINCIBLE) && deathtype != DEATH_KILL.m_id && !ITEM_DAMAGE_NEEDKILL(deathtype))
return;
- if(self.frozen && deathtype != DEATH_KILL && deathtype != DEATH_NADE_ICE_FREEZE)
+ if(STAT(FROZEN, self) && deathtype != DEATH_KILL.m_id && deathtype != DEATH_NADE_ICE_FREEZE.m_id)
return;
- //if(time < self.pain_finished && deathtype != DEATH_KILL)
+ //if(time < self.pain_finished && deathtype != DEATH_KILL.m_id)
//return;
- if(time < self.spawnshieldtime && deathtype != DEATH_KILL)
+ if(time < self.spawnshieldtime && deathtype != DEATH_KILL.m_id)
return;
- if(deathtype == DEATH_FALL && self.draggedby != world)
+ if(deathtype == DEATH_FALL.m_id && self.draggedby != world)
return;
vector v;
damage_take = take;
frag_attacker = attacker;
frag_deathtype = deathtype;
- MON_ACTION(self.monsterid, MR_PAIN);
+ Monster mon = get_monsterinfo(self.monsterid);
+ mon.mr_pain(mon);
take = damage_take;
if(take)
self.dmg_time = time;
- if(sound_allowed(MSG_BROADCAST, attacker) && deathtype != DEATH_DROWN)
+ if(sound_allowed(MSG_BROADCAST, attacker) && deathtype != DEATH_DROWN.m_id)
spamsound (self, CH_PAIN, SND(BODYIMPACT1), VOL_BASE, ATTEN_NORM); // FIXME: PLACEHOLDER
self.velocity += force * self.damageforcescale;
- if(deathtype != DEATH_DROWN && take)
+ if(deathtype != DEATH_DROWN.m_id && take)
{
Violence_GibSplash_At(hitloc, force, 2, bound(0, take, 200) / 16, self, attacker);
if (take > 50)
if(self.health <= 0)
{
- if(deathtype == DEATH_KILL)
+ if(deathtype == DEATH_KILL.m_id)
self.candrop = false; // killed by mobkill command
// TODO: fix this?
SUB_UseTargets();
self.target2 = self.oldtarget2; // reset to original target on death, incase we respawn
- Monster_Dead(attacker, (self.health <= -100 || deathtype == DEATH_KILL));
+ Monster_Dead(attacker, (self.health <= -100 || deathtype == DEATH_KILL.m_id));
WaypointSprite_Kill(self.sprite);
frag_target = self;
MUTATOR_CALLHOOK(MonsterDies, attacker);
- if(self.health <= -100 || deathtype == DEATH_KILL) // check if we're already gibbed
+ if(self.health <= -100 || deathtype == DEATH_KILL.m_id) // check if we're already gibbed
{
Violence_GibSplash(self, 1, 0.5, attacker);
- self.think = SUB_Remove;
+ self.think = SUB_Remove_self;
self.nextthink = time + 0.1;
}
}
mspeed = 0;
if(time >= self.spawn_time)
setanim(self, self.anim_idle, true, false, false);
- movelib_beak_simple(0.6);
+ movelib_brake_simple(0.6);
return;
}
- float reverse = FALSE;
+ float reverse = false;
vector a, b;
makevectors(self.angles);
if(trace_fraction != 1.0)
{
- reverse = TRUE;
+ reverse = true;
if(trace_ent)
if(IS_PLAYER(trace_ent) && !(trace_ent.items & IT_STRENGTH))
- reverse = FALSE;
+ reverse = false;
}
// TODO: fix this... tracing is broken if the floor is thin
a = b - '0 0 32';
traceline(b, a, MOVE_WORLDONLY, self);
if(trace_fraction == 1.0)
- reverse = TRUE;
+ reverse = true;
} */
if(reverse)
movelib_move_simple_gravity(v_forward, mspeed, 1);
if(time > self.pain_finished)
- if(time > self.attack_finished_single)
+ if(time > self.attack_finished_single[0])
if(vlen(self.velocity) > 10)
setanim(self, self.anim_walk, true, false, false);
else
deadbits = 0;
}
int animbits = deadbits;
- if(self.frozen)
+ if(STAT(FROZEN, self))
animbits |= ANIMSTATE_FROZEN;
if(self.crouch)
animbits |= ANIMSTATE_DUCK; // not that monsters can crouch currently...
animdecide_setstate(self, animbits, false);
- animdecide_setimplicitstate(self, (self.flags & FL_ONGROUND));
+ animdecide_setimplicitstate(self, (IS_ONGROUND(self)));
/* // weapon entities for monsters?
if (self.weaponentity)
if(self.monster_lifetime)
if(time >= self.monster_lifetime)
{
- Damage(self, self, self, self.health + self.max_health, DEATH_KILL, self.origin, self.origin);
+ Damage(self, self, self, self.health + self.max_health, DEATH_KILL.m_id, self.origin, self.origin);
return;
}
- if(MON_ACTION(self.monsterid, MR_THINK))
+ Monster mon = get_monsterinfo(self.monsterid);
+ if(mon.mr_think(mon))
Monster_Move(self.speed2, self.speed, self.stopspeed);
Monster_Anim();
float Monster_Spawn_Setup()
{SELFPARAM();
- MON_ACTION(self.monsterid, MR_SETUP);
+ Monster mon = get_monsterinfo(self.monsterid);
+ mon.mr_setup(mon);
// ensure some basic needs are met
if(!self.health) { self.health = 100; }
if(!autocvar_g_monsters) { Monster_Remove(self); return false; }
- self.mdl = mon.model;
if(Monster_Appear_Check(self, mon_id)) { return true; } // return true so the monster isn't removed
if(!self.monster_skill)
if(!(self.spawnflags & MONSTERFLAG_RESPAWNED)) // don't count re-spawning monsters either
monsters_total += 1;
- _setmodel(self, self.mdl);
+ setmodel(self, mon.m_model);
self.flags = FL_MONSTER;
self.classname = "monster";
self.takedamage = DAMAGE_AIM;
self.deadflag = DEAD_NO;
self.noalign = ((mon.spawnflags & MONSTER_TYPE_FLY) || (mon.spawnflags & MONSTER_TYPE_SWIM));
self.spawn_time = time;
- self.spider_slowness = 0;
self.gravity = 1;
self.monster_moveto = '0 0 0';
self.monster_face = '0 0 0';
self.movetype = MOVETYPE_FLY;
}
- if(mon.spawnflags & MONSTER_SIZE_BROKEN)
if(!(self.spawnflags & MONSTERFLAG_RESPAWNED))
- self.scale *= 1.3;
+ {
+ if(mon.spawnflags & MONSTER_SIZE_BROKEN)
+ self.scale *= 1.3;
+
+ if(mon.spawnflags & MONSTER_SIZE_QUAKE)
+ if(autocvar_g_monsters_quake_resize)
+ self.scale *= 1.3;
+ }
setsize(self, mon.mins * self.scale, mon.maxs * self.scale);