]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/common/monsters/sv_monsters.qc
Greatly simplify monster velocity calculation and use an intrusive list for monster...
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / monsters / sv_monsters.qc
index c7d5190e0429a55b006ff086a47998835f28fc95..d7147e0bcedfd7bfefb8f3f0dcdf587e018967f8 100644 (file)
@@ -25,8 +25,8 @@
 
 void monsters_setstatus(entity this)
 {
-       this.stat_monsters_total = monsters_total;
-       this.stat_monsters_killed = monsters_killed;
+       STAT(MONSTERS_TOTAL, this) = monsters_total;
+       STAT(MONSTERS_KILLED, this) = monsters_killed;
 }
 
 void monster_dropitem(entity this, entity attacker)
@@ -46,7 +46,7 @@ void monster_dropitem(entity this, entity attacker)
        if(e && e.monster_loot)
        {
                e.noalign = true;
-               e.monster_loot(e);
+               StartItem(e, e.monster_loot);
                e.gravity = 1;
                set_movetype(e, MOVETYPE_TOSS);
                e.reset = SUB_Remove;
@@ -99,9 +99,10 @@ bool Monster_ValidTarget(entity this, entity targ)
                return false;
        }
 
-       traceline(this.origin + this.view_ofs, targ.origin, MOVE_NOMONSTERS, this);
+       vector targ_origin = ((targ.absmin + targ.absmax) * 0.5);
+       traceline(this.origin + this.view_ofs, targ_origin, MOVE_NOMONSTERS, this);
 
-       if(trace_fraction < 1)
+       if(trace_fraction < 1 && trace_ent != targ)
                return false; // solid
 
        if(autocvar_g_monsters_target_infront || (this.spawnflags & MONSTERFLAG_INFRONT))
@@ -124,7 +125,7 @@ entity Monster_FindTarget(entity this)
        vector my_center = CENTER_OR_VIEWOFS(this);
 
        // find the closest acceptable target to pass to
-       FOREACH_ENTITY_RADIUS(this.origin, this.target_range, it.monster_attack,
+       IL_EACH(g_monster_targets, it.monster_attack && vdist(it.origin - this.origin, <, this.target_range),
        {
                if(Monster_ValidTarget(this, it))
                {
@@ -172,6 +173,8 @@ void monster_changeteam(entity this, int newteam)
        if(!teamplay) { return; }
 
        this.team = newteam;
+       if(!this.monster_attack)
+               IL_PUSH(g_monster_targets, this);
        this.monster_attack = true; // new team, activate attacking
        monster_setupcolors(this);
 
@@ -244,7 +247,7 @@ void Monster_Sound_Precache(string f)
        {
                if(tokenize_console(s) != 3)
                {
-                       LOG_TRACE("Invalid sound info line: ", s);
+                       //LOG_DEBUG("Invalid sound info line: ", s); // probably a comment, no need to spam warnings
                        continue;
                }
                PrecacheGlobalSound(strcat(argv(1), " ", argv(2)));
@@ -298,7 +301,7 @@ bool Monster_Sounds_Load(entity this, string f, int first)
        float fh = fopen(f, FILE_READ);
        if(fh < 0)
        {
-               LOG_TRACE("Monster sound file not found: ", f);
+               //LOG_DEBUG("Monster sound file not found: ", f); // no biggie, monster has no sounds, let's not spam it
                return false;
        }
        while((s = fgets(fh)))
@@ -564,7 +567,7 @@ vector Monster_Move_Target(entity this, entity targ)
                        || ((trace_fraction < 1) && (trace_ent != this.enemy)))
                {
                        this.enemy = NULL;
-                       this.pass_distance = 0;
+                       //this.pass_distance = 0;
                }
 
                if(this.enemy)
@@ -655,12 +658,13 @@ vector Monster_Move_Target(entity this, entity targ)
 
 void Monster_CalculateVelocity(entity this, vector to, vector from, float turnrate, float movespeed)
 {
-       float current_distance = vlen((('1 0 0' * to.x) + ('0 1 0' * to.y)) - (('1 0 0' * from.x) + ('0 1 0' * from.y))); // for the sake of this check, exclude Z axis
-       float initial_height = 0; //min(50, (targ_distance * tanh(20)));
-       float current_height = (initial_height * min(1, (this.pass_distance) ? (current_distance / this.pass_distance) : current_distance));
+       //float current_distance = vlen((('1 0 0' * to.x) + ('0 1 0' * to.y)) - (('1 0 0' * from.x) + ('0 1 0' * from.y))); // for the sake of this check, exclude Z axis
+       //float initial_height = 0; //min(50, (targ_distance * tanh(20)));
+       //float current_height = (initial_height * min(1, (this.pass_distance) ? (current_distance / this.pass_distance) : current_distance));
        //print("current_height = ", ftos(current_height), ", initial_height = ", ftos(initial_height), ".\n");
 
-       vector targpos;
+       vector targpos = to;
+#if 0
        if(current_height) // make sure we can actually do this arcing path
        {
                targpos = (to + ('0 0 1' * current_height));
@@ -676,6 +680,7 @@ void Monster_CalculateVelocity(entity this, vector to, vector from, float turnra
                }
        }
        else { targpos = to; }
+#endif
 
        //this.angles = normalize(('0 1 0' * to_y) - ('0 1 0' * from_y));
 
@@ -693,7 +698,8 @@ void Monster_CalculateVelocity(entity this, vector to, vector from, float turnra
 void Monster_Move(entity this, float runspeed, float walkspeed, float stpspeed)
 {
        // update goal entity if lost
-       if(this.target2 && this.goalentity.targetname != this.target2) { this.goalentity = find(NULL, targetname, this.target2); }
+       if(this.target2 && this.target2 != "" && this.goalentity.targetname != this.target2)
+               this.goalentity = find(NULL, targetname, this.target2);
 
        if(STAT(FROZEN, this) == 2)
        {
@@ -782,7 +788,7 @@ void Monster_Move(entity this, float runspeed, float walkspeed, float stpspeed)
        entity targ = this.goalentity;
 
        if (MUTATOR_CALLHOOK(MonsterMove, this, runspeed, walkspeed, targ)
-               || gameover
+               || game_stopped
                || this.draggedby != NULL
                || (round_handler_IsActive() && !round_handler_IsRoundStarted())
                || time < game_starttime
@@ -817,7 +823,7 @@ void Monster_Move(entity this, float runspeed, float walkspeed, float stpspeed)
                                this.monster_moveto = '0 0 0';
                                this.monster_face = '0 0 0';
 
-                               this.pass_distance = vlen((('1 0 0' * this.enemy.origin_x) + ('0 1 0' * this.enemy.origin_y)) - (('1 0 0' *  this.origin_x) + ('0 1 0' *  this.origin_y)));
+                               //this.pass_distance = vlen((('1 0 0' * this.enemy.origin_x) + ('0 1 0' * this.enemy.origin_y)) - (('1 0 0' *  this.origin_x) + ('0 1 0' *  this.origin_y)));
                                Monster_Sound(this, monstersound_sight, 0, false, CH_VOICE);
                        }
                }
@@ -866,9 +872,9 @@ void Monster_Move(entity this, float runspeed, float walkspeed, float stpspeed)
        else
        {
                entity e = this.goalentity; //find(NULL, targetname, this.target2);
-               if(e.target2)
+               if(e.target2 && e.target2 != "")
                        this.target2 = e.target2;
-               else if(e.target) // compatibility
+               else if(e.target && e.target != "") // compatibility
                        this.target2 = e.target;
 
                movelib_brake_simple(this, stpspeed);
@@ -1010,6 +1016,9 @@ void Monster_Dead(entity this, entity attacker, float gibbed)
                totalspawned -= 1;
        }
 
+       if(!gibbed && this.mdl_dead && this.mdl_dead != "")
+               _setmodel(this, this.mdl_dead);
+
        this.event_damage       = ((gibbed) ? func_null : Monster_Dead_Damage);
        this.solid                      = SOLID_CORPSE;
        this.takedamage         = DAMAGE_AIM;
@@ -1073,8 +1082,8 @@ void Monster_Damage(entity this, entity inflictor, entity attacker, float damage
 
        this.dmg_time = time;
 
-       if(sound_allowed(MSG_BROADCAST, attacker) && deathtype != DEATH_DROWN.m_id)
-               spamsound (this, CH_PAIN, SND(BODYIMPACT1), VOL_BASE, ATTEN_NORM);  // FIXME: PLACEHOLDER
+       if(deathtype != DEATH_DROWN.m_id && deathtype != DEATH_FIRE.m_id && sound_allowed(MSG_BROADCAST, attacker))
+               spamsound (this, CH_PAIN, SND_BODYIMPACT1, VOL_BASE, ATTEN_NORM);  // FIXME: PLACEHOLDER
 
        this.velocity += force * this.damageforcescale;
 
@@ -1115,7 +1124,7 @@ void Monster_Damage(entity this, entity inflictor, entity attacker, float damage
 // don't check for enemies, just keep walking in a straight line
 void Monster_Move_2D(entity this, float mspeed, bool allow_jumpoff)
 {
-       if(gameover || (round_handler_IsActive() && !round_handler_IsRoundStarted()) || this.draggedby != NULL || time < game_starttime || (autocvar_g_campaign && !campaign_bots_may_start) || time < this.spawn_time)
+       if(game_stopped || (round_handler_IsActive() && !round_handler_IsRoundStarted()) || this.draggedby != NULL || time < game_starttime || (autocvar_g_campaign && !campaign_bots_may_start) || time < this.spawn_time)
        {
                mspeed = 0;
                if(time >= this.spawn_time)
@@ -1256,7 +1265,11 @@ bool Monster_Spawn_Setup(entity this)
        Monster_Sounds_Update(this);
 
        if(teamplay)
+       {
+               if(!this.monster_attack)
+                       IL_PUSH(g_monster_targets, this);
                this.monster_attack = true; // we can have monster enemies in team games
+       }
 
        Monster_Sound(this, monstersound_spawn, 0, false, CH_VOICE);
 
@@ -1290,7 +1303,13 @@ bool Monster_Spawn(entity this, bool check_appear, int mon_id)
        if(!autocvar_g_monsters) { Monster_Remove(this); return false; }
 
        if(!(this.spawnflags & MONSTERFLAG_RESPAWNED))
+       {
                IL_PUSH(g_monsters, this);
+               if(this.mdl && this.mdl != "")
+                       precache_model(this.mdl);
+               if(this.mdl_dead && this.mdl_dead != "")
+                       precache_model(this.mdl_dead);
+       }
 
        if(check_appear && Monster_Appear_Check(this, mon_id)) { return true; } // return true so the monster isn't removed
 
@@ -1309,7 +1328,11 @@ bool Monster_Spawn(entity this, bool check_appear, int mon_id)
        if(!(this.spawnflags & MONSTERFLAG_RESPAWNED)) // don't count re-spawning monsters either
                monsters_total += 1;
 
-       setmodel(this, mon.m_model);
+       if(this.mdl && this.mdl != "")
+               _setmodel(this, this.mdl);
+       else
+               setmodel(this, mon.m_model);
+
        this.flags                              = FL_MONSTER;
        this.classname                  = "monster";
        this.takedamage                 = DAMAGE_AIM;
@@ -1340,7 +1363,7 @@ bool Monster_Spawn(entity this, bool check_appear, int mon_id)
        this.candrop                    = true;
        this.view_ofs                   = '0 0 0.7' * (this.maxs_z * 0.5);
        this.oldtarget2                 = this.target2;
-       this.pass_distance              = 0;
+       //this.pass_distance            = 0;
        this.deadflag                   = DEAD_NO;
        this.spawn_time                 = time;
        this.gravity                    = 1;
@@ -1374,7 +1397,7 @@ bool Monster_Spawn(entity this, bool check_appear, int mon_id)
                        this.scale *= 1.3;
        }
 
-       setsize(this, mon.mins * this.scale, mon.maxs * this.scale);
+       setsize(this, mon.m_mins * this.scale, mon.m_maxs * this.scale);
 
        this.ticrate = bound(sys_frametime, ((!this.ticrate) ? autocvar_g_monsters_think_delay : this.ticrate), 60);