1 #include "g_local.h"
2 
3 //==========================================================
4 
5 /*QUAKED target_steam (1 0 0) (-8 -8 -8) (8 8 8)
6 Creates a steam effect (particles w/ velocity in a line).
7 
8   speed = velocity of particles (default 50)
9   count = number of particles (default 32)
10   sounds = color of particles (default 8 for steam)
11      the color range is from this color to this color + 6
12   wait = seconds to run before stopping (overrides default
13      value derived from func_timer)
14 
15   best way to use this is to tie it to a func_timer that "pokes"
16   it every second (or however long you set the wait time, above)
17 
18   note that the width of the base is proportional to the speed
19   good colors to use:
20   6-9 - varying whites (darker to brighter)
21   224 - sparks
22   176 - blue water
23   80  - brown water
24   208 - slime
25   232 - blood
26 */
27 
use_target_steam(edict_t * self,edict_t * other,edict_t * activator)28 void use_target_steam (edict_t *self, edict_t *other, edict_t *activator)
29 {
30 	// FIXME - this needs to be a global
31 	static int	nextid;
32 	vec3_t		point;
33 
34 	if (nextid > 20000)
35 		nextid = nextid %20000;
36 
37 	nextid++;
38 
39 	// automagically set wait from func_timer unless they set it already, or
40 	// default to 1000 if not called by a func_timer (eek!)
41 	if (!self->wait)
42 		if (other)
43 			self->wait = other->wait * 1000;
44 		else
45 			self->wait = 1000;
46 
47 	if (self->enemy)
48 	{
49 		VectorMA (self->enemy->absmin, 0.5, self->enemy->size, point);
50 		VectorSubtract (point, self->s.origin, self->movedir);
51 		VectorNormalize (self->movedir);
52 	}
53 
54 	VectorMA (self->s.origin, self->plat2flags*0.5, self->movedir, point);
55 	if (self->wait > 100)
56 	{
57 		gi.WriteByte (svc_temp_entity);
58 		gi.WriteByte (TE_STEAM);
59 		gi.WriteShort (nextid);
60 		gi.WriteByte (self->count);
61 		gi.WritePosition (self->s.origin);
62 		gi.WriteDir (self->movedir);
63 		gi.WriteByte (self->sounds&0xff);
64 		gi.WriteShort ( (short int)(self->plat2flags) );
65 		gi.WriteLong ( (int)(self->wait) );
66 		gi.multicast (self->s.origin, MULTICAST_PVS);
67 	}
68 	else
69 	{
70 		gi.WriteByte (svc_temp_entity);
71 		gi.WriteByte (TE_STEAM);
72 		gi.WriteShort ((short int)-1);
73 		gi.WriteByte (self->count);
74 		gi.WritePosition (self->s.origin);
75 		gi.WriteDir (self->movedir);
76 		gi.WriteByte (self->sounds&0xff);
77 		gi.WriteShort ( (short int)(self->plat2flags) );
78 		gi.multicast (self->s.origin, MULTICAST_PVS);
79 	}
80 }
81 
target_steam_start(edict_t * self)82 void target_steam_start (edict_t *self)
83 {
84 	edict_t	*ent;
85 
86 	self->use = use_target_steam;
87 
88 	if (self->target)
89 	{
90 		ent = G_Find (NULL, FOFS(targetname), self->target);
91 		if (!ent)
92 			gi.dprintf ("%s at %s: %s is a bad target\n", self->classname, vtos(self->s.origin), self->target);
93 		self->enemy = ent;
94 	}
95 	else
96 	{
97 		G_SetMovedir (self->s.angles, self->movedir);
98 	}
99 
100 	if (!self->count)
101 		self->count = 32;
102 	if (!self->plat2flags)
103 		self->plat2flags = 75;
104 	if (!self->sounds)
105 		self->sounds = 8;
106 	if (self->wait)
107 		self->wait *= 1000;  // we want it in milliseconds, not seconds
108 
109 	// paranoia is good
110 	self->sounds &= 0xff;
111 	self->count &= 0xff;
112 
113 	self->svflags = SVF_NOCLIENT;
114 
115 	gi.linkentity (self);
116 }
117 
SP_target_steam(edict_t * self)118 void SP_target_steam (edict_t *self)
119 {
120 	self->plat2flags = self->speed;
121 
122 	if (self->target)
123 	{
124 		self->think = target_steam_start;
125 		self->nextthink = level.time + 1;
126 	}
127 	else
128 		target_steam_start (self);
129 }
130 
131 
132 //==========================================================
133 // target_anger
134 //==========================================================
135 
target_anger_use(edict_t * self,edict_t * other,edict_t * activator)136 void target_anger_use (edict_t *self, edict_t *other, edict_t *activator)
137 {
138 	edict_t		*target;
139 	edict_t		*t;
140 
141 	t = NULL;
142 	target = G_Find (t, FOFS(targetname), self->killtarget);
143 
144 	if (target && self->target)
145 	{
146 		// Make whatever a "good guy" so the monster will try to kill it!
147 		target->monsterinfo.aiflags |= AI_GOOD_GUY;
148 		target->svflags |= SVF_MONSTER;
149 		target->health = 300;
150 
151 		t = NULL;
152 		while ((t = G_Find (t, FOFS(targetname), self->target)))
153 		{
154 			if (t == self)
155 			{
156 				gi.dprintf ("WARNING: entity used itself.\n");
157 			}
158 			else
159 			{
160 				if (t->use)
161 				{
162 					if (t->health < 0)
163 					{
164 //						if ((g_showlogic) && (g_showlogic->value))
165 //							gi.dprintf ("target_anger with dead monster!\n");
166 						return;
167 					}
168 					t->enemy = target;
169 					t->monsterinfo.aiflags |= AI_TARGET_ANGER;
170 					FoundTarget (t);
171 				}
172 			}
173 			if (!self->inuse)
174 			{
175 				gi.dprintf("entity was removed while using targets\n");
176 				return;
177 			}
178 		}
179 	}
180 
181 }
182 
183 /*QUAKED target_anger (1 0 0) (-8 -8 -8) (8 8 8)
184 This trigger will cause an entity to be angry at another entity when a player touches it. Target the
185 entity you want to anger, and killtarget the entity you want it to be angry at.
186 
187 target - entity to piss off
188 killtarget - entity to be pissed off at
189 */
SP_target_anger(edict_t * self)190 void SP_target_anger (edict_t *self)
191 {
192 	if (!self->target)
193 	{
194 		gi.dprintf("target_anger without target!\n");
195 		G_FreeEdict (self);
196 		return;
197 	}
198 	if (!self->killtarget)
199 	{
200 		gi.dprintf("target_anger without killtarget!\n");
201 		G_FreeEdict (self);
202 		return;
203 	}
204 
205 	self->use = target_anger_use;
206 	self->svflags = SVF_NOCLIENT;
207 }
208 
209 // ================
210 // target_spawn
211 // ================
212 /*
213 extern edict_t *CreateMonster(vec3_t origin, vec3_t angles, char *classname);
214 
215 void target_spawn_use (edict_t *self, edict_t *other, edict_t *activator)
216 {
217 	edict_t		*newEnt;
218 
219 	newEnt = CreateMonster (self->s.origin, self->s.angles, "monster_infantry");
220 	if(newEnt)
221 		newEnt->enemy = other;
222 }
223 */
224 
225 /*Q U AKED target_spawn (1 0 0) (-32 -32 -24) (32 32 72)
226 */
227 /*
228 void SP_target_spawn (edict_t *self)
229 {
230 	self->use = target_spawn_use;
231 	self->svflags = SVF_NOCLIENT;
232 }
233 */
234 
235 // ***********************************
236 // target_killplayers
237 // ***********************************
238 
target_killplayers_use(edict_t * self,edict_t * other,edict_t * activator)239 void target_killplayers_use (edict_t *self, edict_t *other, edict_t *activator)
240 {
241 	int		i;
242 	edict_t	*ent, *player;
243 
244 	// kill the players
245 	for (i=0 ; i<game.maxclients ; i++)
246 	{
247 		player = &g_edicts[1+i];
248 		if (!player->inuse)
249 			continue;
250 
251 		// nail it
252 		T_Damage (player, self, self, vec3_origin, self->s.origin, vec3_origin, 100000, 0, DAMAGE_NO_PROTECTION, MOD_TELEFRAG);
253 	}
254 
255 	// kill any visible monsters
256 	for (ent = g_edicts; ent < &g_edicts[globals.num_edicts] ; ent++)
257 	{
258 		if (!ent->inuse)
259 			continue;
260 		if (ent->health < 1)
261 			continue;
262 		if (!ent->takedamage)
263 			continue;
264 
265 		for(i=0;i<game.maxclients ; i++)
266 		{
267 			player = &g_edicts[1+i];
268 			if(!player->inuse)
269 				continue;
270 
271 			if(visible(player, ent))
272 			{
273 				T_Damage (ent, self, self, vec3_origin, ent->s.origin, vec3_origin,
274 							ent->health, 0, DAMAGE_NO_PROTECTION, MOD_TELEFRAG);
275 				break;
276 			}
277 		}
278 	}
279 
280 }
281 
282 /*QUAKED target_killplayers (1 0 0) (-8 -8 -8) (8 8 8)
283 When triggered, this will kill all the players on the map.
284 */
SP_target_killplayers(edict_t * self)285 void SP_target_killplayers (edict_t *self)
286 {
287 	self->use = target_killplayers_use;
288 	self->svflags = SVF_NOCLIENT;
289 }
290 
291 /*QUAKED target_blacklight (1 0 1) (-16 -16 -24) (16 16 24)
292 Pulsing black light with sphere in the center
293 */
blacklight_think(edict_t * self)294 void blacklight_think (edict_t *self)
295 {
296 	self->s.angles[0] = rand()%360;
297 	self->s.angles[1] = rand()%360;
298 	self->s.angles[2] = rand()%360;
299 	self->nextthink = level.time + 0.1;
300 }
301 
SP_target_blacklight(edict_t * ent)302 void SP_target_blacklight(edict_t *ent)
303 {
304 	if (deathmatch->value)
305 	{	// auto-remove for deathmatch
306 		G_FreeEdict (ent);
307 		return;
308 	}
309 
310 	VectorClear (ent->mins);
311 	VectorClear (ent->maxs);
312 
313 	ent->s.effects |= (EF_TRACKERTRAIL|EF_TRACKER);
314 	ent->think = blacklight_think;
315 	ent->s.modelindex = gi.modelindex ("models/items/spawngro2/tris.md2");
316 	ent->s.frame = 1;
317 	ent->nextthink = level.time + 0.1;
318 	gi.linkentity (ent);
319 }
320 
321 /*QUAKED target_orb (1 0 1) (-16 -16 -24) (16 16 24)
322 Translucent pulsing orb with speckles
323 */
orb_think(edict_t * self)324 void orb_think (edict_t *self)
325 {
326 	self->s.angles[0] = rand()%360;
327 	self->s.angles[1] = rand()%360;
328 	self->s.angles[2] = rand()%360;
329 //	self->s.effects |= (EF_TRACKERTRAIL|EF_DOUBLE);
330 	self->nextthink = level.time + 0.1;
331 }
332 
SP_target_orb(edict_t * ent)333 void SP_target_orb(edict_t *ent)
334 {
335 	if (deathmatch->value)
336 	{	// auto-remove for deathmatch
337 		G_FreeEdict (ent);
338 		return;
339 	}
340 
341 	VectorClear (ent->mins);
342 	VectorClear (ent->maxs);
343 
344 //	ent->s.effects |= EF_TRACKERTRAIL;
345 	ent->think = orb_think;
346 	ent->nextthink = level.time + 0.1;
347 	ent->s.modelindex = gi.modelindex ("models/items/spawngro2/tris.md2");
348 	ent->s.frame = 2;
349 	ent->s.effects |= EF_SPHERETRANS;
350 	gi.linkentity (ent);
351 }
352 
353