Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
okrpc.qc
Go to the documentation of this file.
1#include "okrpc.qh"
2
3#ifdef SVQC
4
5.float m_chainsaw_damage; // accumulated damage of the missile as it passes trough enemies
6
8{
9 this.event_damage = func_null;
10 this.takedamage = DAMAGE_NO;
11
12 float explosion_damage = RadiusDamage(this, this.realowner,
13 WEP_CVAR_PRI(WEP_OVERKILL_RPC, damage),
14 WEP_CVAR_PRI(WEP_OVERKILL_RPC, edgedamage),
15 WEP_CVAR_PRI(WEP_OVERKILL_RPC, radius),
16 NULL,
17 NULL,
18 WEP_CVAR_PRI(WEP_OVERKILL_RPC, force),
21 directhitentity
22 );
23 if (explosion_damage > 0 && this.m_chainsaw_damage > 0)
24 {
25 // if chainsaw hit something, it removed fired damage (so that direct hit is 100%)
26 // now that we also damaged something by explosion we'd go over 100% so let's add the fired damage back
27 accuracy_add(this.realowner, DEATH_WEAPONOF(this.projectiledeathtype), WEP_CVAR(WEP_OVERKILL_RPC, damage), 0, 0); // add to fired
28 }
29
30 delete(this);
31}
32
37
45
46void W_OverkillRocketPropelledChainsaw_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
47{
48 if (GetResource(this, RES_HEALTH) <= 0)
49 return;
50 if (!W_CheckProjectileDamage(inflictor.realowner, this.realowner, deathtype, -1)) // no exceptions
51 return; // g_projectiles_damage says to halt
52
53 TakeResource(this, RES_HEALTH, damage);
54 if (GetResource(this, RES_HEALTH) <= 0)
56}
57
59{
60 if (this.cnt <= time)
61 {
62 delete(this);
63 return;
64 }
65
66 float myspeed = vlen(this.velocity);
67 float myspeed_accel = myspeed * sys_frametime;
68 vector mydir = this.velocity * (1 / myspeed);
69
70 WarpZone_TraceBox(this.origin, this.mins, this.maxs, this.origin + mydir * (2 * myspeed_accel), MOVE_NORMAL, this);
72 {
73 float hit_damage = WEP_CVAR_PRI(WEP_OVERKILL_RPC, damage2);
75 {
76 if (this.m_chainsaw_damage == 0) // first hit
77 {
78 // The fired damage of the explosion is already counted in the statistics (when launching the chainsaw).
79 // We remove it here so that a direct hit that passes through and doesn't damage anything by the explosion later is still 100%.
80 float fired_damage = hit_damage - WEP_CVAR_PRI(WEP_OVERKILL_RPC, damage);
81 accuracy_add(this.realowner, DEATH_WEAPONOF(this.projectiledeathtype), fired_damage, hit_damage, 0); // add to fired and hit
82 }
83 this.m_chainsaw_damage += hit_damage;
84 }
85 vector hitloc = WarpZone_TransformOrigin(this, this.origin);
86 Damage(trace_ent, this, this.realowner,
87 hit_damage,
90 hitloc,
91 normalize(hitloc - trace_ent.origin) * WEP_CVAR_PRI(WEP_OVERKILL_RPC, force)
92 );
93 }
94
95 this.velocity = mydir * (myspeed + (WEP_CVAR_PRI(WEP_OVERKILL_RPC, speedaccel) * sys_frametime));
96
98 this.nextthink = time;
99}
100
102{
103 entity missile = spawn(); //WarpZone_RefSys_SpawnSameRefSys(actor);
104
105 W_DecreaseAmmo(thiswep, actor, WEP_CVAR_PRI(WEP_OVERKILL_RPC, ammo), weaponentity);
106 W_SetupShot_ProjectileSize(actor, weaponentity, '-3 -3 -3', '3 3 3', false, 5, SND_RPC_FIRE, CH_WEAPON_A, WEP_CVAR_PRI(WEP_OVERKILL_RPC, damage), thiswep.m_id);
107 W_MuzzleFlash(thiswep, actor, weaponentity, w_shotorg, w_shotdir);
108 PROJECTILE_MAKETRIGGER(missile);
109
110 missile.owner = missile.realowner = actor;
111 missile.bot_dodge = true;
112 missile.bot_dodgerating = WEP_CVAR_PRI(WEP_OVERKILL_RPC, damage) * 2;
113
114 missile.takedamage = DAMAGE_YES;
115 missile.damageforcescale = WEP_CVAR_PRI(WEP_OVERKILL_RPC, damageforcescale);
116 SetResourceExplicit(missile, RES_HEALTH, WEP_CVAR_PRI(WEP_OVERKILL_RPC, health));
117 missile.event_damage = W_OverkillRocketPropelledChainsaw_Damage;
118 missile.damagedbycontents = true;
120 set_movetype(missile, MOVETYPE_FLY);
121
122 missile.projectiledeathtype = thiswep.m_id;
123 missile.weaponentity_fld = weaponentity;
124 setsize (missile, '-3 -3 -3', '3 3 3'); // give it some size so it can be shot
125
126 setorigin(missile, w_shotorg - v_forward * 3); // move it back so it hits the wall at the right point
127 W_SetupProjVelocity_Basic(missile, WEP_CVAR_PRI(WEP_OVERKILL_RPC, speed), 0);
128
130
132 missile.cnt = time + WEP_CVAR_PRI(WEP_OVERKILL_RPC, lifetime);
133 missile.nextthink = time;
134 missile.flags = FL_PROJECTILE;
135 IL_PUSH(g_projectiles, missile);
136 IL_PUSH(g_bot_dodge, missile);
137
138 CSQCProjectile(missile, true, PROJECTILE_RPC, false);
139
140 missile.m_chainsaw_damage = 0;
141
142 MUTATOR_CALLHOOK(EditProjectile, actor, missile);
143}
144
145METHOD(OverkillRocketPropelledChainsaw, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
146{
147 PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR_PRI(WEP_OVERKILL_RPC, speed), 0, WEP_CVAR_PRI(WEP_OVERKILL_RPC, lifetime), false, true);
148}
149
150METHOD(OverkillRocketPropelledChainsaw, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
151{
152 if (WEP_CVAR_SEC(WEP_OVERKILL_RPC, refire_type) == 1 && (fire & 2)
153 && time >= actor.jump_interval)
154 {
155 // Secondary uses it's own refire timer if refire_type is 1.
156 actor.jump_interval = time + WEP_CVAR_PRI(WEP_BLASTER, refire) * W_WeaponRateFactor(actor);
157 makevectors(actor.v_angle);
158 W_Blaster_Attack(actor, weaponentity);
159 if (actor.(weaponentity).wframe == WFRAME_IDLE
160 || actor.(weaponentity).wframe == WFRAME_FIRE2)
161 {
162 // Set secondary fire animation.
163 actor.(weaponentity).wframe = WFRAME_FIRE2;
165 if (it == actor || (IS_SPEC(it) && it.enemy == actor))
166 wframe_send(it, actor.(weaponentity), WFRAME_FIRE2, autocvar_g_weaponratefactor, true);
167 ));
169 }
170 }
171 if (WEP_CVAR(WEP_OVERKILL_RPC, reload_ammo) && actor.(weaponentity).clip_load < WEP_CVAR_PRI(WEP_OVERKILL_RPC, ammo))
172 { // forced reload
173 thiswep.wr_reload(thiswep, actor, weaponentity);
174 return;
175 }
176
177 if (fire & 1) // Primary attack
178 {
179 if (!weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(WEP_OVERKILL_RPC, refire)))
180 return;
181 W_OverkillRocketPropelledChainsaw_Attack(thiswep, actor, weaponentity);
182 weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(WEP_OVERKILL_RPC, animtime), w_ready);
183 return;
184 }
185 if ((fire & 2) && WEP_CVAR_SEC(WEP_OVERKILL_RPC, refire_type) == 0) // Secondary attack
186 {
187 if (!weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(WEP_BLASTER, refire)))
188 return;
189 makevectors(actor.v_angle);
190 W_Blaster_Attack(actor, weaponentity);
191 weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_PRI(WEP_BLASTER, animtime), w_ready);
192 }
193}
194
195METHOD(OverkillRocketPropelledChainsaw, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
196{
197 float ammo_amount = GetResource(actor, thiswep.ammo_type) >= WEP_CVAR_PRI(WEP_OVERKILL_RPC, ammo);
198 ammo_amount += actor.(weaponentity).(weapon_load[thiswep.m_id]) >= WEP_CVAR_PRI(WEP_OVERKILL_RPC, ammo);
199 return ammo_amount;
200}
201
202METHOD(OverkillRocketPropelledChainsaw, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity))
203{
204 float ammo_amount = GetResource(actor, thiswep.ammo_type) >= WEP_CVAR_PRI(WEP_BLASTER, ammo);
205 ammo_amount += actor.(weaponentity).(weapon_load[thiswep.m_id]) >= WEP_CVAR_PRI(WEP_BLASTER, ammo);
206 return ammo_amount;
207}
208
209METHOD(OverkillRocketPropelledChainsaw, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
210{
211 W_Reload(actor, weaponentity, WEP_CVAR_PRI(WEP_OVERKILL_RPC, ammo), SND_RELOAD);
212}
213
214METHOD(OverkillRocketPropelledChainsaw, wr_suicidemessage, Notification(entity thiswep))
215{
217 return WEAPON_OVERKILL_RPC_SUICIDE_SPLASH;
218 else
219 return WEAPON_OVERKILL_RPC_SUICIDE_DIRECT;
220}
221
223{
225 return WEAPON_OVERKILL_RPC_MURDER_SPLASH;
226 else
227 return WEAPON_OVERKILL_RPC_MURDER_DIRECT;
228}
229
230#endif // SVQC
231#ifdef CSQC
232
233METHOD(OverkillRocketPropelledChainsaw, wr_impacteffect, void(entity thiswep, entity actor))
234{
235 vector org2 = w_org + w_backoff * 2;
236 pointparticles(EFFECT_ROCKET_EXPLODE, org2, '0 0 0', 1);
237 if (!w_issilent)
238 sound(actor, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
239}
240
241METHOD(OverkillRocketPropelledChainsaw, wr_damageeffect_getname, string(entity thiswep))
242{
243 return "damage_devastator";
244}
245
246#endif // CSQC
247#ifdef MENUQC
250
252{
255 PAR(_("As the name suggests, the %s is a superweapon that fires a rocket propelled chainsaw which explodes on impact, dealing a lot of splash damage to any players close by."), COLORED_NAME(this));
256 PAR(_("Like with all %s weapons, the secondary fire shoots a laser which doesn't damage or push enemies, but can be used to push yourself around."), COLORED_NAME(MUTATOR_ok));
257 PAR(_("It is a superweapon found on some maps, meaning that it breaks down after some time."));
258 PAR(_("The primary fire consumes %s ammo, although you spawn with an infinite amount of it in %s."), COLORED_NAME(ITEM_Rockets), COLORED_NAME(MUTATOR_ok));
259 PAR(_("Since it is the only %s weapon which deals splash damage, the %s is a good choice of weapon for attacking groups of enemies."), COLORED_NAME(MUTATOR_ok), COLORED_NAME(this));
260 PAR(W_Guide_Keybinds(this));
262 return PAGE_TEXT;
263}
264
265#endif // MENUQC
void accuracy_add(entity this, Weapon w, float fired, float hit, float real)
update accuracy stats
Definition accuracy.qc:102
bool accuracy_isgooddamage(entity attacker, entity targ)
does this damage count towards accuracy stats?
Definition accuracy.qc:133
void animdecide_setaction(entity e, float action, float restart)
const int ANIMACTION_SHOOT
bool bot_aim(entity this,.entity weaponentity, float shotspeed, float shotspeedupward, float maxshottime, float applygravity, bool shot_accurate)
IntrusiveList g_bot_dodge
Definition api.qh:150
#define MUTATOR_CALLHOOK(id,...)
Definition base.qh:143
void W_Blaster_Attack(entity actor,.entity weaponentity)
Definition blaster.qc:52
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...
Definition weapon.qh:42
int m_id
Definition weapon.qh:43
string netname
Definition powerups.qc:20
float lifetime
Definition powerups.qc:23
float cnt
Definition powerups.qc:24
#define COLORED_NAME(this)
Definition color.qh:189
float radius
Definition impulse.qh:11
#define IS_PLAYER(s)
Definition player.qh:242
#define PHYS_INPUT_BUTTON_ATCK(s)
Definition player.qh:152
float W_WeaponRateFactor(entity this)
const int FL_PROJECTILE
Definition constants.qh:77
entity trace_ent
const float MOVE_NORMAL
vector mins
vector velocity
float time
vector maxs
float nextthink
vector v_forward
vector origin
#define spawn
void UpdateCSQCProjectile(entity e)
void CSQCProjectile(entity e, float clientanimate, int type, float docull)
void Damage(entity targ, entity inflictor, entity attacker, float damage, int deathtype,.entity weaponentity, vector hitloc, vector force)
Definition damage.qc:484
float RadiusDamage(entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float forceintensity, int deathtype,.entity weaponentity, entity directhitentity)
Definition damage.qc:937
IntrusiveList g_damagedbycontents
Definition damage.qh:143
vector w_org
int w_deathtype
float damageforcescale
vector w_backoff
float w_issilent
const int HITTYPE_BOUNCE
set manually after projectile has bounced
Definition all.qh:33
const int HITTYPE_SPLASH
automatically set by RadiusDamage
Definition all.qh:32
#define DEATH_WEAPONOF(t)
Definition all.qh:47
float speed
Definition dynlight.qc:9
#define pointparticles(effect, org, vel, howmany)
Definition effect.qh:6
SetResourceExplicit(ent, RES_ARMOR, ReadByte() *DEC_FACTOR)) ENTCS_PROP(NAME
ERASEABLE entity IL_PUSH(IntrusiveList this, entity it)
Push to tail.
#define TC(T, sym)
Definition _all.inc:82
vector WarpZone_TransformOrigin(entity wz, vector org)
Transforms origin org across warpzone wz.
Definition common.qc:489
#define WarpZone_TraceBox(org, mi, ma, end, nomonsters, forent)
Definition common.qh:49
float vlen(vector v)
vector normalize(vector v)
#define LAMBDA(...)
Definition misc.qh:34
void set_movetype(entity this, int mt)
Definition movetypes.qc:4
const int MOVETYPE_FLY
Definition movetypes.qh:138
var void func_null()
entity Notification
always last
Definition all.qh:85
void W_OverkillRocketPropelledChainsaw_Explode_think(entity this)
Definition okrpc.qc:33
void W_OverkillRocketPropelledChainsaw_Touch(entity this, entity toucher)
Definition okrpc.qc:38
void W_OverkillRocketPropelledChainsaw_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype,.entity weaponentity, vector hitloc, vector force)
Definition okrpc.qc:46
float m_chainsaw_damage
Definition okrpc.qc:5
void W_OverkillRocketPropelledChainsaw_Explode(entity this, entity directhitentity)
Definition okrpc.qc:7
void W_OverkillRocketPropelledChainsaw_Attack(Weapon thiswep, entity actor,.entity weaponentity)
Definition okrpc.qc:101
void W_OverkillRocketPropelledChainsaw_Think(entity this)
Definition okrpc.qc:58
#define METHOD(cname, name, prototype)
Definition oo.qh:274
#define NULL
Definition post.qh:14
#define makevectors
Definition post.qh:21
const int PROJECTILE_RPC
float health
Legacy fields for the resources. To be removed.
Definition resources.qh:9
#define setthink(e, f)
vector
Definition self.qh:96
entity entity toucher
Definition self.qh:76
#define settouch(e, f)
Definition self.qh:77
float sys_frametime
Definition common.qh:57
float W_CheckProjectileDamage(entity inflictor, entity projowner, int deathtype, float exception)
Definition common.qc:45
void W_PrepareExplosionByDamage(entity this, entity attacker, void(entity this) explode)
Definition common.qc:87
int projectiledeathtype
Definition common.qh:33
IntrusiveList g_projectiles
Definition common.qh:70
#define PROJECTILE_MAKETRIGGER(e)
Definition common.qh:46
float WarpZone_Projectile_Touch(entity this, entity toucher)
Definition server.qc:344
const float VOL_BASE
Definition sound.qh:36
const int CH_SHOTS
Definition sound.qh:14
const int CH_WEAPON_A
Definition sound.qh:7
const float ATTEN_NORM
Definition sound.qh:30
#define sound(e, c, s, v, a)
Definition sound.qh:52
#define PAGE_TEXT
Definition string.qh:651
#define PAR(...)
Adds an individually translatable paragraph to PAGE_TEXT without having to deal with strcat and sprin...
Definition string.qh:657
#define PAGE_TEXT_INIT()
Definition string.qh:650
const int DAMAGE_YES
Definition subs.qh:80
const int DAMAGE_NO
Definition subs.qh:79
float takedamage
Definition subs.qh:78
float ammo
Definition sv_turrets.qh:43
entity realowner
vector w_shotdir
Definition tracing.qh:20
#define W_SetupShot_ProjectileSize(ent, wepent, mi, ma, antilag, recoil, snd, chan, maxdamage, deathtype)
Definition tracing.qh:30
vector w_shotorg
Definition tracing.qh:19
#define W_SetupProjVelocity_Basic(ent, pspeed, pspread)
Definition tracing.qh:51
#define IS_SPEC(v)
Definition utils.qh:10
#define FOREACH_CLIENT(cond, body)
Definition utils.qh:52
void wframe_send(entity actor, entity weaponentity, int wepframe, float attackrate, bool restartanim)
Definition all.qc:577
string W_Guide_Keybinds(Weapon wep)
Definition all.qc:824
string W_Guide_DPS_onlyOne_andDirectHit(string name, string fire)
Definition all.qc:910
void W_MuzzleFlash(Weapon thiswep, entity actor,.entity weaponentity, vector shotorg, vector shotdir)
Definition all.qc:715
#define WEP_CVAR_PRI(wep, name)
Definition all.qh:338
WFRAME wframe
Definition all.qh:439
#define WEP_CVAR(wep, name)
Definition all.qh:337
#define WEP_CVAR_SEC(wep, name)
Definition all.qh:339
void W_DecreaseAmmo(Weapon wep, entity actor, float ammo_use,.entity weaponentity)
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)
entity weaponentity_fld
float autocvar_g_weaponratefactor
float weapon_load[REGISTRY_MAX(Weapons)]