]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/triggers/triggers.qc
Shoot rockets through doors
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / triggers / triggers.qc
1 void SUB_DontUseTargets() { }
2
3 void() SUB_UseTargets;
4
5 void DelayThink()
6 {
7         activator = self.enemy;
8         SUB_UseTargets ();
9         remove(self);
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 void trigger_setnextthink(entity e, float dtime)
24 {
25 #ifdef CSQC
26         e.nextthink = time + dtime;
27 #else
28         e.nextthink = dtime;
29 #endif
30 }
31
32 #ifdef SVQC
33 void trigger_common_write(bool withtarget)
34 {
35         WriteByte(MSG_ENTITY, self.warpzone_isboxy);
36         WriteByte(MSG_ENTITY, self.scale);
37
38         if(withtarget)
39         {
40                 WriteString(MSG_ENTITY, self.target);
41                 WriteString(MSG_ENTITY, self.target2);
42                 WriteString(MSG_ENTITY, self.target3);
43                 WriteString(MSG_ENTITY, self.target4);
44                 WriteString(MSG_ENTITY, self.targetname);
45                 WriteString(MSG_ENTITY, self.killtarget);
46         }
47
48         WriteCoord(MSG_ENTITY, self.origin_x);
49         WriteCoord(MSG_ENTITY, self.origin_y);
50         WriteCoord(MSG_ENTITY, self.origin_z);
51
52         WriteCoord(MSG_ENTITY, self.mins_x);
53         WriteCoord(MSG_ENTITY, self.mins_y);
54         WriteCoord(MSG_ENTITY, self.mins_z);
55         WriteCoord(MSG_ENTITY, self.maxs_x);
56         WriteCoord(MSG_ENTITY, self.maxs_y);
57         WriteCoord(MSG_ENTITY, self.maxs_z);
58
59         WriteCoord(MSG_ENTITY, self.movedir_x);
60         WriteCoord(MSG_ENTITY, self.movedir_y);
61         WriteCoord(MSG_ENTITY, self.movedir_z);
62
63         WriteCoord(MSG_ENTITY, self.angles_x);
64         WriteCoord(MSG_ENTITY, self.angles_y);
65         WriteCoord(MSG_ENTITY, self.angles_z);
66 }
67
68 #elif defined(CSQC)
69
70 void trigger_common_read(bool withtarget)
71 {
72         self.warpzone_isboxy = ReadByte();
73         self.scale = ReadByte();
74
75         if(withtarget)
76         {
77                 self.target = strzone(ReadString());
78                 self.target2 = strzone(ReadString());
79                 self.target3 = strzone(ReadString());
80                 self.target4 = strzone(ReadString());
81                 self.targetname = strzone(ReadString());
82                 self.killtarget = strzone(ReadString());
83         }
84
85         self.origin_x = ReadCoord();
86         self.origin_y = ReadCoord();
87         self.origin_z = ReadCoord();
88         setorigin(self, self.origin);
89
90         self.mins_x = ReadCoord();
91         self.mins_y = ReadCoord();
92         self.mins_z = ReadCoord();
93         self.maxs_x = ReadCoord();
94         self.maxs_y = ReadCoord();
95         self.maxs_z = ReadCoord();
96         setsize(self, self.mins, self.maxs);
97
98         self.movedir_x = ReadCoord();
99         self.movedir_y = ReadCoord();
100         self.movedir_z = ReadCoord();
101
102         self.angles_x = ReadCoord();
103         self.angles_y = ReadCoord();
104         self.angles_z = ReadCoord();
105 }
106
107 void trigger_remove_generic()
108 {
109         if(self.target) { strunzone(self.target); }
110         self.target = string_null;
111
112         if(self.target2) { strunzone(self.target2); }
113         self.target2 = string_null;
114
115         if(self.target3) { strunzone(self.target3); }
116         self.target3 = string_null;
117
118         if(self.target4) { strunzone(self.target4); }
119         self.target4 = string_null;
120
121         if(self.targetname) { strunzone(self.targetname); }
122         self.target = string_null;
123
124         if(self.killtarget) { strunzone(self.killtarget); }
125         self.killtarget = string_null;
126 }
127 #endif
128
129 /*
130 ==============================
131 SUB_UseTargets
132
133 the global "activator" should be set to the entity that initiated the firing.
134
135 If self.delay is set, a DelayedUse entity will be created that will actually
136 do the SUB_UseTargets after that many seconds have passed.
137
138 Centerprints any self.message to the activator.
139
140 Removes all entities with a targetname that match self.killtarget,
141 and removes them, so some events can remove other triggers.
142
143 Search for (string)targetname in all entities that
144 match (string)self.target and call their .use function
145
146 ==============================
147 */
148 void SUB_UseTargets()
149 {
150         entity t, stemp, otemp, act;
151         string s;
152         float i;
153
154 //
155 // check for a delay
156 //
157         if (self.delay)
158         {
159         // create a temp object to fire at a later time
160                 t = spawn();
161                 t.classname = "DelayedUse";
162                 t.nextthink = time + self.delay;
163                 t.think = DelayThink;
164                 t.enemy = activator;
165                 t.message = self.message;
166                 t.killtarget = self.killtarget;
167                 t.target = self.target;
168                 t.target2 = self.target2;
169                 t.target3 = self.target3;
170                 t.target4 = self.target4;
171                 return;
172         }
173
174
175 //
176 // print the message
177 //
178 #ifdef SVQC
179         if(self)
180         if(IS_PLAYER(activator) && self.message != "")
181         if(IS_REAL_CLIENT(activator))
182         {
183                 centerprint(activator, self.message);
184                 if (self.noise == "")
185                         play2(activator, "misc/talk.wav");
186         }
187
188 //
189 // kill the killtagets
190 //
191         s = self.killtarget;
192         if (s != "")
193         {
194                 for(t = world; (t = find(t, targetname, s)); )
195                         remove(t);
196         }
197 #endif
198
199 //
200 // fire targets
201 //
202         act = activator;
203         stemp = self;
204         otemp = other;
205
206         if(stemp.target_random)
207                 RandomSelection_Init();
208
209         for(i = 0; i < 4; ++i)
210         {
211                 switch(i)
212                 {
213                         default:
214                         case 0: s = stemp.target; break;
215                         case 1: s = stemp.target2; break;
216                         case 2: s = stemp.target3; break;
217                         case 3: s = stemp.target4; break;
218                 }
219                 if (s != "")
220                 {
221                         for(t = world; (t = find(t, targetname, s)); )
222                         if(t.use)
223                         {
224                                 if(stemp.target_random)
225                                 {
226                                         RandomSelection_Add(t, 0, string_null, 1, 0);
227                                 }
228                                 else
229                                 {
230                                         self = t;
231                                         other = stemp;
232                                         activator = act;
233                                         self.use();
234                                 }
235                         }
236                 }
237         }
238
239         if(stemp.target_random && RandomSelection_chosen_ent)
240         {
241                 self = RandomSelection_chosen_ent;
242                 other = stemp;
243                 activator = act;
244                 self.use();
245         }
246
247         activator = act;
248         self = stemp;
249         other = otemp;
250 }
251
252 #ifdef CSQC
253 void trigger_touch_generic(void() touchfunc)
254 {
255         entity e;
256         for(e = findradius((self.absmin + self.absmax) * 0.5, vlen(self.absmax - self.absmin) * 0.5 + 1); e; e = e.chain)
257         if(e.isplayermodel || e.classname == "csqcprojectile")
258         {
259                 vector emin = e.absmin, emax = e.absmax;
260                 if(self.solid == SOLID_BSP)
261                 {
262                         emin -= '1 1 1';
263                         emax += '1 1 1';
264                 }
265                 if(boxesoverlap(emin, emax, self.absmin, self.absmax)) // quick
266                 if(WarpZoneLib_BoxTouchesBrush(emin, emax, self, e)) // accurate
267                 {
268                         other = e;
269                         touchfunc();
270                 }
271         }
272 }
273 void trigger_draw_generic()
274 {
275         float dt = time - self.move_time;
276         self.move_time = time;
277         if(dt <= 0) { return; }
278
279         setorigin(self, self.origin + self.velocity * frametime);
280
281         if(self.trigger_touch) { trigger_touch_generic(self.trigger_touch); }
282 }
283 #endif