]> git.rm.cloudns.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Tweak mage animations and add a chance to teleport randomly around while attacking
authorMario <mario@smbclan.net>
Sat, 20 Oct 2018 14:14:17 +0000 (00:14 +1000)
committerMario <mario@smbclan.net>
Sat, 20 Oct 2018 14:14:17 +0000 (00:14 +1000)
qcsrc/common/monsters/monster/mage.qc
qcsrc/server/miscfunctions.qc
qcsrc/server/miscfunctions.qh

index 8f16459da87385a59ad7c71e0ceb8f939fe50fff..0ca1c18c0b3298abe0c1cd1741325bc5e73a35eb 100644 (file)
@@ -45,16 +45,22 @@ float autocvar_g_monster_mage_attack_spike_radius;
 float autocvar_g_monster_mage_attack_spike_delay;
 float autocvar_g_monster_mage_attack_spike_accel;
 float autocvar_g_monster_mage_attack_spike_decel;
+float autocvar_g_monster_mage_attack_spike_chance = 0.45;
 float autocvar_g_monster_mage_attack_spike_turnrate;
 float autocvar_g_monster_mage_attack_spike_speed_max;
 float autocvar_g_monster_mage_attack_spike_smart;
 float autocvar_g_monster_mage_attack_spike_smart_trace_min;
 float autocvar_g_monster_mage_attack_spike_smart_trace_max;
 float autocvar_g_monster_mage_attack_spike_smart_mindist;
+float autocvar_g_monster_mage_attack_push_chance = 0.7;
 float autocvar_g_monster_mage_attack_push_damage;
 float autocvar_g_monster_mage_attack_push_radius;
 float autocvar_g_monster_mage_attack_push_delay;
 float autocvar_g_monster_mage_attack_push_force;
+float autocvar_g_monster_mage_attack_teleport_chance = 0.2;
+float autocvar_g_monster_mage_attack_teleport_delay = 2;
+float autocvar_g_monster_mage_attack_teleport_random = 0.4;
+float autocvar_g_monster_mage_attack_teleport_random_range = 1200;
 float autocvar_g_monster_mage_heal_self;
 float autocvar_g_monster_mage_heal_allies;
 float autocvar_g_monster_mage_heal_minhealth;
@@ -223,7 +229,7 @@ void M_Mage_Attack_Spike(entity this, vector dir)
 
 void M_Mage_Defend_Heal(entity this)
 {
-       float washealed = false;
+       bool washealed = false;
 
        FOREACH_ENTITY_RADIUS(this.origin, autocvar_g_monster_mage_heal_range, M_Mage_Defend_Heal_Check(this, it),
        {
@@ -277,7 +283,7 @@ void M_Mage_Defend_Heal(entity this)
 
        if(washealed)
        {
-               setanim(this, this.anim_shoot, true, true, true);
+               setanim(this, this.anim_melee, true, true, true);
                this.attack_finished_single[0] = time + (autocvar_g_monster_mage_heal_delay);
                this.state = MONSTER_ATTACK_MELEE;
                this.anim_finished = time + 1.5;
@@ -291,16 +297,37 @@ void M_Mage_Attack_Push(entity this)
                                                NULL, NULL, (autocvar_g_monster_mage_attack_push_force), DEATH_MONSTER_MAGE.m_id, DMG_NOWEP, this.enemy);
        Send_Effect(EFFECT_TE_EXPLOSION, this.origin, '0 0 0', 1);
 
-       setanim(this, this.anim_shoot, true, true, true);
+       setanim(this, this.anim_duckjump, true, true, true);
        this.attack_finished_single[0] = time + (autocvar_g_monster_mage_attack_push_delay);
+       this.anim_finished = time + 1;
+       this.state = MONSTER_ATTACK_MELEE; // prevent moving while firing spike
 }
 
 void M_Mage_Attack_Teleport(entity this, entity targ)
 {
        if(!targ) return;
-       if(!IS_ONGROUND(targ)) return;
        if(vdist(targ.origin - this.origin, >, 1500)) return;
 
+       if(autocvar_g_monster_mage_attack_teleport_random && random() <= autocvar_g_monster_mage_attack_teleport_random)
+       {
+               vector oldpos = this.origin;
+               vector extrasize = '1 1 1' * autocvar_g_monster_mage_attack_teleport_random_range;
+               if(MoveToRandomLocationWithinBounds(this, this.absmin - extrasize, this.absmax + extrasize,
+                                                                                       DPCONTENTS_SOLID | DPCONTENTS_CORPSE | DPCONTENTS_PLAYERCLIP, DPCONTENTS_SLIME | DPCONTENTS_LAVA | DPCONTENTS_SKY | DPCONTENTS_BODY | DPCONTENTS_DONOTENTER, 
+                                                                                       Q3SURFACEFLAG_SKY, 10, 1024, 256, true))
+               {
+                       vector a = vectoangles(targ.origin - this.origin);
+                       this.angles = '0 1 0' * a.y;
+                       this.fixangle = true;
+                       Send_Effect(EFFECT_SPAWN_NEUTRAL, oldpos, '0 0 0', 1);
+                       Send_Effect(EFFECT_SPAWN_NEUTRAL, this.origin, '0 0 0', 1);
+                       this.attack_finished_single[0] = time + autocvar_g_monster_mage_attack_teleport_delay;
+                       return;
+               }
+       }
+
+       if(!IS_ONGROUND(targ)) return;
+
        makevectors(targ.angles);
        tracebox(CENTER_OR_VIEWOFS(targ), this.mins, this.maxs, CENTER_OR_VIEWOFS(targ) + ((v_forward * -1) * 200), MOVE_NOMONSTERS, this);
 
@@ -321,7 +348,7 @@ void M_Mage_Attack_Teleport(entity this, entity targ)
        this.fixangle = true;
        this.velocity *= 0.5;
 
-       this.attack_finished_single[0] = time + 0.2;
+       this.attack_finished_single[0] = time + autocvar_g_monster_mage_attack_teleport_delay;
 }
 
 void M_Mage_Defend_Shield_Remove(entity this)
@@ -337,7 +364,7 @@ void M_Mage_Defend_Shield(entity this)
        SetResourceAmountExplicit(this, RESOURCE_ARMOR, autocvar_g_monster_mage_shield_blockpercent);
        this.mage_shield_time = time + (autocvar_g_monster_mage_shield_time);
        setanim(this, this.anim_shoot, true, true, true);
-       this.attack_finished_single[0] = time + 1;
+       this.attack_finished_single[0] = time + 1; // give just a short cooldown on attacking
        this.anim_finished = time + 1;
 }
 
@@ -347,7 +374,7 @@ bool M_Mage_Attack(int attack_type, entity actor, entity targ, .entity weaponent
        {
                case MONSTER_ATTACK_MELEE:
                {
-                       if(random() <= 0.7)
+                       if(random() <= autocvar_g_monster_mage_attack_push_chance)
                        {
                                Weapon wep = WEP_MAGE_SPIKE;
 
@@ -359,30 +386,25 @@ bool M_Mage_Attack(int attack_type, entity actor, entity targ, .entity weaponent
                }
                case MONSTER_ATTACK_RANGED:
                {
-                       if(!actor.mage_spike)
+                       if(random() <= autocvar_g_monster_mage_attack_teleport_chance)
                        {
-                               if(random() <= 0.4)
-                               {
-                                       OffhandWeapon off = OFFHAND_MAGE_TELEPORT;
-                                       actor.OffhandMageTeleport_key_pressed = 0;
-                                       off.offhand_think(off, actor, 1);
-                                       return true;
-                               }
-                               else
-                               {
-                                       setanim(actor, actor.anim_shoot, true, true, true);
-                                       actor.attack_finished_single[0] = time + (autocvar_g_monster_mage_attack_spike_delay);
-                                       actor.anim_finished = time + 1;
-                                       Weapon wep = WEP_MAGE_SPIKE;
-                                       wep.wr_think(wep, actor, weaponentity, 1);
-                                       return true;
-                               }
+                               OffhandWeapon off = OFFHAND_MAGE_TELEPORT;
+                               actor.OffhandMageTeleport_key_pressed = 0;
+                               off.offhand_think(off, actor, 1);
+                               return true;
                        }
-
-                       if(actor.mage_spike)
+                       else if(!actor.mage_spike && random() <= autocvar_g_monster_mage_attack_spike_chance)
+                       {
+                               setanim(actor, actor.anim_shoot, true, true, true);
+                               actor.attack_finished_single[0] = time + (autocvar_g_monster_mage_attack_spike_delay);
+                               actor.anim_finished = time + 1;
+                               actor.state = MONSTER_ATTACK_MELEE; // prevent moving while firing spike
+                               Weapon wep = WEP_MAGE_SPIKE;
+                               wep.wr_think(wep, actor, weaponentity, 1);
                                return true;
-                       else
-                               return false;
+                       }
+
+                       return false;
                }
        }
 
@@ -448,7 +470,7 @@ METHOD(Mage, mr_pain, float(Mage this, entity actor, float damage_take, entity a
 METHOD(Mage, mr_death, bool(Mage this, entity actor))
 {
     TC(Mage, this);
-    setanim(actor, actor.anim_die1, false, true, true);
+    setanim(actor, ((random() > 0.5) ? actor.anim_die2 : actor.anim_die1), false, true, true);
     return true;
 }
 
@@ -462,6 +484,8 @@ METHOD(Mage, mr_anim, bool(Mage this, entity actor))
     actor.anim_walk = animfixfps(actor, '1 1 1', none);
     actor.anim_run = animfixfps(actor, '1 1 1', none);
     actor.anim_shoot = animfixfps(actor, '2 1 5', none); // analyze models and set framerate
+    actor.anim_duckjump = animfixfps(actor, '4 1 5', none); // analyze models and set framerate
+    actor.anim_melee = animfixfps(actor, '5 1 5', none); // analyze models and set framerate
     //actor.anim_fire1 = animfixfps(actor, '3 1 5', none); // analyze models and set framerate
     //actor.anim_fire2 = animfixfps(actor, '4 1 5', none); // analyze models and set framerate
     //actor.anim_fire3 = animfixfps(actor, '5 1 5', none); // analyze models and set framerate
index 47c0cb2fe4615af49105c651d2bc3192c9452b5f..aa025cc48867ada7d9adf7679cd4e6900edb69e1 100644 (file)
@@ -1179,7 +1179,7 @@ string uid2name(string myuid) {
        return s;
 }
 
-float MoveToRandomLocationWithinBounds(entity e, vector boundmin, vector boundmax, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance)
+bool MoveToRandomLocationWithinBounds(entity e, vector boundmin, vector boundmax, float goodcontents, float badcontents, float badsurfaceflags, int attempts, float maxaboveground, float minviewdistance, bool frompos)
 {
     float m, i;
     vector start, org, delta, end, enddown, mstart;
@@ -1239,14 +1239,22 @@ float MoveToRandomLocationWithinBounds(entity e, vector boundmin, vector boundma
 
        // rule 4: we must "see" some spawnpoint or item
     entity sp = NULL;
-    IL_EACH(g_spawnpoints, checkpvs(mstart, it),
+    if(frompos)
     {
-       if((traceline(mstart, it.origin, MOVE_NORMAL, e), trace_fraction) >= 1)
-       {
-               sp = it;
-               break;
-       }
-    });
+       if((traceline(mstart, e.origin, MOVE_NORMAL, e), trace_fraction) >= 1)
+               sp = e;
+    }
+    if(!sp)
+    {
+           IL_EACH(g_spawnpoints, checkpvs(mstart, it),
+           {
+               if((traceline(mstart, it.origin, MOVE_NORMAL, e), trace_fraction) >= 1)
+               {
+                       sp = it;
+                       break;
+               }
+           });
+       }
        if(!sp)
        {
                int items_checked = 0;
@@ -1304,9 +1312,9 @@ float MoveToRandomLocationWithinBounds(entity e, vector boundmin, vector boundma
         return false;
 }
 
-float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance)
+bool MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, int attempts, float maxaboveground, float minviewdistance)
 {
-       return MoveToRandomLocationWithinBounds(e, world.mins, world.maxs, goodcontents, badcontents, badsurfaceflags, attempts, maxaboveground, minviewdistance);
+       return MoveToRandomLocationWithinBounds(e, world.mins, world.maxs, goodcontents, badcontents, badsurfaceflags, attempts, maxaboveground, minviewdistance, false);
 }
 
 void write_recordmarker(entity pl, float tstart, float dt)
index 2374b4869bc6c5415c08c319a162850ca9871440..19107a01a486da111a28a5a43d32a968aa016707 100644 (file)
@@ -90,9 +90,9 @@ float LostMovetypeFollow(entity ent);
 
 string uid2name(string myuid);
 
-float MoveToRandomLocationWithinBounds(entity e, vector boundmin, vector boundmax, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance);
+bool MoveToRandomLocationWithinBounds(entity e, vector boundmin, vector boundmax, float goodcontents, float badcontents, float badsurfaceflags, int attempts, float maxaboveground, float minviewdistance, bool frompos);
 
-float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance);
+bool MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, int attempts, float maxaboveground, float minviewdistance);
 
 string NearestLocation(vector p);