]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/monsters/lib/monsters.qc
Remove distance check in attack code (enemy is lost at that distance anyway)
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / monsters / lib / monsters.qc
index f7612a76b35a2e076c926a23c76ac51d94a9d4bc..7e05788494ac3020372f0bb9f1c586516b398b37 100644 (file)
@@ -2,7 +2,7 @@
 
 void M_Item_Touch ()
 {
-       if(self && other.classname == STR_PLAYER && other.deadflag == DEAD_NO)
+       if(self && IS_PLAYER(other) && other.deadflag == DEAD_NO)
        {
                Item_Touch();
                self.think = SUB_Remove;
@@ -12,8 +12,6 @@ void M_Item_Touch ()
 
 void Monster_DropItem (string itype, string itemsize)
 {
-       if(itype == "0")
-               return; // someone didnt want an item...
        vector backuporigin = self.origin + ((self.mins + self.maxs) * 0.5);
        entity oldself;
        
@@ -25,7 +23,7 @@ void Monster_DropItem (string itype, string itemsize)
                if(itemsize == "large") spawnfunc_item_armor_large();
                else if (itemsize == "small") spawnfunc_item_armor_small();
                else if (itemsize == "medium") spawnfunc_item_armor_medium();
-               else print("Invalid monster drop item selected.\n");
+               else dprint("Invalid monster drop item selected.\n");
        }
        else if (itype == "health")
        {
@@ -33,7 +31,7 @@ void Monster_DropItem (string itype, string itemsize)
                else if (itemsize == "small") spawnfunc_item_health_small();
                else if (itemsize == "medium") spawnfunc_item_health_medium();
                else if (itemsize == "mega") spawnfunc_item_health_mega();
-               else print("Invalid monster drop item selected.\n");
+               else dprint("Invalid monster drop item selected.\n");
        }
        else if (itype == "ammo")
        {
@@ -41,7 +39,13 @@ void Monster_DropItem (string itype, string itemsize)
                else if (itemsize == "cells") spawnfunc_item_cells();
                else if (itemsize == "bullets") spawnfunc_item_bullets();
                else if (itemsize == "rockets") spawnfunc_item_rockets();
-               else print("Invalid monster drop item selected.\n");
+               else dprint("Invalid monster drop item selected.\n");
+       }
+       else
+       {
+               dprint("Invalid monster drop item selected.\n");
+               self = oldself;
+               return;
        }
        
        self.velocity = randomvec() * 175 + '0 0 325';
@@ -56,7 +60,7 @@ void Monster_DropItem (string itype, string itemsize)
        self = oldself;
 }
 
-float monster_isvalidtarget (entity targ, entity ent, float neutral)
+float monster_isvalidtarget (entity targ, entity ent)
 {
        if(!targ || !ent)
                return FALSE; // this check should fix a crash
@@ -69,22 +73,19 @@ float monster_isvalidtarget (entity targ, entity ent, float neutral)
                
        traceline(ent.origin, targ.origin, FALSE, ent);
        
-       if(vlen(targ.origin - ent.origin) >= 2000)
+       if(vlen(targ.origin - ent.origin) >= ent.target_range)
                return FALSE; // enemy is too far away
 
        if(trace_ent != targ)
                return FALSE; // we can't see the enemy
                
-       if(neutral == TRUE)
-               return TRUE; // we come in peace!
-               
        if(targ.takedamage == DAMAGE_NO)
                return FALSE; // enemy can't be damaged
                
        if(targ.items & IT_INVISIBILITY)
                return FALSE; // enemy is invisible
        
-       if(targ.classname == STR_SPECTATOR || targ.classname == STR_OBSERVER)
+       if(IS_SPEC(targ) || IS_OBSERVER(targ))
                return FALSE; // enemy is a spectator
        
        if(targ.deadflag != DEAD_NO || ent.deadflag != DEAD_NO || targ.health <= 0 || ent.health <= 0)
@@ -100,13 +101,53 @@ float monster_isvalidtarget (entity targ, entity ent, float neutral)
        if(targ.BUTTON_CHAT)
                return FALSE; // no typefragging!
        
-       if(teamplay)
-       if(targ.team == ent.team)
+       if not(IsDifferentTeam(targ, ent))
                return FALSE; // enemy is on our team
        
        return TRUE;
 }
 
+float enemy_stillvalidtarget(entity targ, entity e)
+{
+       if(targ.health < 1 || targ.deadflag)
+               return FALSE; // let's not keep hurting a corpse
+               
+       if not(autocvar_g_monsters_typefrag)
+       if(targ.BUTTON_CHAT)
+               return FALSE; // no typefrags!
+               
+       if(vlen(targ.origin - e.origin) > e.target_range)
+               return FALSE; // out of our reach
+               
+       if not(targ.takedamage)
+               return FALSE; // can't hurt it
+               
+       if(targ.flags & FL_NOTARGET)
+               return FALSE; // can't target it
+               
+       if(targ.items & IT_INVISIBILITY)
+               return FALSE; // currently not used
+               
+       if(!IsDifferentTeam(targ, e))
+               return FALSE;
+               
+       return TRUE; // all is good, keep going!
+}
+
+entity FindTarget (entity ent) 
+{
+       if(MUTATOR_CALLHOOK(MonsterFindTarget)) { return ent.enemy; } // Handled by a mutator
+       local entity e;
+       for(e = world; (e = findflags(e, monster_attack, TRUE)); ) 
+       {
+               if(monster_isvalidtarget(e, ent))
+               {
+                       return e;
+               }
+       }
+       return world;
+}
+
 void MonsterTouch ()
 {
        if(other == world)
@@ -114,10 +155,33 @@ void MonsterTouch ()
                
        if(self.enemy != other)
        if not(other.flags & FL_MONSTER)
-       if(monster_isvalidtarget(other, self, FALSE))
+       if(monster_isvalidtarget(other, self))
                self.enemy = other;
 }
 
+void monster_sound(string msound, float sound_delay, float delaytoo)
+{
+       if(delaytoo && time < self.msound_delay)
+               return; // too early
+               
+       if(msound == "")
+               return; // sound doesn't exist
+
+       sound(self, CH_PAIN_SINGLE, msound, VOL_BASE, ATTN_NORM);
+
+       self.msound_delay = time + sound_delay;
+}
+
+void monster_precachesounds()
+{
+       precache_sound(self.msound_idle);
+       precache_sound(self.msound_death);
+       precache_sound(self.msound_attack_melee);
+       precache_sound(self.msound_attack_ranged);
+       precache_sound(self.msound_sight);
+       precache_sound(self.msound_pain);
+}
+
 void monster_melee (entity targ, float damg, float er, float deathtype)
 {
        float bigdmg = 0, rdmg = damg * random();
@@ -132,14 +196,14 @@ void monster_melee (entity targ, float damg, float er, float deathtype)
                
        bigdmg = rdmg * self.scale;
        
-       if(random() < 0.01) // critical hit ftw
-               bigdmg = 200;
-       
        Damage(targ, self, self, bigdmg * monster_skill, deathtype, targ.origin, normalize(targ.origin - self.origin));
 }
 
 void Monster_CheckDropCvars (string mon)
 {
+       if not(self.candrop)
+               return; // forced off
+       
        string dropitem;
        string dropsize;
        
@@ -172,53 +236,62 @@ void Monster_CheckMinibossFlag ()
        if(MUTATOR_CALLHOOK(MonsterCheckBossFlag))
                return;
                
-       float healthboost = autocvar_g_monsters_miniboss_healthboost;
-       float r = random() * 4;
+       float r = random() * 4, chance = random() * 100;
 
        // g_monsters_miniboss_chance cvar or spawnflags 64 causes a monster to be a miniboss
-       if ((self.spawnflags & MONSTERFLAG_MINIBOSS) || (random() * 100 < autocvar_g_monsters_miniboss_chance))
+       if ((self.spawnflags & MONSTERFLAG_MINIBOSS) || (chance < autocvar_g_monsters_miniboss_chance))
        {
-               if (r < 2 || self.team == COLOR_TEAM2)
+               self.health += autocvar_g_monsters_miniboss_healthboost;
+               ScaleMonster(1.5);
+               self.flags |= MONSTERFLAG_MINIBOSS;
+               
+               if (r < 2 || self.team == NUM_TEAM_2)
                {
                        self.strength_finished = -1;  
-                       healthboost *= monster_skill;
                        self.effects |= (EF_FULLBRIGHT | EF_BLUE);
                }
-               else if (r >= 1 || self.team == COLOR_TEAM1)
+               else if (r >= 1 || self.team == NUM_TEAM_1)
                {
                        self.invincible_finished = -1;
-                       healthboost *= bound(0.5, monster_skill, 1.5);
                        self.effects |= (EF_FULLBRIGHT | EF_RED);
                }
-               self.health += healthboost;
-               self.cnt += 20;
-               ScaleMonster(1.5);
-               self.flags |= MONSTERFLAG_MINIBOSS;
-               if(teamplay && autocvar_g_monsters_teams)
+               else
+                       self.effects |= (EF_FULLBRIGHT | EF_RED | EF_BLUE);
+               
+               if(teamplay)
+               if(self.team)
                        return;
-               do
-               {
-                       self.colormod_x = random();
-                       self.colormod_y = random();
-                       self.colormod_z = random();
-                       self.colormod = normalize(self.colormod);
-               }
-               while (self.colormod_x > 0.6 && self.colormod_y > 0.6 && self.colormod_z > 0.6);
+                       
+               self.colormod = randomvec() * 4;
        }
 }
 
+float Monster_CanRespawn(entity ent)
+{
+       other = ent;
+       if(MUTATOR_CALLHOOK(MonsterRespawn))
+               return TRUE; // enabled by a mutator
+               
+       if(ent.spawnflags & MONSTERFLAG_NORESPAWN)
+               return FALSE;
+               
+       if not(autocvar_g_monsters_respawn)
+               return FALSE;
+               
+       return TRUE;
+}
+
 void Monster_Fade ()
 {
-       if not(self.spawnflags & MONSTERFLAG_NORESPAWN)
-       if(autocvar_g_monsters_respawn)
+       if(Monster_CanRespawn(self))
        {
                self.monster_respawned = TRUE;
                setmodel(self, "");
                self.think = self.monster_spawnfunc;
-               self.nextthink = time + autocvar_g_monsters_respawn_delay;
+               self.nextthink = time + self.respawntime;
                setorigin(self, self.pos1);
                self.angles = self.pos2;
-               self.health = 0;
+               self.health = self.max_health; // TODO: check if resetting to max_health is wise here
                return;
        }
        self.think = SUB_Remove;
@@ -277,27 +350,30 @@ float GenericCheckAttack ()
        
        if (time < self.attack_finished_single)
                return FALSE;
-       
-       if (enemy_range() > 2000) // long traces are slow
-               return FALSE;   
                
        if(self.attack_melee)
-       if(enemy_range() <= 100 * self.scale)
+       if(vlen(self.enemy.origin - self.origin) <= 100 * self.scale)
        {
+               monster_sound(self.msound_attack_melee, 0, FALSE); // no delay for attack sounds
                self.attack_melee(); // don't wait for nextthink - too slow
                return TRUE;
        }
        
        // monster doesn't have a ranged attack function, so stop here
-       if(!self.attack_ranged)
+       if not(self.attack_ranged)
                return FALSE;
 
        // see if any entities are in the way of the shot
-       if (!findtrajectorywithleading(self.origin, '0 0 0', '0 0 0', self.enemy, 800, 0, 2.5, 0, self))
+       if not(findtrajectorywithleading(self.origin, '0 0 0', '0 0 0', self.enemy, 800, 0, 2.5, 0, self))
                return FALSE;
 
-       self.attack_ranged(); // don't wait for nextthink - too slow
-       return TRUE;
+       if(self.attack_ranged())
+       {
+               monster_sound(self.msound_attack_ranged, 0, FALSE); // no delay for attack sounds
+               return TRUE;
+       }
+
+       return FALSE;
 }
 
 void monster_use ()
@@ -307,7 +383,7 @@ void monster_use ()
        if (self.health <= 0)
                return;
 
-       if(!monster_isvalidtarget(activator, self, -1))
+       if(!monster_isvalidtarget(activator, self))
                return;
 
        self.enemy = activator;
@@ -335,6 +411,11 @@ vector monster_pickmovetarget(entity targ)
                self.monster_movestate = MONSTER_MOVE_ENEMY;
                return self.enemy.origin;
        }
+       if(targ)
+       {
+               self.monster_movestate = MONSTER_MOVE_WANDER;
+               return targ.origin;
+       }
        
        switch(self.monster_moveflags)
        {
@@ -347,8 +428,6 @@ vector monster_pickmovetarget(entity targ)
                case MONSTER_MOVE_WANDER:
                {
                        self.monster_movestate = MONSTER_MOVE_WANDER;
-                       if(targ)
-                               return targ.origin;
                                
                        self.angles_y = random() * 500;
                        makevectors(self.angles);
@@ -374,26 +453,23 @@ void monster_move(float runspeed, float walkspeed, float stopspeed, float manim_
        if(self.target)
                self.goalentity = find(world, targetname, self.target);
                
-       float l = vlen(self.moveto - self.origin);
-       float t1 = trace_path(self.origin+'0 0 10', self.moveto+'0 0 10');
-       float t2 = trace_path(self.origin-'0 0 15', self.moveto-'0 0 15'); 
-       entity targ = self.goalentity;
+       entity targ;
 
        if(self.frozen)
        {
                self.revive_progress = bound(0, self.revive_progress + frametime * self.revive_speed, 1);
-               self.health = max(1, self.revive_progress * self.max_health);
+               self.health = max(1, self.max_health * self.revive_progress);
                
-               if(self.sprite)
-               {
-                       WaypointSprite_UpdateHealth(self.sprite, self.health);
-               }
+               if(self.sprite) WaypointSprite_UpdateHealth(self.sprite, self.health);
+                       
+               movelib_beak_simple(stopspeed);
                        
                self.velocity = '0 0 0';
                self.enemy = world;
+               self.nextthink = time + 0.1;
+               
                if(self.revive_progress >= 1)
                        Unfreeze(self); // wait for next think before attacking
-               self.nextthink = time + 0.1;
                        
                return; // no moving while frozen
        }
@@ -402,26 +478,25 @@ void monster_move(float runspeed, float walkspeed, float stopspeed, float manim_
        {
                if(self.waterlevel < WATERLEVEL_WETFEET)
                {
-                       if(time < self.last_trace)
-                               return;
-                       self.last_trace = time + 0.4;
-                       self.angles = '0 0 -90';
-                       Damage (self, world, world, 2, DEATH_DROWN, self.origin, '0 0 0');
-                       if(random() < 0.5)
+                       if(time >= self.last_trace)
                        {
-                               self.velocity_y += random() * 50;
-                               self.velocity_x -= random() * 50;
+                               self.last_trace = time + 0.4;
+                               self.angles = '0 0 -90';
+                               Damage (self, world, world, 2, DEATH_DROWN, self.origin, '0 0 0');
+                               if(random() < 0.5)
+                               {
+                                       self.velocity_y += random() * 50;
+                                       self.velocity_x -= random() * 50;
+                               }
+                               else
+                               {
+                                       self.velocity_y -= random() * 50;
+                                       self.velocity_x += random() * 50;
+                               }
+                               //self.velocity_z += random() * 150;
+                               self.movetype = MOVETYPE_BOUNCE;
+                               self.velocity_z = -200;
                        }
-                       else
-                       {
-                               self.velocity_y -= random() * 50;
-                               self.velocity_x += random() * 50;
-                       }
-                       self.velocity_z += random()*150;
-                       if (self.flags & FL_ONGROUND)
-                               self.flags -= FL_ONGROUND;
-                       self.movetype = MOVETYPE_BOUNCE;
-                       self.velocity_z = -200;
                        return;
                }
                else
@@ -439,8 +514,7 @@ void monster_move(float runspeed, float walkspeed, float stopspeed, float manim_
                return;
        }
        
-       runspeed *= monster_skill;
-       walkspeed *= monster_skill;
+       targ = self.goalentity;
        
        monster_target = targ;
        monster_speed_run = runspeed;
@@ -452,12 +526,16 @@ void monster_move(float runspeed, float walkspeed, float stopspeed, float manim_
                
        if(IsDifferentTeam(self.monster_owner, self))
                self.monster_owner = world;
-       
-       if(self.enemy.health <= 0 || (!autocvar_g_monsters_typefrag && self.enemy.BUTTON_CHAT))
+               
+       if(!enemy_stillvalidtarget(self.enemy, self))
                self.enemy = world;
                
        if not(self.enemy)
+       {
                self.enemy = FindTarget(self);
+               if(self.enemy)
+                       monster_sound(self.msound_sight, 0, FALSE);
+       }
                
        if(time >= self.last_trace)
        {
@@ -467,8 +545,13 @@ void monster_move(float runspeed, float walkspeed, float stopspeed, float manim_
                        self.last_trace = time + 0.5;
                self.moveto = monster_pickmovetarget(targ);
        }
+
+       if not(self.enemy)
+               monster_sound(self.msound_idle, 5, TRUE);
        
        vector angles_face = vectoangles(self.moveto - self.origin);
+       vector owner_face = vectoangles(self.monster_owner.origin - self.origin);
+       vector enemy_face = vectoangles(self.enemy.origin - self.origin);
        self.angles_y = angles_face_y;
        
        if(self.state == MONSTER_STATE_ATTACK_LEAP && (self.flags & FL_ONGROUND))
@@ -479,6 +562,10 @@ void monster_move(float runspeed, float walkspeed, float stopspeed, float manim_
         
        v_forward = normalize(self.moveto - self.origin);
        
+       float l = vlen(self.moveto - self.origin);
+       float t1 = trace_path(self.origin+'0 0 10', self.moveto+'0 0 10');
+       float t2 = trace_path(self.origin-'0 0 15', self.moveto-'0 0 15'); 
+       
        if(t1*l-t2*l>50 && (t1*l > 100 || t1 > 0.8))
        if(self.flags & FL_ONGROUND)
                movelib_jump_simple(100);
@@ -499,16 +586,17 @@ void monster_move(float runspeed, float walkspeed, float stopspeed, float manim_
                if(time > self.attack_finished_single)
                if(time > self.pain_finished)
                if (vlen(self.velocity) <= 30)
+               {
                        self.frame = manim_idle;
+                       if(self.enemy)
+                               self.angles_y = enemy_face_y;
+                       else
+                               self.angles_y = ((self.monster_owner) ? owner_face_y : self.pos2_y); // reset looking angle now?
+               }
        }
                
-       if(self.enemy)
-       {
-               if(!self.checkattack)
-                       return; // to stop other code from crashing here
-                       
+       if(self.enemy && self.checkattack)
                self.checkattack();
-       }
 }
 
 void monsters_setstatus()
@@ -517,15 +605,6 @@ void monsters_setstatus()
        self.stat_monsters_killed = monsters_killed;
 }
 
-
-/*
-===================
-
-Monster spawn code
-
-===================
-*/
-
 void Monster_Appear ()
 {
        self.enemy = activator;
@@ -533,44 +612,29 @@ void Monster_Appear ()
        self.monster_spawnfunc();
 }
 
-entity FindTarget (entity ent) 
-{
-       if(MUTATOR_CALLHOOK(MonsterFindTarget)) { return ent.enemy; } // Handled by a mutator
-       local entity e;
-       for(e = world; (e = findflags(e, monster_attack, TRUE)); ) 
-       {
-               if(monster_isvalidtarget(e, ent, FALSE))
-               {
-                       return e;
-               }
-       }
-       return world;
-}
-
 void monsters_damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
 {
-       if(self.frozen)
+       if(self.frozen && deathtype != DEATH_KILL)
+               return;
+               
+       if(time < self.pain_finished && deathtype != DEATH_KILL)
                return;
                
-       if(monster_isvalidtarget(attacker, self, FALSE))
+       if((ignore_turrets && !(attacker.turrcaps_flags & TFL_TURRCAPS_ISTURRET)) || !ignore_turrets)
+       if(monster_isvalidtarget(attacker, self))
                self.enemy = attacker;
        
        self.health -= damage;
        
        if(self.sprite)
-       {
                WaypointSprite_UpdateHealth(self.sprite, self.health);
-       }
                
        self.dmg_time = time;
 
        if(sound_allowed(MSG_BROADCAST, attacker) && deathtype != DEATH_DROWN)
                spamsound (self, CH_PAIN, "misc/bodyimpact1.wav", VOL_BASE, ATTN_NORM);  // FIXME: PLACEHOLDER
        
-       if(self.damageforcescale < 1 && self.damageforcescale > 0)
-               self.velocity += force * self.damageforcescale;
-       else
-               self.velocity += force;
+       self.velocity += force * self.damageforcescale;
                
        if(deathtype != DEATH_DROWN)
        {
@@ -589,7 +653,10 @@ void monsters_damage (entity inflictor, entity attacker, float damage, float dea
                        WaypointSprite_UpdateHealth(self.sprite, 0);
                }
                
-               if(self.flags & MONSTERFLAG_MINIBOSS) // TODO: cvarise the weapon drop?
+               if(deathtype == DEATH_KILL)
+                       self.candrop = FALSE; // killed by mobkill command
+               
+               if(self.flags & MONSTERFLAG_MINIBOSS && self.candrop)
                        W_ThrowNewWeapon(self, WEP_NEX, 0, self.origin, self.velocity);
                        
                activator = attacker;
@@ -598,7 +665,11 @@ void monsters_damage (entity inflictor, entity attacker, float damage, float dea
                self.target2 = "";
                SUB_UseTargets();
        
-               self.monster_die();     
+               self.monster_die();
+               
+               frag_attacker = attacker;
+               frag_target = self;
+               MUTATOR_CALLHOOK(MonsterDies);
        }
 }
 
@@ -608,29 +679,33 @@ void monster_hook_death()
        if(self.sprite)
         WaypointSprite_Kill(self.sprite);
                
+       monster_sound(self.msound_death, 0, FALSE);
+               
        if(!(self.spawnflags & MONSTERFLAG_SPAWNED) && !self.monster_respawned)
                monsters_killed += 1;
                
        if(self.realowner.classname == "monster_spawner")
                self.realowner.spawner_monstercount -= 1;
                
-       if(self.realowner.flags & FL_CLIENT)
+       if(IS_CLIENT(self.realowner))
                self.realowner.monstercount -= 1;
                
        totalspawned -= 1;
-       
-       MUTATOR_CALLHOOK(MonsterDies);
 }
 
 // used to hook into monster post spawn functions without a mutator
 void monster_hook_spawn()
 {
-       self.health *= monster_skill; // skill based monster health?
+       Monster_CheckMinibossFlag();
+
        self.max_health = self.health;
+       self.pain_finished = self.nextthink;
+
+       monster_precachesounds();
        
-       if(teamplay && autocvar_g_monsters_teams)
+       if(teamplay && self.team)
        {
-               self.colormod = TeamColor(self.team);
+               self.colormod = Team_ColorRGB(self.team);
                self.monster_attack = TRUE;
        }
        
@@ -642,11 +717,13 @@ void monster_hook_spawn()
                
        if(autocvar_g_monsters_healthbars)
        {
-               WaypointSprite_Spawn(self.netname, 0, 600, self, '0 0 1' * self.sprite_height, world, 0, self, sprite, FALSE, RADARICON_DANGER, ((teamplay) ? TeamColor(self.team) : '1 0 0')); 
+               WaypointSprite_Spawn(self.netname, 0, 600, self, '0 0 1' * self.sprite_height, world, 0, self, sprite, FALSE, RADARICON_DANGER, ((self.team) ? Team_ColorRGB(self.team) : '1 0 0'));    
                WaypointSprite_UpdateMaxHealth(self.sprite, self.max_health);
                WaypointSprite_UpdateHealth(self.sprite, self.health);
        }
        
+       monster_sound(self.msound_spawn, 0, FALSE);
+
        MUTATOR_CALLHOOK(MonsterSpawn);
 }
 
@@ -662,11 +739,11 @@ float monster_initialize(string  net_name,
                return FALSE;
                
        // support for quake style removing monsters based on skill
-       if(autocvar_skill <= autocvar_g_monsters_skill_easy && (self.spawnflags & MONSTERSKILL_NOTEASY)) { return FALSE; }
-       else if(autocvar_skill == autocvar_g_monsters_skill_normal && (self.spawnflags & MONSTERSKILL_NOTMEDIUM)) { return FALSE; }
-       else if(autocvar_skill == autocvar_g_monsters_skill_hard && (self.spawnflags & MONSTERSKILL_NOTHARD)) { return FALSE; }
-       else if(autocvar_skill == autocvar_g_monsters_skill_insane && (self.spawnflags & MONSTERSKILL_NOTINSANE)) { return FALSE; }
-       else if(autocvar_skill >= autocvar_g_monsters_skill_nightmare && (self.spawnflags & MONSTERSKILL_NOTNIGHTMARE)) { return FALSE; }
+       if(monster_skill <= autocvar_g_monsters_skill_easy && (self.spawnflags & MONSTERSKILL_NOTEASY)) { return FALSE; }
+       if(monster_skill == autocvar_g_monsters_skill_normal && (self.spawnflags & MONSTERSKILL_NOTMEDIUM)) { return FALSE; }
+       if(monster_skill == autocvar_g_monsters_skill_hard && (self.spawnflags & MONSTERSKILL_NOTHARD)) { return FALSE; }
+       if(monster_skill == autocvar_g_monsters_skill_insane && (self.spawnflags & MONSTERSKILL_NOTINSANE)) { return FALSE; }
+       if(monster_skill >= autocvar_g_monsters_skill_nightmare && (self.spawnflags & MONSTERSKILL_NOTNIGHTMARE)) { return FALSE; }
 
        if(self.model == "")
        if(bodymodel == "")
@@ -674,20 +751,19 @@ float monster_initialize(string  net_name,
 
        if(self.netname == "")
        {
-               if(net_name != "" && self.realowner.classname == STR_PLAYER)
+               if(net_name != "" && IS_PLAYER(self.realowner))
                        net_name = strzone(strdecolorize(sprintf("%s's %s", self.realowner.netname, net_name)));
                self.netname = ((net_name == "") ? self.classname : net_name);
        }
        
+       if not(self.scale)
+               self.scale = 1;
+       
        if(self.spawnflags & MONSTERFLAG_GIANT && !autocvar_g_monsters_nogiants)
                ScaleMonster(5);
-       else if(!self.scale)
-               ScaleMonster(1);
        else
                ScaleMonster(self.scale);
                
-       Monster_CheckMinibossFlag();
-               
        min_s *= self.scale;
        max_s *= self.scale;
 
@@ -730,6 +806,13 @@ float monster_initialize(string  net_name,
        self.moveto                             = self.origin;
        self.pos1                               = self.origin;
        self.pos2                               = self.angles;
+       self.candrop                    = TRUE;
+       
+       if not(self.target_range)
+               self.target_range = autocvar_g_monsters_target_range;
+       
+       if not(self.respawntime)
+               self.respawntime = autocvar_g_monsters_respawn_delay;
        
        if not(self.monster_moveflags)
                self.monster_moveflags = MONSTER_MOVE_WANDER;