Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
common.qc
Go to the documentation of this file.
1#include "common.qh"
2
3#include <common/constants.qh>
8#include <common/state.qh>
9#include <common/stats.qh>
10#include <common/util.qh>
12#include <common/wepent.qh>
14#include <server/damage.qh>
15#include <server/hook.qh>
16#include <server/items/items.qh>
19
21{
22 int held_weapons = 0;
23 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
24 {
25 .entity weaponentity = weaponentities[slot];
26 if(player.(weaponentity) && player.(weaponentity).m_switchweapon != WEP_Null)
27 ++held_weapons;
28 }
29
30 return held_weapons > 1;
31}
32
33void W_GiveWeapon(entity e, int wep)
34{
35 if (!wep) return;
36
37 STAT(WEAPONS, e) |= WepSet_FromWeapon(REGISTRY_GET(Weapons, wep));
38}
39
44
45float W_CheckProjectileDamage(entity inflictor, entity projowner, int deathtype, float exception)
46{
47 float is_from_contents = (deathtype == DEATH_SLIME.m_id || deathtype == DEATH_LAVA.m_id);
48 float is_from_owner = (inflictor == projowner);
49 float is_from_exception = (exception != -1);
50
51 //dprint(strcat("W_CheckProjectileDamage: from_contents ", ftos(is_from_contents), " : from_owner ", ftos(is_from_owner), " : exception ", strcat(ftos(is_from_exception), " (", ftos(exception), "). \n")));
52
54 {
55 return false; // no damage to projectiles at all, not even with the exceptions
56 }
58 {
59 if(is_from_exception)
60 return (exception); // if exception is detected, allow it to override
61 else
62 return false; // otherwise, no other damage is allowed
63 }
65 {
66 if(is_from_exception)
67 return (exception); // if exception is detected, allow it to override
68 else if(!is_from_contents)
69 return false; // otherwise, only allow damage from contents
70 }
72 {
73 if(is_from_exception)
74 return (exception); // if exception is detected, allow it to override
75 else if(!(is_from_contents || is_from_owner))
76 return false; // otherwise, only allow self damage and damage from contents
77 }
78 else if(autocvar_g_projectiles_damage == 2) // allow any damage, but override for exceptions
79 {
80 if(is_from_exception)
81 return (exception); // if exception is detected, allow it to override
82 }
83
84 return true; // if none of these return, then allow damage anyway.
85}
86
87void W_PrepareExplosionByDamage(entity this, entity attacker, void(entity this) explode)
88{
89 this.takedamage = DAMAGE_NO;
90 this.event_damage = func_null;
91
92 MUTATOR_CALLHOOK(PrepareExplosionByDamage, this, attacker);
93
95 {
96 this.owner = attacker;
97 this.realowner = attacker;
98 }
99
100 // do not explode NOW but in the NEXT FRAME!
101 // because recursive calls to RadiusDamage are not allowed
102 this.nextthink = time;
103 setthink(this, explode);
104}
105
106void adaptor_think2use_hittype_splash(entity this) // for timed projectile detonation
107{
108 if(!(IS_ONGROUND(this))) // if onground, we ARE touching something, but HITTYPE_SPLASH is to be networked if the damage causing projectile is not touching ANYTHING
110 adaptor_think2use(this);
111}
112
114{
115 // zero hitcontents = this is not the real impact, but either the
116 // mirror-impact of something hitting the projectile instead of the
117 // projectile hitting the something, or a touchareagrid one. Neither of
118 // these stop the projectile from moving, so...
119 // NOTE: this notice is disabled to prevent spam as projectiles can hit content-less objects (other projectiles!)
120#if 0
121 if(trace_dphitcontents == 0)
122 {
123 LOG_TRACEF("A hit from a projectile happened with no hit contents! DEBUG THIS, this should never happen for projectiles! Projectile will self-destruct. (edict: %i, classname: %s, origin: %v)", this, this.classname, this.origin);
124 checkclient(this); // TODO: .health is checked in the engine with this, possibly replace with a QC function?
125 }
126#endif
128 return true;
129
130 if (toucher == NULL && this.size != '0 0 0')
131 {
132 vector tic;
133 tic = this.velocity * sys_frametime;
134 tic = tic + normalize(tic) * vlen(this.maxs - this.mins);
135 traceline(this.origin - tic, this.origin + tic, MOVE_NORMAL, this);
136 if (trace_fraction >= 1)
137 {
138 // NOTE: this notice can occur when projectiles hit non-world objects, better to not spam the console!
139 //LOG_TRACE("Odd... did not hit...?");
140 }
142 {
143 LOG_TRACE("Detected and prevented the sky-grapple bug.");
144 return true;
145 }
146 }
147
148 return false;
149}
150
152{
153 if(toucher && toucher == this.owner)
154 return true;
155
156 if(autocvar_g_projectiles_interact == 1 && toucher.classname == "blasterbolt")
157 {
159 // We'll bounce off it due to limitations so let it deflect us
160 // to hide the problem, see PROJECTILE_MAKETRIGGER.
161 gettouch(toucher)(toucher, this);
162 return true;
163 }
164
165 if(SUB_NoImpactCheck(this, toucher))
166 {
167 if(this.classname == "nade")
168 return false; // no checks here
169 else if(this.classname == "grapplinghook")
170 RemoveHook(this);
171 else
172 delete(this);
173 return true;
174 }
175 if(trace_ent && trace_ent.solid > SOLID_TRIGGER)
177 return false;
178}
#define MUTATOR_CALLHOOK(id,...)
Definition base.qh:143
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
entity owner
Definition main.qh:87
#define IS_CLIENT(s)
Definition player.qh:242
string classname
float movetype
float trace_dphitcontents
entity trace_ent
const float SOLID_TRIGGER
const float MOVE_NORMAL
vector mins
vector velocity
float time
vector maxs
vector size
float nextthink
float trace_dphitq3surfaceflags
vector origin
float trace_fraction
float Q3SURFACEFLAG_NOIMPACT
void UpdateCSQCProjectile(entity e)
const int HITTYPE_SPLASH
Definition all.qh:30
Weapons
Definition guide.qh:113
#define STAT(...)
Definition stats.qh:82
#define LOG_TRACEF(...)
Definition log.qh:77
#define LOG_TRACE(...)
Definition log.qh:76
float vlen(vector v)
vector normalize(vector v)
const int MOVETYPE_BOUNCEMISSILE
Definition movetypes.qh:140
const int MOVETYPE_BOUNCE
Definition movetypes.qh:139
#define IS_ONGROUND(s)
Definition movetypes.qh:16
var void func_null()
#define NULL
Definition post.qh:14
#define checkclient
Definition pre.qh:4
#define REGISTRY_GET(id, i)
Definition registry.qh:43
#define gettouch(e)
Definition self.qh:74
#define setthink(e, f)
vector
Definition self.qh:92
entity entity toucher
Definition self.qh:72
float sys_frametime
Definition common.qh:57
void RemoveHook(entity this)
Definition hook.qc:48
float W_CheckProjectileDamage(entity inflictor, entity projowner, int deathtype, float exception)
Definition common.qc:45
bool WarpZone_Projectile_Touch_ImpactFilter_Callback(entity this, entity toucher)
Definition common.qc:151
void W_PlayStrengthSound(entity player)
Definition common.qc:40
void W_PrepareExplosionByDamage(entity this, entity attacker, void(entity this) explode)
Definition common.qc:87
void W_GiveWeapon(entity e, int wep)
Definition common.qc:33
bool SUB_NoImpactCheck(entity this, entity toucher)
Definition common.qc:113
void adaptor_think2use_hittype_splash(entity this)
Definition common.qc:106
bool W_DualWielding(entity player)
Definition common.qc:20
int projectiledeathtype
Definition common.qh:21
bool autocvar_g_projectiles_keep_owner
Definition common.qh:5
int autocvar_g_projectiles_damage
Definition common.qh:3
int autocvar_g_projectiles_interact
Definition common.qh:4
const int DAMAGE_NO
Definition subs.qh:79
float takedamage
Definition subs.qh:78
entity realowner
#define WepSet_FromWeapon(it)
Definition all.qh:46
const int MAX_WEAPONSLOTS
Definition weapon.qh:16
entity weaponentities[MAX_WEAPONSLOTS]
Definition weapon.qh:17