Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
blaster.qc
Go to the documentation of this file.
1#include "blaster.qh"
2
3#ifdef SVQC
4
6{
8
9 this.event_damage = func_null;
10
11 vector force_xyzscale = '1 1 1';
12 force_xyzscale.z = WEP_CVAR_PRI(WEP_BLASTER, force_zscale);
13
14 // slightly hacky but probably not worth adding a parameter for this special case
15 bool zero_damageforcescale;
16 if (autocvar_g_projectiles_interact == 1 && (toucher.flags & FL_PROJECTILE) && !toucher.damageforcescale)
17 {
18 toucher.damageforcescale = 1;
19 zero_damageforcescale = true;
20 }
21 else
22 zero_damageforcescale = false;
23
24 RadiusDamageForSource(this, (this.origin + (this.mins + this.maxs) * 0.5), this.velocity, this.realowner,
25 WEP_CVAR_PRI(WEP_BLASTER, damage),
26 WEP_CVAR_PRI(WEP_BLASTER, edgedamage),
27 WEP_CVAR_PRI(WEP_BLASTER, radius),
28 NULL,
29 NULL,
30 false,
31 WEP_CVAR_PRI(WEP_BLASTER, force),
32 force_xyzscale,
36 );
37
38 if (zero_damageforcescale)
39 toucher.damageforcescale = 0;
40
41 delete(this);
42}
43
45{
47 setthink(this, SUB_Remove);
48 this.nextthink = time + WEP_CVAR_PRI(WEP_BLASTER, lifetime);
49 CSQCProjectile(this, true, PROJECTILE_BLASTER, true);
50}
51
52void W_Blaster_Attack(entity actor, .entity weaponentity)
53{
54 float atk_shotangle = WEP_CVAR_PRI(WEP_BLASTER, shotangle) * DEG2RAD;
55 float atk_damage = WEP_CVAR_PRI(WEP_BLASTER, damage);
56 vector s_forward = v_forward * cos(atk_shotangle) + v_up * sin(atk_shotangle);
57 int atk_deathtype = WEP_BLASTER.m_id;
58
59 W_SetupShot_Dir(actor, weaponentity, s_forward, false, 3, SND_BLASTER_FIRE, CH_WEAPON_B, atk_damage, atk_deathtype);
60 W_MuzzleFlash(WEP_BLASTER, actor, weaponentity, w_shotorg, w_shotdir);
61
62 entity missile = new(blasterbolt);
63 missile.owner = missile.realowner = actor;
64 missile.bot_dodge = true;
65 missile.bot_dodgerating = atk_damage;
67
68 setorigin(missile, w_shotorg);
69 setsize(missile, '0 0 0', '0 0 0');
70
71 float atk_speed = WEP_CVAR_PRI(WEP_BLASTER, speed);
72 float atk_spread = WEP_CVAR_PRI(WEP_BLASTER, spread);
73 W_SetupProjVelocity_Explicit(missile, w_shotdir, v_up, atk_speed, 0, 0, atk_spread, false);
74
75 missile.angles = vectoangles(missile.velocity);
76
77 //missile.glow_color = 250; // 244, 250
78 //missile.glow_size = 120;
79
80 settouch(missile, W_Blaster_Touch);
81 missile.flags = FL_PROJECTILE;
82 IL_PUSH(g_projectiles, missile);
83 IL_PUSH(g_bot_dodge, missile);
84 missile.missile_flags = MIF_SPLASH;
85 missile.projectiledeathtype = atk_deathtype;
86 missile.weaponentity_fld = weaponentity;
87 setthink(missile, W_Blaster_Think);
88 missile.nextthink = time + WEP_CVAR_PRI(WEP_BLASTER, delay);
89
90 MUTATOR_CALLHOOK(EditProjectile, actor, missile);
91
92 if (time >= missile.nextthink)
93 getthink(missile)(missile);
94}
95
96METHOD(Blaster, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
97{
98 PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR_PRI(WEP_BLASTER, speed), 0, WEP_CVAR_PRI(WEP_BLASTER, lifetime), false, true);
99}
100
101METHOD(Blaster, wr_think, void(Blaster thiswep, entity actor, .entity weaponentity, int fire))
102{
103 if (fire & 1)
104 {
105 if (weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(WEP_BLASTER, refire)))
106 {
107 W_Blaster_Attack(actor, weaponentity);
108 weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(WEP_BLASTER, animtime), w_ready);
109 }
110 }
111 else if (fire & 2)
112 {
113 if (actor.(weaponentity).m_switchweapon == WEP_BLASTER) // don't do this if already switching
114 W_LastWeapon(actor, weaponentity);
115 }
116}
117
118METHOD(Blaster, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
119{
120 return true; // Blaster has infinite ammo
121}
122
123METHOD(Blaster, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity))
124{
125 return true;
126}
127
128METHOD(Blaster, wr_suicidemessage, Notification(entity thiswep))
129{
130 return WEAPON_BLASTER_SUICIDE;
131}
132
133METHOD(Blaster, wr_killmessage, Notification(entity thiswep))
134{
135 return WEAPON_BLASTER_MURDER;
136}
137
138METHOD(OffhandBlaster, offhand_think, void(OffhandBlaster this, entity actor, bool key_pressed))
139{
140 if (!key_pressed || (time < actor.jump_interval))
141 return;
142
143 actor.jump_interval = time + WEP_CVAR_PRI(WEP_BLASTER, refire) * W_WeaponRateFactor(actor);
144 .entity weaponentity = weaponentities[1];
145 makevectors(actor.v_angle);
146 W_Blaster_Attack(actor, weaponentity);
147}
148
149#endif // SVQC
150#ifdef CSQC
151
152METHOD(Blaster, wr_impacteffect, void(entity thiswep, entity actor))
153{
154 vector org2 = w_org + w_backoff * 2;
155 pointparticles(EFFECT_BLASTER_IMPACT, org2, w_backoff * 1000, 1);
156 if (!w_issilent)
157 sound(actor, CH_SHOTS, SND_LASERIMPACT, VOL_BASE, ATTN_NORM);
158}
159
160#endif // CSQC
161#ifdef MENUQC
162
163METHOD(Blaster, describe, string(Blaster this))
164{
165 TC(Blaster, this);
167 PAR(_("The %s is one of the two main default weapons, firing a relatively weak but high speed laser, dealing some splash damage but importantly a lot of knockback."), COLORED_NAME(this));
168 PAR(_("It has no secondary fire, instead switching to the previously selected weapon."));
169 PAR(_("It doesn't require ammo, meaning it is a great choice if you are running low on ammo and need to preserve some."));
170 PAR(_("The %s is always available so ends up being used a lot when players spawn in, but it's difficult to master when used over a medium to long range. "
171 "Unlike other weapons, the %s can hit other projectiles directly."), COLORED_NAME(this), COLORED_NAME(this));
172 PAR(_("One of the most common uses of the %s is \"laser jumping,\" where you can gain height by aiming down, jumping, then firing to boost yourself up. "
173 "Because it does a lot of knockback, another common usage is alternating between a high damage weapon and the %s to throw the enemy's aim off."), COLORED_NAME(this), COLORED_NAME(this));
174 PAR(W_Guide_Keybinds(this));
175 PAR(W_Guide_DPS_onlyOne(this.netname, "primary"));
176 return PAGE_TEXT;
177}
178
179#endif // MENUQC
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_Think(entity this)
Definition blaster.qc:44
void W_Blaster_Attack(entity actor,.entity weaponentity)
Definition blaster.qc:52
void W_Blaster_Touch(entity this, entity toucher)
Definition blaster.qc:5
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
string netname
Definition powerups.qc:20
float lifetime
Definition powerups.qc:23
float delay
Definition items.qc:17
#define COLORED_NAME(this)
Definition color.qh:195
float radius
Definition impulse.qh:11
#define PHYS_INPUT_BUTTON_ATCK(s)
Definition player.qh:152
float W_WeaponRateFactor(entity this)
const int FL_PROJECTILE
Definition constants.qh:85
vector v_up
float DEG2RAD
vector mins
vector velocity
float time
vector maxs
float nextthink
vector v_forward
vector origin
const float ATTN_NORM
void CSQCProjectile(entity e, float clientanimate, int type, float docull)
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)
Definition damage.qc:718
vector w_org
vector w_backoff
float w_issilent
void SUB_Remove(entity this)
Remove entity.
Definition defer.qh:13
float speed
Definition dynlight.qc:9
#define pointparticles(effect, org, vel, howmany)
Definition effect.qh:7
ERASEABLE entity IL_PUSH(IntrusiveList this, entity it)
Push to tail.
#define TC(T, sym)
Definition _all.inc:82
float cos(float f)
vector vectoangles(vector v)
float sin(float f)
void set_movetype(entity this, int mt)
Definition movetypes.qc:4
const int MOVETYPE_FLY
Definition movetypes.qh:134
var void func_null()
entity Notification
always last
Definition all.qh:81
#define METHOD(cname, name, prototype)
Definition oo.qh:269
#define NULL
Definition post.qh:14
#define makevectors
Definition post.qh:21
const int PROJECTILE_BLASTER
void W_LastWeapon(entity this,.entity weaponentity)
Goto previously used if exists and has ammo, (second) best otherwise.
Definition selection.qc:332
#define setthink(e, f)
#define getthink(e)
vector
Definition self.qh:92
entity entity toucher
Definition self.qh:72
#define settouch(e, f)
Definition self.qh:73
const int MIF_SPLASH
Definition common.qh:46
int projectiledeathtype
Definition common.qh:21
#define PROJECTILE_TOUCH(e, t)
Definition common.qh:28
IntrusiveList g_projectiles
Definition common.qh:58
#define PROJECTILE_MAKETRIGGER(e)
Definition common.qh:34
int autocvar_g_projectiles_interact
Definition common.qh:4
const float VOL_BASE
Definition sound.qh:36
const int CH_SHOTS
Definition sound.qh:14
#define sound(e, c, s, v, a)
Definition sound.qh:52
const int CH_WEAPON_B
Definition sound.qh:8
#define PAGE_TEXT
Definition string.qh:642
#define PAR(...)
Adds an individually translatable paragraph to PAGE_TEXT without having to deal with strcat and sprin...
Definition string.qh:648
#define PAGE_TEXT_INIT()
Definition string.qh:641
entity realowner
void W_SetupProjVelocity_Explicit(entity proj, vector dir, vector upDir, float pSpeed, float pUpSpeed, float pZSpeed, float spread, float forceAbsolute)
Definition tracing.qc:185
vector w_shotdir
Definition tracing.qh:20
vector w_shotorg
Definition tracing.qh:19
#define W_SetupShot_Dir(ent, wepent, s_forward, antilag, recoil, snd, chan, maxdamage, deathtype)
Definition tracing.qh:32
string W_Guide_Keybinds(Weapon wep)
Definition all.qc:824
void W_MuzzleFlash(Weapon thiswep, entity actor,.entity weaponentity, vector shotorg, vector shotdir)
Definition all.qc:715
string W_Guide_DPS_onlyOne(string name, string fire)
Definition all.qc:914
#define WEP_CVAR_PRI(wep, name)
Definition all.qh:338
entity weaponentities[MAX_WEAPONSLOTS]
Definition weapon.qh:17
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