-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #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/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 "../triggers/triggers.qh"
- #include <lib/csqcmodel/sv_model.qh>
- #include <server/round_handler.qh>
-#endif
+#include "sv_monsters.qh"
+
+#include <server/g_subs.qh>
+#include <lib/warpzone/common.qh>
+#include "../constants.qh"
+#include "../teams.qh"
+#include "../util.qh"
+#include "all.qh"
+#include "../physics/movelib.qh"
+#include "../weapons/_mod.qh"
+#include <server/autocvars.qh>
+#include <server/defs.qh>
+#include "../deathtypes/all.qh"
+#include <server/mutators/_mod.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/_mod.qh>
+#include "../triggers/triggers.qh"
+#include <lib/csqcmodel/sv_model.qh>
+#include <server/round_handler.qh>
+#include <server/weapons/_mod.qh>
void monsters_setstatus(entity this)
{
this.stat_monsters_killed = monsters_killed;
}
-void monster_dropitem(entity this)
+void monster_dropitem(entity this, entity attacker)
{
if(!this.candrop || !this.monster_loot)
return;
e.monster_loot = this.monster_loot;
- MUTATOR_CALLHOOK(MonsterDropItem, e);
- e = other;
+ MUTATOR_CALLHOOK(MonsterDropItem, this, e, attacker);
+ e = M_ARGV(1, entity);
if(e && e.monster_loot)
{
e.noalign = true;
- WITH(entity, self, e, e.monster_loot(e));
+ e.monster_loot(e);
e.gravity = 1;
- e.movetype = MOVETYPE_TOSS;
+ set_movetype(e, MOVETYPE_TOSS);
e.reset = SUB_Remove;
setorigin(e, org);
e.velocity = randomvec() * 175 + '0 0 325';
|| (!IS_VEHICLE(targ) && (IS_DEAD(targ) || IS_DEAD(this) || targ.health <= 0 || this.health <= 0))
|| (this.monster_follow == targ || targ.monster_follow == this)
|| (!IS_VEHICLE(targ) && (targ.flags & FL_NOTARGET))
- || (!autocvar_g_monsters_typefrag && targ.BUTTON_CHAT)
+ || (!autocvar_g_monsters_typefrag && PHYS_INPUT_BUTTON_CHAT(targ))
|| (SAME_TEAM(targ, this))
|| (STAT(FROZEN, targ))
|| (targ.alpha != 0 && targ.alpha < 0.5)
+ || (MUTATOR_CALLHOOK(MonsterValidTarget, this, targ))
)
{
// if any of the above checks fail, target is not valid
{
if(MUTATOR_CALLHOOK(MonsterFindTarget)) { return mon.enemy; } // Handled by a mutator
- entity head, closest_target = world;
- head = findradius(mon.origin, mon.target_range);
+ entity closest_target = NULL;
- while(head) // find the closest acceptable target to pass to
+ // find the closest acceptable target to pass to
+ FOREACH_ENTITY_RADIUS(mon.origin, mon.target_range, it.monster_attack,
{
- if(head.monster_attack)
- if(Monster_ValidTarget(mon, head))
+ if(Monster_ValidTarget(mon, it))
{
// if it's a player, use the view origin as reference (stolen from RadiusDamage functions in g_damage.qc)
- vector head_center = CENTER_OR_VIEWOFS(head);
+ vector head_center = CENTER_OR_VIEWOFS(it);
vector ent_center = CENTER_OR_VIEWOFS(mon);
if(closest_target)
{
vector closest_target_center = CENTER_OR_VIEWOFS(closest_target);
if(vlen2(ent_center - head_center) < vlen2(ent_center - closest_target_center))
- { closest_target = head; }
+ { closest_target = it; }
}
- else { closest_target = head; }
+ else { closest_target = it; }
}
-
- head = head.chain;
- }
+ });
return closest_target;
}
}
.void(entity) monster_delayedfunc;
-void Monster_Delay_Action_self();
void Monster_Delay_Action(entity this)
{
if(Monster_ValidTarget(this.owner, this.owner.enemy)) { this.monster_delayedfunc(this.owner); }
if(this.cnt > 1)
{
this.cnt -= 1;
- this.think = Monster_Delay_Action_self;
+ setthink(this, Monster_Delay_Action);
this.nextthink = time + this.count;
}
else
{
- this.think = SUB_Remove_self;
+ setthink(this, SUB_Remove);
this.nextthink = time;
}
}
-void Monster_Delay_Action_self()
-{
- Monster_Delay_Action(self);
-}
-
void Monster_Delay(entity this, int repeat_count, float defer_amnt, void(entity) func)
{
// deferred attacking, checks if monster is still alive and target is still valid before attacking
entity e = spawn();
- e.think = Monster_Delay_Action_self;
+ setthink(e, Monster_Delay_Action);
e.nextthink = time + defer_amnt;
e.count = defer_amnt;
e.owner = this;
{
if(tokenize_console(s) != 3)
{
- LOG_TRACE("Invalid sound info line: ", s, "\n");
+ LOG_TRACE("Invalid sound info line: ", s);
continue;
}
PrecacheGlobalSound(strcat(argv(1), " ", argv(2)));
fh = fopen(f, FILE_READ);
if(fh < 0)
{
- LOG_TRACE("Monster sound file not found: ", f, "\n");
+ LOG_TRACE("Monster sound file not found: ", f);
return false;
}
while((s = fgets(fh)))
if(delaytoo)
if(time < this.msound_delay)
return; // too early
- GlobalSound_string(this, this.(samplefield), chan, VOICETYPE_PLAYERSOUND);
+ GlobalSound_string(this, this.(samplefield), chan, VOL_BASE, VOICETYPE_PLAYERSOUND);
this.msound_delay = time + sound_delay;
}
return true;
}
-bool Monster_Attack_Leap(entity this, vector anm, void() touchfunc, vector vel, float animtime)
+bool Monster_Attack_Leap(entity this, vector anm, void(entity this, entity toucher) touchfunc, vector vel, float animtime)
{
if(!Monster_Attack_Leap_Check(this, vel))
return false;
if(this.flags & FL_MONSTER)
this.state = MONSTER_ATTACK_RANGED;
- this.touch = touchfunc;
+ settouch(this, touchfunc);
this.origin_z += 1;
this.velocity = vel;
UNSET_ONGROUND(this);
void Monster_Attack_Check(entity this, entity targ)
{
- if((this == world || targ == world)
+ if((this == NULL || targ == NULL)
|| (!this.monster_attackfunc)
|| (time < this.attack_finished_single[0])
) { return; }
mon.mr_anim(mon, this);
}
-void Monster_Touch()
-{SELFPARAM();
- if(other == world) { return; }
+void Monster_Touch(entity this, entity toucher)
+{
+ if(toucher == NULL) { return; }
- if(other.monster_attack)
- if(this.enemy != other)
- if(!IS_MONSTER(other))
- if(Monster_ValidTarget(this, other))
- this.enemy = other;
+ if(toucher.monster_attack)
+ if(this.enemy != toucher)
+ if(!IS_MONSTER(toucher))
+ if(Monster_ValidTarget(this, toucher))
+ this.enemy = toucher;
}
void Monster_Miniboss_Check(entity this)
return true;
}
-void Monster_Respawn() { SELFPARAM(); Monster_Spawn(this, this.monsterid); }
+void Monster_Respawn(entity this) { Monster_Spawn(this, this.monsterid); }
+
+.vector pos1, pos2;
void Monster_Dead_Fade(entity this)
{
if(Monster_Respawn_Check(this))
{
this.spawnflags |= MONSTERFLAG_RESPAWNED;
- this.think = Monster_Respawn;
+ setthink(this, Monster_Respawn);
this.nextthink = time + this.respawntime;
this.monster_lifetime = 0;
this.deadflag = DEAD_RESPAWNING;
}
}
-void Monster_Use()
-{SELFPARAM();
- if(Monster_ValidTarget(this, activator)) { this.enemy = activator; }
+void Monster_Use(entity this, entity actor, entity trigger)
+{
+ if(Monster_ValidTarget(this, actor)) { this.enemy = actor; }
}
+.float pass_distance;
vector Monster_Move_Target(entity this, entity targ)
{
// enemy is always preferred target
targ_origin = WarpZone_RefSys_TransformOrigin(this.enemy, this, targ_origin); // origin of target as seen by the monster (us)
WarpZone_TraceLine(this.origin, targ_origin, MOVE_NOMONSTERS, this);
- if((this.enemy == world)
+ if((this.enemy == NULL)
|| (IS_DEAD(this.enemy) || this.enemy.health < 1)
|| (STAT(FROZEN, this.enemy))
|| (this.enemy.flags & FL_NOTARGET)
|| (vdist(this.origin - targ_origin, >, this.target_range))
|| ((trace_fraction < 1) && (trace_ent != this.enemy)))
{
- this.enemy = world;
+ this.enemy = NULL;
this.pass_distance = 0;
}
if(this.enemy)
{
- /*WarpZone_TrailParticles(world, particleeffectnum(EFFECT_RED_PASS), this.origin, targ_origin);
+ /*WarpZone_TrailParticles(NULL, particleeffectnum(EFFECT_RED_PASS), this.origin, targ_origin);
print("Trace origin: ", vtos(targ_origin), "\n");
print("Target origin: ", vtos(this.enemy.origin), "\n");
print("My origin: ", vtos(this.origin), "\n"); */
//this.angles = vectoangles(this.velocity);
}
+.entity draggedby;
+.entity target2;
+
void Monster_Move(entity this, float runspeed, float walkspeed, float stpspeed)
{
- if(this.target2) { this.goalentity = find(world, targetname, this.target2); }
+ if(this.target2) { this.goalentity = find(NULL, targetname, this.target2); }
entity targ;
movelib_brake_simple(this, stpspeed);
setanim(this, this.anim_idle, true, false, false);
- this.enemy = world;
+ this.enemy = NULL;
this.nextthink = time + this.ticrate;
if(this.revive_progress >= 1)
movelib_brake_simple(this, stpspeed);
setanim(this, this.anim_idle, true, false, false);
- this.enemy = world;
+ this.enemy = NULL;
this.nextthink = time + this.ticrate;
if(this.health < 1)
{
this.last_trace = time + 0.4;
- Damage (this, world, world, 2, DEATH_DROWN.m_id, this.origin, '0 0 0');
+ Damage (this, NULL, NULL, 2, DEATH_DROWN.m_id, this.origin, '0 0 0');
this.angles = '90 90 0';
if(random() < 0.5)
{
}
- this.movetype = MOVETYPE_BOUNCE;
+ set_movetype(this, MOVETYPE_BOUNCE);
//this.velocity_z = -200;
return;
}
- else if(this.movetype == MOVETYPE_BOUNCE)
+ else if(this.move_movetype == MOVETYPE_BOUNCE)
{
this.angles_x = 0;
- this.movetype = MOVETYPE_WALK;
+ set_movetype(this, MOVETYPE_WALK);
}
}
if (MUTATOR_CALLHOOK(MonsterMove, this, runspeed, walkspeed, targ)
|| gameover
- || this.draggedby != world
+ || this.draggedby != NULL
|| (round_handler_IsActive() && !round_handler_IsRoundStarted())
|| time < game_starttime
|| (autocvar_g_campaign && !campaign_bots_may_start)
return;
}
- targ = monster_target;
- runspeed = bound(0, monster_speed_run * MONSTER_SKILLMOD(this), runspeed * 2.5); // limit maxspeed to prevent craziness
- walkspeed = bound(0, monster_speed_walk * MONSTER_SKILLMOD(this), walkspeed * 2.5); // limit maxspeed to prevent craziness
+ targ = M_ARGV(3, entity);
+ runspeed = bound(0, M_ARGV(1, float) * MONSTER_SKILLMOD(this), runspeed * 2.5); // limit maxspeed to prevent craziness
+ walkspeed = bound(0, M_ARGV(2, float) * MONSTER_SKILLMOD(this), walkspeed * 2.5); // limit maxspeed to prevent craziness
if(teamplay)
if(autocvar_g_monsters_teams)
if(DIFF_TEAM(this.monster_follow, this))
- this.monster_follow = world;
+ this.monster_follow = NULL;
if(time >= this.last_enemycheck)
{
if(this.state == MONSTER_ATTACK_RANGED && IS_ONGROUND(this))
{
this.state = 0;
- this.touch = Monster_Touch;
+ settouch(this, Monster_Touch);
}
if(this.state && time >= this.attack_finished_single[0])
}
else
{
- entity e = find(world, targetname, this.target2);
+ entity e = find(NULL, targetname, this.target2);
if(e.target2)
this.target2 = e.target2;
else if(e.target)
void Monster_Remove(entity this)
{
- .entity weaponentity = weaponentities[0];
+ if(IS_CLIENT(this))
+ return; // don't remove it?
+
if(!this) { return; }
if(!MUTATOR_CALLHOOK(MonsterRemove, this))
Send_Effect(EFFECT_ITEM_PICKUP, this.origin, '0 0 0', 1);
- if(this.(weaponentity)) { remove(this.(weaponentity)); }
- if(this.iceblock) { remove(this.iceblock); }
+ for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ {
+ .entity weaponentity = weaponentities[slot];
+ if(this.(weaponentity))
+ delete(this.(weaponentity));
+ }
+ if(this.iceblock) { delete(this.iceblock); }
WaypointSprite_Kill(this.sprite);
- remove(this);
+ delete(this);
}
-void Monster_Dead_Think()
-{SELFPARAM();
+void Monster_Dead_Think(entity this)
+{
this.nextthink = time + this.ticrate;
if(this.monster_lifetime != 0)
}
}
-void Monster_Appear()
-{SELFPARAM();
- this.enemy = activator;
+void Monster_Appear(entity this, entity actor, entity trigger)
+{
+ this.enemy = actor;
this.spawnflags &= ~MONSTERFLAG_APPEAR; // otherwise, we get an endless loop
Monster_Spawn(this, this.monsterid);
}
if(!(this.spawnflags & MONSTERFLAG_APPEAR))
return false;
- this.think = func_null;
+ setthink(this, func_null);
this.monsterid = monster_id; // set so this monster is properly registered (otherwise, normal initialization is used)
this.nextthink = 0;
this.use = Monster_Appear;
this.health = this.max_health;
this.velocity = '0 0 0';
- this.enemy = world;
- this.goalentity = world;
+ this.enemy = NULL;
+ this.goalentity = NULL;
this.attack_finished_single[0] = 0;
this.moveto = this.origin;
}
// number of monsters spawned with mobspawn command
totalspawned -= 1;
- this.think = SUB_Remove_self;
+ setthink(this, SUB_Remove);
this.nextthink = time + 0.1;
this.event_damage = func_null;
}
void Monster_Dead(entity this, entity attacker, float gibbed)
{
- this.think = Monster_Dead_Think;
+ setthink(this, Monster_Dead_Think);
this.nextthink = time;
this.monster_lifetime = time + 5;
this.health = 0; // reset by Unfreeze
}
- monster_dropitem(this);
+ monster_dropitem(this, attacker);
Monster_Sound(this, monstersound_death, 0, false, CH_VOICE);
this.solid = SOLID_CORPSE;
this.takedamage = DAMAGE_AIM;
this.deadflag = DEAD_DEAD;
- this.enemy = world;
- this.movetype = MOVETYPE_TOSS;
+ this.enemy = NULL;
+ set_movetype(this, MOVETYPE_TOSS);
this.moveto = this.origin;
- this.touch = Monster_Touch; // reset incase monster was pouncing
+ settouch(this, Monster_Touch); // reset incase monster was pouncing
this.reset = func_null;
this.state = 0;
this.attack_finished_single[0] = 0;
if(time < this.spawnshieldtime && deathtype != DEATH_KILL.m_id)
return;
- if(deathtype == DEATH_FALL.m_id && this.draggedby != world)
+ if(deathtype == DEATH_FALL.m_id && this.draggedby != NULL)
return;
vector v;
take = v_x;
save = v_y;
- damage_take = take;
- frag_attacker = attacker;
- frag_deathtype = deathtype;
Monster mon = get_monsterinfo(this.monsterid);
- mon.mr_pain(mon, this);
- take = damage_take;
+ take = mon.mr_pain(mon, this, take, attacker, deathtype);
if(take)
{
this.candrop = false; // killed by mobkill command
// TODO: fix this?
- activator = attacker;
- other = this.enemy;
- WITH(entity, self, this, SUB_UseTargets());
+ SUB_UseTargets(this, attacker, this.enemy);
this.target2 = this.oldtarget2; // reset to original target on death, incase we respawn
Monster_Dead(this, attacker, (this.health <= -100 || deathtype == DEATH_KILL.m_id));
WaypointSprite_Kill(this.sprite);
- MUTATOR_CALLHOOK(MonsterDies, this, attacker);
+ MUTATOR_CALLHOOK(MonsterDies, this, attacker, deathtype);
if(this.health <= -100 || deathtype == DEATH_KILL.m_id) // check if we're already gibbed
{
Violence_GibSplash(this, 1, 0.5, attacker);
- this.think = SUB_Remove_self;
+ setthink(this, SUB_Remove);
this.nextthink = time + 0.1;
}
}
// don't check for enemies, just keep walking in a straight line
void Monster_Move_2D(entity this, float mspeed, bool allow_jumpoff)
{
- if(gameover || (round_handler_IsActive() && !round_handler_IsRoundStarted()) || this.draggedby != world || time < game_starttime || (autocvar_g_campaign && !campaign_bots_may_start) || time < this.spawn_time)
+ if(gameover || (round_handler_IsActive() && !round_handler_IsRoundStarted()) || this.draggedby != NULL || time < game_starttime || (autocvar_g_campaign && !campaign_bots_may_start) || time < this.spawn_time)
{
mspeed = 0;
if(time >= this.spawn_time)
*/
}
-void Monster_Think()
-{SELFPARAM();
- this.think = Monster_Think;
+void Monster_Think(entity this)
+{
+ setthink(this, Monster_Think);
this.nextthink = this.ticrate;
if(this.monster_lifetime)
if(autocvar_g_monsters_healthbars)
{
- entity wp = WaypointSprite_Spawn(WP_Monster, 0, 1024, this, '0 0 1' * (this.maxs.z + 15), world, this.team, this, sprite, true, RADARICON_DANGER);
+ entity wp = WaypointSprite_Spawn(WP_Monster, 0, 1024, this, '0 0 1' * (this.maxs.z + 15), NULL, this.team, this, sprite, true, RADARICON_DANGER);
wp.wp_extra = this.monsterid;
wp.colormod = ((this.team) ? Team_ColorRGB(this.team) : '1 0 0');
if(!(this.spawnflags & MONSTERFLAG_INVINCIBLE))
}
}
- this.think = Monster_Think;
+ setthink(this, Monster_Think);
this.nextthink = time + this.ticrate;
if(MUTATOR_CALLHOOK(MonsterSpawn, this))
if(!autocvar_g_monsters) { Monster_Remove(this); return false; }
+ if(!(this.spawnflags & MONSTERFLAG_RESPAWNED))
+ IL_PUSH(g_monsters, this);
+
if(Monster_Appear_Check(this, mon_id)) { return true; } // return true so the monster isn't removed
if(!this.monster_skill)
this.damagedbycontents = true;
this.monsterid = mon_id;
this.event_damage = Monster_Damage;
- this.touch = Monster_Touch;
+ settouch(this, Monster_Touch);
this.use = Monster_Use;
this.solid = SOLID_BBOX;
- this.movetype = MOVETYPE_WALK;
+ set_movetype(this, MOVETYPE_WALK);
this.spawnshieldtime = time + autocvar_g_monsters_spawnshieldtime;
- this.enemy = world;
+ this.enemy = NULL;
this.velocity = '0 0 0';
this.moveto = this.origin;
this.pos1 = this.origin;
if(mon.spawnflags & MONSTER_TYPE_FLY)
{
this.flags |= FL_FLY;
- this.movetype = MOVETYPE_FLY;
+ set_movetype(this, MOVETYPE_FLY);
}
if(!(this.spawnflags & MONSTERFLAG_RESPAWNED))