7 void M_Mage_Attack_Push(
entity this);
23 M_Mage_Attack_Push(actor);
31 .bool OffhandMageTeleport_key_pressed;
32 METHOD(OffhandMageTeleport, offhand_think,
void(OffhandMageTeleport
this,
entity player,
bool key_pressed))
34 TC(OffhandMageTeleport,
this);
35 if (key_pressed && !player.OffhandMageTeleport_key_pressed)
36 M_Mage_Attack_Teleport(player, player.enemy);
37 player.OffhandMageTeleport_key_pressed = key_pressed;
40 OffhandMageTeleport OFFHAND_MAGE_TELEPORT;
41 STATIC_INIT(OFFHAND_MAGE_TELEPORT) { OFFHAND_MAGE_TELEPORT =
NEW(OffhandMageTeleport); }
43 float autocvar_g_monster_mage_health;
44 float autocvar_g_monster_mage_damageforcescale = 0.5;
45 float autocvar_g_monster_mage_attack_spike_damage;
46 float autocvar_g_monster_mage_attack_spike_radius;
47 float autocvar_g_monster_mage_attack_spike_delay;
48 float autocvar_g_monster_mage_attack_spike_accel;
49 float autocvar_g_monster_mage_attack_spike_decel;
50 float autocvar_g_monster_mage_attack_spike_turnrate;
51 float autocvar_g_monster_mage_attack_spike_speed_max;
52 float autocvar_g_monster_mage_attack_spike_smart;
53 float autocvar_g_monster_mage_attack_spike_smart_trace_min;
54 float autocvar_g_monster_mage_attack_spike_smart_trace_max;
55 float autocvar_g_monster_mage_attack_spike_smart_mindist;
56 float autocvar_g_monster_mage_attack_push_damage;
57 float autocvar_g_monster_mage_attack_push_radius;
58 float autocvar_g_monster_mage_attack_push_delay;
59 float autocvar_g_monster_mage_attack_push_force;
60 float autocvar_g_monster_mage_heal_self;
61 float autocvar_g_monster_mage_heal_allies;
62 float autocvar_g_monster_mage_heal_minhealth;
63 float autocvar_g_monster_mage_heal_range;
64 float autocvar_g_monster_mage_heal_delay;
65 float autocvar_g_monster_mage_shield_time;
66 float autocvar_g_monster_mage_shield_delay;
67 float autocvar_g_monster_mage_shield_blockpercent;
68 float autocvar_g_monster_mage_speed_stop;
69 float autocvar_g_monster_mage_speed_run;
70 float autocvar_g_monster_mage_speed_walk;
81 void M_Mage_Defend_Heal(
entity this);
82 void M_Mage_Defend_Shield(
entity this);
85 .float mage_shield_delay;
95 if(STAT(FROZEN, targ))
99 if(StatusEffects_active(STATUSEFFECT_Shield, targ))
121 void M_Mage_Attack_Spike_Explode(
entity this,
entity directhitentity)
129 Send_Effect(EFFECT_EXPLOSION_SMALL, this.
origin,
'0 0 0', 1);
130 RadiusDamage (
this, this.
realowner, (autocvar_g_monster_mage_attack_spike_damage), (autocvar_g_monster_mage_attack_spike_damage) * 0.5, (autocvar_g_monster_mage_attack_spike_radius),
136 void M_Mage_Attack_Spike_Touch(
entity this,
entity toucher)
140 M_Mage_Attack_Spike_Explode(
this, toucher);
146 void M_Mage_Attack_Spike_Think(
entity this)
150 M_Mage_Attack_Spike_Explode(
this,
NULL);
155 spd - (autocvar_g_monster_mage_attack_spike_decel) *
frametime,
156 (autocvar_g_monster_mage_attack_spike_speed_max),
157 spd + (autocvar_g_monster_mage_attack_spike_accel) * frametime
167 vector eorg = 0.5 * (e.absmin + e.absmax);
168 float turnrate = (autocvar_g_monster_mage_attack_spike_turnrate);
173 if ((autocvar_g_monster_mage_attack_spike_smart) &&
vdist(eorg - this.
origin, >, autocvar_g_monster_mage_attack_spike_smart_mindist))
177 traceline(this.
origin, this.
origin + olddir * this.wait,
false,
this);
179 traceline(this.
origin, eorg,
false,
this);
182 this.wait =
bound((autocvar_g_monster_mage_attack_spike_smart_trace_min),
vlen(this.
origin -
trace_endpos), this.wait = (autocvar_g_monster_mage_attack_spike_smart_trace_max));
203 entity missile =
new(M_Mage_Attack_Spike);
204 missile.owner = missile.realowner =
this;
205 setthink(missile, M_Mage_Attack_Spike_Think);
206 missile.ltime =
time + 7;
207 missile.nextthink =
time;
210 missile.flags = FL_PROJECTILE;
214 setsize(missile,
'0 0 0',
'0 0 0');
215 missile.velocity = dir * 400;
216 missile.avelocity =
'300 300 300';
217 missile.enemy = this.
enemy;
218 settouch(missile, M_Mage_Attack_Spike_Touch);
220 this.mage_spike = missile;
225 void M_Mage_Defend_Heal(
entity this)
227 float washealed =
false;
229 FOREACH_ENTITY_RADIUS(this.
origin, autocvar_g_monster_mage_heal_range, M_Mage_Defend_Heal_Check(
this, it),
251 fx = EFFECT_AMMO_REGEN;
258 fx = EFFECT_ARMOR_REPAIR;
262 float hp = ((it ==
this) ? autocvar_g_monster_mage_heal_self : autocvar_g_monster_mage_heal_allies);
268 Send_Effect(fx, it.origin,
'0 0 0', 1);
272 Send_Effect(EFFECT_HEALING, it.origin,
'0 0 0', 1);
281 setanim(
this, this.anim_shoot,
true,
true,
true);
287 void M_Mage_Attack_Push(
entity this)
290 RadiusDamage (
this,
this, (autocvar_g_monster_mage_attack_push_damage), (autocvar_g_monster_mage_attack_push_damage), (autocvar_g_monster_mage_attack_push_radius),
291 NULL,
NULL, (autocvar_g_monster_mage_attack_push_force), DEATH_MONSTER_MAGE.m_id,
DMG_NOWEP,
this.enemy);
292 Send_Effect(EFFECT_TE_EXPLOSION, this.
origin,
'0 0 0', 1);
294 setanim(
this, this.anim_shoot,
true,
true,
true);
301 if(
vdist(targ.origin -
this.origin, >, 1500))
return;
311 Send_Effect(EFFECT_SPAWN_NEUTRAL, this.
origin,
'0 0 0', 1);
312 Send_Effect(EFFECT_SPAWN_NEUTRAL, newpos,
'0 0 0', 1);
326 void M_Mage_Defend_Shield(
entity this)
328 StatusEffects_apply(STATUSEFFECT_Shield,
this,
time + autocvar_g_monster_mage_shield_time, 0);
329 this.mage_shield_delay =
time + (autocvar_g_monster_mage_shield_delay);
331 setanim(
this, this.anim_shoot,
true,
true,
true);
344 Weapon wep = WEP_MAGE_SPIKE;
346 wep.wr_think(wep, actor, weaponentity, 2);
354 if(!actor.mage_spike)
359 off.offhand_think(off, actor,
true);
364 setanim(actor, actor.anim_shoot,
true,
true,
true);
365 actor.attack_finished_single[0] =
time + (autocvar_g_monster_mage_attack_spike_delay);
366 actor.anim_finished =
time + 1;
367 Weapon wep = WEP_MAGE_SPIKE;
368 wep.wr_think(wep, actor, weaponentity, 1);
391 bool need_help =
false;
395 if(
vdist(it.origin - actor.origin, <=, autocvar_g_monster_mage_heal_range))
396 if(M_Mage_Defend_Heal_Check(actor, it))
407 if(
vdist(it.origin - actor.origin, <=, autocvar_g_monster_mage_heal_range))
408 if(M_Mage_Defend_Heal_Check(actor, it))
417 if(
time >= actor.attack_finished_single[0])
419 M_Mage_Defend_Heal(actor);
421 if(actor.enemy &&
time >= actor.mage_shield_delay &&
random() < 0.5)
422 if(
GetResource(actor,
RES_HEALTH) < actor.max_health && !StatusEffects_active(STATUSEFFECT_Shield, actor))
423 M_Mage_Defend_Shield(actor);
437 setanim(actor, actor.anim_die1,
false,
true,
true);
447 actor.anim_die1 = animfixfps(actor,
'4 1 0.5', none);
448 actor.anim_walk = animfixfps(actor,
'1 1 1', none);
449 actor.anim_idle = animfixfps(actor,
'0 1 1', none);
450 actor.anim_pain1 = animfixfps(actor,
'3 1 2', none);
451 actor.anim_shoot = animfixfps(actor,
'2 1 5', none);
452 actor.anim_run = animfixfps(actor,
'5 1 1', none);
462 if(!actor.speed) { actor.speed = (autocvar_g_monster_mage_speed_walk); }
463 if(!actor.speed2) { actor.speed2 = (autocvar_g_monster_mage_speed_run); }
464 if(!actor.stopspeed) { actor.stopspeed = (autocvar_g_monster_mage_speed_stop); }
465 if(!actor.damageforcescale) { actor.damageforcescale = (autocvar_g_monster_mage_damageforcescale); }
467 actor.monster_loot = ITEM_HealthBig;
468 actor.monster_attackfunc = M_Mage_Attack;
const int HITTYPE_SPLASH
automatically set by RadiusDamage
#define IL_EACH(this, cond, body)
entity Monster_FindTarget(entity this)
bool SetResourceExplicit(entity e, Resource res_type, float amount)
Sets the resource amount of an entity without calling any hooks.
#define FOREACH_CLIENT(cond, body)
void w_ready(Weapon thiswep, entity actor,.entity weaponentity, int fire)
#define STATIC_INIT(func)
during worldspawn
spawnfunc(info_player_attacker)
string W_Sound(string w_snd)
#define METHOD(cname, name, prototype)
void CSQCProjectile(entity e, float clientanimate, int type, float docull)
IntrusiveList g_bot_dodge
void TakeResource(entity receiver, Resource res_type, float amount)
Takes an entity some resource.
#define PROJECTILE_TOUCH(e, t)
float autocvar_g_balance_health_regenstable
int autocvar_g_balance_armor_regenstable
const float MOVE_NOMONSTERS
ERASEABLE entity IL_PUSH(IntrusiveList this, entity it)
Push to tail.
void UpdateCSQCProjectile(entity e)
float autocvar_g_monsters_target_range
void GiveResourceWithLimit(entity receiver, Resource res_type, float amount, float limit)
Gives an entity some resource but not more than a limit.
const int MONSTERFLAG_INVINCIBLE
bool weapon_prepareattack(Weapon thiswep, entity actor,.entity weaponentity, bool secondary, float attacktime)
float g_pickup_rockets_max
const int MONSTER_ATTACK_MELEE
const int MONSTER_ATTACK_RANGED
float g_pickup_shells_max
bool Heal(entity targ, entity inflictor, float amount, float limit)
const int PROJECTILE_MAGE_SPIKE
#define W_SetupShot_Dir(ent, wepent, s_forward, antilag, recoil, snd, chan, maxdamage, deathtype)
void monster_makevectors(entity this, entity targ)
vector(float skel, float bonenum) _skel_get_boneabs_hidden
float MOVETYPE_FLYMISSILE
IntrusiveList g_projectiles
float GetResource(entity e, Resource res_type)
Returns the current amount of resource the given entity has.
bool Monster_Spawn(entity this, bool check_appear, Monster mon)
#define vdist(v, cmp, f)
Vector distance comparison, avoids sqrt()
float g_pickup_plasma_max
void weapon_thinkf(entity actor,.entity weaponentity, WFRAME fr, float t, void(Weapon thiswep, entity actor,.entity weaponentity, int fire) func)
float RadiusDamage(entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float forceintensity, int deathtype,.entity weaponentity, entity directhitentity)
vector trace_plane_normal
#define sound(e, c, s, v, a)
#define SOUND(name, path)
fields which are explicitly/manually set are marked with "M", fields set automatically are marked wit...
void set_movetype(entity this, int mt)
float attack_finished_single[MAX_WEAPONSLOTS]