]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/common/monsters/sv_monsters.qc
Minor monster code cleanup
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / monsters / sv_monsters.qc
index c72c7461ed5e039f39b949c0c5a6543803e3b9f8..f0f789af3762ffcf1a9ebdf8e1b2697c945b9599 100644 (file)
@@ -1,29 +1,27 @@
-#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)
 {
@@ -36,7 +34,7 @@ void monster_dropitem(entity this, entity attacker)
        if(!this.candrop || !this.monster_loot)
                return;
 
-       vector org = this.origin + ((this.mins + this.maxs) * 0.5);
+       vector org = CENTER_OR_VIEWOFS(this);
        entity e = new(droppedweapon); // use weapon handling to remove it on touch
        e.spawnfunc_checked = true;
 
@@ -82,7 +80,7 @@ bool Monster_ValidTarget(entity this, entity targ)
 
        if((targ == this)
        || (autocvar_g_monsters_lineofsight && !checkpvs(this.origin + this.view_ofs, targ)) // enemy cannot be seen
-       || (IS_VEHICLE(targ) && !((get_monsterinfo(this.monsterid)).spawnflags & MON_FLAG_RANGED)) // melee vs vehicle is useless
+       || (IS_VEHICLE(targ) && !((Monsters_from(this.monsterid)).spawnflags & MON_FLAG_RANGED)) // melee vs vehicle is useless
        || (time < game_starttime) // monsters do nothing before match has started
        || (targ.takedamage == DAMAGE_NO)
        || (targ.items & IT_INVISIBILITY)
@@ -101,18 +99,16 @@ bool Monster_ValidTarget(entity this, entity targ)
                return false;
        }
 
-       traceline(this.origin + this.view_ofs, targ.origin, 0, this);
+       traceline(this.origin + this.view_ofs, targ.origin, MOVE_NOMONSTERS, this);
 
-       if((trace_fraction < 1) && (trace_ent != targ))
-               return false;
+       if(trace_fraction < 1)
+               return false; // solid
 
        if(autocvar_g_monsters_target_infront || (this.spawnflags & MONSTERFLAG_INFRONT))
        if(this.enemy != targ)
        {
-               float dot;
-
                makevectors (this.angles);
-               dot = normalize (targ.origin - this.origin) * v_forward;
+               float dot = normalize (targ.origin - this.origin) * v_forward;
 
                if(dot <= autocvar_g_monsters_target_infront_range) { return false; }
        }
@@ -120,25 +116,25 @@ bool Monster_ValidTarget(entity this, entity targ)
        return true; // this target is valid!
 }
 
-entity Monster_FindTarget(entity mon)
+entity Monster_FindTarget(entity this)
 {
-       if(MUTATOR_CALLHOOK(MonsterFindTarget)) { return mon.enemy; } // Handled by a mutator
+       if(MUTATOR_CALLHOOK(MonsterFindTarget)) { return this.enemy; } // Handled by a mutator
 
        entity closest_target = NULL;
+       vector my_center = CENTER_OR_VIEWOFS(this);
 
        // find the closest acceptable target to pass to
-       FOREACH_ENTITY_RADIUS(mon.origin, mon.target_range, it.monster_attack,
+       FOREACH_ENTITY_RADIUS(this.origin, this.target_range, it.monster_attack,
        {
-               if(Monster_ValidTarget(mon, it))
+               if(Monster_ValidTarget(this, 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(it);
-                       vector ent_center = CENTER_OR_VIEWOFS(mon);
+                       vector targ_center = CENTER_OR_VIEWOFS(it);
 
                        if(closest_target)
                        {
                                vector closest_target_center = CENTER_OR_VIEWOFS(closest_target);
-                               if(vlen2(ent_center - head_center) < vlen2(ent_center - closest_target_center))
+                               if(vlen2(my_center - targ_center) < vlen2(my_center - closest_target_center))
                                        { closest_target = it; }
                        }
                        else { closest_target = it; }
@@ -148,43 +144,43 @@ entity Monster_FindTarget(entity mon)
        return closest_target;
 }
 
-void monster_setupcolors(entity mon)
+void monster_setupcolors(entity this)
 {
-       if(IS_PLAYER(mon.realowner))
-               mon.colormap = mon.realowner.colormap;
-       else if(teamplay && mon.team)
-               mon.colormap = 1024 + (mon.team - 1) * 17;
+       if(IS_PLAYER(this.realowner))
+               this.colormap = this.realowner.colormap;
+       else if(teamplay && this.team)
+               this.colormap = 1024 + (this.team - 1) * 17;
        else
        {
-               if(mon.monster_skill <= MONSTER_SKILL_EASY)
-                       mon.colormap = 1029;
-               else if(mon.monster_skill <= MONSTER_SKILL_MEDIUM)
-                       mon.colormap = 1027;
-               else if(mon.monster_skill <= MONSTER_SKILL_HARD)
-                       mon.colormap = 1038;
-               else if(mon.monster_skill <= MONSTER_SKILL_INSANE)
-                       mon.colormap = 1028;
-               else if(mon.monster_skill <= MONSTER_SKILL_NIGHTMARE)
-                       mon.colormap = 1032;
+               if(this.monster_skill <= MONSTER_SKILL_EASY)
+                       this.colormap = 1029;
+               else if(this.monster_skill <= MONSTER_SKILL_MEDIUM)
+                       this.colormap = 1027;
+               else if(this.monster_skill <= MONSTER_SKILL_HARD)
+                       this.colormap = 1038;
+               else if(this.monster_skill <= MONSTER_SKILL_INSANE)
+                       this.colormap = 1028;
+               else if(this.monster_skill <= MONSTER_SKILL_NIGHTMARE)
+                       this.colormap = 1032;
                else
-                       mon.colormap = 1024;
+                       this.colormap = 1024;
        }
 }
 
-void monster_changeteam(entity ent, float newteam)
+void monster_changeteam(entity this, int newteam)
 {
        if(!teamplay) { return; }
 
-       ent.team = newteam;
-       ent.monster_attack = true; // new team, activate attacking
-       monster_setupcolors(ent);
+       this.team = newteam;
+       this.monster_attack = true; // new team, activate attacking
+       monster_setupcolors(this);
 
-       if(ent.sprite)
+       if(this.sprite)
        {
-               WaypointSprite_UpdateTeamRadar(ent.sprite, RADARICON_DANGER, ((newteam) ? Team_ColorRGB(newteam) : '1 0 0'));
+               WaypointSprite_UpdateTeamRadar(this.sprite, RADARICON_DANGER, ((newteam) ? Team_ColorRGB(newteam) : '1 0 0'));
 
-               ent.sprite.team = newteam;
-               ent.sprite.SendFlags |= 1;
+               this.sprite.team = newteam;
+               this.sprite.SendFlags |= 1;
        }
 }
 
@@ -297,10 +293,9 @@ void Monster_Sounds_Clear(entity this)
 
 bool Monster_Sounds_Load(entity this, string f, int first)
 {
-       float fh;
        string s;
        var .string field;
-       fh = fopen(f, FILE_READ);
+       float fh = fopen(f, FILE_READ);
        if(fh < 0)
        {
                LOG_TRACE("Monster sound file not found: ", f);
@@ -332,7 +327,7 @@ void Monster_Sounds_Update(entity this)
                Monster_Sounds_Load(this, get_monster_model_datafilename(this.model, 0, "sounds"), 0);
 }
 
-void Monster_Sound(entity this, .string samplefield, float sound_delay, float delaytoo, float chan)
+void Monster_Sound(entity this, .string samplefield, float sound_delay, bool delaytoo, float chan)
 {
        if(!autocvar_g_monsters_sounds) { return; }
 
@@ -386,7 +381,7 @@ bool Monster_Attack_Leap_Check(entity this, vector vel)
        this.velocity = vel;
        tracetoss(this, this);
        this.velocity = old;
-       if (trace_ent != this.enemy)
+       if(trace_ent != this.enemy)
                return false;
 
        return true;
@@ -399,12 +394,12 @@ bool Monster_Attack_Leap(entity this, vector anm, void(entity this, entity touch
 
        setanim(this, anm, false, true, false);
 
-       if(this.animstate_endtime > time && (this.flags & FL_MONSTER))
+       if(this.animstate_endtime > time && IS_MONSTER(this))
                this.attack_finished_single[0] = this.anim_finished = this.animstate_endtime;
        else
                this.attack_finished_single[0] = this.anim_finished = time + animtime;
 
-       if(this.flags & FL_MONSTER)
+       if(IS_MONSTER(this))
                this.state = MONSTER_ATTACK_RANGED;
        settouch(this, touchfunc);
        this.origin_z += 1;
@@ -416,14 +411,14 @@ bool Monster_Attack_Leap(entity this, vector anm, void(entity this, entity touch
 
 void Monster_Attack_Check(entity this, entity targ)
 {
-       if((this == NULL || targ == NULL)
+       if((!this || !targ)
        || (!this.monster_attackfunc)
        || (time < this.attack_finished_single[0])
        ) { return; }
 
        if(vdist(targ.origin - this.origin, <=, this.attack_range))
        {
-               bool attack_success = this.monster_attackfunc(MONSTER_ATTACK_MELEE, this, targ);
+               int attack_success = this.monster_attackfunc(MONSTER_ATTACK_MELEE, this, targ);
                if(attack_success == 1)
                        Monster_Sound(this, monstersound_melee, 0, false, CH_VOICE);
                else if(attack_success > 0)
@@ -432,7 +427,7 @@ void Monster_Attack_Check(entity this, entity targ)
 
        if(vdist(targ.origin - this.origin, >, this.attack_range))
        {
-               float attack_success = this.monster_attackfunc(MONSTER_ATTACK_RANGED, this, targ);
+               int attack_success = this.monster_attackfunc(MONSTER_ATTACK_RANGED, this, targ);
                if(attack_success == 1)
                        Monster_Sound(this, monstersound_melee, 0, false, CH_VOICE);
                else if(attack_success > 0)
@@ -460,7 +455,7 @@ void Monster_UpdateModel(entity this)
        this.anim_die2   = animfixfps(this, '9 1 0.01', '0 0 0');*/
 
        // then get the real values
-       Monster mon = get_monsterinfo(this.monsterid);
+       Monster mon = Monsters_from(this.monsterid);
        mon.mr_anim(mon, this);
 }
 
@@ -507,7 +502,9 @@ bool Monster_Respawn_Check(entity this)
        return true;
 }
 
-void Monster_Respawn(entity this) { Monster_Spawn(this, this.monsterid); }
+void Monster_Respawn(entity this) { Monster_Spawn(this, true, this.monsterid); }
+
+.vector        pos1, pos2;
 
 void Monster_Dead_Fade(entity this)
 {
@@ -544,6 +541,7 @@ 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
@@ -553,7 +551,8 @@ vector Monster_Move_Target(entity this, entity targ)
                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 == NULL)
+               // cases where the enemy may have changed their state (don't need to check everything here)
+               if((!this.enemy)
                        || (IS_DEAD(this.enemy) || this.enemy.health < 1)
                        || (STAT(FROZEN, this.enemy))
                        || (this.enemy.flags & FL_NOTARGET)
@@ -687,12 +686,12 @@ void Monster_CalculateVelocity(entity this, vector to, vector from, float turnra
 }
 
 .entity draggedby;
+.entity target2;
 
 void Monster_Move(entity this, float runspeed, float walkspeed, float stpspeed)
 {
-       if(this.target2) { this.goalentity = find(NULL, targetname, this.target2); }
-
-       entity targ;
+       // update goal entity if lost
+       if(this.target2 && this.goalentity.targetname != this.target2) { this.goalentity = find(NULL, targetname, this.target2); }
 
        if(STAT(FROZEN, this) == 2)
        {
@@ -778,7 +777,7 @@ void Monster_Move(entity this, float runspeed, float walkspeed, float stpspeed)
                }
        }
 
-       targ = this.goalentity;
+       entity targ = this.goalentity;
 
        if (MUTATOR_CALLHOOK(MonsterMove, this, runspeed, walkspeed, targ)
                || gameover
@@ -799,8 +798,7 @@ void Monster_Move(entity this, float runspeed, float walkspeed, float stpspeed)
        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(teamplay && autocvar_g_monsters_teams)
        if(DIFF_TEAM(this.monster_follow, this))
                this.monster_follow = NULL;
 
@@ -852,13 +850,12 @@ void Monster_Move(entity this, float runspeed, float walkspeed, float stpspeed)
 
        if(vdist(this.origin - this.moveto, >, 100))
        {
-               float do_run = (this.enemy || this.monster_moveto);
+               bool do_run = (this.enemy || this.monster_moveto);
                if(IS_ONGROUND(this) || ((this.flags & FL_FLY) || (this.flags & FL_SWIM)))
                        Monster_CalculateVelocity(this, this.moveto, this.origin, true, ((do_run) ? runspeed : walkspeed));
 
-               if(time > this.pain_finished) // TODO: use anim_finished instead!
+               if(time > this.pain_finished && time > this.anim_finished) // TODO: use anim_finished instead!?
                if(!this.state)
-               if(time > this.anim_finished)
                if(vdist(this.velocity, >, 10))
                        setanim(this, ((do_run) ? this.anim_run : this.anim_walk), true, false, false);
                else
@@ -866,15 +863,14 @@ void Monster_Move(entity this, float runspeed, float walkspeed, float stpspeed)
        }
        else
        {
-               entity e = find(NULL, targetname, this.target2);
+               entity e = this.goalentity; //find(NULL, targetname, this.target2);
                if(e.target2)
                        this.target2 = e.target2;
-               else if(e.target)
+               else if(e.target) // compatibility
                        this.target2 = e.target;
 
                movelib_brake_simple(this, stpspeed);
-               if(time > this.anim_finished)
-               if(time > this.pain_finished)
+               if(time > this.anim_finished && time > this.pain_finished)
                if(!this.state)
                if(vdist(this.velocity, <=, 30))
                        setanim(this, this.anim_idle, true, false, false);
@@ -931,8 +927,7 @@ void Monster_Dead_Think(entity this)
 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);
+       Monster_Spawn(this, false, this.monsterid);
 }
 
 bool Monster_Appear_Check(entity this, int monster_id)
@@ -1030,7 +1025,7 @@ void Monster_Dead(entity this, entity attacker, float gibbed)
 
        CSQCModel_UnlinkEntity(this);
 
-       Monster mon = get_monsterinfo(this.monsterid);
+       Monster mon = Monsters_from(this.monsterid);
        mon.mr_death(mon, this);
 
        if(this.candrop && this.weapon)
@@ -1054,14 +1049,11 @@ void Monster_Damage(entity this, entity inflictor, entity attacker, float damage
        if(deathtype == DEATH_FALL.m_id && this.draggedby != NULL)
                return;
 
-       vector v;
-       float take, save;
-
-       v = healtharmor_applydamage(100, this.armorvalue / 100, deathtype, damage);
-       take = v_x;
-       save = v_y;
+       vector v = healtharmor_applydamage(100, this.armorvalue / 100, deathtype, damage);
+       float take = v.x;
+       //float save = v.y;
 
-       Monster mon = get_monsterinfo(this.monsterid);
+       Monster mon = Monsters_from(this.monsterid);
        take = mon.mr_pain(mon, this, take, attacker, deathtype);
 
        if(take)
@@ -1126,23 +1118,19 @@ void Monster_Move_2D(entity this, float mspeed, bool allow_jumpoff)
                return;
        }
 
-       float reverse = false;
-       vector a, b;
-
        makevectors(this.angles);
-       a = this.origin + '0 0 16';
-       b = this.origin + '0 0 16' + v_forward * 32;
+       vector a = CENTER_OR_VIEWOFS(this);
+       vector b = CENTER_OR_VIEWOFS(this) + v_forward * 32;
 
        traceline(a, b, MOVE_NORMAL, this);
 
+       bool reverse = false;
        if(trace_fraction != 1.0)
-       {
                reverse = true;
-
-               if(trace_ent)
-               if(IS_PLAYER(trace_ent) && !(trace_ent.items & IT_STRENGTH))
-                       reverse = false;
-       }
+       if(trace_ent && IS_PLAYER(trace_ent) && !(trace_ent.items & ITEM_Strength.m_itemid))
+               reverse = false;
+       if(trace_ent && IS_MONSTER(trace_ent))
+               reverse = true;
 
        // TODO: fix this... tracing is broken if the floor is thin
        /*
@@ -1162,8 +1150,7 @@ void Monster_Move_2D(entity this, float mspeed, bool allow_jumpoff)
 
        movelib_move_simple_gravity(this, v_forward, mspeed, 1);
 
-       if(time > this.pain_finished)
-       if(time > this.attack_finished_single[0])
+       if(time > this.pain_finished && time > this.attack_finished_single[0])
        if(vdist(this.velocity, >, 10))
                setanim(this, this.anim_walk, true, false, false);
        else
@@ -1210,16 +1197,15 @@ void Monster_Anim(entity this)
 void Monster_Think(entity this)
 {
        setthink(this, Monster_Think);
-       this.nextthink = this.ticrate;
+       this.nextthink = time + this.ticrate;
 
-       if(this.monster_lifetime)
-       if(time >= this.monster_lifetime)
+       if(this.monster_lifetime && time >= this.monster_lifetime)
        {
                Damage(this, this, this, this.health + this.max_health, DEATH_KILL.m_id, this.origin, this.origin);
                return;
        }
 
-       Monster mon = get_monsterinfo(this.monsterid);
+       Monster mon = Monsters_from(this.monsterid);
        if(mon.mr_think(mon, this))
                Monster_Move(this, this.speed2, this.speed, this.stopspeed);
 
@@ -1289,7 +1275,7 @@ bool Monster_Spawn_Setup(entity this)
        return true;
 }
 
-bool Monster_Spawn(entity this, int mon_id)
+bool Monster_Spawn(entity this, bool check_appear, int mon_id)
 {
        // setup the basic required properties for a monster
        entity mon = Monsters_from(mon_id);
@@ -1300,7 +1286,7 @@ bool Monster_Spawn(entity this, int mon_id)
        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(check_appear && Monster_Appear_Check(this, mon_id)) { return true; } // return true so the monster isn't removed
 
        if(!this.monster_skill)
                this.monster_skill = cvar("g_monsters_skill");
@@ -1321,9 +1307,13 @@ bool Monster_Spawn(entity this, int mon_id)
        this.flags                              = FL_MONSTER;
        this.classname                  = "monster";
        this.takedamage                 = DAMAGE_AIM;
+       if(!this.bot_attack)
+               IL_PUSH(g_bot_targets, this);
        this.bot_attack                 = true;
        this.iscreature                 = true;
        this.teleportable               = true;
+       if(!this.damagedbycontents)
+               IL_PUSH(g_damagedbycontents, this);
        this.damagedbycontents  = true;
        this.monsterid                  = mon_id;
        this.event_damage               = Monster_Damage;
@@ -1346,13 +1336,13 @@ bool Monster_Spawn(entity this, int mon_id)
        this.oldtarget2                 = this.target2;
        this.pass_distance              = 0;
        this.deadflag                   = DEAD_NO;
-       this.noalign                    = ((mon.spawnflags & MONSTER_TYPE_FLY) || (mon.spawnflags & MONSTER_TYPE_SWIM));
        this.spawn_time                 = time;
        this.gravity                    = 1;
        this.monster_moveto             = '0 0 0';
        this.monster_face               = '0 0 0';
        this.dphitcontentsmask  = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_BOTCLIP | DPCONTENTS_MONSTERCLIP;
 
+       if(!this.noalign) { this.noalign = ((mon.spawnflags & MONSTER_TYPE_FLY) || (mon.spawnflags & MONSTER_TYPE_SWIM)); }
        if(!this.scale) { this.scale = 1; }
        if(autocvar_g_monsters_edit) { this.grab = 1; }
        if(autocvar_g_fullbrightplayers) { this.effects |= EF_FULLBRIGHT; }