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
76 bool handled_as_rocketjump =
false;
78 bool allow_rocketjump =
WEP_CVAR(WEP_DEVASTATOR, remote_jump);
80 allow_rocketjump =
M_ARGV(0,
bool);
82 if (allow_rocketjump &&
WEP_CVAR(WEP_DEVASTATOR, remote_jump_radius))
89 handled_as_rocketjump =
true;
92 if (
WEP_CVAR(WEP_DEVASTATOR, remote_jump_velocity_z_add))
94 head.velocity.x *= 0.9;
95 head.velocity.y *= 0.9;
96 head.velocity.z =
bound(
97 WEP_CVAR(WEP_DEVASTATOR, remote_jump_velocity_z_min),
98 head.velocity.z +
WEP_CVAR(WEP_DEVASTATOR, remote_jump_velocity_z_add),
99 WEP_CVAR(WEP_DEVASTATOR, remote_jump_velocity_z_max)
105 WEP_CVAR(WEP_DEVASTATOR, remote_jump_damage),
106 WEP_CVAR(WEP_DEVASTATOR, remote_jump_damage),
107 WEP_CVAR(WEP_DEVASTATOR, remote_jump_radius),
110 (
WEP_CVAR(WEP_DEVASTATOR, remote_jump_force) ?
WEP_CVAR(WEP_DEVASTATOR, remote_jump_force) : 0),
119 WEP_CVAR(WEP_DEVASTATOR, remote_damage),
120 WEP_CVAR(WEP_DEVASTATOR, remote_edgedamage),
121 WEP_CVAR(WEP_DEVASTATOR, remote_radius),
122 (handled_as_rocketjump ? head :
NULL),
124 WEP_CVAR(WEP_DEVASTATOR, remote_force),
130 Weapon thiswep = WEP_DEVASTATOR;
131 if (this.
realowner.(weaponentity).m_weapon == thiswep
145 || !this.
realowner.(weaponentity).lastrocket)
162 if (thisdir * goaldir > maxturn_cos)
164 if (thisdir * goaldir < -0.9998)
175 float f = thisdir * goaldir;
178 float m2 = maxturn_cos * maxturn_cos;
180 return normalize(thisdir + goaldir * v.y);
210 if (this.
realowner.(weaponentity).m_weapon == WEP_DEVASTATOR)
212 if (
this == this.
realowner.(weaponentity).lastrocket
213 && !
this.realowner.(weaponentity).rl_release
215 &&
WEP_CVAR(WEP_DEVASTATOR, guiderate)
219 vector desireddir, olddir, newdir, desiredorigin, goal;
220 float f =
WEP_CVAR(WEP_DEVASTATOR, guideratedelay);
241 goal = desiredorigin + ((this.
origin - desiredorigin) * desireddir +
WEP_CVAR(WEP_DEVASTATOR, guidegoal)) * desireddir;
294 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);
297 entity missile =
new(rocket);
299 missile.weaponentity_fld = weaponentity;
300 missile.owner = missile.realowner = actor;
302 if (
WEP_CVAR(WEP_DEVASTATOR, detonatedelay) >= 0)
303 missile.spawnshieldtime =
time +
WEP_CVAR(WEP_DEVASTATOR, detonatedelay);
305 missile.spawnshieldtime = -1;
306 missile.pushltime =
time +
WEP_CVAR(WEP_DEVASTATOR, guidedelay);
307 missile.bot_dodge =
true;
308 missile.bot_dodgerating =
WEP_CVAR(WEP_DEVASTATOR, damage) * 2;
314 missile.damagedbycontents =
true;
319 missile.projectiledeathtype = thiswep.
m_id;
320 setsize(missile,
'-3 -3 -3',
'3 3 3');
328 missile.nextthink =
time;
330 missile.rl_detonate_later = (fire & 2);
341 if (
time >= missile.nextthink)
347 if (!
WEP_CVAR(WEP_DEVASTATOR, guidestop) && !actor.(weaponentity).rl_release)
349 int fired_rockets = 0;
360 if (
WEP_CVAR(WEP_DEVASTATOR, guiderate) > 0)
361 spd *=
sqrt(
WEP_CVAR(WEP_DEVASTATOR, guiderate)) * (20 / 9.489);
363 bool shot_accurate = (
WEP_CVAR(WEP_DEVASTATOR, guiderate) < 50);
365 float pred_time =
bound(0.02, 0.02 + (8 -
skill) * 0.01, 0.1);
369 float selfdamage = 0, teamdamage = 0, enemydamage = 0;
370 float pred_selfdamage = 0, pred_teamdamage = 0, pred_enemydamage = 0;
371 float edgedamage =
WEP_CVAR(WEP_DEVASTATOR, edgedamage);
372 float coredamage =
WEP_CVAR(WEP_DEVASTATOR, damage);
377 IL_EACH(g_bot_targets, it.bot_attack,
380 vector target_pos = it.origin + (it.maxs - it.mins) * 0.5;
383 float dist = vlen(target_pos - rocket.origin);
385 if (dist <= edgeradius)
387 f = (edgeradius > 0) ? max(0, 1 - (dist / edgeradius)) : 1;
388 dmg = coredamage * f + edgedamage * (1 - f);
391 float pred_dist = vlen(target_pos + it.velocity * pred_time - (rocket.origin + rocket.velocity * pred_time));
393 if (pred_dist <= edgeradius)
395 f = (edgeradius > 0) ? max(0, 1 - (pred_dist / edgeradius)) : 1;
396 pred_dmg = coredamage * f + edgedamage * (1 - f);
402 if (StatusEffects_active(STATUSEFFECT_Strength, it))
403 dmg *= autocvar_g_balance_powerup_strength_damage;
404 if (StatusEffects_active(STATUSEFFECT_Shield, it))
405 dmg *= autocvar_g_balance_powerup_invincible_takedamage;
408 pred_selfdamage += pred_dmg;
410 else if (SAME_TEAM(it, actor))
412 if (StatusEffects_active(STATUSEFFECT_Shield, it))
413 dmg *= autocvar_g_balance_powerup_invincible_takedamage;
416 pred_teamdamage += pred_dmg;
418 else if (bot_shouldattack(actor, it))
420 if (StatusEffects_active(STATUSEFFECT_Shield, it))
421 dmg *= autocvar_g_balance_powerup_invincible_takedamage;
424 pred_enemydamage += pred_dmg;
440 float good_damage = enemydamage;
441 float pred_good_damage = pred_enemydamage;
442 float bad_damage = selfdamage + teamdamage;
443 float pred_bad_damage = pred_selfdamage + pred_teamdamage;
447 if (good_damage > coredamage * 0.1 && good_damage > bad_damage * 1.5
448 && (pred_good_damage < good_damage + 2 || pred_good_damage < pred_bad_damage * 1.5))
461 if (
WEP_CVAR(WEP_DEVASTATOR, reload_ammo) && actor.(weaponentity).clip_load <
WEP_CVAR(WEP_DEVASTATOR,
ammo))
463 thiswep.wr_reload(thiswep, actor, weaponentity);
469 if ((actor.(weaponentity).rl_release ||
WEP_CVAR(WEP_DEVASTATOR, guidestop))
481 && actor.(weaponentity).m_switchweapon == thiswep)
483 bool rockfound =
false;
486 if (!it.rl_detonate_later)
488 it.rl_detonate_later = true;
509 if (
WEP_CVAR(WEP_DEVASTATOR, reload_ammo))
520 if (actor.rl_release == 0)
529 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"));
561 return WEAPON_DEVASTATOR_SUICIDE;
567 return WEAPON_DEVASTATOR_MURDER_SPLASH;
569 return WEAPON_DEVASTATOR_MURDER_DIRECT;
593 PAR(_(
"The %s launches a remote controlled rocket, dealing significant damage when it explodes on impact. "
594 "If the primary fire is held, the rocket can be guided by the user's aim, allowing steering it towards enemies."),
COLORED_NAME(
this));
595 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."));
596 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));
597 PAR(_(
"Due to its high damage output, the %s is one of the most commonly used weapons. "
598 "It can be used in almost any scenario, working best in medium range combat. "
599 "In close range combat, the large splash radius often results in rockets damaging both you and your enemy."),
COLORED_NAME(
this));
600 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, "
601 "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.
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)
Returns total damage applied to creatures.
IntrusiveList g_damagedbycontents
float autocvar_g_balance_selfdamagepercent
const int HITTYPE_BOUNCE
set manually after projectile has bounced
const int HITTYPE_SPLASH
automatically set by RadiusDamage
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)
bool W_Devastator_DoRemoteExplode_cond(entity e)
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)
SetResourceExplicit(ent, RES_ARMOR, ReadByte() *DEC_FACTOR)) ENTCS_PROP(NAME
ERASEABLE entity IL_PUSH(IntrusiveList this, entity it)
Push to tail.
#define IL_EACH(this, cond, body)
entity WarpZone_SearchInRadius(vector org, float rad, float nomonsters, WarpZone_FindRadius_cond_callback_t cb)
Modified findradius aware of warpzones, that only includes entities that meet the "cb" criteria.
vector WarpZone_RefSys_TransformVelocity(entity from, entity to, vector vel)
Transform velocity vel in from's reference into to's reference.
vector WarpZone_RefSys_TransformOrigin(entity from, entity to, vector org)
Transform origin org in from's reference into to's reference.
void WarpZone_RefSys_Copy(entity me, entity from)
Copies the warpzone reference of from onto me.
noref entity WarpZone_SearchInRadius_otherent
Free to use in the callback.
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)]