-
Notifications
You must be signed in to change notification settings - Fork 17
/
Copy patht_ctrl.qc
689 lines (588 loc) · 20.7 KB
/
t_ctrl.qc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
/*
================================================================
CONTROL FLOW
All the relays, counters, and other gates that manipulate the firing
of other entities' .use() functions
including entities that aren't real triggers but are named trigger_*
================================================================
*/
const float SPAWN_RELAY_MSGONCE = 1;
const float SPAWN_RELAY_RANDOM = 2;
const float SPAWN_RELAY_HOLD = 4;
void() trigger_relay_msg =
{
activator = self.enemy;
SUB_PrintMessage();
if (self.noise)
sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
if (self.spawnflags & SPAWN_RELAY_MSGONCE)
self.message = string_null;
}
void() trigger_relay_release =
{
activator = self.enemy;
self.attack_finished = 0;
if (self.spawnflags & SPAWN_ALT_TARG)
{
SUB_UseTargetsAlt(target3);
SUB_UseTargetsAlt(target4);
}
else SUB_UseTargets();
if (self.noise2 != string_null)
{
if (self.delay > 0)
sound_delayed(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM, self.delay);
else
sound (self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
}
}
void() trigger_relay_use =
{
if (self.customflags & CFL_LOCKED)
{
dprint(" trigger_relay is locked: not relaying\n");
return;
}
if (self.spawnflags & SPAWN_RELAY_HOLD && self.attack_finished > time)
{
self.attack_finished = time + self.wait;
self.nextthink = time + self.wait;
return;
}
self.enemy = activator;
if (self.spawnflags & SPAWN_RELAY_RANDOM)
{
SUB_CountTargets();
SUB_UseRandomTarget();
}
else if ((self.spawnflags & SPAWN_RELAY_HOLD) && (self.spawnflags & SPAWN_ALT_TARG))
{
SUB_PrintMessage();
SUB_UseTargetsAlt(target);
SUB_UseTargetsAlt(target2);
}
else SUB_UseTargets();
if (self.spawnflags & SPAWN_RELAY_MSGONCE)
self.message = string_null;
if (self.noise != string_null)
{
if (self.delay > 0)
sound_delayed(self, CHAN_VOICE, self.noise, 1, ATTN_NORM, self.delay);
else
sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
}
playercount_convert(count);
if (self.count > 0)
{
self.count -= 1;
if (self.count == 0)
remove(self);
}
if (self.spawnflags & SPAWN_RELAY_HOLD)
{
self.attack_finished = time + self.wait;
self.nextthink = time + self.wait;
self.think = trigger_relay_release;
}
}
/*QUAKED trigger_relay (.5 .0 .5) (-8 -8 -8) (8 8 8) MSG_ONCE RANDOM HOLD
This fixed size trigger cannot be touched, it can only be fired by other events. Target this with a target_lock to selectively disable/reenable it for logic fun.
Keys:
"delay" delay before firing (after trigger)
"killtarget" removes target
"message" displayed when fired
"target/2/3/4" fires target when triggered
"targetname" entity name (required)
"sounds" same as other triggers, plays after 'delay'
"noise" or, pick any wav
"count" only fire this many times, then auto self-destruct
Spawnflags:
"MSG_ONCE" only print its message on the first firing, otherwise it prints every time
"RANDOM" randomly fire one of its targets (and/or kill one of its killtargets) instead of them all
"HOLD" fire only the first time triggered (toggle on), and fire again after 'wait' seconds have passed without being triggered (toggle off)
Alt Target Pattern: If 'Hold', 'target'/'target2' on first trigger, 'target3'/'target4' on end trigger
*/
/*FGD
@PointClass size(16 16 16) color(160 0 160) base(Appearflags, TriggerSounds, Target, Targetname, AltTarget) = trigger_relay : "Trigger: Relay.
This fixed size trigger cannot be touched, it can only be fired by other events. Target this with a target_lock to selectively disable/reenable it for logic fun.
The 'Hold' spawnflag will cause the relay to fire only the first time it is triggered (toggle on), and fire again after 'wait' seconds have passed without being triggered (toggle off)."
[
spawnflags(flags) = [
1 : "Only print message once" : 0
2 : "Choose one target at random" : 0
4 : "Hold" : 0
]
message(string) : "Print when triggered"
count(integer) : "Limit uses (then self destruct)" : 0
]
*/
void() trigger_relay =
{
if (!SUB_ShouldSpawn()) return;
if (self.targetname == string_null)
{
// IW fix - no longer objerror, which is a game-ender in old engines
dprint3("\bwarning:\b trigger_relay at ", vtos(self.origin), "not targeted by anything\n");
//remove(self);
//return;
}
self.use = trigger_relay_use;
InitTriggerSounds();
}
//=============================================================================
float(entity inc) target_state_compare =
{
dprint5("tstate '", self.targetname, "' comparing to '", self.include,"': ");
dprint4(ftos(self.state), " vs ", ftos(inc.state), "\n");
float out = FALSE;
if (self.style & 1)
out |= (inc.state == self.state);
if (self.style & 2)
out |= (inc.state > self.state);
else if (self.style & 4)
out |= (inc.state < self.state);
if (self.spawnflags & 2) return !out;
return out;
}
void() target_state_use =
{
if (self.customflags & CFL_LOCKED)
return;
if (self.spawnflags & 1)
{
entity inc;
inc = find(world, targetname, self.include);
if (inc)
{
if (target_state_compare(inc))
SUB_UseTargets();
}
return;
}
playercount_convert(count);
float mx = max(1, self.count);
if (self.spawnflags & 2)
{
self.state = self.state - 1;
if (self.state < 0) self.state = mx;
}
else
{
self.state = self.state + 1;
if (self.state > mx) self.state = 0;
}
//bprint3("state is now ",ftos(self.state),"\n");
}
/*QUAKED target_state (.5 .0 .5) (-8 -8 -8) (8 8 8) RELAY INVERSE
Holds a numeric variable, or tests other entities for theirs before firing targets. Set 'state' to initial value. triggering this will cycle the value (swapping 0 and 1).
If "RELAY" is checked, it acts as a relay instead of holding state. It fires its targets based on the value of the 'state' member of another entity, specified by setting 'state' to the value it has to match and 'include' to that entity's targetname. This can be another target_state, or any other entity which has a 'state', such as doors or plats.
0: off (lights/etc)/top (plats)/open (doors)/pushed (buttons)
1: on (lights/etc)/bottom (plats)/closed (doors)/unpushed (buttons)
2: going up (plats)/opening (doors)/pushing (buttons)
3: going down (plats)/closing (doors)/unpushing (buttons)
A trigger_counter's 'state' is its current trigger count.
Keys:
"style" comparison to make if RELAY
1: self = include (default)
2: self < include
3: self <= include
4: self > include
5: self >= include
"count" if > 1, state will be incremented on each trigger to a maximum of 'count' before cycling to 0
"delay" delay before firing (after trigger)
"target2/3/4/kill" targets to fire if RELAY
Spawnflags:
"INVERSE" if RELAY, will fire if state is anything other than a match. otherwise, will decrement when triggered instead of increment
*/
/*FGD
@PointClass size(16 16 16) color(255 0 255) base(Appearflags, Target, Targetname) = target_state : "Target : State.
Holds a numeric variable, or tests other entities for theirs before firing targets.
Set 'state' to initial value. triggering this will cycle the value (swapping 0 and 1).
If 'Relay' spawnflag is checked, it acts as a relay instead of holding state. It fires its targets based on the value of the 'state' member of another entity, specified by setting 'state' to the value it has to match and 'include' to that entity's targetname. This can be another target_state, or any other entity which has a 'state', such as doors or plats.
0: off (lights/etc)/top (plats)/open (doors)/pushed (buttons)
1: on (lights/etc)/bottom (plats)/closed (doors)/unpushed (buttons)
2: going up (plats)/opening (doors)/pushing (buttons)
3: going down (plats)/closing (doors)/unpushing (buttons)
A trigger_counter's 'state' is its current trigger count.
If 'Inverse' spawnflag is set, will decrement when triggered instead of increment. If both 'Relay' and 'Inverse', will fire targets if the state of 'include' is anything other than a match."
[
spawnflags(flags) = [
1 : "Relay" : 0
2 : "Inverse" : 0
]
style(choices) : "Comparison operator for relay" = [
1 : "self = include"
2 : "self < include"
3 : "self <= include"
4 : "self > include"
5 : "self >= include"
]
include(target_destination) : "Targetname of entity to monitor"
count(integer) : "Max state value to cycle to. if > 1, state will be incremented on each trigger to a maximum of 'count' before cycling to 0." : 1
state(integer) : "Value"
]
*/
void() target_state =
{
if (!SUB_ShouldSpawn()) return;
if (self.targetname == string_null && !self.impulse)
objerror("target_state not targeted by anything");
if (self.spawnflags & 1 && self.include == string_null)
objerror("target_state relay has no include");
if (self.style < 1 || self.style > 5)
self.style = 1;
self.use = target_state_use;
}
//=============================================================================
const float SPAWN_LOCK_START = 1;
const float SPAWN_LOCK_LOCK_ONLY = 2;
const float SPAWN_LOCK_UNLOCK_ONLY = 4;
const float SPAWN_LOCK_NOTOGGLE = 6;
// state 1 = targets are currently locked
// state 0 = targets are currently unlocked
void(string tname, float locking) target_lock_do =
{
if (tname == string_null) return;
entity t, oself;
t = world;
do {
t = find (t, targetname, tname);
if (!t) break;
if (t.lock)
{
oself = self;
self = t;
self.lock(!locking);
self = oself;
}
else
{
if (locking)
t.customflags |= CFL_LOCKED;
else
t.customflags = not(t.customflags, CFL_LOCKED);
}
if (locking)
dprint4(t.classname, " with targetname ", t.targetname, " is locked\n");
else
dprint4(t.classname, " with targetname ", t.targetname, " is unlocked\n");
} while ( t );
}
void() lock_targets =
{
target_lock_do(self.target, TRUE);
target_lock_do(self.target2, TRUE);
target_lock_do(self.target3, TRUE);
target_lock_do(self.target4, TRUE);
self.state = TRUE;
}
void() unlock_targets =
{
target_lock_do(self.target, FALSE);
target_lock_do(self.target2, FALSE);
target_lock_do(self.target3, FALSE);
target_lock_do(self.target4, FALSE);
self.state = FALSE;
}
void() target_lock_use =
{
float locking, undoing;
if (self.wait || self.rand)
{
undoing = TRUE;
self.nextthink = time + self.wait + random() * self.rand;
}
if (!(self.spawnflags & SPAWN_LOCK_NOTOGGLE))
{
self.state = !self.state;
locking = self.state;
}
else if (self.spawnflags & SPAWN_LOCK_LOCK_ONLY)
locking = TRUE;
else
locking = FALSE;
if (locking)
{
lock_targets();
if (undoing) self.think = unlock_targets;
return;
}
unlock_targets();
if (undoing) self.think = lock_targets;
}
/*QUAKED target_lock (0 .5 .8) (-8 -8 -8) (8 8 8) START_LOCKED LOCK_ONLY UNLOCK_ONLY
Locks and unlocks targeted entities independent of their toggle/start_open/etc states. Works on various entities:
- A locked func_door won't respond to touches or triggers. Use this for doors behind temporary bars.
- A locked func_plat behaves as an unreleased LOW_TRIGGER plat
- A locked trigger_relay will not fire or evaluate at all
- Locked path_corners are not considered valid patrol/train destinations
- Locked trigger volumes (once/multi/teleport/secret/changelevel/push/monsterjump) will not activate when touched or triggered
If 'wait' or 'rand' are set, will automatically undo itself after 'wait' seconds plus up to 'rand' additional seconds.
Spawnflags:
"start_locked" Targeted entities start out locked.
"lock_only" Will only lock its targets rather than toggling
"unlock_only" Will only unlock its targets rather than toggling
*/
/*FGD
@Pointclass base(Targetname, Appearflags) color(192 64 0) size(16 16 16) = target_lock :
"Locks and unlocks targeted entities independent of their toggle/start_open/etc states. Works on various entities:
- A locked func_door won't respond to touches or triggers. Use this for doors behind temporary bars.
- A locked func_plat behaves as an unreleased LOW_TRIGGER plat
- A locked trigger_relay will not fire or evaluate at all
- Locked path_corners are not considered valid patrol/train destinations
- Locked trigger volumes (once/multi/teleport/secret/changelevel/push/monsterjump) will not activate when touched or triggered
If 'wait' is set, will automatically undo itself after 'wait' seconds."
[
spawnflags(flags) = [
1: "Targeted entities start locked" : 0
2: "Lock only" : 0
4: "Unlock only" : 0
]
target(target_destination) : "Target: acts on all with matching targetname"
target2(target_destination) : "Target 2: acts on all with matching targetname"
target3(target_destination) : "Target 3: acts on all with matching targetname"
target4(target_destination) : "Target 4: acts on all with matching targetname"
wait(string) : "Wait before undoing" : 0
rand(string) : "Additional random wait" : 0
]
*/
void() target_lock =
{
if (!SUB_ShouldSpawn()) return;
self.use = target_lock_use;
self.state = 0;
if (self.spawnflags & SPAWN_LOCK_START)
{
self.think = lock_targets;
self.nextthink = time + 0.25;
}
}
//============================================================================
void() counter_reset =
{
self.state = 0;
if (self.spawnflags & SPAWNFLAG_NOMESSAGE)
return;
centerprint (self.enemy, "Counter has reset!");
sound (self.enemy, CHAN_VOICE, "misc/talk.wav", 1, ATTN_NORM);
}
void() counter_use =
{
playercount_convert(count);
if (time < self.attack_finished) return;
self.enemy = SUB_PlayerizeActivator();
// eager reset spawnflag: reset 'wait' seconds after any trigger, not just upon
// completion - for requiring a number of impulses within a window of time
if (self.spawnflags & 4)
{
self.think = counter_reset;
self.nextthink = time + self.wait;
}
self.state = self.state + 1;
if (self.state > self.count)
return;
if (self.state != self.count)
{
float rem = self.count - self.state;
if (self.enemy.classname == "player" && !(self.spawnflags & SPAWNFLAG_NOMESSAGE))
{
if (rem >= 6)
centerprint (self.enemy, "There are more to go ...");
else if (rem == 5)
centerprint (self.enemy, "There are 5 more to go ...");
else if (rem == 4)
centerprint (self.enemy, "There are 4 more to go ...");
else if (rem == 3)
centerprint (self.enemy, "There are 3 more to go ...");
else if (rem == 2)
centerprint (self.enemy, "Only 2 more to go ...");
else
centerprint (self.enemy, "Only 1 more to go ...");
}
return;
}
self.nextthink = 0;
if (self.enemy.classname == "player" && self.message != string_null)
SUB_PrintMessage();
// centerprint(activator, self.message);
if (self.wait >= 0)
self.state = 0; // repeatable
//multi_trigger ();
SUB_UseTargetsSilent();
if (self.wait > 0)
self.attack_finished = time + self.wait;
}
/*QUAKED trigger_counter (.5 .0 .5) (-8 -8 -8) (8 8 8) NOMESSAGE REPEAT EAGER_RESET
Acts as an intermediary for an action that takes multiple inputs.
If nomessage is not set, it will print "1 more.. " etc when triggered and "sequence complete" when finished. After the counter has been triggered "count" times, it will fire all of it's targets and remove itself, unless 'repeat' has been set, in which case it resets after 'wait' seconds.
Flags:
"nomessage" disables count display
"repeat" reusable
"eager reset" resets its own count 'wait' seconds after being triggered (for requiring multiple triggerings within a narrow window of time)
Keys:
"count" number of triggers needed to fire own target, default is 2
"target" entity to trigger (required)
"targetname" entity name (required)
"message" specify text to print on completion (will always print - overrides 'nomessage' on completion)
*/
/*FGD
@PointClass size(16 16 16) color(160 0 160) base(Appearflags, Target, Targetname) = trigger_counter : "Trigger: Counter.
Acts as an intermediary for an action that takes multiple inputs.
If nomessage is not set, it will print '1 more...' etc when triggered and 'sequence complete' when finished. After the counter has been triggered 'count' times, it will fire all of it's targets and remove itself, unless 'repeat' has been set, in which case it resets after 'wait' seconds.
If the 'Eager Reset' spawnflag is set, the relay will reset 'wait' seconds after ANY input, which has the effect of requiring all triggering inputs to happen within a window of 'wait' seconds."
[
spawnflags(flags) = [
1: "No Message" : 0
2: "Repeat" : 0
4: "Eager Reset" : 0
]
count(integer) : "Count before trigger" : 2
message(string) : "Message"
]
*/
void() trigger_counter =
{
if (!SUB_ShouldSpawn()) return;
if (!self.wait)
{
if (self.spawnflags & 6) // 2 or 4
self.wait = 1;
else
self.wait = -1;
}
if (!self.count)
self.count = 2;
if (!(self.spawnflags & SPAWNFLAG_NOMESSAGE) && self.message == string_null)
self.message = "Sequence completed!";
//self.cnt = self.count;
self.use = counter_use;
}
//============================================================================
void() timer_think =
{
playercount_convert(count);
if (self.state == self.count) {
//SUB_Remove();
return;
}
if (self.nextthink > time) // turn off again
{
self.nextthink = 0;
return;
}
self.nextthink = time + self.wait + random() * self.rand;
self.state += 1;
activator = self.owner;
SUB_UseTargets();
}
void() timer_use =
{
dprint("in timer_use\n");
self.owner = activator;
self.state = 0;
timer_think();
}
/*QUAKED trigger_timer (.5 .5 .5) (-16 -16 -16) (16 16 16) START_ON
Fires its targets once every "wait" seconds. If "count" is set, it will only fire that many times and then stop. Set "rand" to add a random extra delay to the wait interval.
SPAWNFLAGS
START_ON: do not wait until triggered to begin firing
*/
/*FGD
@PointClass size(32 32 32) color(160 0 160) base(Appearflags, Target, Targetname) = trigger_timer : "Trigger: Timer
Fires its targets once every 'wait' seconds once activated. If 'count' is set, it will only fire that many times and then stop. Set 'rand' to add a random extra delay to the wait interval."
[
spawnflags(flags) = [
1: "Start On" : 0
]
count(integer) : "Limit" : 0
wait(string) : "Interval"
rand(string) : "Random Extra Interval"
]
*/
void() trigger_timer =
{
if (!SUB_ShouldSpawn()) return;
if (!self.wait)
self.wait = 1;
if (self.rand < 0)
self.rand = 0;
self.think = timer_think;
self.use = timer_use;
if (self.spawnflags & 1) // start on
{
self.nextthink = time + self.wait;
self.owner = nextent(world); // use first player as activator since we're never triggered by an activator
}
if (!self.count)
self.count = -1;
}
//============================================================================
float SPAWN_TPC_LT_EQUAL = 1;
float SPAWN_TPC_BY_TWOS = 2;
void() target_playercount_go =
{
float f;
if (self.spawnflags & SPAWN_TPC_BY_TWOS)
f = 2;
else
f = 1;
if (self.spawnflags & SPAWN_TPC_LT_EQUAL)
{
SUB_UseTargetsByField(target);
if (clients > 1 * f) SUB_UseTargetsByField(target2);
if (clients > 2 * f) SUB_UseTargetsByField(target3);
if (clients > 3 * f) SUB_UseTargetsByField(target4);
}
else
{
if (clients <= 1 * f) SUB_UseTargetsByField(target);
else if (clients <= 2 * f) SUB_UseTargetsByField(target2);
else if (clients <= 3 * f) SUB_UseTargetsByField(target3);
else if (clients <= 4 * f) SUB_UseTargetsByField(target4);
}
SUB_KillTargets(self.killtarget);
}
void() target_playercount_go_delay =
{
target_playercount_go();
remove(self);
}
void() target_playercount_use =
{
entity tpc;
if (self.delay > 0)
{
tpc = spawn();
tpc.spawnflags = self.spawnflags;
SUB_CopyTargets(tpc);
tpc.nextthink = time + self.delay;
tpc.think = target_playercount_go_delay;
return;
}
target_playercount_go();
}
/*QUAKED target_playercount (.5 .5 .5) (-8 -8 -8) (8 8 8) LT_EQUAL BY_TWOS
Checks the number of players currently connected when triggered, and fires exclusively one of target/2/3/4 depending on the count. If one player is connected, it only fires 'target', if two are connected it fires 'target2', and so on.
SPAWNFLAGS
LT_EQUAL: Fires all targetnames UP TO the current player count (so with four players connected, all four targets would fire instead of just target4)
BY_TWOS: require double the number of players for each threshhold (for scaling up to 8 players)
*/
/*FGD
@PointClass size(16 16 16) color(128 128 128) base(Appearflags, Target, Targetname) = target_playercount : "Target: Playercount.
Checks the number of players currently connected when triggered, and fires exclusively one of target/2/3/4 depending on the count. If one player is connected, it only fires 'target', if two are connected it fires 'target2', and so on.
If 'Less Or Equal' is set, fires all targetnames UP TO the current player count (so with four players connected, all four targets would fire instead of just target4).
If 'Two Players Per' is set, requires double the number of players for each threshhold (for scaling up to 8 players).
"
[
spawnflags(flags) = [
1: "Less Or Equal" : 0
1: "Two Players Per" : 0
]
]
*/
void() target_playercount =
{
if (!SUB_ShouldSpawn())
return;
self.use = target_playercount_use;
}