12 if (this.
realowner.(weaponentity).lastrocket ==
this)
29 vector force_xyzscale =
'1 1 1';
30 force_xyzscale.x =
WEP_CVAR(WEP_DEVASTATOR, force_xyscale);
31 force_xyzscale.y =
WEP_CVAR(WEP_DEVASTATOR, force_xyscale);
35 WEP_CVAR(WEP_DEVASTATOR, edgedamage),
47 Weapon thiswep = WEP_DEVASTATOR;
49 if (this.
realowner.(weaponentity).m_weapon == thiswep
72 bool handled_as_rocketjump =
false;
74 bool allow_rocketjump =
WEP_CVAR(WEP_DEVASTATOR, remote_jump);
76 allow_rocketjump =
M_ARGV(0,
bool);
78 if (allow_rocketjump &&
WEP_CVAR(WEP_DEVASTATOR, remote_jump_radius))
81 for (; head; head = head.chain)
82 if (head.takedamage && head ==
this.realowner
83 &&
vdist(this.
origin - head.WarpZone_findradius_nearest, <=,
WEP_CVAR(WEP_DEVASTATOR, remote_jump_radius)))
86 handled_as_rocketjump =
true;
89 if (
WEP_CVAR(WEP_DEVASTATOR, remote_jump_velocity_z_add))
91 head.velocity.x *= 0.9;
92 head.velocity.y *= 0.9;
93 head.velocity.z =
bound(
94 WEP_CVAR(WEP_DEVASTATOR, remote_jump_velocity_z_min),
95 head.velocity.z +
WEP_CVAR(WEP_DEVASTATOR, remote_jump_velocity_z_add),
96 WEP_CVAR(WEP_DEVASTATOR, remote_jump_velocity_z_max)
102 WEP_CVAR(WEP_DEVASTATOR, remote_jump_damage),
103 WEP_CVAR(WEP_DEVASTATOR, remote_jump_damage),
104 WEP_CVAR(WEP_DEVASTATOR, remote_jump_radius),
107 (
WEP_CVAR(WEP_DEVASTATOR, remote_jump_force) ?
WEP_CVAR(WEP_DEVASTATOR, remote_jump_force) : 0),
117 WEP_CVAR(WEP_DEVASTATOR, remote_damage),
118 WEP_CVAR(WEP_DEVASTATOR, remote_edgedamage),
119 WEP_CVAR(WEP_DEVASTATOR, remote_radius),
120 (handled_as_rocketjump ? head :
NULL),
122 WEP_CVAR(WEP_DEVASTATOR, remote_force),
128 Weapon thiswep = WEP_DEVASTATOR;
129 if (this.
realowner.(weaponentity).m_weapon == thiswep
143 && this.
realowner.(weaponentity).lastrocket)
156 if (thisdir * goaldir > maxturn_cos)
158 if (thisdir * goaldir < -0.9998)
169 float f = thisdir * goaldir;
172 float m2 = maxturn_cos * maxturn_cos;
174 return normalize(thisdir + goaldir * v.y);
204 if (this.
realowner.(weaponentity).m_weapon == WEP_DEVASTATOR)
206 if (
this == this.
realowner.(weaponentity).lastrocket
207 && !
this.realowner.(weaponentity).rl_release
209 &&
WEP_CVAR(WEP_DEVASTATOR, guiderate)
213 vector desireddir, olddir, newdir, desiredorigin, goal;
214 float f =
WEP_CVAR(WEP_DEVASTATOR, guideratedelay);
235 goal = desiredorigin + ((this.
origin - desiredorigin) * desireddir +
WEP_CVAR(WEP_DEVASTATOR, guidegoal)) * desireddir;
288 W_SetupShot_ProjectileSize(actor, weaponentity,
'-3 -3 -3',
'3 3 3',
false, 5, SND_DEVASTATOR_FIRE,
CH_WEAPON_A,
WEP_CVAR(WEP_DEVASTATOR, damage), thiswep.
m_id);
292 missile.weaponentity_fld = weaponentity;
293 missile.owner = missile.realowner = actor;
295 if (
WEP_CVAR(WEP_DEVASTATOR, detonatedelay) >= 0)
296 missile.spawnshieldtime =
time +
WEP_CVAR(WEP_DEVASTATOR, detonatedelay);
298 missile.spawnshieldtime = -1;
299 missile.pushltime =
time +
WEP_CVAR(WEP_DEVASTATOR, guidedelay);
300 missile.classname =
"rocket";
301 missile.bot_dodge =
true;
302 missile.bot_dodgerating =
WEP_CVAR(WEP_DEVASTATOR, damage) * 2;
308 missile.damagedbycontents =
true;
313 missile.projectiledeathtype = thiswep.
m_id;
314 setsize(missile,
'-3 -3 -3',
'3 3 3');
322 missile.nextthink =
time;
324 missile.rl_detonate_later = (fire & 2);
335 if (
time >= missile.nextthink)
341 if (!
WEP_CVAR(WEP_DEVASTATOR, guidestop) && !actor.(weaponentity).rl_release)
343 int fired_rockets = 0;
354 if (
WEP_CVAR(WEP_DEVASTATOR, guiderate) > 0)
355 spd *=
sqrt(
WEP_CVAR(WEP_DEVASTATOR, guiderate)) * (20 / 9.489);
357 bool shot_accurate = (
WEP_CVAR(WEP_DEVASTATOR, guiderate) < 50);
359 float pred_time =
bound(0.02, 0.02 + (8 -
skill) * 0.01, 0.1);
363 float selfdamage = 0, teamdamage = 0, enemydamage = 0;
364 float pred_selfdamage = 0, pred_teamdamage = 0, pred_enemydamage = 0;
365 float edgedamage =
WEP_CVAR(WEP_DEVASTATOR, edgedamage);
366 float coredamage =
WEP_CVAR(WEP_DEVASTATOR, damage);
371 IL_EACH(g_bot_targets, it.bot_attack,
374 vector target_pos = it.origin + (it.maxs - it.mins) * 0.5;
377 float dist = vlen(target_pos - rocket.origin);
379 if (dist <= edgeradius)
381 f = (edgeradius > 0) ? max(0, 1 - (dist / edgeradius)) : 1;
382 dmg = coredamage * f + edgedamage * (1 - f);
385 float pred_dist = vlen(target_pos + it.velocity * pred_time - (rocket.origin + rocket.velocity * pred_time));
387 if (pred_dist <= edgeradius)
389 f = (edgeradius > 0) ? max(0, 1 - (pred_dist / edgeradius)) : 1;
390 pred_dmg = coredamage * f + edgedamage * (1 - f);
396 if (StatusEffects_active(STATUSEFFECT_Strength, it))
397 dmg *= autocvar_g_balance_powerup_strength_damage;
398 if (StatusEffects_active(STATUSEFFECT_Shield, it))
399 dmg *= autocvar_g_balance_powerup_invincible_takedamage;
402 pred_selfdamage += pred_dmg;
404 else if (SAME_TEAM(it, actor))
406 if (StatusEffects_active(STATUSEFFECT_Shield, it))
407 dmg *= autocvar_g_balance_powerup_invincible_takedamage;
410 pred_teamdamage += pred_dmg;
412 else if (bot_shouldattack(actor, it))
414 if (StatusEffects_active(STATUSEFFECT_Shield, it))
415 dmg *= autocvar_g_balance_powerup_invincible_takedamage;
418 pred_enemydamage += pred_dmg;
434 float good_damage = enemydamage;
435 float pred_good_damage = pred_enemydamage;
436 float bad_damage = selfdamage + teamdamage;
437 float pred_bad_damage = pred_selfdamage + pred_teamdamage;
441 if (good_damage > coredamage * 0.1 && good_damage > bad_damage * 1.5
442 && (pred_good_damage < good_damage + 2 || pred_good_damage < pred_bad_damage * 1.5))
455 if (
WEP_CVAR(WEP_DEVASTATOR, reload_ammo) && actor.(weaponentity).clip_load <
WEP_CVAR(WEP_DEVASTATOR,
ammo))
457 thiswep.wr_reload(thiswep, actor, weaponentity);
463 if ((actor.(weaponentity).rl_release ||
WEP_CVAR(WEP_DEVASTATOR, guidestop))
475 && actor.(weaponentity).m_switchweapon == thiswep)
477 bool rockfound =
false;
480 if (!it.rl_detonate_later)
482 it.rl_detonate_later = true;
503 if (
WEP_CVAR(WEP_DEVASTATOR, reload_ammo))
514 if (actor.rl_release == 0)
523 LOG_INFOF(
"W_Devastator(WR_CHECKAMMO1): %d, %.2f, %d: %s", actor.rl_release,
GetResource(actor, thiswep.ammo_type),
WEP_CVAR(WEP_DEVASTATOR,
ammo), (ammo_amount ?
"TRUE" :
"FALSE"));
555 return WEAPON_DEVASTATOR_SUICIDE;
561 return WEAPON_DEVASTATOR_MURDER_SPLASH;
563 return WEAPON_DEVASTATOR_MURDER_DIRECT;
587 PAR(_(
"The %s launches a remote controlled rocket, dealing significant damage when it explodes on impact. "
588 "If the primary fire is held, the rocket can be guided by the user's aim, allowing steering it towards enemies."),
COLORED_NAME(
this));
589 PAR(_(
"The secondary fire can be used to immediately detonate rockets, allowing dealing damage to enemies even if the rocket barely missed colliding with them."));
590 PAR(_(
"It consumes a bunch of %s ammo for each rocket, which can end up being depleted quickly, so often players alternate with another weapon like %s."),
COLORED_NAME(ITEM_Rockets),
COLORED_NAME(WEP_VORTEX));
591 PAR(_(
"Due to its high damage output, the %s is one of the most commonly used weapons. "
592 "It can be used in almost any scenario, working best in medium range combat. "
593 "In close range combat, the large splash radius often results in rockets damaging both you and your enemy."),
COLORED_NAME(
this));
594 PAR(_(
"Due to the ability to remotely detonate rockets, a common usage is \"rocket flying,\" where you fire a rocket and immediately detonate it to boost yourself while mid-air, "
595 "much more effective with the %s mutator enabled."),
COLORED_NAME(MUTATOR_rocketflying));
bool bot_aim(entity this,.entity weaponentity, float shotspeed, float shotspeedupward, float maxshottime, float applygravity, bool shot_accurate)
IntrusiveList g_bot_dodge
#define MUTATOR_CALLHOOK(id,...)
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
float GetResource(entity e, Resource res_type)
Returns the current amount of resource the given entity has.
void TakeResource(entity receiver, Resource res_type, float amount)
Takes an entity some resource.
bool SetResourceExplicit(entity e, Resource res_type, float amount)
Sets the resource amount of an entity without calling any hooks.
fields which are explicitly/manually set are marked with "M", fields set automatically are marked wit...
Resource ammo_type
M: ammotype : main ammo type.
#define COLORED_NAME(this)
const int IT_UNLIMITED_AMMO
bool IsFlying(entity this)
#define PHYS_INPUT_BUTTON_ATCK(s)
#define PHYS_INPUT_BUTTON_ATCK2(s)
void UpdateCSQCProjectile(entity e)
void CSQCProjectile(entity e, float clientanimate, int type, float docull)
float csqcprojectile_clientanimate
float RadiusDamage(entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float forceintensity, int deathtype,.entity weaponentity, entity directhitentity)
float RadiusDamageForSource(entity inflictor, vector inflictororigin, vector inflictorvelocity, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, bool inflictorselfdamage, float forceintensity, vector forcexyzscale, int deathtype,.entity weaponentity, entity directhitentity)
IntrusiveList g_damagedbycontents
float autocvar_g_balance_selfdamagepercent
void W_Devastator_Explode(entity this, entity directhitentity)
void W_Devastator_Explode_think(entity this)
void W_Devastator_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype,.entity weaponentity, vector hitloc, vector force)
void W_Devastator_DoRemoteExplode(entity this,.entity weaponentity)
void W_Devastator_Attack(Weapon thiswep, entity actor,.entity weaponentity, int fire)
void W_Devastator_Touch(entity this, entity toucher)
void W_Devastator_RemoteExplode(entity this,.entity weaponentity)
void W_Devastator_Unregister(entity this)
vector W_Devastator_SteerTo(vector thisdir, vector goaldir, float maxturn_cos)
void W_Devastator_Think(entity this)
#define pointparticles(effect, org, vel, howmany)
void Send_Effect(entity eff, vector eff_loc, vector eff_vel, int eff_cnt)
ERASEABLE entity IL_PUSH(IntrusiveList this, entity it)
Push to tail.
#define IL_EACH(this, cond, body)
vector WarpZone_RefSys_TransformVelocity(entity from, entity to, vector vel)
entity WarpZone_FindRadius(vector org, float rad, bool needlineofsight)
entity WarpZone_RefSys_SpawnSameRefSys(entity me)
vector WarpZone_RefSys_TransformOrigin(entity from, entity to, vector org)
ERASEABLE vector solve_quadratic(float a, float b, float c)
ax^2 + bx + c = 0
void set_movetype(entity this, int mt)
void Send_Notification(NOTIF broadcast, entity client, MSG net_type, Notification net_name,...count)
entity Notification
always last
#define METHOD(cname, name, prototype)
const int PROJECTILE_ROCKET
float health
Legacy fields for the resources. To be removed.
#define w_getbestweapon(ent, wepent)
float W_CheckProjectileDamage(entity inflictor, entity projowner, int deathtype, float exception)
void W_PrepareExplosionByDamage(entity this, entity attacker, void(entity this) explode)
bool W_DualWielding(entity player)
IntrusiveList g_projectiles
#define PROJECTILE_MAKETRIGGER(e)
float WarpZone_Projectile_Touch(entity this, entity toucher)
#define sound(e, c, s, v, a)
bool StatusEffects_active(StatusEffect this, entity actor)
float autocvar_g_balance_powerup_strength_damage
#define PAR(...)
Adds an individually translatable paragraph to PAGE_TEXT without having to deal with strcat and sprin...
#define W_SetupShot_ProjectileSize(ent, wepent, mi, ma, antilag, recoil, snd, chan, maxdamage, deathtype)
#define W_SetupProjVelocity_Basic(ent, pspeed, pspread)
#define vdist(v, cmp, f)
Vector distance comparison, avoids sqrt()
ERASEABLE vector NearestPointOnBox(entity box, vector org)
string W_Guide_Keybinds(Weapon wep)
void W_MuzzleFlash(Weapon thiswep, entity actor,.entity weaponentity, vector shotorg, vector shotdir)
string W_Guide_DPS_onlyOne_unnamed(string name)
#define WEP_CVAR(wep, name)
const int MAX_WEAPONSLOTS
entity weaponentities[MAX_WEAPONSLOTS]
void W_DecreaseAmmo(Weapon wep, entity actor, float ammo_use,.entity weaponentity)
float W_WeaponSpeedFactor(entity this)
void W_Reload(entity actor,.entity weaponentity, float sent_ammo_min, Sound sent_sound)
void weapon_thinkf(entity actor,.entity weaponentity, WFRAME fr, float t, void(Weapon thiswep, entity actor,.entity weaponentity, int fire) func)
bool weapon_prepareattack(Weapon thiswep, entity actor,.entity weaponentity, bool secondary, float attacktime)
void w_ready(Weapon thiswep, entity actor,.entity weaponentity, int fire)
#define ATTACK_FINISHED(ent, w)
float weapon_load[REGISTRY_MAX(Weapons)]