Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
sv_monsters.qc File Reference
Include dependency graph for sv_monsters.qc:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Macros

#define _MSOUND(m)
#define _MSOUND(m)

Functions

string get_monster_model_datafilename (string m, float sk, string fil)
void Monster_Anim (entity this)
void Monster_Appear (entity this, entity actor, entity trigger)
bool Monster_Appear_Check (entity this, Monster monster_id)
void Monster_Attack_Check (entity this, entity targ,.entity weaponentity)
bool Monster_Attack_Leap (entity this, vector anm, void(entity this, entity toucher) touchfunc, vector vel, float animtime)
bool Monster_Attack_Leap_Check (entity this, vector vel)
bool Monster_Attack_Melee (entity this, entity targ, float damg, vector anim, float er, float animtime, int deathtype, bool dostop)
void monster_changeteam (entity this, int newteam)
int Monster_CheckDanger (entity this, vector dst_ahead)
void Monster_Damage (entity this, entity inflictor, entity attacker, float damage, int deathtype,.entity weaponentity, vector hitloc, vector force)
void Monster_Dead (entity this, entity attacker, float gibbed)
void Monster_Dead_Damage (entity this, entity inflictor, entity attacker, float damage, int deathtype,.entity weaponentity, vector hitloc, vector force)
void Monster_Dead_Fade (entity this)
void Monster_Dead_Think (entity this)
void Monster_Delay (entity this, int repeat_count, float defer_amnt, void(entity) func)
void Monster_Delay_Action (entity this)
void monster_dropitem (entity this, entity attacker)
void Monster_Enemy_Check (entity this)
bool monster_facing (entity this, entity targ)
entity Monster_FindTarget (entity this)
bool Monster_Heal (entity targ, entity inflictor, float amount, float limit)
void monster_makevectors (entity this, entity targ)
void Monster_Miniboss_Setup (entity this)
void Monster_Move (entity this, float runspeed, float walkspeed, float stpspeed)
void Monster_Move_2D (entity this, float mspeed, bool allow_jumpoff)
vector Monster_Move_Target (entity this, entity targ)
void Monster_Remove (entity this)
void Monster_Reset (entity this)
void Monster_Respawn (entity this)
bool Monster_Respawn_Check (entity this)
void monster_setupcolors (entity this)
void Monster_Sound (entity this,.string samplefield, float sound_delay, bool delaytoo, float chan)
void Monster_Sound_Precache (string f)
string Monster_Sound_SampleField (string type)
void Monster_Sounds_Clear (entity this)
bool Monster_Sounds_Load (entity this, string f, int first)
void Monster_Sounds_Precache (entity this)
void Monster_Sounds_Update (entity this)
bool Monster_Spawn (entity this, bool check_appear, Monster mon)
 Setup the basic required properties for a monster.
bool Monster_Spawn_Setup (entity this)
void Monster_Think (entity this)
void Monster_Touch (entity this, entity toucher)
void Monster_UpdateModel (entity this)
void Monster_Use (entity this, entity actor, entity trigger)
bool Monster_ValidTarget (entity this, entity targ, bool skipfacing)
vector Monster_WanderTarget (entity this, vector targetorigin)
 Returns an origin that's near targetorigin and visible to this monster.
void monsters_setstatus (entity this)
 void (entity) monster_delayedfunc

Variables

entity draggedby
vector pos1
vector pos2
int skin_for_monstersound

Macro Definition Documentation

◆ _MSOUND [1/2]

#define _MSOUND ( m)
Value:
strfree(this.monstersound_##m);
#define strfree(this)
Definition string.qh:59

◆ _MSOUND [2/2]

#define _MSOUND ( m)
Value:
case #m: \
return monstersound_##m;

Function Documentation

◆ get_monster_model_datafilename()

string get_monster_model_datafilename ( string m,
float sk,
string fil )

Definition at line 261 of file sv_monsters.qc.

262{
263 if (m)
264 m = strcat(m, "_");
265 else
266 m = "models/monsters/*_";
267 if (sk >= 0)
268 m = strcat(m, ftos(sk));
269 else
270 m = strcat(m, "*");
271 return strcat(m, ".", fil);
272}
string ftos(float f)
strcat(_("^F4Countdown stopped!"), "\n^BG", _("Teams are too unbalanced."))

References ftos(), and strcat().

Referenced by Monster_Sounds_Update().

◆ Monster_Anim()

void Monster_Anim ( entity this)

Definition at line 1212 of file sv_monsters.qc.

1213{
1214 int deadbits = (this.anim_state & (ANIMSTATE_DEAD1 | ANIMSTATE_DEAD2));
1215 if (IS_DEAD(this))
1216 {
1217 if (!deadbits)
1218 deadbits = (random() < 0.5) // Decide on which death animation to use.
1221 }
1222 else
1223 deadbits = 0; // Clear a previous death animation.
1224
1225 int animbits = deadbits;
1226 if (StatusEffects_active(STATUSEFFECT_Frozen, this))
1227 animbits |= ANIMSTATE_FROZEN;
1228 if (IS_DUCKED(this))
1229 animbits |= ANIMSTATE_DUCK; // not that monsters can crouch currently...
1230 animdecide_setstate(this, animbits, false);
1232
1233 /* // weapon entities for monsters?
1234 if (this.weaponentity)
1235 {
1236 updateanim(this.weaponentity);
1237 if (!this.weaponentity.animstate_override)
1238 setanim(this.weaponentity, this.weaponentity.anim_idle, true, false, false);
1239 }
1240 */
1241}
void animdecide_setimplicitstate(entity e, float onground)
void animdecide_setstate(entity e, int newstate, float restart)
const int ANIMSTATE_FROZEN
const int ANIMSTATE_DEAD1
int anim_state
const int ANIMSTATE_DEAD2
const int ANIMSTATE_DUCK
#define IS_DEAD(s)
Definition player.qh:244
#define IS_DUCKED(s)
Definition player.qh:212
float random(void)
#define IS_ONGROUND(s)
Definition movetypes.qh:16
bool StatusEffects_active(StatusEffect this, entity actor)

References anim_state, animdecide_setimplicitstate(), animdecide_setstate(), ANIMSTATE_DEAD1, ANIMSTATE_DEAD2, ANIMSTATE_DUCK, ANIMSTATE_FROZEN, entity(), IS_DEAD, IS_DUCKED, IS_ONGROUND, random(), and StatusEffects_active().

Referenced by Monster_Think().

◆ Monster_Appear()

void Monster_Appear ( entity this,
entity actor,
entity trigger )

Definition at line 979 of file sv_monsters.qc.

980{
981 this.enemy = actor;
982 Monster_Spawn(this, false, this.monsterdef);
983}
entity monsterdef
Definition monster.qh:21
entity enemy
Definition sv_ctf.qh:153
bool Monster_Spawn(entity this, bool check_appear, Monster mon)
Setup the basic required properties for a monster.

References enemy, entity(), Monster_Spawn(), and monsterdef.

Referenced by Monster_Appear_Check().

◆ Monster_Appear_Check()

bool Monster_Appear_Check ( entity this,
Monster monster_id )

Definition at line 985 of file sv_monsters.qc.

986{
987 if (!(this.spawnflags & MONSTERFLAG_APPEAR))
988 return false;
989
990 setthink(this, func_null);
991 this.monsterdef = monster_id; // set so this monster is properly registered (otherwise, normal initialization is used)
992 this.nextthink = 0;
993 this.use = Monster_Appear;
994 this.flags = FL_MONSTER; // set so this monster can get butchered
995
996 return true;
997}
int spawnflags
Definition ammo.qh:15
const int FL_MONSTER
Definition constants.qh:74
float flags
float nextthink
#define use
var void func_null()
#define setthink(e, f)
void Monster_Appear(entity this, entity actor, entity trigger)
const int MONSTERFLAG_APPEAR
delay monster spawn until triggered

References entity(), FL_MONSTER, flags, func_null(), Monster_Appear(), monsterdef, MONSTERFLAG_APPEAR, nextthink, setthink, spawnflags, and use.

Referenced by Monster_Spawn().

◆ Monster_Attack_Check()

void Monster_Attack_Check ( entity this,
entity targ,
.entity weaponentity )

Definition at line 452 of file sv_monsters.qc.

453{
454 int slot = weaponslot(weaponentity);
455
456 if (!this || !targ
457 || !this.monster_attackfunc
458 || game_stopped
459 || time < this.attack_finished_single[slot]
461 return;
462
463 if (vdist(targ.origin - this.origin, <=, this.attack_range))
464 {
465 monster_makevectors(this, targ);
466 int attack_success = this.monster_attackfunc(MONSTER_ATTACK_MELEE, this, targ, weaponentity);
467 if (attack_success == 1)
468 Monster_Sound(this, monstersound_melee, 0, false, CH_VOICE);
469 else if (attack_success > 0)
470 return;
471 }
472
473 if (vdist(targ.origin - this.origin, >, this.attack_range))
474 {
475 monster_makevectors(this, targ);
476 int attack_success = this.monster_attackfunc(MONSTER_ATTACK_RANGED, this, targ, weaponentity);
477 if (attack_success == 1)
478 Monster_Sound(this, monstersound_melee, 0, false, CH_VOICE);
479 else if (attack_success > 0)
480 return;
481 }
482}
float game_stopped
Definition stats.qh:81
float time
const int CH_VOICE
Definition sound.qh:10
void Monster_Sound(entity this,.string samplefield, float sound_delay, bool delaytoo, float chan)
void monster_makevectors(entity this, entity targ)
bool monster_facing(entity this, entity targ)
const int MONSTERFLAG_INFRONT
only check for enemies infront of us, for monsters
const int MONSTER_ATTACK_MELEE
bool autocvar_g_monsters_target_infront
const int MONSTER_ATTACK_RANGED
#define vdist(v, cmp, f)
Vector distance comparison, avoids sqrt()
Definition vector.qh:8
int weaponslot(.entity weaponentity)
Definition weapon.qh:19
float attack_finished_single[MAX_WEAPONSLOTS]

References attack_finished_single, autocvar_g_monsters_target_infront, CH_VOICE, entity(), game_stopped, MONSTER_ATTACK_MELEE, MONSTER_ATTACK_RANGED, monster_facing(), monster_makevectors(), Monster_Sound(), MONSTERFLAG_INFRONT, spawnflags, time, vdist, and weaponslot().

Referenced by Monster_Think().

◆ Monster_Attack_Leap()

bool Monster_Attack_Leap ( entity this,
vector anm,
void(entity this, entity toucher) touchfunc,
vector vel,
float animtime )

Definition at line 430 of file sv_monsters.qc.

431{
432 if (!Monster_Attack_Leap_Check(this, vel))
433 return false;
434
435 setanim(this, anm, false, true, false);
436
437 if (this.animstate_endtime > time && IS_MONSTER(this))
439 else
440 this.attack_finished_single[0] = this.anim_finished = time + animtime;
441
442 if (IS_MONSTER(this))
444 settouch(this, touchfunc);
445 ++this.origin_z;
446 this.velocity = vel;
447 UNSET_ONGROUND(this);
448
449 return true;
450}
float animstate_endtime
Definition anim.qh:38
#define setanim(...)
Definition anim.qh:45
vector velocity
int state
#define UNSET_ONGROUND(s)
Definition movetypes.qh:18
#define settouch(e, f)
Definition self.qh:73
bool Monster_Attack_Leap_Check(entity this, vector vel)
float anim_finished
will be phased out when we have proper animations system
#define IS_MONSTER(v)
Definition utils.qh:23

References anim_finished, animstate_endtime, attack_finished_single, entity(), IS_MONSTER, Monster_Attack_Leap_Check(), MONSTER_ATTACK_RANGED, setanim, settouch, state, time, toucher, UNSET_ONGROUND, vector, and velocity.

Referenced by M_Zombie_Attack().

◆ Monster_Attack_Leap_Check()

bool Monster_Attack_Leap_Check ( entity this,
vector vel )

Definition at line 414 of file sv_monsters.qc.

415{
416 if ((this.state && IS_MONSTER(this)) // already attacking
417 || !IS_ONGROUND(this) // not on the ground
418 || GetResource(this, RES_HEALTH) <= 0 || IS_DEAD(this) // called when dead?
419 || time < this.attack_finished_single[0]) // still attacking
420 return false;
421
422 vector old = this.velocity;
423 this.velocity = vel;
424 tracetoss(this, this);
425 this.velocity = old;
426
427 return trace_ent == this.enemy;
428}
float GetResource(entity e, Resource res_type)
Returns the current amount of resource the given entity has.
entity trace_ent
vector
Definition self.qh:92

References attack_finished_single, enemy, entity(), GetResource(), IS_DEAD, IS_MONSTER, IS_ONGROUND, state, time, trace_ent, vector, and velocity.

Referenced by Monster_Attack_Leap().

◆ Monster_Attack_Melee()

bool Monster_Attack_Melee ( entity this,
entity targ,
float damg,
vector anim,
float er,
float animtime,
int deathtype,
bool dostop )

Definition at line 388 of file sv_monsters.qc.

389{
390 if (dostop && IS_MONSTER(this))
392
393 setanim(this, anim, false, true, false);
394
395 if (this.animstate_endtime > time && IS_MONSTER(this))
397 else
398 this.attack_finished_single[0] = this.anim_finished = time + animtime;
399
400 traceline(this.origin + this.view_ofs, this.origin + v_forward * er, 0, this);
401
402 if (trace_ent.takedamage)
403 Damage(trace_ent, this, this.realowner,
404 damg * MONSTER_SKILLMOD(this),
405 deathtype,
406 DMG_NOWEP,
407 trace_ent.origin,
408 normalize(trace_ent.origin - this.origin)
409 );
410
411 return true;
412}
vector v_forward
vector origin
void Damage(entity targ, entity inflictor, entity attacker, float damage, int deathtype,.entity weaponentity, vector hitloc, vector force)
Definition damage.qc:493
#define DMG_NOWEP
Definition damage.qh:104
entity anim
Definition menu.qh:25
vector normalize(vector v)
vector view_ofs
Definition progsdefs.qc:151
#define MONSTER_SKILLMOD(mon)
entity realowner

References anim, anim_finished, animstate_endtime, attack_finished_single, Damage(), DMG_NOWEP, entity(), IS_MONSTER, MONSTER_ATTACK_MELEE, MONSTER_SKILLMOD, normalize(), origin, realowner, setanim, state, time, trace_ent, v_forward, vector, and view_ofs.

Referenced by M_Golem_Attack_Swing(), and M_Zombie_Attack().

◆ monster_changeteam()

void monster_changeteam ( entity this,
int newteam )

Definition at line 200 of file sv_monsters.qc.

201{
202 if (!teamplay)
203 return;
204
205 this.team = newteam;
206 if (!this.monster_attack)
208 this.monster_attack = true; // new team, activate attacking
210
211 if (this.sprite)
212 {
213 WaypointSprite_UpdateTeamRadar(this.sprite, RADARICON_DANGER, ((newteam) ? Team_ColorRGB(newteam) : '1 0 0'));
214
215 this.sprite.team = newteam;
216 this.sprite.SendFlags |= 1;
217 }
218}
int team
Definition main.qh:188
ERASEABLE entity IL_PUSH(IntrusiveList this, entity it)
Push to tail.
entity sprite
Definition sv_assault.qc:11
void monster_setupcolors(entity this)
bool monster_attack
indicates whether an entity can be attacked by monsters
IntrusiveList g_monster_targets
vector Team_ColorRGB(int teamid)
Definition teams.qh:76
bool teamplay
Definition teams.qh:59
void WaypointSprite_UpdateTeamRadar(entity e, entity icon, vector col)

References entity(), g_monster_targets, IL_PUSH(), monster_attack, monster_setupcolors(), sprite, team, Team_ColorRGB(), teamplay, and WaypointSprite_UpdateTeamRadar().

◆ Monster_CheckDanger()

int Monster_CheckDanger ( entity this,
vector dst_ahead )

Definition at line 711 of file sv_monsters.qc.

712{
713 float s;
714
715 if (this.flags & (FL_FLY | FL_SWIM))
716 {
717 // Look ahead
718 traceline(this.origin + this.view_ofs, dst_ahead, true, NULL);
719
720 // Only care about the skybox if it's below
721 // bones_was_here: does this even matter when flying/swimming?
722 if (trace_endpos.z < this.origin.z + this.mins.z
724 return 1;
725
726 s = pointcontents(trace_endpos + '0 0 1');
727 if (s != CONTENT_SOLID)
728 {
729 if (s == CONTENT_LAVA
730 || s == CONTENT_SLIME)
731 return 3;
732
733 if (tracebox_hits_trigger_hurt(dst_ahead, this.mins, this.maxs, trace_endpos))
734 {
735 // the traceline check isn't enough but is good as optimization,
736 // when not true (most of the time) this tracebox call is avoided
737 tracebox(this.origin + this.view_ofs, this.mins, this.maxs, dst_ahead, true, this);
738 if (tracebox_hits_trigger_hurt(dst_ahead, this.mins, this.maxs, trace_endpos))
739 return 4;
740 }
741 }
742 }
743 else
744 {
745 vector dst_down = dst_ahead - '0 0 3000';
746
747 // Look downwards
748 traceline(dst_ahead, dst_down, true, NULL);
749 //te_lightning2(NULL, this.origin + this.view_ofs, dst_ahead); // Draw "ahead" look
750 //te_lightning2(NULL, dst_ahead, trace_endpos); // Draw "downwards" look
751 if (trace_endpos.z < this.origin.z + this.mins.z)
752 {
754 return 1;
755
756 // If following an enemy ignore probably-non-fatal falls,
757 // if wandering only ignore small falls.
758 if (trace_endpos.z < (this.origin.z + this.mins.z) - (this.enemy ? 1024 : 100))
759 return 2;
760
761 s = pointcontents(trace_endpos + '0 0 1');
762 if (s != CONTENT_SOLID)
763 {
764 if (s == CONTENT_LAVA
765 || s == CONTENT_SLIME)
766 return 3;
767
768 if (tracebox_hits_trigger_hurt(dst_ahead, this.mins, this.maxs, trace_endpos))
769 {
770 // the traceline check isn't enough but is good as optimization,
771 // when not true (most of the time) this tracebox call is avoided
772 tracebox(dst_ahead, this.mins, this.maxs, dst_down, true, this);
773 if (tracebox_hits_trigger_hurt(dst_ahead, this.mins, this.maxs, trace_endpos))
774 return 4;
775 }
776 }
777 }
778 }
779
780 return 0;
781}
const int FL_SWIM
Definition constants.qh:71
const int FL_FLY
Definition constants.qh:70
float Q3SURFACEFLAG_SKY
const float CONTENT_SOLID
vector mins
vector trace_endpos
vector maxs
float trace_dphitq3surfaceflags
const float CONTENT_LAVA
const float CONTENT_SLIME
bool tracebox_hits_trigger_hurt(vector start, vector e_min, vector e_max, vector end)
Definition hurt.qc:78
#define NULL
Definition post.qh:14

References CONTENT_LAVA, CONTENT_SLIME, CONTENT_SOLID, entity(), FL_FLY, FL_SWIM, flags, maxs, mins, NULL, origin, Q3SURFACEFLAG_SKY, trace_dphitq3surfaceflags, trace_endpos, tracebox_hits_trigger_hurt(), vector, and view_ofs.

Referenced by Monster_Move().

◆ Monster_Damage()

void Monster_Damage ( entity this,
entity inflictor,
entity attacker,
float damage,
int deathtype,
.entity weaponentity,
vector hitloc,
vector force )

Definition at line 1083 of file sv_monsters.qc.

1084{
1085 if (((this.spawnflags & MONSTERFLAG_INVINCIBLE) && deathtype != DEATH_KILL.m_id && !ITEM_DAMAGE_NEEDKILL(deathtype))
1086 //|| (time < this.pain_finished && deathtype != DEATH_KILL.m_id)
1087 || (StatusEffects_active(STATUSEFFECT_SpawnShield, this) && deathtype != DEATH_KILL.m_id)
1088 || (deathtype == DEATH_FALL.m_id && this.draggedby != NULL))
1089 return;
1090
1091 vector v = healtharmor_applydamage(100, GetResource(this, RES_ARMOR) / 100, deathtype, damage);
1092 float take = v.x;
1093 //float save = v.y;
1094
1095 Monster mon = this.monsterdef;
1096 take = mon.mr_pain(mon, this, take, attacker, deathtype);
1097
1098 if (take)
1099 {
1100 TakeResource(this, RES_HEALTH, take);
1101 Monster_Sound(this, monstersound_pain, 1.2, true, CH_PAIN);
1102 }
1103
1104 if (this.sprite)
1105 WaypointSprite_UpdateHealth(this.sprite, GetResource(this, RES_HEALTH));
1106
1107 this.dmg_time = time;
1108
1109 if (deathtype != DEATH_DROWN.m_id && deathtype != DEATH_FIRE.m_id && sound_allowed(MSG_BROADCAST, attacker))
1110 spamsound(this, CH_PAIN, SND_BODYIMPACT1, VOL_BASE, ATTEN_NORM); // FIXME: PLACEHOLDER
1111
1112 this.velocity += force * this.damageforcescale;
1113
1114 if (deathtype != DEATH_DROWN.m_id && take)
1115 {
1116 Violence_GibSplash_At(hitloc, force, 2, bound(0, take, 200) / 16, this, attacker);
1117 if (take > 50)
1118 Violence_GibSplash_At(hitloc, force * -0.1, 3, 1, this, attacker);
1119 if (take > 100)
1120 Violence_GibSplash_At(hitloc, force * -0.2, 3, 1, this, attacker);
1121 }
1122
1123 if (GetResource(this, RES_HEALTH) <= 0)
1124 {
1125 if (deathtype == DEATH_KILL.m_id)
1126 this.candrop = false; // killed by mobkill command
1127
1128 // TODO: fix this?
1129 SUB_UseTargets(this, attacker, this.enemy);
1130 this.target2 = this.oldtarget2; // reset to original target on death, incase we respawn
1131
1132 Monster_Dead(this, attacker, (GetResource(this, RES_HEALTH) <= -100 || deathtype == DEATH_KILL.m_id));
1133
1135
1136 MUTATOR_CALLHOOK(MonsterDies, this, attacker, deathtype);
1137
1138 if (GetResource(this, RES_HEALTH) <= -100 || deathtype == DEATH_KILL.m_id) // check if we're already gibbed
1139 {
1140 Violence_GibSplash(this, 1, 0.5, attacker);
1141
1142 setthink(this, SUB_Remove);
1143 this.nextthink = time + 0.1;
1144 }
1145 }
1146}
#define MUTATOR_CALLHOOK(id,...)
Definition base.qh:143
void TakeResource(entity receiver, Resource res_type, float amount)
Takes an entity some resource.
virtual void mr_pain()
(SERVER) called when monster is damaged
Definition monster.qh:82
vector healtharmor_applydamage(float a, float armorblock, int deathtype, float damage)
Definition util.qc:1413
float damageforcescale
void SUB_Remove(entity this)
Remove entity.
Definition defer.qh:13
RES_ARMOR
Definition ent_cs.qc:130
void Violence_GibSplash(entity source, float type, float amount, entity attacker)
Definition gibs.qc:53
void Violence_GibSplash_At(vector org, vector dir, float type, float amount, entity gibowner, entity attacker)
Definition gibs.qc:23
void SUB_UseTargets(entity this, entity actor, entity trigger)
Definition triggers.qc:344
float bound(float min, float value, float max)
float MSG_BROADCAST
Definition menudefs.qc:55
#define ITEM_DAMAGE_NEEDKILL(dt)
Definition items.qh:123
const int CH_PAIN
Definition sound.qh:18
const float VOL_BASE
Definition sound.qh:36
const float ATTEN_NORM
Definition sound.qh:30
float spamsound(entity e, int chan, Sound samp, float vol, float _atten)
use this one if you might be causing spam (e.g.
Definition all.qc:124
bool sound_allowed(int to, entity e)
Definition all.qc:9
void Monster_Dead(entity this, entity attacker, float gibbed)
bool candrop
toggle to allow disabling monster item drops
const int MONSTERFLAG_INVINCIBLE
monster doesn't take damage (may be used for map objects & temporary monsters)
string oldtarget2
a copy of the original follow target string for monsters
string target2
float dmg_time
void WaypointSprite_Kill(entity wp)
void WaypointSprite_UpdateHealth(entity e, float f)

References ATTEN_NORM, bound(), candrop, CH_PAIN, damageforcescale, dmg_time, enemy, entity(), GetResource(), healtharmor_applydamage(), ITEM_DAMAGE_NEEDKILL, Monster_Dead(), Monster_Sound(), monsterdef, MONSTERFLAG_INVINCIBLE, Monster::mr_pain(), MSG_BROADCAST, MUTATOR_CALLHOOK, nextthink, NULL, oldtarget2, RES_ARMOR, setthink, sound_allowed(), spamsound(), spawnflags, sprite, StatusEffects_active(), SUB_Remove(), SUB_UseTargets(), TakeResource(), target2, time, vector, velocity, Violence_GibSplash(), Violence_GibSplash_At(), VOL_BASE, WaypointSprite_Kill(), and WaypointSprite_UpdateHealth().

Referenced by Monster_Spawn().

◆ Monster_Dead()

void Monster_Dead ( entity this,
entity attacker,
float gibbed )

Definition at line 1036 of file sv_monsters.qc.

1037{
1039 this.nextthink = time;
1040 this.monster_lifetime = time + 5;
1041
1042 monster_dropitem(this, attacker);
1043
1044 Monster_Sound(this, monstersound_death, 0, false, CH_VOICE);
1045
1048
1049 if (IS_PLAYER(attacker)
1052
1053 if (gibbed)
1054 --totalspawned; // number of monsters spawned with mobspawn command
1055
1056 if (!gibbed && this.mdl_dead && this.mdl_dead != "")
1057 _setmodel(this, this.mdl_dead);
1058
1059 this.event_damage = (gibbed ? func_null : Monster_Dead_Damage);
1060 this.event_heal = func_null;
1061 this.solid = SOLID_CORPSE;
1062 this.takedamage = DAMAGE_AIM;
1063 this.deadflag = DEAD_DEAD;
1064 this.enemy = NULL;
1066 this.moveto = this.origin;
1067 settouch(this, Monster_Touch); // reset incase monster was pouncing
1068 this.reset = func_null;
1069 this.state = 0;
1070 this.attack_finished_single[0] = 0;
1071 this.effects = 0;
1073
1074 if (!(this.flags & (FL_FLY | FL_SWIM)))
1075 this.velocity = '0 0 0';
1076
1078
1079 Monster mon = this.monsterdef;
1080 mon.mr_death(mon, this);
1081}
string mdl_dead
Definition breakable.qc:27
virtual void mr_death()
(SERVER) called when monster dies
Definition monster.qh:76
#define IS_PLAYER(s)
Definition player.qh:242
const float SOLID_CORPSE
float DPCONTENTS_BODY
float effects
float dphitcontentsmask
solid
Definition ent_cs.qc:165
vector moveto
Definition movelib.qc:4
void set_movetype(entity this, int mt)
Definition movetypes.qc:4
const int MOVETYPE_TOSS
Definition movetypes.qh:135
float deadflag
Definition progsdefs.qc:149
float DEAD_DEAD
Definition progsdefs.qc:276
const int DAMAGE_AIM
Definition subs.qh:81
float takedamage
Definition subs.qh:78
void CSQCModel_UnlinkEntity(entity e)
Definition sv_model.qc:139
void monster_dropitem(entity this, entity attacker)
void Monster_Dead_Think(entity this)
void Monster_Touch(entity this, entity toucher)
void Monster_Dead_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype,.entity weaponentity, vector hitloc, vector force)
int autocvar_g_monsters_score_spawned
int totalspawned
number of monsters spawned with mobspawn command
const int MONSTERFLAG_SPAWNED
flag for spawned monsters
int monsters_killed
int autocvar_g_monsters_score_kill
const int MONSTERFLAG_RESPAWNED
flag for respawned monsters
float monster_lifetime
monster dies instantly after this delay, set from spawn
#define GameRules_scoring_add(client, fld, value)
Definition sv_rules.qh:85

References attack_finished_single, autocvar_g_monsters_score_kill, autocvar_g_monsters_score_spawned, CH_VOICE, CSQCModel_UnlinkEntity(), DAMAGE_AIM, DEAD_DEAD, deadflag, DPCONTENTS_BODY, dphitcontentsmask, effects, enemy, entity(), FL_FLY, FL_SWIM, flags, func_null(), GameRules_scoring_add, IS_PLAYER, mdl_dead, Monster_Dead_Damage(), Monster_Dead_Think(), monster_dropitem(), monster_lifetime, Monster_Sound(), Monster_Touch(), monsterdef, MONSTERFLAG_RESPAWNED, MONSTERFLAG_SPAWNED, monsters_killed, moveto, MOVETYPE_TOSS, Monster::mr_death(), nextthink, NULL, origin, set_movetype(), setthink, settouch, solid, SOLID_CORPSE, spawnflags, state, takedamage, time, totalspawned, and velocity.

Referenced by Monster_Damage().

◆ Monster_Dead_Damage()

void Monster_Dead_Damage ( entity this,
entity inflictor,
entity attacker,
float damage,
int deathtype,
.entity weaponentity,
vector hitloc,
vector force )

Definition at line 1018 of file sv_monsters.qc.

1019{
1020 TakeResource(this, RES_HEALTH, damage);
1021
1022 Violence_GibSplash_At(hitloc, force, 2, bound(0, damage, 200) / 16, this, attacker);
1023
1024 if (GetResource(this, RES_HEALTH) <= -50) // 100 health until gone?
1025 {
1026 Violence_GibSplash_At(hitloc, force, 2, bound(0, damage, 200) / 16, this, attacker);
1027
1028 --totalspawned; // number of monsters spawned with mobspawn command
1029
1030 setthink(this, SUB_Remove);
1031 this.nextthink = time + 0.1;
1032 this.event_damage = func_null;
1033 }
1034}

References bound(), entity(), func_null(), GetResource(), nextthink, setthink, SUB_Remove(), TakeResource(), time, totalspawned, vector, and Violence_GibSplash_At().

Referenced by Monster_Dead().

◆ Monster_Dead_Fade()

void Monster_Dead_Fade ( entity this)

Definition at line 567 of file sv_monsters.qc.

568{
569 if (Monster_Respawn_Check(this))
570 {
573 this.nextthink = time + this.respawntime;
574 this.monster_lifetime = 0;
577 {
578 this.pos1 = this.origin;
579 this.pos2 = this.angles;
580 }
581 this.event_damage = func_null;
582 this.event_heal = func_null;
583 this.takedamage = DAMAGE_NO;
584 setorigin(this, this.pos1);
585 this.angles = this.pos2;
586 SetResourceExplicit(this, RES_HEALTH, this.max_health);
587 setmodel(this, MDL_Null);
588 }
589 else
590 {
591 // number of monsters spawned with mobspawn command
592 --totalspawned;
593
594 SUB_SetFade(this, time + 3, 1);
595 }
596}
float max_health
bool SetResourceExplicit(entity e, Resource res_type, float amount)
Sets the resource amount of an entity without calling any hooks.
#define setmodel(this, m)
Definition model.qh:26
ent angles
Definition ent_cs.qc:121
const int MONSTER_RESPAWN_DEATHPOINT
re-spawn where we died
Definition monster.qh:5
float DEAD_RESPAWNING
Definition progsdefs.qc:278
float respawntime
Definition items.qh:31
void SUB_SetFade(entity ent, float vanish_time, float fading_time)
Definition subs.qc:77
const int DAMAGE_NO
Definition subs.qh:79
vector pos2
Definition subs.qh:50
vector pos1
Definition subs.qh:50
bool Monster_Respawn_Check(entity this)
void Monster_Respawn(entity this)

References angles, DAMAGE_NO, DEAD_RESPAWNING, deadflag, entity(), func_null(), max_health, monster_lifetime, Monster_Respawn(), Monster_Respawn_Check(), MONSTER_RESPAWN_DEATHPOINT, MONSTERFLAG_RESPAWNED, nextthink, origin, pos1, pos2, respawntime, setmodel, SetResourceExplicit(), setthink, spawnflags, SUB_SetFade(), takedamage, time, and totalspawned.

Referenced by Monster_Dead_Think().

◆ Monster_Dead_Think()

void Monster_Dead_Think ( entity this)

Definition at line 965 of file sv_monsters.qc.

966{
967 this.nextthink = time;
968
969 Monster mon = REGISTRY_GET(Monsters, this.monsterid);
970 mon.mr_deadthink(mon, this);
971
972 if (this.monster_lifetime != 0 && time >= this.monster_lifetime)
973 {
974 Monster_Dead_Fade(this);
975 return;
976 }
977}
virtual void mr_deadthink()
(SERVER) logic to run every frame after the monster has died
Definition monster.qh:70
#define REGISTRY_GET(id, i)
Definition registry.qh:43
void Monster_Dead_Fade(entity this)

References entity(), Monster_Dead_Fade(), monster_lifetime, Monster::mr_deadthink(), nextthink, REGISTRY_GET, and time.

Referenced by Monster_Dead().

◆ Monster_Delay()

void Monster_Delay ( entity this,
int repeat_count,
float defer_amnt,
void(entity) func )

Definition at line 243 of file sv_monsters.qc.

244{
245 // deferred attacking, checks if monster is still alive and target is still valid before attacking
247
249 e.nextthink = time + defer_amnt;
250 e.count = defer_amnt;
251 e.owner = this;
252 e.monster_delayedfunc = func;
253 e.cnt = repeat_count;
254}
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
#define new_pure(class)
purely logical entities (not linked to the area grid)
Definition oo.qh:67
void Monster_Delay(entity this, int repeat_count, float defer_amnt, void(entity) func)
void Monster_Delay_Action(entity this)

References entity(), Monster_Delay(), Monster_Delay_Action(), new_pure, setthink, and time.

Referenced by M_Golem_Attack(), M_Wyvern_Attack(), M_Zombie_Defend_Block(), and Monster_Delay().

◆ Monster_Delay_Action()

void Monster_Delay_Action ( entity this)

Definition at line 221 of file sv_monsters.qc.

222{
223 // TODO: maybe do check for facing here
224 if (Monster_ValidTarget(this.owner, this.owner.enemy, false))
225 {
226 monster_makevectors(this.owner, this.owner.enemy);
227 this.monster_delayedfunc(this.owner);
228 }
229
230 if (this.cnt > 1)
231 {
232 --this.cnt;
234 this.nextthink = time + this.count;
235 }
236 else
237 {
238 setthink(this, SUB_Remove);
239 this.nextthink = time;
240 }
241}
float cnt
Definition powerups.qc:24
float count
Definition powerups.qc:22
entity owner
Definition main.qh:87
bool Monster_ValidTarget(entity this, entity targ, bool skipfacing)

References cnt, count, entity(), Monster_Delay_Action(), monster_makevectors(), Monster_ValidTarget(), nextthink, owner, setthink, SUB_Remove(), and time.

Referenced by Monster_Delay(), and Monster_Delay_Action().

◆ monster_dropitem()

void monster_dropitem ( entity this,
entity attacker )

Definition at line 40 of file sv_monsters.qc.

41{
42 if (!this.candrop || autocvar_g_monsters_drop_time <= 0)
43 return;
44
45 // TODO: mapper customization (different field?)
46 string itemlist = this.monster_loot;
47
50
51 MUTATOR_CALLHOOK(MonsterDropItem, this, itemlist, attacker);
52 itemlist = M_ARGV(1, string);
53
54 entity loot_itemdef = Item_RandomFromList(itemlist);
55 if (!loot_itemdef)
56 return;
57
58 entity e = spawn();
59 e.monster_item = true;
60 ITEM_SET_LOOT(e, true);
61 e.colormap = this.colormap;
62 e.itemdef = loot_itemdef;
63 setorigin(e, CENTER_OR_VIEWOFS(this));
64 e.velocity = randomvec() * 175 + '0 0 325';
66
68}
#define M_ARGV(x, type)
Definition events.qh:17
float colormap
#define spawn
entity Item_RandomFromList(string itemlist)
Takes a space-separated list of netnames, returns the itemdef of one of them (or NULL if none are ava...
Definition spawning.qc:71
bool Item_Initialise(entity item)
An optimised and generic way to initialise items (loot or permanent)
Definition spawning.qc:27
#define ITEM_SET_LOOT(item, loot)
Sets the item loot status.
Definition spawning.qh:45
vector randomvec(void)
string monster_loot
Definition events.qh:390
const int MONSTERFLAG_MINIBOSS
monster spawns as mini-boss (also has a chance of naturally becoming one)
string autocvar_g_monsters_miniboss_loot
float autocvar_g_monsters_drop_time
#define CENTER_OR_VIEWOFS(ent)
Definition utils.qh:31

References autocvar_g_monsters_drop_time, autocvar_g_monsters_miniboss_loot, candrop, CENTER_OR_VIEWOFS, colormap, entity(), Item_Initialise(), Item_RandomFromList(), ITEM_SET_LOOT, M_ARGV, monster_loot, MONSTERFLAG_MINIBOSS, MUTATOR_CALLHOOK, randomvec(), spawn, and spawnflags.

Referenced by Monster_Dead().

◆ Monster_Enemy_Check()

void Monster_Enemy_Check ( entity this)

Definition at line 1243 of file sv_monsters.qc.

1244{
1245 if (this.enemy)
1246 {
1247 vector targ_origin = ((this.enemy.absmin + this.enemy.absmax) * 0.5);
1248 targ_origin = WarpZone_RefSys_TransformOrigin(this.enemy, this, targ_origin); // origin of target as seen by the monster (us)
1249 WarpZone_TraceLine(this.origin, targ_origin, MOVE_NOMONSTERS, this);
1250
1251 // cases where the enemy may have changed their state (don't need to check everything here)
1252 // TODO: mutator hook
1253 if (IS_DEAD(this.enemy) || GetResource(this.enemy, RES_HEALTH) < 1
1254 || STAT(FROZEN, this.enemy)
1255 || (this.enemy.flags & FL_NOTARGET)
1256 || (this.enemy.alpha < 0.5 && this.enemy.alpha != 0)
1257 || this.enemy.takedamage == DAMAGE_NO
1258 || vdist(this.origin - targ_origin, >, this.target_range)
1259 || (trace_fraction < 1 && trace_ent != this.enemy))
1260 this.enemy = NULL;
1261 else
1262 return;
1263 }
1264
1265 this.enemy = Monster_FindTarget(this);
1266 if (this.enemy)
1267 {
1268 WarpZone_RefSys_Copy(this.enemy, this);
1269 WarpZone_RefSys_AddInverse(this.enemy, this); // wz1^-1 ... wzn^-1 receiver
1270 // update move target immediately?
1271 this.moveto = WarpZone_RefSys_TransformOrigin(this.enemy, this, 0.5 * (this.enemy.absmin + this.enemy.absmax));
1272 this.monster_moveto = '0 0 0';
1273 this.monster_face = '0 0 0';
1274
1275 Monster_Sound(this, monstersound_sight, 0, false, CH_VOICE);
1276 }
1277}
const int FL_NOTARGET
Definition constants.qh:76
const float MOVE_NOMONSTERS
float trace_fraction
#define STAT(...)
Definition stats.qh:82
void WarpZone_TraceLine(vector org, vector end, float nomonsters, entity forent)
Definition common.qc:348
void WarpZone_RefSys_AddInverse(entity me, entity wz)
Definition common.qc:741
vector WarpZone_RefSys_TransformOrigin(entity from, entity to, vector org)
Definition common.qc:763
void WarpZone_RefSys_Copy(entity me, entity from)
Definition common.qc:795
entity Monster_FindTarget(entity this)
vector monster_moveto
custom destination for monster (reset to '0 0 0' when you're done!)
vector monster_face
custom looking direction for monster (reset to '0 0 0' when you're done!)

References CH_VOICE, DAMAGE_NO, enemy, entity(), FL_NOTARGET, GetResource(), IS_DEAD, monster_face, Monster_FindTarget(), monster_moveto, Monster_Sound(), MOVE_NOMONSTERS, moveto, NULL, origin, STAT, trace_ent, trace_fraction, vdist, vector, WarpZone_RefSys_AddInverse(), WarpZone_RefSys_Copy(), WarpZone_RefSys_TransformOrigin(), and WarpZone_TraceLine().

Referenced by Monster_Think().

◆ monster_facing()

bool monster_facing ( entity this,
entity targ )

Definition at line 70 of file sv_monsters.qc.

71{
72 // relies on target having an origin
73 makevectors(this.angles);
74 vector targ_org = targ.origin, my_org = this.origin;
76 {
77 targ_org = vec2(targ_org);
78 my_org = vec2(my_org);
79 }
80 float dot = normalize(targ_org - my_org) * v_forward;
81
83}
#define makevectors
Definition post.qh:21
bool autocvar_g_monsters_target_infront_2d
float autocvar_g_monsters_target_infront_range
#define vec2(...)
Definition vector.qh:90

References angles, autocvar_g_monsters_target_infront_2d, autocvar_g_monsters_target_infront_range, entity(), makevectors, normalize(), origin, v_forward, vec2, and vector.

Referenced by Monster_Attack_Check(), and Monster_ValidTarget().

◆ Monster_FindTarget()

entity Monster_FindTarget ( entity this)

Definition at line 137 of file sv_monsters.qc.

138{
139 if (MUTATOR_CALLHOOK(MonsterFindTarget))
140 return this.enemy; // Handled by a mutator
141
142 entity closest_target = NULL;
143 vector my_center = CENTER_OR_VIEWOFS(this);
144
145 float trange;
146 // find the closest acceptable target to pass to
147 IL_EACH(g_monster_targets, it.monster_attack,
148 {
149 trange = this.target_range;
150 if (PHYS_INPUT_BUTTON_CROUCH(it))
151 trange *= 0.75; // TODO cvar this
152 vector theirmid = (it.absmin + it.absmax) * 0.5;
153 if (vdist(theirmid - this.origin, >, trange) || !Monster_ValidTarget(this, it, false))
154 continue;
155
156 // if it's a player, use the view origin as reference (stolen from RadiusDamage functions in g_damage.qc)
157 vector targ_center = CENTER_OR_VIEWOFS(it);
158
159 if (closest_target)
160 {
161 vector closest_target_center = CENTER_OR_VIEWOFS(closest_target);
162 if (vlen2(my_center - targ_center) < vlen2(my_center - closest_target_center))
163 closest_target = it;
164 }
165 else
166 closest_target = it;
167 });
168
169 return closest_target;
170}
#define IL_EACH(this, cond, body)

References CENTER_OR_VIEWOFS, enemy, entity(), g_monster_targets, IL_EACH, MUTATOR_CALLHOOK, NULL, and vector.

Referenced by Monster_Enemy_Check().

◆ Monster_Heal()

bool Monster_Heal ( entity targ,
entity inflictor,
float amount,
float limit )

Definition at line 1148 of file sv_monsters.qc.

1149{
1150 float true_limit = (limit != RES_LIMIT_NONE) ? limit : targ.max_health;
1151 if (GetResource(targ, RES_HEALTH) <= 0 || GetResource(targ, RES_HEALTH) >= true_limit)
1152 return false;
1153
1154 GiveResourceWithLimit(targ, RES_HEALTH, amount, true_limit);
1155 if (targ.sprite)
1156 WaypointSprite_UpdateHealth(targ.sprite, GetResource(targ, RES_HEALTH));
1157 return true;
1158}
const int RES_LIMIT_NONE
Definition resources.qh:60
void GiveResourceWithLimit(entity receiver, Resource res_type, float amount, float limit)
Gives an entity some resource but not more than a limit.

References entity(), GetResource(), GiveResourceWithLimit(), RES_LIMIT_NONE, and WaypointSprite_UpdateHealth().

Referenced by Monster_Spawn().

◆ monster_makevectors()

void monster_makevectors ( entity this,
entity targ )

Definition at line 85 of file sv_monsters.qc.

86{
87 if (IS_MONSTER(this))
88 {
89 vector v = targ.origin + (targ.mins + targ.maxs) * 0.5;
90 this.v_angle = vectoangles(v - (this.origin + this.view_ofs));
91 this.v_angle.x = -this.v_angle.x;
92 }
93
94 makevectors(this.v_angle);
95}
vector v_angle
Definition player.qh:236
vector vectoangles(vector v)

References entity(), IS_MONSTER, makevectors, origin, v_angle, vectoangles(), vector, and view_ofs.

Referenced by M_Golem_Attack_Lightning(), Monster_Attack_Check(), and Monster_Delay_Action().

◆ Monster_Miniboss_Setup()

void Monster_Miniboss_Setup ( entity this)

Definition at line 521 of file sv_monsters.qc.

522{
524 {
525 // already performed initial setup, just reapply statuses as needed
527 this.effects |= EF_RED;
528 return;
529 }
530
531 if (MUTATOR_CALLHOOK(MonsterCheckBossFlag, this))
532 {
533 // prevent other code from identifying the monster as a miniboss
535 return;
536 }
537
538 // g_monsters_miniboss_chance cvar or spawnflags 64 causes a monster to be a miniboss
540 {
542 this.effects |= EF_RED;
543 this.spawnflags |= MONSTERFLAG_MINIBOSS; // identifier for other code
544 }
545}
const float EF_RED
float autocvar_g_monsters_miniboss_chance
float autocvar_g_monsters_miniboss_healthboost
void GiveResource(entity receiver, Resource res_type, float amount)
Gives an entity some resource.

References autocvar_g_monsters_miniboss_chance, autocvar_g_monsters_miniboss_healthboost, EF_RED, effects, entity(), GiveResource(), MONSTERFLAG_MINIBOSS, MONSTERFLAG_RESPAWNED, MUTATOR_CALLHOOK, random(), and spawnflags.

Referenced by Monster_Spawn_Setup().

◆ Monster_Move()

void Monster_Move ( entity this,
float runspeed,
float walkspeed,
float stpspeed )

Definition at line 784 of file sv_monsters.qc.

785{
786 // update goal entity if lost
787 if (this.target2 && this.target2 != "" && this.goalentity.targetname != this.target2)
788 this.goalentity = find(NULL, targetname, this.target2);
789
790 if (StatusEffects_active(STATUSEFFECT_Frozen, this))
791 {
792 movelib_brake_simple(this, stpspeed);
793 setanim(this, this.anim_idle, true, false, false);
794 return; // no physics while frozen!
795 }
796
797 if (this.flags & FL_SWIM)
798 {
800 {
801 if (time >= this.last_trace)
802 {
803 this.last_trace = time + 0.4;
804
805 Damage(this, NULL, NULL,
806 2,
807 DEATH_DROWN.m_id,
808 DMG_NOWEP,
809 this.origin,
810 '0 0 0'
811 );
812 this.angles = '90 90 0';
813 if (random() < 0.5)
814 {
815 this.velocity.y += random() * 50;
816 this.velocity.x -= random() * 50;
817 }
818 else
819 {
820 this.velocity.y -= random() * 50;
821 this.velocity.x += random() * 50;
822 }
823 this.velocity.z += random() * 150;
824 }
825
826
828 //this.velocity.z = -200;
829
830 return;
831 }
832 else if (this.move_movetype == MOVETYPE_BOUNCE)
833 {
834 this.angles.x = 0;
836 }
837 }
838
839 entity targ = this.goalentity;
840
841 if (MUTATOR_CALLHOOK(MonsterMove, this, runspeed, walkspeed, targ)
842 || game_stopped
843 || this.draggedby != NULL
847 || time < this.spawn_time)
848 {
849 runspeed = walkspeed = 0;
850 if (time >= this.spawn_time)
851 setanim(this, this.anim_idle, true, false, false);
852 movelib_brake_simple(this, stpspeed);
853 return;
854 }
855
856 targ = M_ARGV(3, entity);
857 runspeed = bound(0, M_ARGV(1, float) * MONSTER_SKILLMOD(this), runspeed * 2.5); // limit maxspeed to prevent craziness
858 walkspeed = bound(0, M_ARGV(2, float) * MONSTER_SKILLMOD(this), walkspeed * 2.5); // limit maxspeed to prevent craziness
859
860 if (this.monster_follow)
863 this.monster_follow = NULL;
864
865 if (this.state == MONSTER_ATTACK_RANGED && IS_ONGROUND(this))
866 {
867 this.state = 0;
868 settouch(this, Monster_Touch);
869 }
870
871 if (this.state && time >= this.attack_finished_single[0])
872 this.state = 0; // attack is over
873
874 // Select destination
875 if (this.state != MONSTER_ATTACK_MELEE // don't move if set
876 && (time >= this.last_trace || this.enemy)) // update enemy or rider instantly
877 this.moveto = Monster_Move_Target(this, targ);
878
879 if (!this.enemy)
880 Monster_Sound(this, monstersound_idle, 7, true, CH_VOICE);
881
882 if (this.state == MONSTER_ATTACK_MELEE)
883 this.moveto = this.origin;
884
885 if (this.enemy && this.enemy.vehicle)
886 runspeed = 0;
887
888 if (!(this.spawnflags & MONSTERFLAG_FLY_VERTICAL) && !(this.flags & FL_SWIM))
889 this.moveto.z = this.origin.z;
890
891 // Steer towards destination
892 this.steerto = steerlib_attract2(this, ((this.monster_face) ? this.monster_face : this.moveto), 0.5, 500, 0.95);
893 vector real_angle = vectoangles(this.steerto) - this.angles;
894
895 if (this.state != MONSTER_ATTACK_MELEE)
896 this.angles.y += bound(-25, shortangle_f(real_angle.y, this.angles.y), 25);
897
898 // Update velocity
900 float vz = this.velocity.z;
901
902 // Check for danger ahead
903 float bboxwidth = min(this.maxs.x - this.mins.x, this.maxs.y - this.mins.y);
904 int danger = Monster_CheckDanger(this, this.origin + this.view_ofs
905 + (vdist(this.velocity, >, bboxwidth * 5) ? this.velocity * 0.2 : v_forward * bboxwidth));
906
907 if (!danger && !turret_closetotarget(this, this.moveto, 16))
908 {
909 bool do_run = (this.enemy || this.monster_moveto);
910 movelib_move_simple(this, v_forward, (do_run ? runspeed : walkspeed), 0.4);
911
912 if (time > this.pain_finished && time > this.anim_finished
913 && !this.state)
914 {
915 if (vdist(this.velocity, >, 10))
916 setanim(this, (do_run ? this.anim_run : this.anim_walk), true, false, false);
917 else
918 setanim(this, this.anim_idle, true, false, false);
919 }
920 }
921 else
922 {
923 entity e = this.goalentity; //find(NULL, targetname, this.target2);
924 if (e.target2 && e.target2 != "")
925 this.target2 = e.target2;
926 else if (e.target && e.target != "") // compatibility
927 this.target2 = e.target;
928
929 movelib_brake_simple(this, stpspeed);
930 if (time > this.anim_finished && time > this.pain_finished
931 && !this.state
932 && vdist(this.velocity, <=, 30))
933 setanim(this, this.anim_idle, true, false, false);
934 }
935
936 if (!(this.flags & (FL_FLY | FL_SWIM)))
937 this.velocity.z = vz;
938
939 // If this path is dangerous try to find a different one next frame
940 if (danger)
941 {
942 this.last_trace = time + 0.3;
943 this.moveto = Monster_WanderTarget(this, this.origin);
944 }
945}
ERASEABLE float shortangle_f(float ang1, float ang2)
Definition angle.qc:29
void fixedmakevectors(vector a)
float pain_finished
float waterlevel
Definition player.qh:225
float game_starttime
Definition stats.qh:82
entity goalentity
Definition viewloc.qh:16
bool autocvar_g_campaign
Definition menu.qc:752
entity find(entity start,.string field, string match)
float min(float f,...)
vector anim_walk
Definition monster.qh:31
void movelib_brake_simple(entity this, float force)
Definition movelib.qc:163
#define movelib_move_simple(e, newdir, velo, blendrate)
Definition movelib.qh:36
const int MOVETYPE_WALK
Definition movetypes.qh:132
const int WATERLEVEL_WETFEET
Definition movetypes.qh:12
float move_movetype
Definition movetypes.qh:76
const int MOVETYPE_BOUNCE
Definition movetypes.qh:139
#define round_handler_IsActive()
#define round_handler_IsRoundStarted()
bool campaign_bots_may_start
campaign mode: bots shall spawn but wait for the player to spawn before they do anything in other gam...
Definition campaign.qh:26
vector steerlib_attract2(entity this, vector point, float min_influense, float max_distance, float max_influense)
Definition steerlib.qc:45
vector steerto
Definition steerlib.qh:3
vector Monster_Move_Target(entity this, entity targ)
entity draggedby
int Monster_CheckDanger(entity this, vector dst_ahead)
vector Monster_WanderTarget(entity this, vector targetorigin)
Returns an origin that's near targetorigin and visible to this monster.
entity monster_follow
monster follow target
float spawn_time
delay monster thinking until spawn animation has completed
float last_trace
monster logic delay between target tracing
const int MONSTERFLAG_FLY_VERTICAL
monster can fly/swim vertically
bool autocvar_g_monsters_teams
bool turret_closetotarget(entity this, vector targ, float range)
#define DIFF_TEAM(a, b)
Definition teams.qh:242
string targetname
Definition triggers.qh:56
#define IS_OBSERVER(v)
Definition utils.qh:11
#define IS_SPEC(v)
Definition utils.qh:10
vector anim_idle
Definition all.qh:424

References angles, anim_finished, anim_idle, anim_walk, attack_finished_single, autocvar_g_campaign, autocvar_g_monsters_teams, bound(), campaign_bots_may_start, CH_VOICE, Damage(), DIFF_TEAM, DMG_NOWEP, draggedby, enemy, entity(), find(), fixedmakevectors(), FL_FLY, FL_SWIM, flags, game_starttime, game_stopped, goalentity, IS_OBSERVER, IS_ONGROUND, IS_SPEC, last_trace, M_ARGV, maxs, min(), MONSTER_ATTACK_MELEE, MONSTER_ATTACK_RANGED, Monster_CheckDanger(), monster_face, monster_follow, Monster_Move_Target(), monster_moveto, MONSTER_SKILLMOD, Monster_Sound(), Monster_Touch(), Monster_WanderTarget(), MONSTERFLAG_FLY_VERTICAL, move_movetype, movelib_brake_simple(), movelib_move_simple, moveto, MOVETYPE_BOUNCE, MOVETYPE_WALK, MUTATOR_CALLHOOK, NULL, origin, pain_finished, random(), round_handler_IsActive, round_handler_IsRoundStarted, set_movetype(), setanim, settouch, shortangle_f(), spawn_time, spawnflags, state, StatusEffects_active(), steerlib_attract2(), steerto, target2, targetname, teamplay, time, turret_closetotarget(), v_forward, vdist, vectoangles(), vector, velocity, view_ofs, waterlevel, and WATERLEVEL_WETFEET.

Referenced by Monster_Think().

◆ Monster_Move_2D()

void Monster_Move_2D ( entity this,
float mspeed,
bool allow_jumpoff )

Definition at line 1161 of file sv_monsters.qc.

1162{
1164 || time < game_starttime || time < this.spawn_time
1166 {
1167 mspeed = 0;
1168 if (time >= this.spawn_time)
1169 setanim(this, this.anim_idle, true, false, false);
1170 movelib_brake_simple(this, 0.6);
1171 return;
1172 }
1173
1174 makevectors(this.angles);
1175 vector a = CENTER_OR_VIEWOFS(this);
1176 vector b = CENTER_OR_VIEWOFS(this) + v_forward * 32;
1177
1178 traceline(a, b, MOVE_NORMAL, this);
1179
1180 bool reverse = false;
1181 if (trace_fraction != 1.0)
1182 reverse = true;
1184 reverse = false;
1186 reverse = true;
1187
1188 if (!allow_jumpoff && IS_ONGROUND(this))
1189 {
1190 traceline(b, b - '0 0 32', MOVE_NORMAL, this);
1191 if (trace_fraction == 1.0)
1192 reverse = true;
1193 }
1194
1195 if (reverse)
1196 {
1197 this.angles.y = anglemods(this.angles.y - 180);
1198 makevectors(this.angles);
1199 }
1200
1201 movelib_move_simple_gravity(this, v_forward, mspeed, 1);
1202
1203 if (time > this.pain_finished && time > this.attack_finished_single[0])
1204 {
1205 if (vdist(this.velocity, >, 10))
1206 setanim(this, this.anim_walk, true, false, false);
1207 else
1208 setanim(this, this.anim_idle, true, false, false);
1209 }
1210}
ERASEABLE float anglemods(float v)
Definition angle.qc:13
const float MOVE_NORMAL
#define movelib_move_simple_gravity(e, newdir, velo, blendrate)
Definition movelib.qh:39

References anglemods(), angles, anim_idle, anim_walk, attack_finished_single, autocvar_g_campaign, campaign_bots_may_start, CENTER_OR_VIEWOFS, draggedby, entity(), game_starttime, game_stopped, IS_MONSTER, IS_ONGROUND, IS_PLAYER, makevectors, MOVE_NORMAL, movelib_brake_simple(), movelib_move_simple_gravity, NULL, pain_finished, round_handler_IsActive, round_handler_IsRoundStarted, setanim, spawn_time, time, trace_ent, trace_fraction, v_forward, vdist, vector, and velocity.

◆ Monster_Move_Target()

vector Monster_Move_Target ( entity this,
entity targ )

Definition at line 624 of file sv_monsters.qc.

625{
626 // enemy is always preferred target
627 if (this.enemy)
628 {
629 vector targ_origin = (this.enemy.absmin + this.enemy.absmax) * 0.5;
630 targ_origin = WarpZone_RefSys_TransformOrigin(this.enemy, this, targ_origin); // origin of target as seen by the monster (us)
631
632 /*
633 WarpZone_TrailParticles(NULL, particleeffectnum(EFFECT_RED_PASS), this.origin, targ_origin);
634 print("Trace origin: ", vtos(targ_origin), "\n");
635 print("Target origin: ", vtos(this.enemy.origin), "\n");
636 print("My origin: ", vtos(this.origin), "\n");
637 */
638
640 this.last_trace = time + 1.2;
641 if (this.monster_moveto)
642 return this.monster_moveto; // assumes code is properly setting this when monster has an enemy
643 else
644 return targ_origin;
645
646 /*
647 makevectors(this.angles);
648 this.monster_movestate = MONSTER_MOVE_ENEMY;
649 this.last_trace = time + 1.2;
650 return this.enemy.origin;
651 */
652 }
653
654 switch (this.monster_moveflags)
655 {
658 this.last_trace = time + 0.3;
659 if (this.monster_follow)
660 {
661 if (vdist(this.origin - this.monster_follow.origin, <, this.wander_distance))
662 this.last_trace = time + this.wander_delay;
663 return Monster_WanderTarget(this, this.monster_follow.origin);
664 }
665 else
666 return this.origin;
667
670 this.last_trace = time + 2;
671 return this.pos1;
672
674 if (this.monster_moveto)
675 {
676 this.last_trace = time + 0.5;
677 return this.monster_moveto;
678 }
679 else
680 {
682 this.last_trace = time + 2;
683 }
684 return this.origin;
685
686 default:
689 if (this.monster_moveto)
690 {
691 this.last_trace = time + 0.5;
692 return this.monster_moveto;
693 }
694 else if (targ)
695 {
696 this.last_trace = time + 0.5;
697 return targ.origin;
698 }
699 else
700 {
701 this.last_trace = time + this.wander_delay;
702 return Monster_WanderTarget(this, this.origin);
703 }
704 }
705}
int monster_moveflags
const int MONSTER_MOVE_FOLLOW
monster will follow if in range, or stand still
const int MONSTER_MOVE_ENEMY
used only as a movestate, for monsters
float wander_delay
monster logic delay between moving while idle
const int MONSTER_MOVE_SPAWNLOC
monster will move to its spawn location when not attacking
const int MONSTER_MOVE_WANDER
monster will ignore owner & wander around
int monster_movestate
monster move target priority
const int MONSTER_MOVE_NOMOVE
monster simply stands still

References enemy, entity(), last_trace, monster_follow, MONSTER_MOVE_ENEMY, MONSTER_MOVE_FOLLOW, MONSTER_MOVE_NOMOVE, MONSTER_MOVE_SPAWNLOC, MONSTER_MOVE_WANDER, monster_moveflags, monster_movestate, monster_moveto, Monster_WanderTarget(), origin, pos1, time, vdist, vector, wander_delay, and WarpZone_RefSys_TransformOrigin().

Referenced by Monster_Move().

◆ Monster_Remove()

void Monster_Remove ( entity this)

Definition at line 947 of file sv_monsters.qc.

948{
949 if (!this || IS_CLIENT(this))
950 return; // don't remove it?
951
952 if (!MUTATOR_CALLHOOK(MonsterRemove, this))
953 Send_Effect(EFFECT_ITEM_PICKUP, this.origin, '0 0 0', 1);
954
955 for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
956 {
957 .entity weaponentity = weaponentities[slot];
958 if (this.(weaponentity))
959 delete(this.(weaponentity));
960 }
962 delete(this);
963}
#define IS_CLIENT(s)
Definition player.qh:241
void Send_Effect(entity eff, vector eff_loc, vector eff_vel, int eff_cnt)
Definition all.qc:120
const int MAX_WEAPONSLOTS
Definition weapon.qh:16
entity weaponentities[MAX_WEAPONSLOTS]
Definition weapon.qh:17

References entity(), IS_CLIENT, MAX_WEAPONSLOTS, MUTATOR_CALLHOOK, origin, Send_Effect(), sprite, WaypointSprite_Kill(), and weaponentities.

Referenced by CommonCommand_editmob(), Invasion_CheckWinner(), Monster_Reset(), and Monster_Spawn().

◆ Monster_Reset()

void Monster_Reset ( entity this)

Definition at line 999 of file sv_monsters.qc.

1000{
1002 {
1003 Monster_Remove(this);
1004 return;
1005 }
1006
1007 setorigin(this, this.pos1);
1008 this.angles = this.pos2;
1009
1010 SetResourceExplicit(this, RES_HEALTH, this.max_health);
1011 this.velocity = '0 0 0';
1012 this.enemy = NULL;
1013 this.goalentity = NULL;
1014 this.attack_finished_single[0] = 0;
1015 this.moveto = this.origin;
1016}
void Monster_Remove(entity this)

References angles, attack_finished_single, enemy, entity(), goalentity, max_health, Monster_Remove(), MONSTERFLAG_SPAWNED, moveto, NULL, origin, pos1, pos2, SetResourceExplicit(), spawnflags, and velocity.

Referenced by Monster_Spawn().

◆ Monster_Respawn()

void Monster_Respawn ( entity this)

Definition at line 559 of file sv_monsters.qc.

560{
561 Monster_Spawn(this, true, this.monsterdef);
562}

References entity(), Monster_Spawn(), and monsterdef.

Referenced by Monster_Dead_Fade().

◆ Monster_Respawn_Check()

bool Monster_Respawn_Check ( entity this)

Definition at line 547 of file sv_monsters.qc.

548{
549 if (this.deadflag == DEAD_DEAD // don't call when monster isn't dead
550 && MUTATOR_CALLHOOK(MonsterRespawn, this))
551 return true; // enabled by a mutator
552
554 return false;
555
556 return true;
557}
const int MONSTERFLAG_NORESPAWN
monster doesn't respawn (revive)
bool autocvar_g_monsters_respawn

References autocvar_g_monsters_respawn, DEAD_DEAD, deadflag, entity(), MONSTERFLAG_NORESPAWN, MUTATOR_CALLHOOK, and spawnflags.

Referenced by Monster_Dead_Fade().

◆ monster_setupcolors()

void monster_setupcolors ( entity this)

Definition at line 172 of file sv_monsters.qc.

173{
174 if (teamplay && this.team)
175 this.colormap = 1024 + (this.team - 1) * 17;
176 else if (IS_PLAYER(this.realowner))
177 this.colormap = this.realowner.colormap;
178 else
179 {
181 this.colormap = 1126;
182 else if (this.monster_skill <= MONSTER_SKILL_MEDIUM)
183 this.colormap = 1075;
184 else if (this.monster_skill <= MONSTER_SKILL_HARD)
185 this.colormap = 1228;
186 else if (this.monster_skill <= MONSTER_SKILL_INSANE)
187 this.colormap = 1092;
188 else if (this.monster_skill <= MONSTER_SKILL_NIGHTMARE)
189 this.colormap = 1160;
190 else
191 this.colormap = 1024;
192 }
193
194 if (this.colormap > 0)
195 this.glowmod = colormapPaletteColor(this.colormap & 0x0F, false);
196 else
197 this.glowmod = '1 1 1';
198}
#define colormapPaletteColor(c, isPants)
Definition color.qh:5
vector glowmod
const int MONSTER_SKILL_EASY
const int MONSTER_SKILL_MEDIUM
int monster_skill
const int MONSTER_SKILL_INSANE
const int MONSTER_SKILL_HARD
const int MONSTER_SKILL_NIGHTMARE

References colormap, colormapPaletteColor, entity(), glowmod, IS_PLAYER, monster_skill, MONSTER_SKILL_EASY, MONSTER_SKILL_HARD, MONSTER_SKILL_INSANE, MONSTER_SKILL_MEDIUM, MONSTER_SKILL_NIGHTMARE, realowner, team, and teamplay.

Referenced by monster_changeteam(), and Monster_Spawn().

◆ Monster_Sound()

void Monster_Sound ( entity this,
.string samplefield,
float sound_delay,
bool delaytoo,
float chan )

Definition at line 368 of file sv_monsters.qc.

369{
371 || (delaytoo && time < this.msound_delay)) // too early
372 return;
373
374 string sample = this.(samplefield);
375 if (sample != "")
376 sample = GlobalSound_sample(sample, random());
377 float myscale = (this.scale ? this.scale : 1); // safety net
378 sound7(this, chan, sample, VOL_BASE, ATTEN_NORM, 100 / myscale, 0);
379
380 this.msound_delay = time + sound_delay;
381}
string GlobalSound_sample(string pair, float r)
float scale
Definition projectile.qc:14
bool autocvar_g_monsters_sounds
Definition sv_monsters.qh:7
float msound_delay
temporary antilag system

References ATTEN_NORM, autocvar_g_monsters_sounds, entity(), GlobalSound_sample(), msound_delay, random(), scale, time, and VOL_BASE.

Referenced by Monster_Attack_Check(), Monster_Damage(), Monster_Dead(), Monster_Enemy_Check(), Monster_Move(), and Monster_Spawn_Setup().

◆ Monster_Sound_Precache()

void Monster_Sound_Precache ( string f)

Definition at line 274 of file sv_monsters.qc.

275{
276 float fh = fopen(f, FILE_READ);
277 if (fh < 0)
278 return;
279 string s;
280 while ((s = fgets(fh)))
281 {
282 if (tokenize_console(s) != 3)
283 {
284 //LOG_DEBUG("Invalid sound info line: ", s); // probably a comment, no need to spam warnings
285 continue;
286 }
287 PrecacheGlobalSound(strcat(argv(1), " ", argv(2)));
288 }
289 fclose(fh);
290}
const float FILE_READ
#define tokenize_console
void PrecacheGlobalSound(string sample)
string fgets(float fhandle)
void fclose(float fhandle)
float fopen(string filename, float mode)
string argv(float n)

References argv(), fclose(), fgets(), FILE_READ, fopen(), PrecacheGlobalSound(), strcat(), and tokenize_console.

Referenced by Monster_Sounds_Precache().

◆ Monster_Sound_SampleField()

string Monster_Sound_SampleField ( string type)

Definition at line 318 of file sv_monsters.qc.

319{
321 switch (type)
322 {
323 #define _MSOUND(m) \
324 case #m: \
325 return monstersound_##m;
327 #undef _MSOUND
328 }
330 return string_null;
331}
string string_null
Definition nil.qh:9
#define ALLMONSTERSOUNDS
ALLMONSTERSOUNDS bool GetMonsterSoundSampleField_notFound

References ALLMONSTERSOUNDS, GetMonsterSoundSampleField_notFound, and string_null.

Referenced by Monster_Sounds_Load().

◆ Monster_Sounds_Clear()

void Monster_Sounds_Clear ( entity this)

Definition at line 311 of file sv_monsters.qc.

312{
313#define _MSOUND(m) strfree(this.monstersound_##m);
315#undef _MSOUND
316}

References ALLMONSTERSOUNDS, and entity().

Referenced by Monster_Sounds_Update().

◆ Monster_Sounds_Load()

bool Monster_Sounds_Load ( entity this,
string f,
int first )

Definition at line 333 of file sv_monsters.qc.

334{
335 float fh = fopen(f, FILE_READ);
336 if (fh < 0)
337 {
338 //LOG_DEBUG("Monster sound file not found: ", f); // no biggie, monster has no sounds, let's not spam it
339 return false;
340 }
341 var .string field;
342 string s;
343 while ((s = fgets(fh)))
344 {
345 if (tokenize_console(s) != 3)
346 continue;
349 continue;
350 strcpy(this.(field), strcat(argv(1), " ", argv(2)));
351 }
352 fclose(fh);
353 return true;
354}
#define strcpy(this, s)
Definition string.qh:52
string Monster_Sound_SampleField(string type)

References argv(), entity(), fclose(), fgets(), FILE_READ, fopen(), GetMonsterSoundSampleField_notFound, Monster_Sound_SampleField(), strcat(), strcpy, and tokenize_console.

Referenced by Monster_Sounds_Update().

◆ Monster_Sounds_Precache()

void Monster_Sounds_Precache ( entity this)

Definition at line 292 of file sv_monsters.qc.

293{
294 string m = this.monsterdef.m_model.model_str();
295
296 float globhandle = search_begin(strcat(m, "_*.sounds"), true, false);
297 if (globhandle < 0)
298 return;
299
300 float n = search_getsize(globhandle);
301 string f;
302 for (int i = 0; i < n; ++i)
303 {
304 //print(search_getfilename(globhandle, i), "\n");
305 f = search_getfilename(globhandle, i);
307 }
308 search_end(globhandle);
309}
string search_getfilename(float handle, float num)
float search_getsize(float handle)
float search_begin(string pattern, float caseinsensitive, float quiet)
void search_end(float handle)
void Monster_Sound_Precache(string f)

References entity(), Monster_Sound_Precache(), monsterdef, search_begin(), search_end(), search_getfilename(), search_getsize(), and strcat().

Referenced by Monster_Spawn_Setup().

◆ Monster_Sounds_Update()

void Monster_Sounds_Update ( entity this)

Definition at line 357 of file sv_monsters.qc.

358{
359 if (this.skin == this.skin_for_monstersound)
360 return;
361
362 this.skin_for_monstersound = this.skin;
364 if (!Monster_Sounds_Load(this, get_monster_model_datafilename(this.model, this.skin, "sounds"), 0))
365 Monster_Sounds_Load(this, get_monster_model_datafilename(this.model, 0, "sounds"), 0);
366}
float skin
model
Definition ent_cs.qc:139
void Monster_Sounds_Clear(entity this)
string get_monster_model_datafilename(string m, float sk, string fil)
int skin_for_monstersound
bool Monster_Sounds_Load(entity this, string f, int first)

References entity(), get_monster_model_datafilename(), model, Monster_Sounds_Clear(), Monster_Sounds_Load(), skin, and skin_for_monstersound.

Referenced by Monster_Spawn_Setup().

◆ Monster_Spawn()

bool Monster_Spawn ( entity this,
bool check_appear,
Monster mon )

Setup the basic required properties for a monster.

Definition at line 1388 of file sv_monsters.qc.

1389{
1390 if (!mon || mon == MON_Null) // invalid monster
1391 return false;
1393 {
1394 Monster_Remove(this);
1395 return false;
1396 }
1397
1398 if (!(this.spawnflags & MONSTERFLAG_RESPAWNED) && !(this.flags & FL_MONSTER))
1399 {
1400 IL_PUSH(g_monsters, this);
1401 if (this.mdl && this.mdl != "")
1402 precache_model(this.mdl);
1403 if (this.mdl_dead && this.mdl_dead != "")
1404 precache_model(this.mdl_dead);
1405 }
1406
1407 if (check_appear && Monster_Appear_Check(this, mon))
1408 return true; // return true so the monster isn't removed
1409
1410 if (!this.monster_skill)
1411 this.monster_skill = cvar("g_monsters_skill");
1412
1413 // support for quake style removing monsters based on skill
1417 {
1418 Monster_Remove(this);
1419 return false;
1420 }
1421
1422 if (this.team && !teamplay)
1423 this.team = 0;
1424
1425 if (!(this.spawnflags & MONSTERFLAG_SPAWNED) // naturally spawned monster
1426 && !(this.spawnflags & MONSTERFLAG_RESPAWNED)) // don't count re-spawning monsters either
1428
1429 if (this.mdl && this.mdl != "")
1430 _setmodel(this, this.mdl);
1431 else
1432 setmodel(this, mon.m_model);
1433
1434 if (!this.m_name || this.m_name == "")
1435 this.m_name = mon.m_name;
1436
1437 if (this.statuseffects && this.statuseffects.owner == this)
1438 {
1441 }
1442 else
1443 this.statuseffects = NULL;
1444
1445 this.flags = FL_MONSTER;
1446 this.classname = "monster";
1447 this.takedamage = DAMAGE_AIM;
1448 if (!this.bot_attack)
1449 IL_PUSH(g_bot_targets, this);
1450 this.bot_attack = true;
1451 this.iscreature = true;
1452 this.teleportable = true;
1453 if (!this.damagedbycontents)
1455 this.damagedbycontents = true;
1456 this.monsterdef = mon;
1457 this.event_damage = Monster_Damage;
1458 this.event_heal = Monster_Heal;
1459 settouch(this, Monster_Touch);
1460 this.use = Monster_Use;
1461 this.solid = SOLID_BBOX;
1463 StatusEffects_apply(STATUSEFFECT_SpawnShield, this, time + autocvar_g_monsters_spawnshieldtime, 0);
1464 this.enemy = NULL;
1465 this.velocity = '0 0 0';
1466 this.moveto = this.origin;
1467 this.pos1 = this.origin;
1468 this.pos2 = this.angles;
1469 this.reset = Monster_Reset;
1470 this.netname = mon.netname;
1471 this.monster_attackfunc = mon.monster_attackfunc;
1472 this.candrop = true;
1473 this.oldtarget2 = this.target2;
1474 this.deadflag = DEAD_NO;
1475 this.spawn_time = time;
1476 this.gravity = 1;
1477 this.monster_moveto = '0 0 0';
1478 this.monster_face = '0 0 0';
1480
1481 if (!this.noalign) this.noalign = (mon.spawnflags & (MONSTER_TYPE_FLY | MONSTER_TYPE_SWIM));
1482 if (!this.scale) this.scale = 1;
1483 if (autocvar_g_monsters_edit) this.grab = 1;
1486 if (mon.spawnflags & MONSTER_TYPE_SWIM) this.flags |= FL_SWIM;
1487
1490
1491 if (mon.spawnflags & MONSTER_TYPE_FLY)
1492 {
1493 this.flags |= FL_FLY;
1495 }
1496
1498 this.scale *= 1.3;
1499
1500 setsize(this, RoundPerfectVector(mon.m_mins * this.scale), RoundPerfectVector(mon.m_maxs * this.scale));
1501 this.view_ofs = '0 0 0.35' * this.maxs.z;
1502
1503 Monster_UpdateModel(this);
1504
1505 if (!Monster_Spawn_Setup(this))
1506 {
1507 Monster_Remove(this);
1508 return false;
1509 }
1510
1511 if (!this.noalign)
1512 {
1513 setorigin(this, this.origin + '0 0 20');
1514 tracebox(this.origin + '0 0 64', this.mins, this.maxs, this.origin - '0 0 10000', MOVE_WORLDONLY, this);
1515 setorigin(this, trace_endpos);
1516 }
1517
1518 if (!nudgeoutofsolid_OrFallback(this))
1519 {
1520 // Stuck and not fixable
1521 Monster_Remove(this);
1522 return false;
1523 }
1524
1525 if (!(this.spawnflags & MONSTERFLAG_RESPAWNED))
1526 monster_setupcolors(this);
1527
1528 CSQCMODEL_AUTOINIT(this);
1529
1530 return true;
1531}
float bot_attack
Definition api.qh:38
IntrusiveList g_bot_targets
Definition api.qh:149
int grab
Definition cheats.qh:26
string netname
short name
Definition monster.qh:44
string m_name
human readable name
Definition monster.qh:42
vector m_mins
hitbox size
Definition monster.qh:53
int spawnflags
attributes
Definition monster.qh:39
vector m_maxs
hitbox size
Definition monster.qh:55
string netname
Definition powerups.qc:20
float gravity
Definition items.qh:17
string mdl
Definition item.qh:89
string m_name
Definition scores.qh:142
string classname
float DPCONTENTS_BOTCLIP
float DPCONTENTS_SOLID
const float SOLID_BBOX
const float EF_FULLBRIGHT
float DPCONTENTS_PLAYERCLIP
float DPCONTENTS_MONSTERCLIP
float MOVE_WORLDONLY
const float EF_NODEPTHTEST
#define CSQCMODEL_AUTOINIT(e)
float damagedbycontents
Definition damage.qh:45
IntrusiveList g_damagedbycontents
Definition damage.qh:143
float cvar(string name)
const int MONSTER_TYPE_FLY
Definition monster.qh:6
const int MONSTER_TYPE_SWIM
Definition monster.qh:7
const int MONSTER_SIZE_QUAKE
Definition monster.qh:14
const int MOVETYPE_FLY
Definition movetypes.qh:134
float DEAD_NO
Definition progsdefs.qc:274
bool autocvar_g_fullbrightplayers
Definition client.qh:17
bool autocvar_g_nodepthtestplayers
Definition client.qh:34
bool noalign
Definition items.qh:37
bool iscreature
Definition main.qh:46
void StatusEffects_apply(StatusEffect this, entity actor, float eff_time, int eff_flags)
StatusEffect statuseffects
Entity statuseffects.
void StatusEffects_update(entity e)
void StatusEffects_clearall(entity store)
void Monster_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype,.entity weaponentity, vector hitloc, vector force)
bool Monster_Heal(entity targ, entity inflictor, float amount, float limit)
void Monster_Use(entity this, entity actor, entity trigger)
void Monster_Reset(entity this)
bool Monster_Appear_Check(entity this, Monster monster_id)
void Monster_UpdateModel(entity this)
bool Monster_Spawn_Setup(entity this)
const int MONSTERSKILL_NOTHARD
monster will not spawn on skill >= 3
bool autocvar_g_monsters_quake_resize
bool autocvar_g_monsters_playerclip_collisions
const int MONSTERSKILL_NOTMEDIUM
monster will not spawn on skill 2
int monsters_total
float autocvar_g_monsters_spawnshieldtime
float autocvar_g_monsters
Definition sv_monsters.qh:5
bool autocvar_g_monsters_edit
Definition sv_monsters.qh:6
const int MONSTERSKILL_NOTEASY
monster will not spawn on skill <= 1
IntrusiveList g_monsters
float teleportable
ERASEABLE vector RoundPerfectVector(vector v)
Definition vector.qh:209

References angles, autocvar_g_fullbrightplayers, autocvar_g_monsters, autocvar_g_monsters_edit, autocvar_g_monsters_playerclip_collisions, autocvar_g_monsters_quake_resize, autocvar_g_monsters_spawnshieldtime, autocvar_g_nodepthtestplayers, bot_attack, candrop, classname, CSQCMODEL_AUTOINIT, cvar(), DAMAGE_AIM, damagedbycontents, DEAD_NO, deadflag, DPCONTENTS_BODY, DPCONTENTS_BOTCLIP, DPCONTENTS_MONSTERCLIP, DPCONTENTS_PLAYERCLIP, DPCONTENTS_SOLID, dphitcontentsmask, EF_FULLBRIGHT, EF_NODEPTHTEST, effects, enemy, entity(), FL_FLY, FL_MONSTER, FL_SWIM, flags, g_bot_targets, g_damagedbycontents, g_monsters, grab, gravity, IL_PUSH(), iscreature, Monster::m_maxs, Monster::m_mins, m_name, Monster::m_name, maxs, mdl, mdl_dead, mins, Monster_Appear_Check(), Monster_Damage(), monster_face, Monster_Heal(), monster_moveto, Monster_Remove(), Monster_Reset(), monster_setupcolors(), MONSTER_SIZE_QUAKE, monster_skill, MONSTER_SKILL_EASY, MONSTER_SKILL_HARD, MONSTER_SKILL_MEDIUM, Monster_Spawn_Setup(), Monster_Touch(), MONSTER_TYPE_FLY, MONSTER_TYPE_SWIM, Monster_UpdateModel(), Monster_Use(), monsterdef, MONSTERFLAG_RESPAWNED, MONSTERFLAG_SPAWNED, monsters_total, MONSTERSKILL_NOTEASY, MONSTERSKILL_NOTHARD, MONSTERSKILL_NOTMEDIUM, MOVE_WORLDONLY, moveto, MOVETYPE_FLY, MOVETYPE_WALK, Monster::netname, netname, noalign, NULL, oldtarget2, origin, pos1, pos2, RoundPerfectVector(), scale, set_movetype(), setmodel, settouch, solid, SOLID_BBOX, spawn_time, Monster::spawnflags, spawnflags, statuseffects, StatusEffects_apply(), StatusEffects_clearall(), StatusEffects_update(), takedamage, target2, team, teamplay, teleportable, time, trace_endpos, use, velocity, and view_ofs.

Referenced by Monster_Appear(), Monster_Respawn(), spawnfunc(), spawnfunc(), spawnfunc(), spawnfunc(), spawnfunc(), and spawnmonster().

◆ Monster_Spawn_Setup()

bool Monster_Spawn_Setup ( entity this)

Definition at line 1319 of file sv_monsters.qc.

1320{
1321 Monster mon = this.monsterdef;
1322 mon.mr_setup(mon, this);
1323
1324 // ensure some basic needs are met
1325 if (!GetResource(this, RES_HEALTH))
1326 SetResourceExplicit(this, RES_HEALTH, 100);
1327 if (!GetResource(this, RES_ARMOR))
1328 SetResourceExplicit(this, RES_ARMOR, bound(0.2, 0.5 * MONSTER_SKILLMOD(this), 0.9));
1329 if (!this.target_range) this.target_range = autocvar_g_monsters_target_range;
1334
1336
1337 if (!(this.spawnflags & MONSTERFLAG_RESPAWNED))
1338 {
1339 SetResourceExplicit(this, RES_HEALTH, GetResource(this, RES_HEALTH) * MONSTER_SKILLMOD(this));
1340
1341 if (!this.skin)
1342 this.skin = rint(random() * 4);
1343 }
1344
1345 this.max_health = GetResource(this, RES_HEALTH);
1346 this.pain_finished = this.nextthink;
1347 this.last_enemycheck = this.spawn_time + random(); // slight delay
1348
1349 if (!this.wander_delay)
1350 this.wander_delay = 2;
1351 if (!this.wander_distance)
1352 this.wander_distance = 600;
1353
1356
1357 if (teamplay)
1358 {
1359 if (!this.monster_attack)
1361 this.monster_attack = true; // we can have monster enemies in team games
1362 }
1363
1364 Monster_Sound(this, monstersound_spawn, 0, false, CH_VOICE);
1365
1367 {
1368 entity wp = WaypointSprite_Spawn(WP_Monster, 0, 1024, this, '0 0 1' * (this.maxs.z + 15), NULL, this.team, this, sprite, true, RADARICON_DANGER);
1369 wp.wp_extra = this.monsterdef.monsterid;
1370 wp.colormod = (this.team ? Team_ColorRGB(this.team) : '1 0 0');
1371 if (!(this.spawnflags & MONSTERFLAG_INVINCIBLE))
1372 {
1374 WaypointSprite_UpdateHealth(this.sprite, GetResource(this, RES_HEALTH));
1375 }
1376 }
1377
1378 setthink(this, Monster_Think);
1379 this.nextthink = time;
1380
1381 if (MUTATOR_CALLHOOK(MonsterSpawn, this))
1382 return false;
1383
1384 return true;
1385}
virtual void mr_setup()
(SERVER) setup monster data
Definition monster.qh:58
float rint(float f)
void Monster_Sounds_Update(entity this)
void Monster_Miniboss_Setup(entity this)
void Monster_Sounds_Precache(entity this)
void Monster_Think(entity this)
float autocvar_g_monsters_attack_range
float wander_distance
distance to move between wander delays for monsters
float autocvar_g_monsters_damageforcescale
float autocvar_g_monsters_target_range
float attack_range
melee attack if closer, ranged attack if further away (TODO: separate ranged attack range?...
float autocvar_g_monsters_healthbars
float autocvar_g_monsters_respawn_delay
float last_enemycheck
for checking monster enemy
void WaypointSprite_UpdateMaxHealth(entity e, float f)
entity WaypointSprite_Spawn(entity spr, float _lifetime, float maxdistance, entity ref, vector ofs, entity showto, float t, entity own,.entity ownfield, float hideable, entity icon)

References attack_range, autocvar_g_monsters_attack_range, autocvar_g_monsters_damageforcescale, autocvar_g_monsters_healthbars, autocvar_g_monsters_respawn_delay, autocvar_g_monsters_target_range, bound(), CH_VOICE, damageforcescale, entity(), g_monster_targets, GetResource(), IL_PUSH(), last_enemycheck, max_health, maxs, monster_attack, Monster_Miniboss_Setup(), MONSTER_MOVE_WANDER, monster_moveflags, MONSTER_SKILLMOD, Monster_Sound(), Monster_Sounds_Precache(), Monster_Sounds_Update(), Monster_Think(), monsterdef, MONSTERFLAG_INVINCIBLE, MONSTERFLAG_RESPAWNED, Monster::mr_setup(), MUTATOR_CALLHOOK, nextthink, NULL, pain_finished, random(), RES_ARMOR, respawntime, rint(), SetResourceExplicit(), setthink, skin, spawn_time, spawnflags, sprite, team, Team_ColorRGB(), teamplay, time, wander_delay, wander_distance, WaypointSprite_Spawn(), WaypointSprite_UpdateHealth(), and WaypointSprite_UpdateMaxHealth().

Referenced by Monster_Spawn().

◆ Monster_Think()

void Monster_Think ( entity this)

Definition at line 1279 of file sv_monsters.qc.

1280{
1281 setthink(this, Monster_Think);
1282 this.nextthink = time;
1283
1284 if (this.monster_lifetime && time >= this.monster_lifetime)
1285 {
1286 Damage(this, this, this,
1287 GetResource(this, RES_HEALTH) + this.max_health,
1288 DEATH_KILL.m_id,
1289 DMG_NOWEP,
1290 this.origin,
1291 this.origin
1292 );
1293 return;
1294 }
1295
1296 // TODO: mutator hook to control monster thinking
1297 if (StatusEffects_active(STATUSEFFECT_Frozen, this))
1298 this.enemy = NULL; // TODO: save enemy, and attack when revived?
1299 else if (time >= this.last_enemycheck)
1300 {
1301 Monster_Enemy_Check(this);
1302 this.last_enemycheck = time + 1; // check for enemies every second
1303 }
1304
1305 Monster mon = this.monsterdef;
1306 if (mon.mr_think(mon, this))
1307 {
1308 Monster_Move(this, this.speed2, this.speed, this.stopspeed);
1309
1310 .entity weaponentity = weaponentities[0]; // TODO?
1311 Monster_Attack_Check(this, this.enemy, weaponentity);
1312 }
1313
1314 Monster_Anim(this);
1315
1317}
virtual void mr_think()
(SERVER) logic to run every frame
Definition monster.qh:64
#define CSQCMODEL_AUTOUPDATE(e)
float speed
Definition dynlight.qc:9
void Monster_Move(entity this, float runspeed, float walkspeed, float stpspeed)
void Monster_Anim(entity this)
void Monster_Enemy_Check(entity this)
void Monster_Attack_Check(entity this, entity targ,.entity weaponentity)
float stopspeed
float speed2
monster run speed

References CSQCMODEL_AUTOUPDATE, Damage(), DMG_NOWEP, enemy, entity(), GetResource(), last_enemycheck, max_health, Monster_Anim(), Monster_Attack_Check(), Monster_Enemy_Check(), monster_lifetime, Monster_Move(), Monster_Think(), monsterdef, Monster::mr_think(), nextthink, NULL, setthink, speed, speed2, StatusEffects_active(), stopspeed, time, and weaponentities.

Referenced by Monster_Spawn_Setup(), and Monster_Think().

◆ Monster_Touch()

void Monster_Touch ( entity this,
entity toucher )

Definition at line 510 of file sv_monsters.qc.

511{
512 if (!toucher)
513 return;
514
515 if (toucher.monster_attack && this.enemy != toucher && !IS_MONSTER(toucher)
516 && time >= this.spawn_time
517 && Monster_ValidTarget(this, toucher, true))
518 this.enemy = toucher;
519}
entity entity toucher
Definition self.qh:72

References enemy, entity(), IS_MONSTER, Monster_ValidTarget(), spawn_time, time, and toucher.

Referenced by M_Zombie_Attack_Leap_Touch(), Monster_Dead(), Monster_Move(), and Monster_Spawn().

◆ Monster_UpdateModel()

void Monster_UpdateModel ( entity this)

Definition at line 489 of file sv_monsters.qc.

490{
491 // assume some defaults
492 /*
493 this.anim_idle = animfixfps(this, '0 1 0.01', '0 0 0');
494 this.anim_walk = animfixfps(this, '1 1 0.01', '0 0 0');
495 this.anim_run = animfixfps(this, '2 1 0.01', '0 0 0');
496 this.anim_fire1 = animfixfps(this, '3 1 0.01', '0 0 0');
497 this.anim_fire2 = animfixfps(this, '4 1 0.01', '0 0 0');
498 this.anim_melee = animfixfps(this, '5 1 0.01', '0 0 0');
499 this.anim_pain1 = animfixfps(this, '6 1 0.01', '0 0 0');
500 this.anim_pain2 = animfixfps(this, '7 1 0.01', '0 0 0');
501 this.anim_die1 = animfixfps(this, '8 1 0.01', '0 0 0');
502 this.anim_die2 = animfixfps(this, '9 1 0.01', '0 0 0');
503 */
504
505 // then get the real values
506 Monster mon = this.monsterdef;
507 mon.mr_anim(mon, this);
508}
virtual void mr_anim()
(BOTH?) sets animations for monster
Definition monster.qh:90

References entity(), monsterdef, and Monster::mr_anim().

Referenced by Monster_Spawn().

◆ Monster_Use()

void Monster_Use ( entity this,
entity actor,
entity trigger )

Definition at line 598 of file sv_monsters.qc.

599{
600 if (Monster_ValidTarget(this, actor, true))
601 this.enemy = actor;
602}

References enemy, entity(), and Monster_ValidTarget().

Referenced by Monster_Spawn().

◆ Monster_ValidTarget()

bool Monster_ValidTarget ( entity this,
entity targ,
bool skipfacing )

Definition at line 101 of file sv_monsters.qc.

102{
103 // ensure we're not checking nonexistent monster/target
104 if (!this || !targ)
105 return false;
106
107 if (targ == this
108 || (IS_VEHICLE(targ) && !(this.monsterdef.spawnflags & MON_FLAG_RANGED)) // melee vs vehicle is useless
109 || game_stopped || time < game_starttime // monsters do nothing before match has started
110 || targ.takedamage == DAMAGE_NO
111 || IS_SPEC(targ) || IS_OBSERVER(targ) // don't attack spectators
112 || (!IS_VEHICLE(targ) && (IS_DEAD(targ) || IS_DEAD(this) || GetResource(targ, RES_HEALTH) <= 0 || GetResource(this, RES_HEALTH) <= 0))
113 || this.monster_follow == targ || targ.monster_follow == this
114 || (!IS_VEHICLE(targ) && (targ.flags & FL_NOTARGET))
116 || SAME_TEAM(targ, this)
117 || (targ.alpha != 0 && targ.alpha < 0.5)
118 || (autocvar_g_monsters_lineofsight && !checkpvs(this.origin + this.view_ofs, targ)) // enemy cannot be seen
119 || MUTATOR_CALLHOOK(MonsterValidTarget, this, targ))
120 // if any of the above checks fail, target is not valid
121 return false;
122
123 vector targ_origin = (targ.absmin + targ.absmax) * 0.5;
124 traceline(this.origin + this.view_ofs, targ_origin, MOVE_NOMONSTERS, this); // TODO: maybe we can rely a bit on PVS data instead?
125
126 if (trace_fraction < 1 && trace_ent != targ)
127 return false; // solid
128
130 && this.enemy != targ
131 && !monster_facing(this, targ))
132 return false;
133
134 return true; // this target is valid!
135}
#define PHYS_INPUT_BUTTON_CHAT(s)
Definition player.qh:161
float checkpvs(vector viewpos, entity viewee)
const int MON_FLAG_RANGED
monster shoots projectiles
Definition monster.qh:10
bool autocvar_g_monsters_typefrag
bool autocvar_g_monsters_lineofsight
#define SAME_TEAM(a, b)
Definition teams.qh:241
#define IS_VEHICLE(v)
Definition utils.qh:24

References autocvar_g_monsters_lineofsight, autocvar_g_monsters_target_infront, autocvar_g_monsters_typefrag, checkpvs(), DAMAGE_NO, enemy, entity(), FL_NOTARGET, game_starttime, game_stopped, GetResource(), IS_DEAD, IS_OBSERVER, IS_SPEC, IS_VEHICLE, MON_FLAG_RANGED, monster_facing(), monster_follow, monsterdef, MONSTERFLAG_INFRONT, MOVE_NOMONSTERS, MUTATOR_CALLHOOK, origin, PHYS_INPUT_BUTTON_CHAT, SAME_TEAM, spawnflags, time, trace_ent, trace_fraction, vector, and view_ofs.

Referenced by Monster_Delay_Action(), Monster_Touch(), and Monster_Use().

◆ Monster_WanderTarget()

vector Monster_WanderTarget ( entity this,
vector targetorigin )

Returns an origin that's near targetorigin and visible to this monster.

Definition at line 605 of file sv_monsters.qc.

606{
607 vector ang;
608 ang.y = rint(random() * 500);
609 ang.x = this.angles.x;
610 ang.z = this.angles.z;
612 vector pos = targetorigin + v_forward * this.wander_distance;
613 if (((this.flags & FL_FLY) && (this.spawnflags & MONSTERFLAG_FLY_VERTICAL)) || (this.flags & FL_SWIM))
614 {
615 pos.z = random() * 200;
616 if (random() >= 0.5)
617 pos.z = -pos.z;
618 }
619 // truncate movement so we don't do walking into walls animations
620 traceline(this.origin + this.view_ofs, pos, MOVE_NORMAL, this);
621 return trace_endpos;
622}
vector vector ang
Definition self.qh:92

References ang, angles, entity(), FL_FLY, FL_SWIM, flags, makevectors, MONSTERFLAG_FLY_VERTICAL, MOVE_NORMAL, origin, random(), rint(), spawnflags, trace_endpos, v_forward, vector, view_ofs, and wander_distance.

Referenced by Monster_Move(), and Monster_Move_Target().

◆ monsters_setstatus()

void monsters_setstatus ( entity this)

Definition at line 34 of file sv_monsters.qc.

35{
36 STAT(MONSTERS_TOTAL, this) = monsters_total;
37 STAT(MONSTERS_KILLED, this) = monsters_killed;
38}

References entity(), monsters_killed, monsters_total, and STAT.

Referenced by PlayerThink().

◆ void()

void ( entity )

References entity().

Variable Documentation

◆ draggedby

entity draggedby

Definition at line 783 of file sv_monsters.qc.

Referenced by havocbot_ai(), Monster_Move(), and Monster_Move_2D().

◆ pos1

vector pos1

Definition at line 564 of file sv_monsters.qc.

◆ pos2

vector pos2

Definition at line 565 of file sv_monsters.qc.

◆ skin_for_monstersound

int skin_for_monstersound

Definition at line 356 of file sv_monsters.qc.

Referenced by Monster_Sounds_Update().