]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/mapobjects/triggers.qc
Move item_key to mapobjects
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / mapobjects / triggers.qc
1 #include "triggers.qh"
2
3 void SUB_DontUseTargets(entity this, entity actor, entity trigger) { }
4
5 void SUB_UseTargets(entity this, entity actor, entity trigger);
6
7 void DelayThink(entity this)
8 {
9         SUB_UseTargets (this, this.enemy, NULL);
10         delete(this);
11 }
12
13 void FixSize(entity e)
14 {
15         e.mins_x = rint(e.mins_x);
16         e.mins_y = rint(e.mins_y);
17         e.mins_z = rint(e.mins_z);
18
19         e.maxs_x = rint(e.maxs_x);
20         e.maxs_y = rint(e.maxs_y);
21         e.maxs_z = rint(e.maxs_z);
22 }
23
24 #ifdef SVQC
25 void generic_setactive(entity this, int act)
26 {
27         if(act == ACTIVE_TOGGLE)
28         {
29                 if(this.active == ACTIVE_ACTIVE)
30                 {
31                         this.active = ACTIVE_NOT;
32                 }
33                 else
34                 {
35                         this.active = ACTIVE_ACTIVE;
36                 }
37         }
38         else
39         {
40                 this.active = act;
41         }
42 }
43
44 void generic_netlinked_setactive(entity this, int act)
45 {
46         int old_status = this.active;
47         generic_setactive(this, act);
48
49         if (this.active != old_status)
50         {
51                 this.SendFlags |= SF_TRIGGER_UPDATE;
52         }
53 }
54
55 void generic_netlinked_reset(entity this)
56 {
57         IFTARGETED
58         {
59                 if(this.spawnflags & START_ENABLED)
60                 {
61                         this.active = ACTIVE_ACTIVE;
62                 }
63                 else
64                 {
65                         this.active = ACTIVE_NOT;
66                 }
67         }
68         else
69         {
70                 this.active = ACTIVE_ACTIVE;
71         }
72
73         this.SendFlags |= SF_TRIGGER_UPDATE;
74 }
75
76 // Compatibility with old maps
77 void generic_netlinked_legacy_use(entity this, entity actor, entity trigger)
78 {
79         //LOG_WARNF("Entity %s was (de)activated by a trigger, please update map to use relays", this.targetname);
80         this.setactive(this, ACTIVE_TOGGLE);
81 }
82
83 bool autocvar_g_triggers_debug = true;
84
85 void trigger_init(entity this)
86 {
87         string m = this.model;
88         EXACTTRIGGER_INIT;
89         if(autocvar_g_triggers_debug)
90         {
91                 if(m != "")
92                 {
93                         precache_model(m);
94                         _setmodel(this, m); // no precision needed
95                 }
96                 setorigin(this, this.origin);
97                 if(this.scale)
98                         setsize(this, this.mins * this.scale, this.maxs * this.scale);
99                 else
100                         setsize(this, this.mins, this.maxs);
101         }
102
103         if(autocvar_g_triggers_debug)
104                 BITSET_ASSIGN(this.effects, EF_NODEPTHTEST);
105 }
106
107 void trigger_link(entity this, bool(entity this, entity to, int sendflags) sendfunc)
108 {
109         setSendEntity(this, sendfunc);
110         this.SendFlags = 0xFFFFFF;
111 }
112
113 void trigger_common_write(entity this, bool withtarget)
114 {
115         int f = 0;
116         if(this.warpzone_isboxy)
117                 BITSET_ASSIGN(f, 1);
118         if(this.origin != '0 0 0')
119                 BITSET_ASSIGN(f, 4);
120         if(this.movedir != '0 0 0')
121                 BITSET_ASSIGN(f, 8);
122         if(this.angles != '0 0 0')
123                 BITSET_ASSIGN(f, 16);
124         WriteByte(MSG_ENTITY, f);
125
126         if(withtarget)
127         {
128                 // probably some way to clean this up...
129                 int targbits = 0;
130                 if(this.target && this.target != "") targbits |= BIT(0);
131                 if(this.target2 && this.target2 != "") targbits |= BIT(1);
132                 if(this.target3 && this.target3 != "") targbits |= BIT(2);
133                 if(this.target4 && this.target4 != "") targbits |= BIT(3);
134                 if(this.targetname && this.targetname != "") targbits |= BIT(4);
135                 if(this.killtarget && this.killtarget != "") targbits |= BIT(5);
136
137                 WriteByte(MSG_ENTITY, targbits);
138
139                 if(targbits & BIT(0))
140                         WriteString(MSG_ENTITY, this.target);
141                 if(targbits & BIT(1))
142                         WriteString(MSG_ENTITY, this.target2);
143                 if(targbits & BIT(2))
144                         WriteString(MSG_ENTITY, this.target3);
145                 if(targbits & BIT(3))
146                         WriteString(MSG_ENTITY, this.target4);
147                 if(targbits & BIT(4))
148                         WriteString(MSG_ENTITY, this.targetname);
149                 if(targbits & BIT(5))
150                         WriteString(MSG_ENTITY, this.killtarget);
151         }
152
153         if(f & 4)
154                 WriteVector(MSG_ENTITY, this.origin);
155
156         if(f & 8)
157                 WriteVector(MSG_ENTITY, this.movedir);
158
159         if(f & 16)
160                 WriteVector(MSG_ENTITY, this.angles);
161
162         WriteShort(MSG_ENTITY, this.modelindex);
163         WriteVector(MSG_ENTITY, this.mins);
164         WriteVector(MSG_ENTITY, this.maxs);
165         WriteByte(MSG_ENTITY, bound(1, this.scale * 16, 255));
166 }
167
168 #elif defined(CSQC)
169
170 void trigger_common_read(entity this, bool withtarget)
171 {
172         int f = ReadByte();
173         this.warpzone_isboxy = (f & 1);
174
175         if(withtarget)
176         {
177                 strfree(this.target);
178                 strfree(this.target2);
179                 strfree(this.target3);
180                 strfree(this.target4);
181                 strfree(this.targetname);
182                 strfree(this.killtarget);
183
184                 int targbits = ReadByte();
185
186                 this.target = ((targbits & BIT(0)) ? strzone(ReadString()) : string_null);
187                 this.target2 = ((targbits & BIT(1)) ? strzone(ReadString()) : string_null);
188                 this.target3 = ((targbits & BIT(2)) ? strzone(ReadString()) : string_null);
189                 this.target4 = ((targbits & BIT(3)) ? strzone(ReadString()) : string_null);
190                 this.targetname = ((targbits & BIT(4)) ? strzone(ReadString()) : string_null);
191                 this.killtarget = ((targbits & BIT(5)) ? strzone(ReadString()) : string_null);
192         }
193
194         if(f & 4)
195                 this.origin = ReadVector();
196         else
197                 this.origin = '0 0 0';
198         setorigin(this, this.origin);
199
200         if(f & 8)
201                 this.movedir = ReadVector();
202         else
203                 this.movedir = '0 0 0';
204
205         if(f & 16)
206                 this.angles = ReadVector();
207         else
208                 this.angles = '0 0 0';
209
210         this.modelindex = ReadShort();
211         this.mins = ReadVector();
212         this.maxs = ReadVector();
213         this.scale = ReadByte() / 16;
214         setsize(this, this.mins, this.maxs);
215 }
216
217 void trigger_remove_generic(entity this)
218 {
219         strfree(this.target);
220         strfree(this.target2);
221         strfree(this.target3);
222         strfree(this.target4);
223         strfree(this.targetname);
224         strfree(this.killtarget);
225 }
226 #endif
227
228
229 /*
230 ==============================
231 SUB_UseTargets
232
233 the global "activator" should be set to the entity that initiated the firing.
234
235 If this.delay is set, a DelayedUse entity will be created that will actually
236 do the SUB_UseTargets after that many seconds have passed.
237
238 Centerprints any this.message to the activator.
239
240 Removes all entities with a targetname that match this.killtarget,
241 and removes them, so some events can remove other triggers.
242
243 Search for (string)targetname in all entities that
244 match (string)this.target and call their .use function
245
246 ==============================
247 */
248
249 void SUB_UseTargets_Ex(entity this, entity actor, entity trigger, bool preventReuse)
250 {
251 //
252 // check for a delay
253 //
254         if (this.delay)
255         {
256         // create a temp object to fire at a later time
257                 entity t = new(DelayedUse);
258                 t.nextthink = time + this.delay;
259                 setthink(t, DelayThink);
260                 t.enemy = actor;
261                 t.message = this.message;
262                 t.killtarget = this.killtarget;
263                 t.target = this.target;
264                 t.target2 = this.target2;
265                 t.target3 = this.target3;
266                 t.target4 = this.target4;
267                 t.antiwall_flag = this.antiwall_flag;
268                 return;
269         }
270
271         string s;
272
273 //
274 // print the message
275 //
276 #ifdef SVQC
277         if(this)
278         if(IS_PLAYER(actor) && this.message != "")
279         if(IS_REAL_CLIENT(actor))
280         {
281                 centerprint(actor, this.message);
282                 if (this.noise == "")
283                         play2(actor, SND(TALK));
284         }
285
286 //
287 // kill the killtagets
288 //
289         s = this.killtarget;
290         if (s != "")
291         {
292                 for(entity t = NULL; (t = find(t, targetname, s)); )
293                         delete(t);
294         }
295 #endif
296
297 //
298 // fire targets
299 //
300
301         if(this.target_random)
302                 RandomSelection_Init();
303
304         for(int i = 0; i < 4; ++i)
305         {
306                 switch(i)
307                 {
308                         default:
309                         case 0: s = this.target; break;
310                         case 1: s = this.target2; break;
311                         case 2: s = this.target3; break;
312                         case 3: s = this.target4; break;
313                 }
314                 if (s != "")
315                 {
316                         // Flag to set func_clientwall state
317                         // 1 == deactivate, 2 == activate, 0 == do nothing
318                         int aw_flag = this.antiwall_flag;
319                         for(entity t = NULL; (t = find(t, targetname, s)); )
320                         {
321                                 if(t.use && (t.sub_target_used != time || !preventReuse))
322                                 {
323                                         if(this.target_random)
324                                         {
325                                                 RandomSelection_AddEnt(t, 1, 0);
326                                         }
327                                         else
328                                         {
329                                                 if (t.classname == "func_clientwall" || t.classname == "func_clientillusionary")
330                                                         t.antiwall_flag = aw_flag;
331
332                                                 t.use(t, actor, this);
333                                                 if(preventReuse)
334                                                         t.sub_target_used = time;
335                                         }
336                                 }
337                         }
338                 }
339         }
340
341         if(this.target_random && RandomSelection_chosen_ent)
342         {
343                 RandomSelection_chosen_ent.use(RandomSelection_chosen_ent, actor, this);
344                 if(preventReuse)
345                         RandomSelection_chosen_ent.sub_target_used = time;
346         }
347 }
348
349 void SUB_UseTargets(entity this, entity actor, entity trigger) { SUB_UseTargets_Ex(this, actor, trigger, false); }
350 void SUB_UseTargets_PreventReuse(entity this, entity actor, entity trigger) { SUB_UseTargets_Ex(this, actor, trigger, true); }