]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Fix some weird problems with zombie movement, fix spawner not spawning monsters
authorMario <mario.mario@y7mail.com>
Tue, 22 Jan 2013 12:20:45 +0000 (23:20 +1100)
committerMario <mario.mario@y7mail.com>
Tue, 22 Jan 2013 12:20:45 +0000 (23:20 +1100)
monsters.cfg
qcsrc/server/monsters/lib/defs.qh
qcsrc/server/monsters/lib/monsters.qc
qcsrc/server/monsters/monster/spawner.qc
qcsrc/server/monsters/monster/zombie.qc

index e73529cee501f4458cf54f0bd3004e18583cddf9..3d79f77e69891f27c3c54f56323a059350061ab6 100644 (file)
@@ -166,11 +166,8 @@ set g_monster_shalrath_speed 50 "Vore move speed"
 // Spawner
 set g_monster_spawner 1 "Enable Monster Spawner"
 set g_monster_spawner_health 100 "Spawner health"
-set g_monster_spawner_target_recheck_delay 1 "Spawner enemy check delay"
-set g_monster_spawner_target_range 600 "Spawner maximum enemy distance"
-set g_monster_spawner_spawn_range 600 "Spawn monsters while enemy is within this range"
 set g_monster_spawner_maxmobs 4 "Maximum number of spawned monsters"
-set g_monster_spawner_forcespawn 0 "Force spawner to spawn this type of monster"
+set g_monster_spawner_forcespawn "" "Force spawner to spawn this type of monster"
 
 // Zombie
 set g_monster_zombie 1 "Enable Zombies"
@@ -183,12 +180,9 @@ set g_monster_zombie_attack_stand_damage 35 "Damage when zombie hits from a stan
 set g_monster_zombie_attack_stand_delay 1.2 "Delay after a zombie hits from a standing position"
 set g_monster_zombie_attack_stand_range 48 "Range of a zombie standing position attack"
 set g_monster_zombie_health 200 "Zombie health"
-set g_monster_zombie_idle_timer 1 "Minimum time a zombie can stay idle"
 set g_monster_zombie_speed_walk 150 "Zombie walk speed"
 set g_monster_zombie_speed_run 400 "Zombie run speed"
 set g_monster_zombie_stopspeed 100 "Speed at which zombie stops"
-set g_monster_zombie_target_recheck_delay 5 How much time should a zombie run afer an enemy before checking if it's still in range"
-set g_monster_zombie_target_range 1200 How far the zombie can see an enemy"
 set g_monster_zombie_drop health "Zombie drops this item on death"
 set g_monster_zombie_drop_size large "Size of the item zombies drop. Possible values are: small, medium, large"
 
index 6ea667f4cd03416808d965c5d5e907ff9d0e034a..eca1d73403d26fd11fbf2bd56d70c8af8ace1689 100644 (file)
@@ -29,11 +29,13 @@ const float MONSTERFLAG_SPAWNED = 1024; // flag for spawned monsters
 .void() monster_die;
 .void() monster_delayedattack;
 
-.float monster_moveflags; // checks where to move when not attacking (currently unused)
+.float monster_moveflags; // checks where to move when not attacking
+.float monster_movestate; // used to tell what the monster is currently doing
 const float MONSTER_MOVE_OWNER = 1; // monster will move to owner if in range, or stand still
 const float MONSTER_MOVE_WANDER = 2; // monster will ignore owner & wander around
 const float MONSTER_MOVE_SPAWNLOC = 3; // monster will move to its spawn location when not attacking
 const float MONSTER_MOVE_NOMOVE = 4; // monster simply stands still
+const float MONSTER_MOVE_ENEMY = 5; // used only as a movestate
 
 float enemy_range () { return vlen(self.enemy.origin - self.origin); }
 
index 97cac39a5c77a993e1a2d14ce1584ba9799b1b9b..8229e10ca37d711d33d0c9bb33100f3f5854b533 100644 (file)
@@ -329,18 +329,23 @@ float trace_path(vector from, vector to)
 vector monster_pickmovetarget(entity targ)
 {
        // enemy is always preferred target
-       if(self.enemy && trace_path(self.origin + '0 0 10', self.enemy.origin + '0 0 10') > 0.99)
-               return self.enemy.origin + 60 * normalize(self.enemy.origin - self.origin);
+       if(self.enemy)
+       {
+               self.monster_movestate = MONSTER_MOVE_ENEMY;
+               return self.enemy.origin;
+       }
        
        switch(self.monster_moveflags)
        {
                case MONSTER_MOVE_OWNER:
                {
-                       if(self.monster_owner && self.monster_owner.classname != "monster_swarm" && trace_path(self.origin + '0 0 10', self.monster_owner.origin + '0 0 10') > 0.99)
+                       self.monster_movestate = MONSTER_MOVE_OWNER;
+                       if(self.monster_owner && self.monster_owner.classname != "monster_swarm")
                                return self.monster_owner.origin;
                }
                case MONSTER_MOVE_WANDER:
                {
+                       self.monster_movestate = MONSTER_MOVE_WANDER;
                        if(targ)
                                return targ.origin;
                                
@@ -349,10 +354,16 @@ vector monster_pickmovetarget(entity targ)
                        return self.origin + v_forward * 600;
                }
                case MONSTER_MOVE_SPAWNLOC:
+               {
+                       self.monster_movestate = MONSTER_MOVE_SPAWNLOC;
                        return self.pos1;
+               }
                default:
                case MONSTER_MOVE_NOMOVE:
+               {
+                       self.monster_movestate = MONSTER_MOVE_NOMOVE;
                        return self.origin;
+               }
        }
 }
 
@@ -460,7 +471,7 @@ void monster_move(float runspeed, float walkspeed, float stopspeed, float manim_
                
        if(time >= self.last_trace)
        {
-               if(self.monster_moveflags & MONSTER_MOVE_WANDER)
+               if(self.monster_movestate == MONSTER_MOVE_WANDER)
                        self.last_trace = time + 2;
                else
                        self.last_trace = time + 0.5;
@@ -482,23 +493,23 @@ void monster_move(float runspeed, float walkspeed, float stopspeed, float manim_
        if(self.flags & FL_ONGROUND)
                movelib_jump_simple(100);
 
-       if(vlen(self.moveto - self.origin) > 64)
+       if(vlen(self.origin - self.moveto) > 64)
        {
                if(self.flags & FL_FLY)
                        movelib_move_simple(v_forward, ((self.enemy) ? runspeed : walkspeed), 0.6);
                else
                        movelib_move_simple_gravity(v_forward, ((self.enemy) ? runspeed : walkspeed), 0.6);
                if(time > self.pain_finished)
-                       if(time > self.attack_finished_single)
-                               self.frame = ((self.enemy) ? manim_run : manim_walk);
+               if(time > self.attack_finished_single)
+                       self.frame = ((self.enemy) ? manim_run : manim_walk);
        }
        else
        {
                movelib_beak_simple(stopspeed);
-                       if(time > self.attack_finished_single)
-                               if(time > self.pain_finished)
-                                       if (vlen(self.velocity) <= 30)
-                                               self.frame = manim_idle;
+               if(time > self.attack_finished_single)
+               if(time > self.pain_finished)
+               if (vlen(self.velocity) <= 30)
+                       self.frame = manim_idle;
        }
                
        if(self.enemy)
@@ -534,7 +545,7 @@ void Monster_Appear ()
 
 entity FindTarget (entity ent) 
 {
-       if(MUTATOR_CALLHOOK(MonsterFindTarget)) { return self.goalentity; } // Handled by a mutator
+       if(MUTATOR_CALLHOOK(MonsterFindTarget)) { return ent.goalentity; } // Handled by a mutator
        local entity e;
        for(e = world; (e = findflags(e, monster_attack, TRUE)); ) 
        {
index 627cb777d394ec7fe4fbf98a83dfef2a500d6c8d..d625bd9f9f9a815af9f4c1a83bd83635ae78c93b 100644 (file)
@@ -5,9 +5,6 @@ const vector SPAWNER_MAX = '35 35 70';
 // cvars
 float autocvar_g_monster_spawner;
 float autocvar_g_monster_spawner_health;
-float autocvar_g_monster_spawner_target_recheck_delay;
-float autocvar_g_monster_spawner_target_range;
-float autocvar_g_monster_spawner_spawn_range;
 float autocvar_g_monster_spawner_maxmobs;
 string autocvar_g_monster_spawner_forcespawn;
 
@@ -18,35 +15,35 @@ void spawnmonsters ()
        if(self.spawner_monstercount >= autocvar_g_monster_spawner_maxmobs || self.frozen || self.freezetag_frozen)
                return;
                
-       vector posi1 = '0 0 0', posi2 = '0 0 0', posi3 = '0 0 0', posi4 = '0 0 0', chosenposi = '0 0 0';
+       vector p1, p2, p3, p4, chosenposi;
        float r = random();
-       string type = string_null;
-       entity e = world;
+       string type = "";
+       entity e;
        
        self.spawner_monstercount += 1;
        
        if(self.spawnmob != "")
                type = self.spawnmob;
                
-       if(autocvar_g_monster_spawner_forcespawn != "0")
+       if(autocvar_g_monster_spawner_forcespawn != "")
                type = autocvar_g_monster_spawner_forcespawn;
                
        if(type == "" || type == "spawner") // spawner spawning spawners?!
                type = "knight";
        
-       posi1 = self.origin - '0 70 -50' * self.scale;
-       posi2 = self.origin + '0 70 50' * self.scale;
-       posi3 = self.origin - '70 0 -50' * self.scale;
-       posi4 = self.origin + '70 0 -50' * self.scale;
+       p1 = self.origin - '0 70 -50' * self.scale;
+       p2 = self.origin + '0 70 50' * self.scale;
+       p3 = self.origin - '70 0 -50' * self.scale;
+       p4 = self.origin + '70 0 -50' * self.scale;
           
        if (r < 0.20)
-               chosenposi = posi1;
+               chosenposi = p1;
        else if (r < 0.50)
-               chosenposi = posi2;
+               chosenposi = p2;
        else if (r < 80)
-               chosenposi = posi3;
+               chosenposi = p3;
        else
-               chosenposi = posi4;
+               chosenposi = p4;
 
        e = spawnmonster(type, self, self, chosenposi, FALSE, MONSTER_MOVE_WANDER);
        
@@ -85,46 +82,21 @@ void spawner_recount()
 
 void spawner_think() 
 {
-       float finished = FALSE, enemyDistance = 0;
+       float finished = FALSE;
        self.think = spawner_think;
        
-       if(self.spawner_monstercount == autocvar_g_monster_spawner_maxmobs)
+       if(self.spawner_monstercount >= autocvar_g_monster_spawner_maxmobs)
        {
                self.think = spawner_recount;
-               self.nextthink = time + 20;
+               self.nextthink = time + 10 + random() * 4;
                return;
        }
-         
-       // remove enemy that ran away
-       if (self.enemy)
-       if (self.delay <= time) // check if we can do the rescan now
-       if (vlen(self.origin - self.enemy.origin) > autocvar_g_monster_spawner_target_range * self.scale)
-               self.enemy = world;
-       else
-               self.delay = time + autocvar_g_monster_spawner_target_recheck_delay;
-       
-       if not(self.enemy) 
-       {
-               self.enemy = FindTarget(self);
-               if (self.enemy)
-                       self.delay = time + autocvar_g_monster_spawner_target_recheck_delay;
-       }
 
-       if (self.enemy) 
+       if (self.spawner_monstercount <= autocvar_g_monster_spawner_maxmobs)
        {
-               // this spawner has an enemy
-               traceline(self.origin, self.enemy.origin, FALSE, self);
-               enemyDistance = vlen(trace_endpos - self.origin);
-               
-               if (trace_ent == self.enemy)
-               if (self.enemy.deadflag == DEAD_NO)
-               if (self.spawner_monstercount <= autocvar_g_monster_spawner_maxmobs)
-               if (enemyDistance <= autocvar_g_monster_spawner_spawn_range * self.scale) 
-               {
-                       spawnmonsters();
-                       finished = TRUE;
-               }               
-       }
+               spawnmonsters();
+               finished = TRUE;
+       }               
        
        self.nextthink = time + 1;
 
@@ -132,10 +104,7 @@ void spawner_think()
                self.nextthink = time + 0.1;
        
        if not(finished) 
-       {
-               if (self.enemy)
-                       self.nextthink = time + 0.1;
-       }  
+               self.nextthink = time + 0.1;
 }
 
 void spawner_spawn() 
@@ -144,7 +113,7 @@ void spawner_spawn()
                self.health = autocvar_g_monster_spawner_health * self.scale;
        
        self.classname                  = "monster_spawner";
-       self.nextthink                  = time + 2.1;
+       self.nextthink                  = time + 0.2;
        self.velocity                   = '0 0 0';
        self.think                              = spawner_think;
        self.touch                              = func_null;    
index 108deed0056f036400cc76105f2392706d339912..ff73c8efa4a1313dd7763fcf9a57d73609dec901 100644 (file)
@@ -2,7 +2,6 @@
  * Special purpose fields:
  * .delay - time at which to check if zombie's enemy is still in range
  * .enemy - enemy of this zombie
- * .state - state of the zombie, see ZOMBIE_STATE_*
  */
  
 // cvars
@@ -11,17 +10,12 @@ float autocvar_g_monster_zombie_stopspeed;
 float autocvar_g_monster_zombie_attack_leap_damage;
 float autocvar_g_monster_zombie_attack_leap_delay;
 float autocvar_g_monster_zombie_attack_leap_force;
-float autocvar_g_monster_zombie_attack_leap_range;
 float autocvar_g_monster_zombie_attack_leap_speed;
 float autocvar_g_monster_zombie_attack_stand_damage;
 float autocvar_g_monster_zombie_attack_stand_delay;
-float autocvar_g_monster_zombie_attack_stand_range;
 float autocvar_g_monster_zombie_health;
-float autocvar_g_monster_zombie_idle_timer;
 float autocvar_g_monster_zombie_speed_walk;
 float autocvar_g_monster_zombie_speed_run;
-float autocvar_g_monster_zombie_target_recheck_delay;
-float autocvar_g_monster_zombie_target_range;
 
 // zombie animations
 #define zombie_anim_attackleap                 0
@@ -59,11 +53,6 @@ float autocvar_g_monster_zombie_target_range;
 const vector ZOMBIE_MIN                                 = '-18 -18 -25';
 const vector ZOMBIE_MAX                                 = '18 18 47';
 
-#define ZOMBIE_STATE_SPAWNING          0
-#define ZOMBIE_STATE_IDLE                      1
-#define ZOMBIE_STATE_ANGRY                     2
-#define ZOMBIE_STATE_ATTACK_LEAP       3
-
 void zombie_spawn();
 void spawnfunc_monster_zombie();
 void zombie_think();
@@ -123,11 +112,12 @@ void zombie_attack_standing()
                self.frame = zombie_anim_attackstanding3;
 
        self.nextthink = time + autocvar_g_monster_zombie_attack_stand_delay;
+       self.attack_finished_single = self.nextthink;
 }
 
 void zombie_attack_leap_touch()
 {
-       vector angles_face = '0 0 0';
+       vector angles_face;
        float bigdmg = autocvar_g_monster_zombie_attack_leap_damage * self.scale;
        
        if (other.deadflag != DEAD_NO)
@@ -145,130 +135,25 @@ void zombie_attack_leap_touch()
        angles_face = vectoangles(self.moveto - self.origin);
        angles_face = normalize(angles_face) * autocvar_g_monster_zombie_attack_leap_force;
        Damage(other, self, self, bigdmg * monster_skill, DEATH_MONSTER_MELEE, trace_endpos, angles_face);      
-
-       // make this guy zombie's priority if it wasn't already
-       if (other.deadflag == DEAD_NO)
-       if (self.enemy != other)
-               self.enemy = other;
                
        self.touch = MonsterTouch;
 }
 
-void zombie_attack_leap()
+float zombie_attack_ranged()
 {
-       vector angles_face = '0 0 0', vel = '0 0 0';
-
-       // face the enemy       
-       self.state = ZOMBIE_STATE_ATTACK_LEAP;
-       self.frame = zombie_anim_attackleap;
-       angles_face = vectoangles(self.enemy.origin - self.origin);
-       self.angles_y = angles_face_y ;
-       self.nextthink = time + autocvar_g_monster_zombie_attack_leap_delay;
-       self.touch = zombie_attack_leap_touch;
        makevectors(self.angles);
-       vel = normalize(v_forward);
-       self.velocity = vel * autocvar_g_monster_zombie_attack_leap_speed;
+       if(monster_leap(zombie_anim_attackleap, zombie_attack_leap_touch, v_forward * autocvar_g_monster_zombie_attack_leap_speed + '0 0 200', autocvar_g_monster_zombie_attack_leap_delay))
+               return TRUE;
+               
+       return FALSE;
 }
 
 void zombie_think()
 {
-       float finished = FALSE, enemyDistance = 0, mySpeed = 0;
-       
        self.think = zombie_think;
-       
-       if (self.state == ZOMBIE_STATE_ATTACK_LEAP) {
-               // reset to angry
-               self.state = ZOMBIE_STATE_ANGRY;
-               self.touch = func_null;
-       }
-       
-       if (self.state == ZOMBIE_STATE_SPAWNING) {
-               // become idle when zombie spawned
-               self.frame = zombie_anim_idle;
-               self.state = ZOMBIE_STATE_IDLE;
-       }
-       
-       if(self.enemy && !monster_isvalidtarget(self.enemy, self, FALSE))
-               self.enemy = world;
-       
-       if (self.enemy)
-       if (self.enemy.team == self.team || self.monster_owner == self.enemy)
-               self.enemy = world;
-       
-       if(teamplay && autocvar_g_monsters_teams && self.monster_owner.team != self.team)
-               self.monster_owner = world;     
-       
-       // remove enemy that ran away
-       if (self.enemy)
-       if (self.delay <= time) // check if we can do the rescan now
-       if (vlen(self.origin - self.enemy.origin) > autocvar_g_monster_zombie_target_range * self.scale) 
-       {
-               //print("removing enemy, he is too far: ", ftos(vlen(self.origin - self.enemy.origin)), "\n");
-               //print("delay was ", ftos(self.delay), "\n");
-               self.enemy = world;
-       } 
-       else
-               self.delay = time + autocvar_g_monster_zombie_target_recheck_delay;
-       
-       // find an enemy if no enemy available
-       if not(self.enemy) 
-       {
-               self.enemy = FindTarget(self);
-               if (self.enemy)
-                       self.delay = time + autocvar_g_monster_zombie_target_recheck_delay;
-       }
-
-       if (self.enemy) 
-       {
-               // make sure zombie is angry
-               self.state = ZOMBIE_STATE_ANGRY;
-               
-
-               // this zombie has an enemy, attack if close enough, go to it if not!
-               traceline(self.origin, self.enemy.origin, FALSE, self);
-               enemyDistance = vlen(trace_endpos - self.origin);
-               mySpeed = vlen(self.velocity);
-               
-               //print("speed ", ftos(mySpeed), "\n");
-               
-               if (trace_ent == self.enemy)
-               if (self.enemy.deadflag == DEAD_NO)
-               if (mySpeed <= 30)
-                       if (enemyDistance <= autocvar_g_monster_zombie_attack_stand_range * self.scale) 
-                       {
-                               //RadiusDamage (entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity ignore, float forceintensity, float deathtype, entity directhitentity)
-                               zombie_attack_standing();
-                               finished = TRUE;
-                       } 
-                       else if (enemyDistance <= autocvar_g_monster_zombie_attack_leap_range * self.scale) 
-                       {
-                               // do attackleap (set yaw, velocity, and check do damage on the first player entity it touches)
-                               zombie_attack_leap();
-                               finished = TRUE;
-                       }
-               
-       }
-       
-       self.nextthink = time + 1;
+       self.nextthink = time + 0.3;
 
-       if not(finished) 
-       {
-               monster_move(autocvar_g_monster_zombie_speed_run, autocvar_g_monster_zombie_speed_walk, autocvar_g_monster_zombie_stopspeed, zombie_anim_runforward, zombie_anim_runforward, zombie_anim_idle);
-               
-               if (self.enemy || self.monster_owner)
-               {
-                       self.nextthink = time + 0.1;
-                       return;
-               }   
-       }
-       
-       if not(self.enemy || self.monster_owner || self.goalentity) 
-       {
-               // stay idle
-               //print("zombie is idling while waiting for some fresh meat...\n");
-               self.frame = ((mySpeed <= 20) ? zombie_anim_idle : zombie_anim_runforward);
-               self.nextthink = time + autocvar_g_monster_zombie_idle_timer * random();        
-       }
+       monster_move(autocvar_g_monster_zombie_speed_run, autocvar_g_monster_zombie_speed_walk, autocvar_g_monster_zombie_stopspeed, zombie_anim_runforward, zombie_anim_runforward, zombie_anim_idle);
 }
 
 void zombie_spawn() 
@@ -279,10 +164,12 @@ void zombie_spawn()
        self.classname                  = "monster_zombie";
        self.nextthink                  = time + 2.1;
        self.pain_finished      = self.nextthink;
-       self.state                              = ZOMBIE_STATE_SPAWNING;
        self.frame                              = zombie_anim_spawn;
        self.think                              = zombie_think;
        self.sprite_height      = 50 * self.scale;
+       self.checkattack                = GenericCheckAttack;
+       self.attack_melee               = zombie_attack_standing;
+       self.attack_ranged              = zombie_attack_ranged;
        self.skin                               = rint(random() * 4);
        
        monster_hook_spawn(); // for post-spawn mods