Xonotic
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_IsLoot(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 
35 void SUB_DontUseTargets(entity this, entity actor, entity trigger) { }
36 
37 void SUB_UseTargets(entity this, entity actor, entity trigger);
38 
39 void DelayThink(entity this)
40 {
41  SUB_UseTargets (this, this.enemy, NULL);
42  delete(this);
43 }
44 
45 #ifdef SVQC
46 void 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 
65 void generic_netlinked_setactive(entity this, int act)
66 {
67  int old_status = this.active;
68  generic_setactive(this, act);
69 
70  if (this.active != old_status)
71  {
72  this.SendFlags |= SF_TRIGGER_UPDATE;
73  }
74 }
75 
76 void generic_netlinked_reset(entity this)
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 
94  this.SendFlags |= SF_TRIGGER_UPDATE;
95 }
96 
97 // Compatibility with old maps
98 void generic_netlinked_legacy_use(entity this, entity actor, entity trigger)
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 
104 bool autocvar_g_triggers_debug = true;
105 
106 void trigger_init(entity this)
107 {
108  string m = this.model;
110  if(autocvar_g_triggers_debug)
111  {
112  if(m != "")
113  {
114  precache_model(m);
115  _setmodel(this, m); // no precision needed
116  }
117  setorigin(this, this.origin);
118  if(this.scale)
119  setsize(this, this.mins * this.scale, this.maxs * this.scale);
120  else
121  setsize(this, this.mins, this.maxs);
122  }
123 
124  if(autocvar_g_triggers_debug)
126 }
127 
128 void trigger_link(entity this, bool(entity this, entity to, int sendflags) sendfunc)
129 {
130  setSendEntity(this, sendfunc);
131  this.SendFlags = 0xFFFFFF;
132 }
133 
134 void trigger_common_write(entity this, bool withtarget)
135 {
136  int f = 0;
137  if(this.warpzone_isboxy)
138  BITSET_ASSIGN(f, 1);
139  if(this.origin != '0 0 0')
140  BITSET_ASSIGN(f, 4);
141  if(this.movedir != '0 0 0')
142  BITSET_ASSIGN(f, 8);
143  if(this.angles != '0 0 0')
144  BITSET_ASSIGN(f, 16);
145  WriteByte(MSG_ENTITY, f);
146 
147  if(withtarget)
148  {
149  // probably some way to clean this up...
150  int targbits = 0;
151  if(this.target && this.target != "") targbits |= BIT(0);
152  if(this.target2 && this.target2 != "") targbits |= BIT(1);
153  if(this.target3 && this.target3 != "") targbits |= BIT(2);
154  if(this.target4 && this.target4 != "") targbits |= BIT(3);
155  if(this.targetname && this.targetname != "") targbits |= BIT(4);
156  if(this.killtarget && this.killtarget != "") targbits |= BIT(5);
157 
158  WriteByte(MSG_ENTITY, targbits);
159 
160  if(targbits & BIT(0))
161  WriteString(MSG_ENTITY, this.target);
162  if(targbits & BIT(1))
163  WriteString(MSG_ENTITY, this.target2);
164  if(targbits & BIT(2))
165  WriteString(MSG_ENTITY, this.target3);
166  if(targbits & BIT(3))
167  WriteString(MSG_ENTITY, this.target4);
168  if(targbits & BIT(4))
169  WriteString(MSG_ENTITY, this.targetname);
170  if(targbits & BIT(5))
171  WriteString(MSG_ENTITY, this.killtarget);
172  }
173 
174  if(f & 4)
175  WriteVector(MSG_ENTITY, this.origin);
176 
177  if(f & 8)
178  WriteVector(MSG_ENTITY, this.movedir);
179 
180  if(f & 16)
181  WriteVector(MSG_ENTITY, this.angles);
182 
183  WriteShort(MSG_ENTITY, this.modelindex);
184  WriteVector(MSG_ENTITY, this.mins);
185  WriteVector(MSG_ENTITY, this.maxs);
186  WriteByte(MSG_ENTITY, bound(1, this.scale * 16, 255));
187 }
188 
189 #elif defined(CSQC)
190 
191 void trigger_common_read(entity this, bool withtarget)
192 {
193  int f = ReadByte();
194  this.warpzone_isboxy = (f & 1);
195 
196  if(withtarget)
197  {
198  strfree(this.target);
199  strfree(this.target2);
200  strfree(this.target3);
201  strfree(this.target4);
202  strfree(this.targetname);
203  strfree(this.killtarget);
204 
205  int targbits = ReadByte();
206 
207  this.target = ((targbits & BIT(0)) ? strzone(ReadString()) : string_null);
208  this.target2 = ((targbits & BIT(1)) ? strzone(ReadString()) : string_null);
209  this.target3 = ((targbits & BIT(2)) ? strzone(ReadString()) : string_null);
210  this.target4 = ((targbits & BIT(3)) ? strzone(ReadString()) : string_null);
211  this.targetname = ((targbits & BIT(4)) ? strzone(ReadString()) : string_null);
212  this.killtarget = ((targbits & BIT(5)) ? strzone(ReadString()) : string_null);
213  }
214 
215  if(f & 4)
216  this.origin = ReadVector();
217  else
218  this.origin = '0 0 0';
219  setorigin(this, this.origin);
220 
221  if(f & 8)
222  this.movedir = ReadVector();
223  else
224  this.movedir = '0 0 0';
225 
226  if(f & 16)
227  this.angles = ReadVector();
228  else
229  this.angles = '0 0 0';
230 
231  this.modelindex = ReadShort();
232  this.mins = ReadVector();
233  this.maxs = ReadVector();
234  this.scale = ReadByte() / 16;
235  setsize(this, this.mins, this.maxs);
236 }
237 
238 void trigger_remove_generic(entity this)
239 {
240  strfree(this.target);
241  strfree(this.target2);
242  strfree(this.target3);
243  strfree(this.target4);
244  strfree(this.targetname);
245  strfree(this.killtarget);
246 }
247 #endif
248 
249 
250 /*
251 ==============================
252 SUB_UseTargets
253 
254 the global "activator" should be set to the entity that initiated the firing.
255 
256 If this.delay is set, a DelayedUse entity will be created that will actually
257 do the SUB_UseTargets after that many seconds have passed.
258 
259 Centerprints any this.message to the activator.
260 
261 Removes all entities with a targetname that match this.killtarget,
262 and removes them, so some events can remove other triggers.
263 
264 Search for (string)targetname in all entities that
265 match (string)this.target and call their .use function
266 
267 ==============================
268 */
269 
270 void SUB_UseTargets_Ex(entity this, entity actor, entity trigger, bool preventReuse, int skiptargets)
271 {
272 //
273 // check for a delay
274 //
275  if (this.delay)
276  {
277  // create a temp object to fire at a later time
278  entity t = new_pure(DelayedUse);
279  t.nextthink = time + this.delay;
280  setthink(t, DelayThink);
281  t.enemy = actor;
282  t.message = this.message;
283  t.killtarget = this.killtarget;
284  if(!(skiptargets & BIT(1))) t.target = this.target;
285  if(!(skiptargets & BIT(2))) t.target2 = this.target2;
286  if(!(skiptargets & BIT(3))) t.target3 = this.target3;
287  if(!(skiptargets & BIT(4))) t.target4 = this.target4;
288  t.antiwall_flag = this.antiwall_flag;
289  return;
290  }
291 
292  string s;
293 
294 //
295 // print the message
296 //
297 #ifdef SVQC
298  if(this)
299  if(IS_PLAYER(actor) && this.message != "")
300  if(IS_REAL_CLIENT(actor))
301  {
302  centerprint(actor, this.message);
303  if (this.noise == "")
304  play2(actor, SND(TALK));
305  }
306 
307 //
308 // kill the killtagets
309 //
310  s = this.killtarget;
311  if (s != "")
312  {
313  for(entity t = NULL; (t = find(t, targetname, s)); )
314  delete(t);
315  }
316 #endif
317 
318 //
319 // fire targets
320 //
321 
322  if(this.target_random)
324 
325  for(int i = 0; i < 4; ++i)
326  {
327  if(skiptargets & BIT(i + 1))
328  continue;
329  switch(i)
330  {
331  default:
332  case 0: s = this.target; break;
333  case 1: s = this.target2; break;
334  case 2: s = this.target3; break;
335  case 3: s = this.target4; break;
336  }
337  if (s != "")
338  {
339  for(entity t = NULL; (t = find(t, targetname, s)); )
340  {
341  if(t != this && t.use && (t.sub_target_used != time || !preventReuse))
342  {
343  if(this.target_random)
344  {
345  RandomSelection_AddEnt(t, 1, 0);
346  }
347  else
348  {
349  t.use(t, actor, this);
350  if(preventReuse)
351  t.sub_target_used = time;
352  }
353  }
354  }
355  }
356  }
357 
359  {
361  if(preventReuse)
362  RandomSelection_chosen_ent.sub_target_used = time;
363  }
364 }
365 
366 void SUB_UseTargets(entity this, entity actor, entity trigger) { SUB_UseTargets_Ex(this, actor, trigger, false, 0); }
367 void SUB_UseTargets_PreventReuse(entity this, entity actor, entity trigger) { SUB_UseTargets_Ex(this, actor, trigger, true, 0); }
368 void SUB_UseTargets_SkipTargets(entity this, entity actor, entity trigger, int skiptargets) { SUB_UseTargets_Ex(this, actor, trigger, false, skiptargets); }
string string_null
Definition: nil.qh:9
float target_random
Definition: subs.qh:57
void SUB_UseTargets_PreventReuse(entity this, entity actor, entity trigger)
Definition: triggers.qc:367
void SUB_UseTargets_Ex(entity this, entity actor, entity trigger, bool preventReuse, int skiptargets)
Definition: triggers.qc:270
void DelayThink(entity this)
Definition: triggers.qc:39
#define SND(id)
Definition: all.qh:35
string killtarget
Definition: subs.qh:48
#define EXACTTRIGGER_INIT
Definition: common.qh:117
string noise
Definition: progsdefs.qc:209
#define ReadString
float modelindex
Definition: csprogsdefs.qc:91
const int ACTIVE_TOGGLE
Definition: defs.qh:40
string target3
Definition: subs.qh:54
ERASEABLE void RandomSelection_Init()
Definition: random.qc:4
entity() spawn
void SUB_UseTargets_SkipTargets(entity this, entity actor, entity trigger, int skiptargets)
Definition: triggers.qc:368
vector maxs
Definition: csprogsdefs.qc:113
void SUB_UseTargets(entity this, entity actor, entity trigger)
Definition: triggers.qc:366
entity to
Definition: self.qh:96
origin
Definition: ent_cs.qc:114
const int START_ENABLED
Definition: defs.qh:6
const float EF_NODEPTHTEST
Definition: csprogsdefs.qc:304
void SUB_DontUseTargets(entity this, entity actor, entity trigger)
Definition: triggers.qc:35
float effects
Definition: csprogsdefs.qc:111
float spawnflags
Definition: progsdefs.qc:191
string model
Definition: csprogsdefs.qc:108
#define BITSET_ASSIGN(a, b)
Definition: common.qh:104
#define IS_REAL_CLIENT(v)
Definition: utils.qh:17
#define RandomSelection_AddEnt(e, weight, priority)
Definition: random.qh:14
#define BIT(n)
Only ever assign into the first 24 bits in QC (so max is BIT(23)).
Definition: bits.qh:8
vector movedir
Definition: progsdefs.qc:203
entity enemy
Definition: sv_ctf.qh:143
vector mins
Definition: csprogsdefs.qc:113
entity RandomSelection_chosen_ent
Definition: random.qh:5
float delay
Definition: subs.qh:38
const int ACTIVE_ACTIVE
Definition: defs.qh:37
string message
Definition: powerups.qc:19
#define setSendEntity(e, f)
Definition: self.qh:97
#define NULL
Definition: post.qh:17
float scale
Definition: projectile.qc:14
string target2
Definition: sv_onslaught.qh:45
#define IS_VEHICLE(v)
Definition: utils.qh:22
float warpzone_isboxy
Definition: common.qh:12
string targetname
Definition: progsdefs.qc:194
int active
Definition: defs.qh:34
#define new_pure(class)
purely logical entities (.origin doesn&#39;t work)
Definition: oo.qh:62
entity int sendflags
Definition: self.qh:96
setorigin(ent, v)
bool Item_IsLoot(entity item)
Returns whether the item is loot.
Definition: spawning.qc:121
#define setthink(e, f)
#define strfree(this)
Definition: string.qh:56
vector angles
Definition: csprogsdefs.qc:104
float antiwall_flag
Definition: triggers.qh:6
string target
Definition: progsdefs.qc:193
const int ACTIVE_NOT
Definition: defs.qh:36
float time
Definition: csprogsdefs.qc:16
bool isPushable(entity e)
Definition: triggers.qc:3
#define IS_PLAYER(v)
Definition: utils.qh:9
const int SF_TRIGGER_UPDATE
Definition: defs.qh:23
string target4
Definition: subs.qh:55