Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
triggers.qc
Go to the documentation of this file.
1#include "triggers.qh"
2
4{
5 if(e.pushable)
6 return true;
7#ifdef SVQC
8 if(IS_VEHICLE(e))
9 return false;
10 if(e.iscreature)
11 return true;
12 if (ITEM_IS_LOOT(e))
13 {
14 return true;
15 }
16 switch(e.classname)
17 {
18 case "body":
19 return true;
20 case "bullet": // antilagged bullets can't hit this either
21 return false;
22 }
23 if (e.projectiledeathtype)
24 return true;
25#endif
26#ifdef CSQC
27 if(e.flags & FL_PROJECTILE)
28 return true;
29 if(e.isplayermodel)
30 return true;
31#endif
32 return false;
33}
34
35void SUB_DontUseTargets(entity this, entity actor, entity trigger) { }
36
37void SUB_UseTargets(entity this, entity actor, entity trigger);
38
40{
41 SUB_UseTargets (this, this.enemy, NULL);
42 delete(this);
43}
44
45#ifdef SVQC
46void generic_setactive(entity this, int act)
47{
48 if(act == ACTIVE_TOGGLE)
49 {
50 if(this.active == ACTIVE_ACTIVE)
51 {
52 this.active = ACTIVE_NOT;
53 }
54 else
55 {
56 this.active = ACTIVE_ACTIVE;
57 }
58 }
59 else
60 {
61 this.active = act;
62 }
63}
64
66{
67 int old_status = this.active;
68 generic_setactive(this, act);
69
70 if (this.active != old_status)
71 {
73 }
74}
75
77{
78 if(this.targetname && this.targetname != "")
79 {
80 if(this.spawnflags & START_ENABLED)
81 {
82 this.active = ACTIVE_ACTIVE;
83 }
84 else
85 {
86 this.active = ACTIVE_NOT;
87 }
88 }
89 else
90 {
91 this.active = ACTIVE_ACTIVE;
92 }
93
95}
96
97// Compatibility with old maps
99{
100 //LOG_WARNF("Entity %s was (de)activated by a trigger, please update map to use relays", this.targetname);
101 this.setactive(this, ACTIVE_TOGGLE);
102}
103
104void trigger_link(entity this, bool(entity this, entity to, int sendflags) sendfunc)
105{
106 setSendEntity(this, sendfunc);
107 this.SendFlags = 0xFFFFFF;
108}
109
110void trigger_common_write(entity this, bool withtarget)
111{
112 int f = 0;
113 if(this.warpzone_isboxy)
114 BITSET_ASSIGN(f, 1);
115 if(this.origin != '0 0 0')
116 BITSET_ASSIGN(f, 4);
117 if(this.movedir != '0 0 0')
118 BITSET_ASSIGN(f, 8);
119 if(this.angles != '0 0 0')
120 BITSET_ASSIGN(f, 16);
122
123 if(withtarget)
124 {
125 // probably some way to clean this up...
126 int targbits = 0;
127 if(this.target && this.target != "") targbits |= BIT(0);
128 if(this.target2 && this.target2 != "") targbits |= BIT(1);
129 if(this.target3 && this.target3 != "") targbits |= BIT(2);
130 if(this.target4 && this.target4 != "") targbits |= BIT(3);
131 if(this.targetname && this.targetname != "") targbits |= BIT(4);
132 if(this.killtarget && this.killtarget != "") targbits |= BIT(5);
133
134 WriteByte(MSG_ENTITY, targbits);
135
136 if(targbits & BIT(0))
138 if(targbits & BIT(1))
140 if(targbits & BIT(2))
142 if(targbits & BIT(3))
144 if(targbits & BIT(4))
146 if(targbits & BIT(5))
148 }
149
150 if(f & 4)
151 WriteVector(MSG_ENTITY, this.origin);
152
153 if(f & 8)
154 WriteVector(MSG_ENTITY, this.movedir);
155
156 if(f & 16)
157 WriteVector(MSG_ENTITY, this.angles);
158
160 WriteVector(MSG_ENTITY, this.mins);
161 WriteVector(MSG_ENTITY, this.maxs);
162 WriteByte(MSG_ENTITY, bound(1, this.scale * 16, 255));
163}
164
165#elif defined(CSQC)
166
167void trigger_common_read(entity this, bool withtarget)
168{
169 int f = ReadByte();
170 this.warpzone_isboxy = (f & 1);
171
172 if(withtarget)
173 {
174 strfree(this.target);
175 strfree(this.target2);
176 strfree(this.target3);
177 strfree(this.target4);
178 strfree(this.targetname);
179 strfree(this.killtarget);
180
181 int targbits = ReadByte();
182
183 this.target = ((targbits & BIT(0)) ? strzone(ReadString()) : string_null);
184 this.target2 = ((targbits & BIT(1)) ? strzone(ReadString()) : string_null);
185 this.target3 = ((targbits & BIT(2)) ? strzone(ReadString()) : string_null);
186 this.target4 = ((targbits & BIT(3)) ? strzone(ReadString()) : string_null);
187 this.targetname = ((targbits & BIT(4)) ? strzone(ReadString()) : string_null);
188 this.killtarget = ((targbits & BIT(5)) ? strzone(ReadString()) : string_null);
189 }
190
191 if(f & 4)
192 this.origin = ReadVector();
193 else
194 this.origin = '0 0 0';
195 setorigin(this, this.origin);
196
197 if(f & 8)
198 this.movedir = ReadVector();
199 else
200 this.movedir = '0 0 0';
201
202 if(f & 16)
203 this.angles = ReadVector();
204 else
205 this.angles = '0 0 0';
206
207 this.modelindex = ReadShort();
208 if (this.modelindex)
209 setmodelindex(this, this.modelindex);
210 this.mins = ReadVector();
211 this.maxs = ReadVector();
212 this.scale = ReadByte() / 16;
213 setsize(this, this.mins, this.maxs);
214}
215
217{
218 strfree(this.target);
219 strfree(this.target2);
220 strfree(this.target3);
221 strfree(this.target4);
222 strfree(this.targetname);
223 strfree(this.killtarget);
224}
225#endif
226
227
228/*
229==============================
230SUB_UseTargets
231
232the global "activator" should be set to the entity that initiated the firing.
233
234If this.delay is set, a DelayedUse entity will be created that will actually
235do the SUB_UseTargets after that many seconds have passed.
236
237Centerprints any this.message to the activator.
238
239Removes all entities with a targetname that match this.killtarget,
240and removes them, so some events can remove other triggers.
241
242Search for (string)targetname in all entities that
243match (string)this.target and call their .use function
244
245==============================
246*/
247
248void SUB_UseTargets_Ex(entity this, entity actor, entity trigger, bool preventReuse, int skiptargets)
249{
250//
251// check for a delay
252//
253 if (this.delay)
254 {
255 // create a temp object to fire at a later time
256 entity t = new_pure(DelayedUse);
257 t.nextthink = time + this.delay;
259 t.enemy = actor;
260 t.message = this.message;
261 t.killtarget = this.killtarget;
262 if(!(skiptargets & BIT(1))) t.target = this.target;
263 if(!(skiptargets & BIT(2))) t.target2 = this.target2;
264 if(!(skiptargets & BIT(3))) t.target3 = this.target3;
265 if(!(skiptargets & BIT(4))) t.target4 = this.target4;
266 t.antiwall_flag = this.antiwall_flag;
267 return;
268 }
269
270 string s;
271
272//
273// print the message
274//
275#ifdef SVQC
276 if(this)
277 if(IS_PLAYER(actor) && this.message != "")
278 if(IS_REAL_CLIENT(actor))
279 {
280 centerprint(actor, this.message);
281 if (this.noise == "")
282 play2(actor, SND(TALK));
283 }
284
285//
286// kill the killtagets
287//
288 s = this.killtarget;
289 if (s != "")
290 {
291 for(entity t = NULL; (t = find(t, targetname, s)); )
292 delete(t);
293 }
294#endif
295
296//
297// fire targets
298//
299
300 if(this.target_random)
302
303 for(int i = 0; i < 4; ++i)
304 {
305 if(skiptargets & BIT(i + 1))
306 continue;
307 switch(i)
308 {
309 default:
310 case 0: s = this.target; break;
311 case 1: s = this.target2; break;
312 case 2: s = this.target3; break;
313 case 3: s = this.target4; break;
314 }
315 if (s != "")
316 {
317 for(entity t = NULL; (t = find(t, targetname, s)); )
318 {
319 if(t != this && t.use && (t.sub_target_used != time || !preventReuse))
320 {
321 if(this.target_random)
322 {
323 RandomSelection_AddEnt(t, 1, 0);
324 }
325 else
326 {
327 t.use(t, actor, this);
328 if(preventReuse)
329 t.sub_target_used = time;
330 }
331 }
332 }
333 }
334 }
335
337 {
339 if(preventReuse)
340 RandomSelection_chosen_ent.sub_target_used = time;
341 }
342}
343
344void SUB_UseTargets(entity this, entity actor, entity trigger) { SUB_UseTargets_Ex(this, actor, trigger, false, 0); }
345void SUB_UseTargets_PreventReuse(entity this, entity actor, entity trigger) { SUB_UseTargets_Ex(this, actor, trigger, true, 0); }
346void SUB_UseTargets_SkipTargets(entity this, entity actor, entity trigger, int skiptargets) { SUB_UseTargets_Ex(this, actor, trigger, false, skiptargets); }
#define BIT(n)
Only ever assign into the first 24 bits in QC (so max is BIT(23)).
Definition bits.qh:8
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
#define ReadString
string message
Definition powerups.qc:19
float delay
Definition items.qc:17
int spawnflags
Definition ammo.qh:15
#define IS_PLAYER(s)
Definition player.qh:243
const int FL_PROJECTILE
Definition constants.qh:85
float modelindex
vector mins
float time
vector maxs
vector origin
const int ACTIVE_TOGGLE
Definition defs.qh:40
const int ACTIVE_NOT
Definition defs.qh:36
int active
Definition defs.qh:34
const int ACTIVE_ACTIVE
Definition defs.qh:37
const int START_ENABLED
Definition defs.qh:6
const int SF_TRIGGER_UPDATE
Definition defs.qh:23
ent angles
Definition ent_cs.qc:121
#define ITEM_IS_LOOT(item)
Returns whether the item is loot.
Definition spawning.qh:39
int SendFlags
Definition net.qh:118
const int MSG_ENTITY
Definition net.qh:115
#define ReadVector()
Definition net.qh:367
int ReadByte()
#define BITSET_ASSIGN(a, b)
Definition common.qh:104
float warpzone_isboxy
Definition common.qh:12
vector movedir
Definition viewloc.qh:18
float bound(float min, float value, float max)
void WriteString(string data, float dest, float desto)
entity find(entity start,.string field, string match)
void WriteShort(float data, float dest, float desto)
void centerprint(string text,...)
void WriteByte(float data, float dest, float desto)
string strzone(string s)
string string_null
Definition nil.qh:9
#define new_pure(class)
purely logical entities (not linked to the area grid)
Definition oo.qh:67
#define NULL
Definition post.qh:14
float scale
Definition projectile.qc:14
ERASEABLE void RandomSelection_Init()
Definition random.qc:4
#define RandomSelection_AddEnt(e, weight, priority)
Definition random.qh:14
entity RandomSelection_chosen_ent
Definition random.qh:5
#define setSendEntity(e, f)
#define setthink(e, f)
void play2(entity e, string filename)
Definition all.qc:116
#define SND(id)
Definition all.qh:35
#define strfree(this)
Definition string.qh:59
string noise
Definition subs.qh:83
string killtarget
Definition subs.qh:48
string target4
Definition subs.qh:55
string target3
Definition subs.qh:54
float target_random
Definition subs.qh:57
entity enemy
Definition sv_ctf.qh:153
string target2
void generic_netlinked_reset(entity this)
Definition triggers.qc:76
void DelayThink(entity this)
Definition triggers.qc:39
void generic_netlinked_legacy_use(entity this, entity actor, entity trigger)
Definition triggers.qc:98
void trigger_link(entity this, bool(entity this, entity to, int sendflags) sendfunc)
Definition triggers.qc:104
void SUB_UseTargets(entity this, entity actor, entity trigger)
Definition triggers.qc:344
void generic_setactive(entity this, int act)
Definition triggers.qc:46
bool isPushable(entity e)
Definition triggers.qc:3
void SUB_UseTargets_Ex(entity this, entity actor, entity trigger, bool preventReuse, int skiptargets)
Definition triggers.qc:248
void SUB_UseTargets_PreventReuse(entity this, entity actor, entity trigger)
Definition triggers.qc:345
void SUB_DontUseTargets(entity this, entity actor, entity trigger)
Definition triggers.qc:35
void trigger_common_write(entity this, bool withtarget)
Definition triggers.qc:110
void generic_netlinked_setactive(entity this, int act)
Definition triggers.qc:65
void SUB_UseTargets_SkipTargets(entity this, entity actor, entity trigger, int skiptargets)
Definition triggers.qc:346
void trigger_remove_generic(entity this)
float antiwall_flag
Definition triggers.qh:6
string targetname
Definition triggers.qh:56
void trigger_common_read(entity this, bool withtarget)
string target
Definition triggers.qh:55
#define IS_REAL_CLIENT(v)
Definition utils.qh:17
#define IS_VEHICLE(v)
Definition utils.qh:22