1
2/*QUAKED info_null (0 0.5 0) (-4 -4 -4) (4 4 4)
3Used as a positional target for spotlights, etc.
4*/
5void() info_null =
6{
7	remove(self);
8};
9
10/*QUAKED info_notnull (0 0.5 0) (-4 -4 -4) (4 4 4)
11Used as a positional target for lightning.
12*/
13void() info_notnull =
14{
15};
16
17//============================================================================
18
19float START_OFF = 1;
20
21void() light_use =
22{
23	if (self.spawnflags & START_OFF)
24	{
25		lightstyle(self.style, "m");
26		self.spawnflags = self.spawnflags - START_OFF;
27	}
28	else
29	{
30		lightstyle(self.style, "a");
31		self.spawnflags = self.spawnflags + START_OFF;
32	}
33};
34
35/*QUAKED light (0 1 0) (-8 -8 -8) (8 8 8) START_OFF
36Non-displayed light.
37Default light value is 300
38Default style is 0
39If targeted, it will toggle between on or off.
40*/
41void() light =
42{
43	if (!self.targetname)
44	{       // inert light
45		remove(self);
46		return;
47	}
48
49	if (self.style >= 32)
50	{
51		self.use = light_use;
52		if (self.spawnflags & START_OFF)
53			lightstyle(self.style, "a");
54		else
55			lightstyle(self.style, "m");
56	}
57};
58
59/*QUAKED light_fluoro (0 1 0) (-8 -8 -8) (8 8 8) START_OFF
60Non-displayed light.
61Default light value is 300
62Default style is 0
63If targeted, it will toggle between on or off.
64Makes steady fluorescent humming sound
65*/
66void() light_fluoro =
67{
68	if (self.style >= 32)
69	{
70		self.use = light_use;
71		if (self.spawnflags & START_OFF)
72			lightstyle(self.style, "a");
73		else
74			lightstyle(self.style, "m");
75	}
76
77	precache_sound ("ambience/fl_hum1.wav");
78	ambientsound (self.origin, "ambience/fl_hum1.wav", 0.5, ATTN_STATIC);
79};
80
81/*QUAKED light_fluorospark (0 1 0) (-8 -8 -8) (8 8 8)
82Non-displayed light.
83Default light value is 300
84Default style is 10
85Makes sparking, broken fluorescent sound
86*/
87void() light_fluorospark =
88{
89	if (!self.style)
90		self.style = 10;
91
92	precache_sound ("ambience/buzz1.wav");
93	ambientsound (self.origin, "ambience/buzz1.wav", 0.5, ATTN_STATIC);
94};
95
96/*QUAKED light_globe (0 1 0) (-8 -8 -8) (8 8 8)
97Sphere globe light.
98Default light value is 300
99Default style is 0
100*/
101void() light_globe =
102{
103	precache_model ("progs/s_light.spr");
104	setmodel (self, "progs/s_light.spr");
105	makestatic (self);
106};
107
108void() FireAmbient =
109{
110	precache_sound ("ambience/fire1.wav");
111// attenuate fast
112	ambientsound (self.origin, "ambience/fire1.wav", 0.5, ATTN_STATIC);
113};
114
115/*QUAKED light_torch_small_walltorch (0 .5 0) (-10 -10 -20) (10 10 20)
116Short wall torch
117Default light value is 200
118Default style is 0
119*/
120void() light_torch_small_walltorch =
121{
122	precache_model ("progs/flame.mdl");
123	setmodel (self, "progs/flame.mdl");
124	FireAmbient ();
125	makestatic (self);
126};
127
128/*QUAKED light_flame_large_yellow (0 1 0) (-10 -10 -12) (12 12 18)
129Large yellow flame ball
130*/
131void() light_flame_large_yellow =
132{
133	precache_model ("progs/flame2.mdl");
134	setmodel (self, "progs/flame2.mdl");
135	self.frame = 1;
136	FireAmbient ();
137	makestatic (self);
138};
139
140/*QUAKED light_flame_small_yellow (0 1 0) (-8 -8 -8) (8 8 8) START_OFF
141Small yellow flame ball
142*/
143void() light_flame_small_yellow =
144{
145	precache_model ("progs/flame2.mdl");
146	setmodel (self, "progs/flame2.mdl");
147	FireAmbient ();
148	makestatic (self);
149};
150
151/*QUAKED light_flame_small_white (0 1 0) (-10 -10 -40) (10 10 40) START_OFF
152Small white flame ball
153*/
154void() light_flame_small_white =
155{
156	precache_model ("progs/flame2.mdl");
157	setmodel (self, "progs/flame2.mdl");
158	FireAmbient ();
159	makestatic (self);
160};
161
162//============================================================================
163
164
165/*QUAKED misc_fireball (0 .5 .8) (-8 -8 -8) (8 8 8)
166Lava Balls
167*/
168
169void() fire_fly;
170void() fire_touch;
171void() misc_fireball =
172{
173
174	precache_model ("progs/lavaball.mdl");
175	self.classname = "fireball";
176	self.nextthink = time + (random() * 5);
177	self.think = fire_fly;
178	if (!self.speed)
179		self.speed == 1000;
180};
181
182void() fire_fly =
183{
184local entity    fireball;
185
186	fireball = spawn();
187	fireball.solid = SOLID_TRIGGER;
188	fireball.movetype = MOVETYPE_TOSS;
189	fireball.velocity = '0 0 1000';
190	fireball.velocity_x = (random() * 100) - 50;
191	fireball.velocity_y = (random() * 100) - 50;
192	fireball.velocity_z = self.speed + (random() * 200);
193	fireball.classname = "fireball";
194	setmodel (fireball, "progs/lavaball.mdl");
195	setsize (fireball, '0 0 0', '0 0 0');
196	setorigin (fireball, self.origin);
197	fireball.nextthink = time + 5;
198	fireball.think = SUB_Remove;
199	fireball.touch = fire_touch;
200
201	self.nextthink = time + (random() * 5) + 3;
202	self.think = fire_fly;
203};
204
205
206void() fire_touch =
207{
208	T_Damage (other, self, self, 20);
209	remove(self);
210};
211
212//============================================================================
213
214
215void() barrel_explode =
216{
217	self.takedamage = DAMAGE_NO;
218	self.classname = "explo_box";
219	// did say self.owner
220	T_RadiusDamage (self, self, 160, world, "");
221	WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
222	WriteByte (MSG_MULTICAST, TE_EXPLOSION);
223	WriteCoord (MSG_MULTICAST, self.origin_x);
224	WriteCoord (MSG_MULTICAST, self.origin_y);
225	WriteCoord (MSG_MULTICAST, self.origin_z+32);
226	multicast (self.origin, MULTICAST_PHS);
227	remove (self);
228};
229
230
231
232/*QUAKED misc_explobox (0 .5 .8) (0 0 0) (32 32 64)
233TESTING THING
234*/
235
236void() misc_explobox =
237{
238	local float     oldz;
239
240	self.solid = SOLID_BBOX;
241	self.movetype = MOVETYPE_NONE;
242	precache_model ("maps/b_explob.bsp");
243	setmodel (self, "maps/b_explob.bsp");
244	setsize (self, '0 0 0', '32 32 64');
245	precache_sound ("weapons/r_exp3.wav");
246	self.health = 20;
247	self.th_die = barrel_explode;
248	self.takedamage = DAMAGE_AIM;
249
250	self.origin_z = self.origin_z + 2;
251	oldz = self.origin_z;
252	droptofloor();
253	if (oldz - self.origin_z > 250)
254	{
255		dprint ("item fell out of level at ");
256		dprint (vtos(self.origin));
257		dprint ("\n");
258		remove(self);
259	}
260};
261
262
263
264
265/*QUAKED misc_explobox2 (0 .5 .8) (0 0 0) (32 32 64)
266Smaller exploding box, REGISTERED ONLY
267*/
268
269void() misc_explobox2 =
270{
271	local float     oldz;
272
273	self.solid = SOLID_BBOX;
274	self.movetype = MOVETYPE_NONE;
275	precache_model2 ("maps/b_exbox2.bsp");
276	setmodel (self, "maps/b_exbox2.bsp");
277	setsize (self, '0 0 0', '32 32 32');
278	precache_sound ("weapons/r_exp3.wav");
279	self.health = 20;
280	self.th_die = barrel_explode;
281	self.takedamage = DAMAGE_AIM;
282
283	self.origin_z = self.origin_z + 2;
284	oldz = self.origin_z;
285	droptofloor();
286	if (oldz - self.origin_z > 250)
287	{
288		dprint ("item fell out of level at ");
289		dprint (vtos(self.origin));
290		dprint ("\n");
291		remove(self);
292	}
293};
294
295//============================================================================
296
297float SPAWNFLAG_SUPERSPIKE      = 1;
298float SPAWNFLAG_LASER = 2;
299
300void() Laser_Touch =
301{
302	local vector org;
303
304	if (other == self.owner)
305		return;         // don't explode on owner
306
307	if (pointcontents(self.origin) == CONTENT_SKY)
308	{
309		remove(self);
310		return;
311	}
312
313	sound (self, CHAN_WEAPON, "enforcer/enfstop.wav", 1, ATTN_STATIC);
314	org = self.origin - 8*normalize(self.velocity);
315
316	if (other.health)
317	{
318		SpawnBlood (org, 15);
319		other.deathtype = "laser";
320		T_Damage (other, self, self.owner, 15);
321	}
322	else
323	{
324		WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
325		WriteByte (MSG_MULTICAST, TE_GUNSHOT);
326		WriteByte (MSG_MULTICAST, 5);
327		WriteCoord (MSG_MULTICAST, org_x);
328		WriteCoord (MSG_MULTICAST, org_y);
329		WriteCoord (MSG_MULTICAST, org_z);
330		multicast (org, MULTICAST_PVS);
331	}
332
333	remove(self);
334};
335
336void(vector org, vector vec) LaunchLaser =
337{
338	local   vector  vec;
339
340	if (self.classname == "monster_enforcer")
341		sound (self, CHAN_WEAPON, "enforcer/enfire.wav", 1, ATTN_NORM);
342
343	vec = normalize(vec);
344
345	newmis = spawn();
346	newmis.owner = self;
347	newmis.movetype = MOVETYPE_FLY;
348	newmis.solid = SOLID_BBOX;
349	newmis.effects = EF_DIMLIGHT;
350
351	setmodel (newmis, "progs/laser.mdl");
352	setsize (newmis, '0 0 0', '0 0 0');
353
354	setorigin (newmis, org);
355
356	newmis.velocity = vec * 600;
357	newmis.angles = vectoangles(newmis.velocity);
358
359	newmis.nextthink = time + 5;
360	newmis.think = SUB_Remove;
361	newmis.touch = Laser_Touch;
362};
363
364void() spikeshooter_use =
365{
366	if (self.spawnflags & SPAWNFLAG_LASER)
367	{
368		sound (self, CHAN_VOICE, "enforcer/enfire.wav", 1, ATTN_NORM);
369		LaunchLaser (self.origin, self.movedir);
370	}
371	else
372	{
373		sound (self, CHAN_VOICE, "weapons/spike2.wav", 1, ATTN_NORM);
374		launch_spike (self.origin, self.movedir);
375		newmis.velocity = self.movedir * 500;
376		if (self.spawnflags & SPAWNFLAG_SUPERSPIKE)
377			newmis.touch = superspike_touch;
378	}
379};
380
381void() shooter_think =
382{
383	spikeshooter_use ();
384	self.nextthink = time + self.wait;
385	newmis.velocity = self.movedir * 500;
386};
387
388
389/*QUAKED trap_spikeshooter (0 .5 .8) (-8 -8 -8) (8 8 8) superspike laser
390When triggered, fires a spike in the direction set in QuakeEd.
391Laser is only for REGISTERED.
392*/
393
394void() trap_spikeshooter =
395{
396	SetMovedir ();
397	self.use = spikeshooter_use;
398	if (self.spawnflags & SPAWNFLAG_LASER)
399	{
400		precache_model2 ("progs/laser.mdl");
401
402		precache_sound2 ("enforcer/enfire.wav");
403		precache_sound2 ("enforcer/enfstop.wav");
404	}
405	else
406		precache_sound ("weapons/spike2.wav");
407};
408
409
410/*QUAKED trap_shooter (0 .5 .8) (-8 -8 -8) (8 8 8) superspike laser
411Continuously fires spikes.
412"wait" time between spike (1.0 default)
413"nextthink" delay before firing first spike, so multiple shooters can be stagered.
414*/
415void() trap_shooter =
416{
417	trap_spikeshooter ();
418
419	if (self.wait == 0)
420		self.wait = 1;
421	self.nextthink = self.nextthink + self.wait + self.ltime;
422	self.think = shooter_think;
423};
424
425
426
427/*
428===============================================================================
429
430
431===============================================================================
432*/
433
434
435void() make_bubbles;
436void() bubble_remove;
437void() bubble_bob;
438
439/*QUAKED air_bubbles (0 .5 .8) (-8 -8 -8) (8 8 8)
440
441testing air bubbles
442*/
443
444void() air_bubbles =
445{
446	remove (self);
447};
448
449void() make_bubbles =
450{
451local entity    bubble;
452
453	bubble = spawn();
454	setmodel (bubble, "progs/s_bubble.spr");
455	setorigin (bubble, self.origin);
456	bubble.movetype = MOVETYPE_NOCLIP;
457	bubble.solid = SOLID_NOT;
458	bubble.velocity = '0 0 15';
459	bubble.nextthink = time + 0.5;
460	bubble.think = bubble_bob;
461	bubble.touch = bubble_remove;
462	bubble.classname = "bubble";
463	bubble.frame = 0;
464	bubble.cnt = 0;
465	setsize (bubble, '-8 -8 -8', '8 8 8');
466	self.nextthink = time + random() + 0.5;
467	self.think = make_bubbles;
468};
469
470void() bubble_split =
471{
472local entity    bubble;
473	bubble = spawn();
474	setmodel (bubble, "progs/s_bubble.spr");
475	setorigin (bubble, self.origin);
476	bubble.movetype = MOVETYPE_NOCLIP;
477	bubble.solid = SOLID_NOT;
478	bubble.velocity = self.velocity;
479	bubble.nextthink = time + 0.5;
480	bubble.think = bubble_bob;
481	bubble.touch = bubble_remove;
482	bubble.classname = "bubble";
483	bubble.frame = 1;
484	bubble.cnt = 10;
485	setsize (bubble, '-8 -8 -8', '8 8 8');
486	self.frame = 1;
487	self.cnt = 10;
488	if (self.waterlevel != 3)
489		remove (self);
490};
491
492void() bubble_remove =
493{
494	if (other.classname == self.classname)
495	{
496//              dprint ("bump");
497		return;
498	}
499	remove(self);
500};
501
502void() bubble_bob =
503{
504local float             rnd1, rnd2, rnd3;
505local vector    vtmp1, modi;
506
507	self.cnt = self.cnt + 1;
508	if (self.cnt == 4)
509		bubble_split();
510	if (self.cnt == 20)
511		remove(self);
512
513	rnd1 = self.velocity_x + (-10 + (random() * 20));
514	rnd2 = self.velocity_y + (-10 + (random() * 20));
515	rnd3 = self.velocity_z + 10 + random() * 10;
516
517	if (rnd1 > 10)
518		rnd1 = 5;
519	if (rnd1 < -10)
520		rnd1 = -5;
521
522	if (rnd2 > 10)
523		rnd2 = 5;
524	if (rnd2 < -10)
525		rnd2 = -5;
526
527	if (rnd3 < 10)
528		rnd3 = 15;
529	if (rnd3 > 30)
530		rnd3 = 25;
531
532	self.velocity_x = rnd1;
533	self.velocity_y = rnd2;
534	self.velocity_z = rnd3;
535
536	self.nextthink = time + 0.5;
537	self.think = bubble_bob;
538};
539
540/*~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>
541~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~*/
542
543/*QUAKED viewthing (0 .5 .8) (-8 -8 -8) (8 8 8)
544
545Just for the debugging level.  Don't use
546*/
547
548void() viewthing =
549
550{
551	self.movetype = MOVETYPE_NONE;
552	self.solid = SOLID_NOT;
553	precache_model ("progs/player.mdl");
554	setmodel (self, "progs/player.mdl");
555};
556
557
558/*
559==============================================================================
560
561SIMPLE BMODELS
562
563==============================================================================
564*/
565
566void() func_wall_use =
567{       // change to alternate textures
568	self.frame = 1 - self.frame;
569};
570
571/*QUAKED func_wall (0 .5 .8) ?
572This is just a solid wall if not inhibitted
573*/
574void() func_wall =
575{
576	self.angles = '0 0 0';
577	self.movetype = MOVETYPE_PUSH;  // so it doesn't get pushed by anything
578	self.solid = SOLID_BSP;
579	self.use = func_wall_use;
580	setmodel (self, self.model);
581};
582
583
584/*QUAKED func_illusionary (0 .5 .8) ?
585A simple entity that looks solid but lets you walk through it.
586*/
587void() func_illusionary =
588
589{
590	self.angles = '0 0 0';
591	self.movetype = MOVETYPE_NONE;
592	self.solid = SOLID_NOT;
593	setmodel (self, self.model);
594	makestatic ();
595};
596
597/*QUAKED func_episodegate (0 .5 .8) ? E1 E2 E3 E4
598This bmodel will appear if the episode has allready been completed, so players can't reenter it.
599*/
600void() func_episodegate =
601
602{
603	if (!(serverflags & self.spawnflags))
604		return;                 // can still enter episode
605
606	self.angles = '0 0 0';
607	self.movetype = MOVETYPE_PUSH;  // so it doesn't get pushed by anything
608	self.solid = SOLID_BSP;
609	self.use = func_wall_use;
610	setmodel (self, self.model);
611};
612
613/*QUAKED func_bossgate (0 .5 .8) ?
614This bmodel appears unless players have all of the episode sigils.
615*/
616void() func_bossgate =
617
618{
619	if ( (serverflags & 15) == 15)
620		return;         // all episodes completed
621	self.angles = '0 0 0';
622	self.movetype = MOVETYPE_PUSH;  // so it doesn't get pushed by anything
623	self.solid = SOLID_BSP;
624	self.use = func_wall_use;
625	setmodel (self, self.model);
626};
627
628//============================================================================
629/*QUAKED ambient_suck_wind (0.3 0.1 0.6) (-10 -10 -8) (10 10 8)
630*/
631void() ambient_suck_wind =
632{
633	precache_sound ("ambience/suck1.wav");
634	ambientsound (self.origin, "ambience/suck1.wav", 1, ATTN_STATIC);
635};
636
637/*QUAKED ambient_drone (0.3 0.1 0.6) (-10 -10 -8) (10 10 8)
638*/
639void() ambient_drone =
640{
641	precache_sound ("ambience/drone6.wav");
642	ambientsound (self.origin, "ambience/drone6.wav", 0.5, ATTN_STATIC);
643};
644
645/*QUAKED ambient_flouro_buzz (0.3 0.1 0.6) (-10 -10 -8) (10 10 8)
646*/
647void() ambient_flouro_buzz =
648{
649	precache_sound ("ambience/buzz1.wav");
650	ambientsound (self.origin, "ambience/buzz1.wav", 1, ATTN_STATIC);
651};
652/*QUAKED ambient_drip (0.3 0.1 0.6) (-10 -10 -8) (10 10 8)
653*/
654void() ambient_drip =
655{
656	precache_sound ("ambience/drip1.wav");
657	ambientsound (self.origin, "ambience/drip1.wav", 0.5, ATTN_STATIC);
658};
659/*QUAKED ambient_comp_hum (0.3 0.1 0.6) (-10 -10 -8) (10 10 8)
660*/
661void() ambient_comp_hum =
662{
663	precache_sound ("ambience/comp1.wav");
664	ambientsound (self.origin, "ambience/comp1.wav", 1, ATTN_STATIC);
665};
666/*QUAKED ambient_thunder (0.3 0.1 0.6) (-10 -10 -8) (10 10 8)
667*/
668void() ambient_thunder =
669{
670	precache_sound ("ambience/thunder1.wav");
671	ambientsound (self.origin, "ambience/thunder1.wav", 0.5, ATTN_STATIC);
672};
673/*QUAKED ambient_light_buzz (0.3 0.1 0.6) (-10 -10 -8) (10 10 8)
674*/
675void() ambient_light_buzz =
676{
677	precache_sound ("ambience/fl_hum1.wav");
678	ambientsound (self.origin, "ambience/fl_hum1.wav", 0.5, ATTN_STATIC);
679};
680/*QUAKED ambient_swamp1 (0.3 0.1 0.6) (-10 -10 -8) (10 10 8)
681*/
682void() ambient_swamp1 =
683{
684	precache_sound ("ambience/swamp1.wav");
685	ambientsound (self.origin, "ambience/swamp1.wav", 0.5, ATTN_STATIC);
686};
687/*QUAKED ambient_swamp2 (0.3 0.1 0.6) (-10 -10 -8) (10 10 8)
688*/
689void() ambient_swamp2 =
690{
691	precache_sound ("ambience/swamp2.wav");
692	ambientsound (self.origin, "ambience/swamp2.wav", 0.5, ATTN_STATIC);
693};
694
695//============================================================================
696
697void() noise_think =
698{
699	self.nextthink = time + 0.5;
700	sound (self, 1, "enforcer/enfire.wav", 1, ATTN_NORM);
701	sound (self, 2, "enforcer/enfstop.wav", 1, ATTN_NORM);
702	sound (self, 3, "enforcer/sight1.wav", 1, ATTN_NORM);
703	sound (self, 4, "enforcer/sight2.wav", 1, ATTN_NORM);
704	sound (self, 5, "enforcer/sight3.wav", 1, ATTN_NORM);
705	sound (self, 6, "enforcer/sight4.wav", 1, ATTN_NORM);
706	sound (self, 7, "enforcer/pain1.wav", 1, ATTN_NORM);
707};
708
709/*QUAKED misc_noisemaker (1 0.5 0) (-10 -10 -10) (10 10 10)
710
711For optimzation testing, starts a lot of sounds.
712*/
713
714void() misc_noisemaker =
715
716{
717	precache_sound2 ("enforcer/enfire.wav");
718	precache_sound2 ("enforcer/enfstop.wav");
719	precache_sound2 ("enforcer/sight1.wav");
720	precache_sound2 ("enforcer/sight2.wav");
721	precache_sound2 ("enforcer/sight3.wav");
722	precache_sound2 ("enforcer/sight4.wav");
723	precache_sound2 ("enforcer/pain1.wav");
724	precache_sound2 ("enforcer/pain2.wav");
725	precache_sound2 ("enforcer/death1.wav");
726	precache_sound2 ("enforcer/idle1.wav");
727
728	self.nextthink = time + 0.1 + random();
729	self.think = noise_think;
730};
731