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