3 #include <server/item_key.qh>
6 void SUB_DontUseTargets(entity this, entity actor, entity trigger) { }
8 void SUB_UseTargets(entity this, entity actor, entity trigger);
10 void DelayThink(entity this)
12 SUB_UseTargets (this, this.enemy, NULL);
16 void FixSize(entity e)
18 e.mins_x = rint(e.mins_x);
19 e.mins_y = rint(e.mins_y);
20 e.mins_z = rint(e.mins_z);
22 e.maxs_x = rint(e.maxs_x);
23 e.maxs_y = rint(e.maxs_y);
24 e.maxs_z = rint(e.maxs_z);
28 void generic_setactive(entity this, int act)
30 if(act == ACTIVE_TOGGLE)
32 if(this.active == ACTIVE_ACTIVE)
34 this.active = ACTIVE_NOT;
38 this.active = ACTIVE_ACTIVE;
47 void generic_netlinked_setactive(entity this, int act)
49 int old_status = this.active;
50 generic_setactive(this, act);
52 if (this.active != old_status)
54 this.SendFlags |= SF_TRIGGER_UPDATE;
58 void generic_netlinked_reset(entity this)
62 if(this.spawnflags & START_ENABLED)
64 this.active = ACTIVE_ACTIVE;
68 this.active = ACTIVE_NOT;
73 this.active = ACTIVE_ACTIVE;
76 this.SendFlags |= SF_TRIGGER_UPDATE;
79 // Compatibility with old maps
80 void generic_netlinked_legacy_use(entity this, entity actor, entity trigger)
82 LOG_WARNF("Entity %s was (de)activated by a trigger, please update map to use relays", this.targetname);
83 this.setactive(this, ACTIVE_TOGGLE);
86 bool autocvar_g_triggers_debug = true;
88 void trigger_init(entity this)
90 string m = this.model;
92 if(autocvar_g_triggers_debug)
97 _setmodel(this, m); // no precision needed
99 setorigin(this, this.origin);
101 setsize(this, this.mins * this.scale, this.maxs * this.scale);
103 setsize(this, this.mins, this.maxs);
106 if(autocvar_g_triggers_debug)
107 BITSET_ASSIGN(this.effects, EF_NODEPTHTEST);
110 void trigger_link(entity this, bool(entity this, entity to, int sendflags) sendfunc)
112 setSendEntity(this, sendfunc);
113 this.SendFlags = 0xFFFFFF;
116 void trigger_common_write(entity this, bool withtarget)
119 if(this.warpzone_isboxy)
121 if(this.origin != '0 0 0')
123 if(this.movedir != '0 0 0')
125 if(this.angles != '0 0 0')
126 BITSET_ASSIGN(f, 16);
127 WriteByte(MSG_ENTITY, f);
131 // probably some way to clean this up...
133 if(this.target && this.target != "") targbits |= BIT(0);
134 if(this.target2 && this.target2 != "") targbits |= BIT(1);
135 if(this.target3 && this.target3 != "") targbits |= BIT(2);
136 if(this.target4 && this.target4 != "") targbits |= BIT(3);
137 if(this.targetname && this.targetname != "") targbits |= BIT(4);
138 if(this.killtarget && this.killtarget != "") targbits |= BIT(5);
140 WriteByte(MSG_ENTITY, targbits);
142 if(targbits & BIT(0))
143 WriteString(MSG_ENTITY, this.target);
144 if(targbits & BIT(1))
145 WriteString(MSG_ENTITY, this.target2);
146 if(targbits & BIT(2))
147 WriteString(MSG_ENTITY, this.target3);
148 if(targbits & BIT(3))
149 WriteString(MSG_ENTITY, this.target4);
150 if(targbits & BIT(4))
151 WriteString(MSG_ENTITY, this.targetname);
152 if(targbits & BIT(5))
153 WriteString(MSG_ENTITY, this.killtarget);
157 WriteVector(MSG_ENTITY, this.origin);
160 WriteVector(MSG_ENTITY, this.movedir);
163 WriteVector(MSG_ENTITY, this.angles);
165 WriteShort(MSG_ENTITY, this.modelindex);
166 WriteVector(MSG_ENTITY, this.mins);
167 WriteVector(MSG_ENTITY, this.maxs);
168 WriteByte(MSG_ENTITY, bound(1, this.scale * 16, 255));
173 void trigger_common_read(entity this, bool withtarget)
176 this.warpzone_isboxy = (f & 1);
180 strfree(this.target);
181 strfree(this.target2);
182 strfree(this.target3);
183 strfree(this.target4);
184 strfree(this.targetname);
185 strfree(this.killtarget);
187 int targbits = ReadByte();
189 this.target = ((targbits & BIT(0)) ? strzone(ReadString()) : string_null);
190 this.target2 = ((targbits & BIT(1)) ? strzone(ReadString()) : string_null);
191 this.target3 = ((targbits & BIT(2)) ? strzone(ReadString()) : string_null);
192 this.target4 = ((targbits & BIT(3)) ? strzone(ReadString()) : string_null);
193 this.targetname = ((targbits & BIT(4)) ? strzone(ReadString()) : string_null);
194 this.killtarget = ((targbits & BIT(5)) ? strzone(ReadString()) : string_null);
198 this.origin = ReadVector();
200 this.origin = '0 0 0';
201 setorigin(this, this.origin);
204 this.movedir = ReadVector();
206 this.movedir = '0 0 0';
209 this.angles = ReadVector();
211 this.angles = '0 0 0';
213 this.modelindex = ReadShort();
214 this.mins = ReadVector();
215 this.maxs = ReadVector();
216 this.scale = ReadByte() / 16;
217 setsize(this, this.mins, this.maxs);
220 void trigger_remove_generic(entity this)
222 strfree(this.target);
223 strfree(this.target2);
224 strfree(this.target3);
225 strfree(this.target4);
226 strfree(this.targetname);
227 strfree(this.killtarget);
233 ==============================
236 the global "activator" should be set to the entity that initiated the firing.
238 If this.delay is set, a DelayedUse entity will be created that will actually
239 do the SUB_UseTargets after that many seconds have passed.
241 Centerprints any this.message to the activator.
243 Removes all entities with a targetname that match this.killtarget,
244 and removes them, so some events can remove other triggers.
246 Search for (string)targetname in all entities that
247 match (string)this.target and call their .use function
249 ==============================
252 void SUB_UseTargets_Ex(entity this, entity actor, entity trigger, bool preventReuse)
259 // create a temp object to fire at a later time
260 entity t = new(DelayedUse);
261 t.nextthink = time + this.delay;
262 setthink(t, DelayThink);
264 t.message = this.message;
265 t.killtarget = this.killtarget;
266 t.target = this.target;
267 t.target2 = this.target2;
268 t.target3 = this.target3;
269 t.target4 = this.target4;
270 t.antiwall_flag = this.antiwall_flag;
281 if(IS_PLAYER(actor) && this.message != "")
282 if(IS_REAL_CLIENT(actor))
284 centerprint(actor, this.message);
285 if (this.noise == "")
286 play2(actor, SND(TALK));
290 // kill the killtagets
295 for(entity t = NULL; (t = find(t, targetname, s)); )
304 if(this.target_random)
305 RandomSelection_Init();
307 for(int i = 0; i < 4; ++i)
312 case 0: s = this.target; break;
313 case 1: s = this.target2; break;
314 case 2: s = this.target3; break;
315 case 3: s = this.target4; break;
319 // Flag to set func_clientwall state
320 // 1 == deactivate, 2 == activate, 0 == do nothing
321 int aw_flag = this.antiwall_flag;
322 for(entity t = NULL; (t = find(t, targetname, s)); )
324 if(t.use && (t.sub_target_used != time || !preventReuse))
326 if(this.target_random)
328 RandomSelection_AddEnt(t, 1, 0);
332 if (t.classname == "func_clientwall" || t.classname == "func_clientillusionary")
333 t.antiwall_flag = aw_flag;
335 t.use(t, actor, this);
337 t.sub_target_used = time;
344 if(this.target_random && RandomSelection_chosen_ent)
346 RandomSelection_chosen_ent.use(RandomSelection_chosen_ent, actor, this);
348 RandomSelection_chosen_ent.sub_target_used = time;
352 void SUB_UseTargets(entity this, entity actor, entity trigger) { SUB_UseTargets_Ex(this, actor, trigger, false); }
353 void SUB_UseTargets_PreventReuse(entity this, entity actor, entity trigger) { SUB_UseTargets_Ex(this, actor, trigger, true); }