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 = false;
16 if (autocvar_g_projectiles_interact == 1 && (toucher.flags & FL_PROJECTILE) && !toucher.damageforcescale)
17 {
18 toucher.damageforcescale = 1;
19 zero_damageforcescale = true;
20 }
21
23 this,
24 (this.origin + (this.mins + this.maxs) * 0.5),
25 this.velocity,
26 this.realowner,
27 WEP_CVAR_PRI(WEP_BLASTER, damage),
28 WEP_CVAR_PRI(WEP_BLASTER, edgedamage),
29 WEP_CVAR_PRI(WEP_BLASTER, radius),
30 NULL,
31 NULL,
32 false,
33 WEP_CVAR_PRI(WEP_BLASTER, force),
34 force_xyzscale,
38 );
39
40 if (zero_damageforcescale)
41 toucher.damageforcescale = 0;
42
43 delete(this);
44}
45
47{
49 setthink(this, SUB_Remove);
50 this.nextthink = time + WEP_CVAR_PRI(WEP_BLASTER, lifetime);
51 CSQCProjectile(this, true, PROJECTILE_BLASTER, true);
52}
53
54void W_Blaster_Attack(entity actor, .entity weaponentity)
55{
56 float atk_shotangle = WEP_CVAR_PRI(WEP_BLASTER, shotangle) * DEG2RAD;
57 float atk_damage = WEP_CVAR_PRI(WEP_BLASTER, damage);
58 vector s_forward = v_forward * cos(atk_shotangle) + v_up * sin(atk_shotangle);
59 int atk_deathtype = WEP_BLASTER.m_id;
60
61 W_SetupShot_Dir(actor, weaponentity, s_forward, false, 3, SND_BLASTER_FIRE, CH_WEAPON_B, atk_damage, atk_deathtype);
62 W_MuzzleFlash(WEP_BLASTER, actor, weaponentity, w_shotorg, w_shotdir);
63
64 entity missile = new(blasterbolt);
65 missile.owner = missile.realowner = actor;
66 missile.bot_dodge = true;
67 missile.bot_dodgerating = atk_damage;
69
70 setorigin(missile, w_shotorg);
71 setsize(missile, '0 0 0', '0 0 0');
72
73 float atk_speed = WEP_CVAR_PRI(WEP_BLASTER, speed);
74 float atk_spread = WEP_CVAR_PRI(WEP_BLASTER, spread);
75 W_SetupProjVelocity_Explicit(missile, w_shotdir, v_up, atk_speed, 0, 0, atk_spread, false);
76
77 missile.angles = vectoangles(missile.velocity);
78
79 //missile.glow_color = 250; // 244, 250
80 //missile.glow_size = 120;
81
82 settouch(missile, W_Blaster_Touch);
83 missile.flags = FL_PROJECTILE;
84 IL_PUSH(g_projectiles, missile);
85 IL_PUSH(g_bot_dodge, missile);
86 missile.missile_flags = MIF_SPLASH;
87 missile.projectiledeathtype = atk_deathtype;
88 missile.weaponentity_fld = weaponentity;
89 setthink(missile, W_Blaster_Think);
90 missile.nextthink = time + WEP_CVAR_PRI(WEP_BLASTER, delay);
91
92 MUTATOR_CALLHOOK(EditProjectile, actor, missile);
93
94 if (time >= missile.nextthink)
95 {
96 getthink(missile)(missile);
97 }
98}
99
100METHOD(Blaster, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
101{
103 bot_aim(actor, weaponentity, WEP_CVAR_PRI(WEP_BLASTER, speed), 0, WEP_CVAR_PRI(WEP_BLASTER, lifetime), false, true);
104}
105
106METHOD(Blaster, wr_think, void(Blaster thiswep, entity actor, .entity weaponentity, int fire))
107{
108 if(fire & 1)
109 {
110 if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(WEP_BLASTER, refire)))
111 {
112 W_Blaster_Attack(actor, weaponentity);
113 weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(WEP_BLASTER, animtime), w_ready);
114 }
115 }
116 else if(fire & 2)
117 {
118 if(actor.(weaponentity).m_switchweapon == WEP_BLASTER) // don't do this if already switching
119 W_LastWeapon(actor, weaponentity);
120 }
121}
122
123METHOD(Blaster, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
124{
125 return true; // infinite ammo
126}
127
128METHOD(Blaster, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity))
129{
130 return true; // blaster has infinite ammo
131}
132
133METHOD(Blaster, wr_suicidemessage, Notification(entity thiswep))
134{
135 return WEAPON_BLASTER_SUICIDE;
136}
137
138METHOD(Blaster, wr_killmessage, Notification(entity thiswep))
139{
140 return WEAPON_BLASTER_MURDER;
141}
142
143METHOD(OffhandBlaster, offhand_think, void(OffhandBlaster this, entity actor, bool key_pressed))
144{
145 if (!key_pressed || (time < actor.jump_interval))
146 {
147 return;
148 }
149 actor.jump_interval = time + WEP_CVAR_PRI(WEP_BLASTER, refire) * W_WeaponRateFactor(actor);
150 .entity weaponentity = weaponentities[1];
151 makevectors(actor.v_angle);
152 W_Blaster_Attack(actor, weaponentity);
153}
154
155#endif
156#ifdef CSQC
157
158METHOD(Blaster, wr_impacteffect, void(entity thiswep, entity actor))
159{
160 vector org2 = w_org + w_backoff * 2;
161 pointparticles(EFFECT_BLASTER_IMPACT, org2, w_backoff * 1000, 1);
162 if(!w_issilent) { sound(actor, CH_SHOTS, SND_LASERIMPACT, VOL_BASE, ATTN_NORM); }
163}
164
165#endif
166#ifdef MENUQC
167
168METHOD(Blaster, describe, string(Blaster this))
169{
170 TC(Blaster, this);
172 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));
173 PAR(_("It has no secondary fire, instead switching to the previously selected weapon."));
174 PAR(_("It doesn't require ammo, meaning it is a great choice if you are running low on ammo and need to preserve some."));
175 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. "
176 "Unlike other weapons, the %s can hit other projectiles directly."), COLORED_NAME(this), COLORED_NAME(this));
177 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. "
178 "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));
179 PAR(W_Guide_Keybinds(this));
180 PAR(W_Guide_DPS_onlyOne(this.netname, "primary"));
181 return PAGE_TEXT;
182}
183
184#endif
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:46
void W_Blaster_Attack(entity actor,.entity weaponentity)
Definition blaster.qc:54
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:150
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, float inflictorselfdamage, float forceintensity, vector forcexyzscale, int deathtype,.entity weaponentity, entity directhitentity)
Definition damage.qc:741
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)
Definition selection.qc:344
#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:643
#define PAR(...)
Adds an individually translatable paragraph to PAGE_TEXT without having to deal with strcat and sprin...
Definition string.qh:649
#define PAGE_TEXT_INIT()
Definition string.qh:642
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:192
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:836
void W_MuzzleFlash(Weapon thiswep, entity actor,.entity weaponentity, vector shotorg, vector shotdir)
Definition all.qc:728
string W_Guide_DPS_onlyOne(string name, string fire)
Definition all.qc:926
#define WEP_CVAR_PRI(wep, name)
Definition all.qh:322
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