X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fcommon%2Fmonsters%2Fmonster%2Fmage.qc;h=8cfa77e6535aa7dfe70925d12a58cb02b9bb4537;hb=8e75c2485213b1e6f41f87caa88d89f8988a1b17;hp=88120a0ea7550acbb93cd46e9b94022165b18ba2;hpb=7e5268799e95d0dd6f2b77ed4e097b0adc755f2b;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/common/monsters/monster/mage.qc b/qcsrc/common/monsters/monster/mage.qc index 88120a0ea..8cfa77e65 100644 --- a/qcsrc/common/monsters/monster/mage.qc +++ b/qcsrc/common/monsters/monster/mage.qc @@ -1,6 +1,40 @@ #include "mage.qh" #ifdef SVQC +float autocvar_g_monster_mage_health; +float autocvar_g_monster_mage_damageforcescale = 0.5; +float autocvar_g_monster_mage_attack_spike_damage; +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; +float autocvar_g_monster_mage_heal_range; +float autocvar_g_monster_mage_heal_delay; +float autocvar_g_monster_mage_shield_time; +float autocvar_g_monster_mage_shield_delay; +float autocvar_g_monster_mage_shield_blockpercent; +float autocvar_g_monster_mage_speed_stop; +float autocvar_g_monster_mage_speed_run; +float autocvar_g_monster_mage_speed_walk; SOUND(MageSpike_FIRE, W_Sound("electro_fire")); void M_Mage_Attack_Spike(entity this, vector dir); @@ -12,6 +46,7 @@ METHOD(MageSpike, wr_think, void(MageSpike thiswep, entity actor, .entity weapon if (!IS_PLAYER(actor) || weapon_prepareattack(thiswep, actor, weaponentity, false, 0.2)) { if (!actor.target_range) actor.target_range = autocvar_g_monsters_target_range; actor.enemy = Monster_FindTarget(actor); + monster_makevectors(actor, actor.enemy); W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_MageSpike_FIRE, CH_WEAPON_B, 0, DEATH_MONSTER_MAGE.m_id); if (!IS_PLAYER(actor)) w_shotdir = normalize((actor.enemy.origin + '0 0 10') - actor.origin); M_Mage_Attack_Spike(actor, w_shotdir); @@ -36,82 +71,44 @@ CLASS(OffhandMageTeleport, OffhandWeapon) player.OffhandMageTeleport_key_pressed = key_pressed; } ENDCLASS(OffhandMageTeleport) -OffhandMageTeleport OFFHAND_MAGE_TELEPORT; STATIC_INIT(OFFHAND_MAGE_TELEPORT) { OFFHAND_MAGE_TELEPORT = NEW(OffhandMageTeleport); } - -float autocvar_g_monster_mage_health; -float autocvar_g_monster_mage_damageforcescale = 0.5; -float autocvar_g_monster_mage_attack_spike_damage; -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_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_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_heal_self; -float autocvar_g_monster_mage_heal_allies; -float autocvar_g_monster_mage_heal_minhealth; -float autocvar_g_monster_mage_heal_range; -float autocvar_g_monster_mage_heal_delay; -float autocvar_g_monster_mage_shield_time; -float autocvar_g_monster_mage_shield_delay; -float autocvar_g_monster_mage_shield_blockpercent; -float autocvar_g_monster_mage_speed_stop; -float autocvar_g_monster_mage_speed_run; -float autocvar_g_monster_mage_speed_walk; - -/* -const float mage_anim_idle = 0; -const float mage_anim_walk = 1; -const float mage_anim_attack = 2; -const float mage_anim_pain = 3; -const float mage_anim_death = 4; -const float mage_anim_run = 5; -*/ +OffhandMageTeleport OFFHAND_MAGE_TELEPORT; +STATIC_INIT(OFFHAND_MAGE_TELEPORT) { OFFHAND_MAGE_TELEPORT = NEW(OffhandMageTeleport); } void M_Mage_Defend_Heal(entity this); void M_Mage_Defend_Shield(entity this); .entity mage_spike; .float mage_shield_delay; -.float mage_shield_time; bool M_Mage_Defend_Heal_Check(entity this, entity targ) { if(targ == NULL) return false; - if(GetResourceAmount(targ, RESOURCE_HEALTH) <= 0) + if(GetResource(targ, RES_HEALTH) <= 0) return false; if(DIFF_TEAM(targ, this) && targ != this.monster_follow) return false; if(STAT(FROZEN, targ)) return false; if(!IS_PLAYER(targ)) - return (IS_MONSTER(targ) && GetResourceAmount(targ, RESOURCE_HEALTH) < targ.max_health); - if(targ.items & ITEM_Shield.m_itemid) + return (IS_MONSTER(targ) && GetResource(targ, RES_HEALTH) < targ.max_health); + if(StatusEffects_active(STATUSEFFECT_Shield, targ)) return false; switch(this.skin) { - case 0: return (GetResourceAmount(targ, RESOURCE_HEALTH) < autocvar_g_balance_health_regenstable); + case 0: return (GetResource(targ, RES_HEALTH) < autocvar_g_balance_health_regenstable); case 1: { - return ((GetResourceAmount(targ, RESOURCE_CELLS) && GetResourceAmount(targ, RESOURCE_CELLS) < g_pickup_cells_max) - || (GetResourceAmount(targ, RESOURCE_PLASMA) && GetResourceAmount(targ, RESOURCE_PLASMA) < g_pickup_plasma_max) - || (GetResourceAmount(targ, RESOURCE_ROCKETS) && GetResourceAmount(targ, RESOURCE_ROCKETS) < g_pickup_rockets_max) - || (GetResourceAmount(targ, RESOURCE_BULLETS) && GetResourceAmount(targ, RESOURCE_BULLETS) < g_pickup_nails_max) - || (GetResourceAmount(targ, RESOURCE_SHELLS) && GetResourceAmount(targ, RESOURCE_SHELLS) < g_pickup_shells_max) + return ((GetResource(targ, RES_CELLS) && GetResource(targ, RES_CELLS) < g_pickup_cells_max) + || (GetResource(targ, RES_PLASMA) && GetResource(targ, RES_PLASMA) < g_pickup_plasma_max) + || (GetResource(targ, RES_ROCKETS) && GetResource(targ, RES_ROCKETS) < g_pickup_rockets_max) + || (GetResource(targ, RES_BULLETS) && GetResource(targ, RES_BULLETS) < g_pickup_nails_max) + || (GetResource(targ, RES_SHELLS) && GetResource(targ, RES_SHELLS) < g_pickup_shells_max) ); } - case 2: return (GetResourceAmount(targ, RESOURCE_ARMOR) < autocvar_g_balance_armor_regenstable); - case 3: return (GetResourceAmount(targ, RESOURCE_HEALTH) > 0); + case 2: return (GetResource(targ, RES_ARMOR) < autocvar_g_balance_armor_regenstable); + case 3: return (GetResource(targ, RES_HEALTH) > 0); } return false; @@ -144,7 +141,7 @@ void M_Mage_Attack_Spike_Touch(entity this, entity toucher) // copied from W_Seeker_Think void M_Mage_Attack_Spike_Think(entity this) { - if (time > this.ltime || (this.enemy && GetResourceAmount(this.enemy, RESOURCE_HEALTH) <= 0) || GetResourceAmount(this.owner, RESOURCE_HEALTH) <= 0) { + if (time > this.ltime || (this.enemy && GetResource(this.enemy, RES_HEALTH) <= 0) || !this.owner || GetResource(this.owner, RES_HEALTH) <= 0) { this.projectiledeathtype |= HITTYPE_SPLASH; M_Mage_Attack_Spike_Explode(this, NULL); } @@ -199,7 +196,7 @@ void M_Mage_Attack_Spike(entity this, vector dir) { makevectors(this.angles); - entity missile = spawn(); + entity missile = new(M_Mage_Attack_Spike); missile.owner = missile.realowner = this; setthink(missile, M_Mage_Attack_Spike_Think); missile.ltime = time + 7; @@ -223,7 +220,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), { @@ -241,25 +238,25 @@ void M_Mage_Defend_Heal(entity this) } case 1: { - if(GetResourceAmount(this, RESOURCE_CELLS)) GiveResourceWithLimit(it, RESOURCE_CELLS, 1, g_pickup_cells_max); - if(GetResourceAmount(this, RESOURCE_PLASMA)) GiveResourceWithLimit(it, RESOURCE_PLASMA, 1, g_pickup_plasma_max); - if(GetResourceAmount(this, RESOURCE_ROCKETS)) GiveResourceWithLimit(it, RESOURCE_ROCKETS, 1, g_pickup_rockets_max); - if(GetResourceAmount(this, RESOURCE_SHELLS)) GiveResourceWithLimit(it, RESOURCE_SHELLS, 2, g_pickup_shells_max); - if(GetResourceAmount(this, RESOURCE_BULLETS)) GiveResourceWithLimit(it, RESOURCE_BULLETS, 5, g_pickup_nails_max); + if(GetResource(it, RES_CELLS)) GiveResourceWithLimit(it, RES_CELLS, 1, g_pickup_cells_max); + if(GetResource(it, RES_PLASMA)) GiveResourceWithLimit(it, RES_PLASMA, 1, g_pickup_plasma_max); + if(GetResource(it, RES_ROCKETS)) GiveResourceWithLimit(it, RES_ROCKETS, 1, g_pickup_rockets_max); + if(GetResource(it, RES_SHELLS)) GiveResourceWithLimit(it, RES_SHELLS, 2, g_pickup_shells_max); + if(GetResource(it, RES_BULLETS)) GiveResourceWithLimit(it, RES_BULLETS, 5, g_pickup_nails_max); // TODO: fuel? fx = EFFECT_AMMO_REGEN; break; } case 2: - if(GetResourceAmount(it, RESOURCE_ARMOR) < autocvar_g_balance_armor_regenstable) + if(GetResource(it, RES_ARMOR) < autocvar_g_balance_armor_regenstable) { - GiveResourceWithLimit(it, RESOURCE_ARMOR, autocvar_g_monster_mage_heal_allies, autocvar_g_balance_armor_regenstable); + GiveResourceWithLimit(it, RES_ARMOR, autocvar_g_monster_mage_heal_allies, autocvar_g_balance_armor_regenstable); fx = EFFECT_ARMOR_REPAIR; } break; case 3: float hp = ((it == this) ? autocvar_g_monster_mage_heal_self : autocvar_g_monster_mage_heal_allies); - TakeResource(it, RESOURCE_HEALTH, hp); // TODO: use regular damage functions? needs a way to bypass friendly fire checks + TakeResource(it, RES_HEALTH, hp); // TODO: use regular damage functions? needs a way to bypass friendly fire checks fx = EFFECT_RAGE; break; } @@ -269,16 +266,17 @@ void M_Mage_Defend_Heal(entity this) else { Send_Effect(EFFECT_HEALING, it.origin, '0 0 0', 1); - Heal(it, this, autocvar_g_monster_mage_heal_allies, RESOURCE_LIMIT_NONE); + Heal(it, this, autocvar_g_monster_mage_heal_allies, RES_LIMIT_NONE); if(!(it.spawnflags & MONSTERFLAG_INVINCIBLE) && it.sprite) - WaypointSprite_UpdateHealth(it.sprite, GetResourceAmount(it, RESOURCE_HEALTH)); + WaypointSprite_UpdateHealth(it.sprite, GetResource(it, RES_HEALTH)); } }); 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; } } @@ -290,22 +288,44 @@ 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(vdist(targ.origin - this.origin, >, 1500)) return; + if(vdist(targ.origin - this.origin, >, autocvar_g_monster_mage_attack_teleport_random_range)) 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, 64, 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(targ.origin + ((v_forward * -1) * 200), this.mins, this.maxs, this.origin, MOVE_NOMONSTERS, this); + tracebox(CENTER_OR_VIEWOFS(targ), this.mins, this.maxs, CENTER_OR_VIEWOFS(targ) + ((v_forward * -1) * 200), MOVE_NOMONSTERS, this); if(trace_fraction < 1) return; - vector newpos = targ.origin + ((v_forward * -1) * 200); + vector newpos = trace_endpos; Send_Effect(EFFECT_SPAWN_NEUTRAL, this.origin, '0 0 0', 1); Send_Effect(EFFECT_SPAWN_NEUTRAL, newpos, '0 0 0', 1); @@ -319,23 +339,16 @@ void M_Mage_Attack_Teleport(entity this, entity targ) this.fixangle = true; this.velocity *= 0.5; - this.attack_finished_single[0] = time + 0.2; -} - -void M_Mage_Defend_Shield_Remove(entity this) -{ - this.effects &= ~(EF_ADDITIVE | EF_BLUE); - SetResourceAmountExplicit(this, RESOURCE_ARMOR, autocvar_g_monsters_armor_blockpercent); + this.attack_finished_single[0] = time + autocvar_g_monster_mage_attack_teleport_delay; } void M_Mage_Defend_Shield(entity this) { - this.effects |= (EF_ADDITIVE | EF_BLUE); + StatusEffects_apply(STATUSEFFECT_Shield, this, time + autocvar_g_monster_mage_shield_time, 0); this.mage_shield_delay = time + (autocvar_g_monster_mage_shield_delay); - SetResourceAmountExplicit(this, RESOURCE_ARMOR, autocvar_g_monster_mage_shield_blockpercent); - this.mage_shield_time = time + (autocvar_g_monster_mage_shield_time); + SetResourceExplicit(this, RES_ARMOR, autocvar_g_monster_mage_shield_blockpercent); 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; } @@ -345,7 +358,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; @@ -357,36 +370,32 @@ 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; - off.offhand_think(off, actor, true); - 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; } } return false; } -spawnfunc(monster_mage) { Monster_Spawn(this, true, MON_MAGE.monsterid); } +spawnfunc(monster_mage) { Monster_Spawn(this, true, MON_MAGE); } #endif // SVQC @@ -419,18 +428,13 @@ METHOD(Mage, mr_think, bool(Mage thismon, entity actor)) }); } - if(GetResourceAmount(actor, RESOURCE_HEALTH) < (autocvar_g_monster_mage_heal_minhealth) || need_help) + if(GetResource(actor, RES_HEALTH) < (autocvar_g_monster_mage_heal_minhealth) || need_help) if(time >= actor.attack_finished_single[0]) if(random() < 0.5) M_Mage_Defend_Heal(actor); - if(time >= actor.mage_shield_time && GetResourceAmount(actor, RESOURCE_ARMOR)) - M_Mage_Defend_Shield_Remove(actor); - - if(actor.enemy) - if(GetResourceAmount(actor, RESOURCE_HEALTH) < actor.max_health) - if(time >= actor.mage_shield_delay) - if(random() < 0.5) + if(actor.enemy && time >= actor.mage_shield_delay && random() < 0.5) + if(GetResource(actor, RES_HEALTH) < actor.max_health && !StatusEffects_active(STATUSEFFECT_Shield, actor)) M_Mage_Defend_Shield(actor); return true; @@ -445,7 +449,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; } @@ -455,12 +459,22 @@ METHOD(Mage, mr_anim, bool(Mage this, entity actor)) { TC(Mage, this); vector none = '0 0 0'; - actor.anim_die1 = animfixfps(actor, '4 1 0.5', none); // 2 seconds - actor.anim_walk = animfixfps(actor, '1 1 1', none); actor.anim_idle = animfixfps(actor, '0 1 1', none); - actor.anim_pain1 = animfixfps(actor, '3 1 2', none); // 0.5 seconds + 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_run = animfixfps(actor, '5 1 1', none); + 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 + actor.anim_pain1 = animfixfps(actor, '6 1 2', none); // 0.5 seconds + actor.anim_pain2 = animfixfps(actor, '7 1 2', none); // 0.5 seconds + //actor.anim_pain3 = animfixfps(actor, '8 1 2', none); // 0.5 seconds + actor.anim_die1 = animfixfps(actor, '9 1 0.5', none); // 2 seconds + actor.anim_die2 = animfixfps(actor, '10 1 0.5', none); // 2 seconds + //actor.anim_dead1 = animfixfps(actor, '11 1 0.5', none); // 2 seconds + //actor.anim_dead2 = animfixfps(actor, '12 1 0.5', none); // 2 seconds return true; } #endif @@ -469,7 +483,7 @@ METHOD(Mage, mr_anim, bool(Mage this, entity actor)) METHOD(Mage, mr_setup, bool(Mage this, entity actor)) { TC(Mage, this); - if(!GetResourceAmount(this, RESOURCE_HEALTH)) SetResourceAmountExplicit(actor, RESOURCE_HEALTH, autocvar_g_monster_mage_health); + if(!GetResource(this, RES_HEALTH)) SetResourceExplicit(actor, RES_HEALTH, autocvar_g_monster_mage_health); if(!actor.speed) { actor.speed = (autocvar_g_monster_mage_speed_walk); } if(!actor.speed2) { actor.speed2 = (autocvar_g_monster_mage_speed_run); } if(!actor.stopspeed) { actor.stopspeed = (autocvar_g_monster_mage_speed_stop); }