X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fcommon%2Fmonsters%2Fmonster%2Fmage.qc;h=70496905b43c98a3840a92079f99a3bb76ed3ae5;hb=80e96d3476de18ec2d27c905eb789bd39b2f52f9;hp=8addac3531f58b4f02625b27d4082c078cf41371;hpb=c05104bde1e758c4022f9755f02f177aa0476134;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/common/monsters/monster/mage.qc b/qcsrc/common/monsters/monster/mage.qc index 8addac353..70496905b 100644 --- a/qcsrc/common/monsters/monster/mage.qc +++ b/qcsrc/common/monsters/monster/mage.qc @@ -47,16 +47,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; @@ -201,7 +207,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; @@ -225,7 +231,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), { @@ -243,11 +249,11 @@ void M_Mage_Defend_Heal(entity this) } case 1: { - if(GetResource(this, RES_CELLS)) GiveResourceWithLimit(it, RES_CELLS, 1, g_pickup_cells_max); - if(GetResource(this, RES_PLASMA)) GiveResourceWithLimit(it, RES_PLASMA, 1, g_pickup_plasma_max); - if(GetResource(this, RES_ROCKETS)) GiveResourceWithLimit(it, RES_ROCKETS, 1, g_pickup_rockets_max); - if(GetResource(this, RES_SHELLS)) GiveResourceWithLimit(it, RES_SHELLS, 2, g_pickup_shells_max); - if(GetResource(this, RES_BULLETS)) GiveResourceWithLimit(it, RES_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; @@ -279,8 +285,9 @@ 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; } } @@ -292,8 +299,10 @@ 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) @@ -301,13 +310,33 @@ void M_Mage_Attack_Teleport(entity this, entity targ) if(!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, 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); @@ -321,7 +350,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 +366,7 @@ void M_Mage_Defend_Shield(entity this) SetResourceExplicit(this, RES_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 +376,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,29 +388,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; - 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; } } @@ -447,7 +472,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; } @@ -457,12 +482,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