|
|
1.1 root 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:
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:
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:
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:
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: */
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:
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: */
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: */
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:
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: */
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:
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.