From 49f862e3de34ebd45b97f346feece776401166ae Mon Sep 17 00:00:00 2001 From: Mario Date: Tue, 22 Jan 2013 23:20:45 +1100 Subject: [PATCH] Fix some weird problems with zombie movement, fix spawner not spawning monsters --- monsters.cfg | 8 +- qcsrc/server/monsters/lib/defs.qh | 4 +- qcsrc/server/monsters/lib/monsters.qc | 35 ++++-- qcsrc/server/monsters/monster/spawner.qc | 73 ++++-------- qcsrc/server/monsters/monster/zombie.qc | 137 ++--------------------- 5 files changed, 60 insertions(+), 197 deletions(-) diff --git a/monsters.cfg b/monsters.cfg index e73529cee..3d79f77e6 100644 --- a/monsters.cfg +++ b/monsters.cfg @@ -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" diff --git a/qcsrc/server/monsters/lib/defs.qh b/qcsrc/server/monsters/lib/defs.qh index 6ea667f4c..eca1d7340 100644 --- a/qcsrc/server/monsters/lib/defs.qh +++ b/qcsrc/server/monsters/lib/defs.qh @@ -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); } diff --git a/qcsrc/server/monsters/lib/monsters.qc b/qcsrc/server/monsters/lib/monsters.qc index 97cac39a5..8229e10ca 100644 --- a/qcsrc/server/monsters/lib/monsters.qc +++ b/qcsrc/server/monsters/lib/monsters.qc @@ -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)); ) { diff --git a/qcsrc/server/monsters/monster/spawner.qc b/qcsrc/server/monsters/monster/spawner.qc index 627cb777d..d625bd9f9 100644 --- a/qcsrc/server/monsters/monster/spawner.qc +++ b/qcsrc/server/monsters/monster/spawner.qc @@ -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; diff --git a/qcsrc/server/monsters/monster/zombie.qc b/qcsrc/server/monsters/monster/zombie.qc index 108deed00..ff73c8efa 100644 --- a/qcsrc/server/monsters/monster/zombie.qc +++ b/qcsrc/server/monsters/monster/zombie.qc @@ -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 -- 2.39.2