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