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