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