|
|
1.1 root 1: #include "g_local.h"
2:
3:
4: /*
5: =================
6: check_dodge
7:
8: This is a support routine used when a client is firing
9: a non-instant attack weapon. It checks to see if a
10: monster's dodge function should be called.
11: =================
12: */
13: static void check_dodge (edict_t *self, vec3_t start, vec3_t dir, int speed)
14: {
15: vec3_t end;
16: vec3_t v;
17: trace_t tr;
18: float eta;
19:
20: // easy mode only ducks one quarter the time
21: if (skill->value == 0)
22: {
23: if (random() > 0.25)
24: return;
25: }
26: VectorMA (start, 8192, dir, end);
27: tr = gi.trace (start, NULL, NULL, end, self, MASK_SHOT);
28: if ((tr.ent) && (tr.ent->svflags & SVF_MONSTER) && (tr.ent->health > 0) && (tr.ent->monsterinfo.dodge) && infront(tr.ent, self))
29: {
30: VectorSubtract (tr.endpos, start, v);
31: eta = (VectorLength(v) - tr.ent->maxs[0]) / speed;
32: tr.ent->monsterinfo.dodge (tr.ent, self, eta);
33: }
34: }
35:
36:
37: /*
38: =================
39: fire_hit
40:
41: Used for all impact (hit/punch/slash) attacks
42: =================
43: */
44: qboolean fire_hit (edict_t *self, vec3_t aim, int damage, int kick)
45: {
46: trace_t tr;
47: vec3_t forward, right, up;
48: vec3_t v;
49: vec3_t point;
50: float range;
51: vec3_t dir;
52:
53: //see if enemy is in range
54: VectorSubtract (self->enemy->s.origin, self->s.origin, dir);
55: range = VectorLength(dir);
56: if (range > aim[0])
57: return false;
58:
59: if (aim[1] > self->mins[0] && aim[1] < self->maxs[0])
60: {
61: // the hit is straight on so back the range up to the edge of their bbox
62: range -= self->enemy->maxs[0];
63: }
64: else
65: {
66: // this is a side hit so adjust the "right" value out to the edge of their bbox
67: if (aim[1] < 0)
68: aim[1] = self->enemy->mins[0];
69: else
70: aim[1] = self->enemy->maxs[0];
71: }
72:
73: VectorMA (self->s.origin, range, dir, point);
74:
75: tr = gi.trace (self->s.origin, NULL, NULL, point, self, MASK_SHOT);
76: if (tr.fraction < 1)
77: {
78: if (!tr.ent->takedamage)
79: return false;
80: // if it will hit any client/monster then hit the one we wanted to hit
81: if ((tr.ent->svflags & SVF_MONSTER) || (tr.ent->client))
82: tr.ent = self->enemy;
83: }
84:
85: AngleVectors(self->s.angles, forward, right, up);
86: VectorMA (self->s.origin, range, forward, point);
87: VectorMA (point, aim[1], right, point);
88: VectorMA (point, aim[2], up, point);
89: VectorSubtract (point, self->enemy->s.origin, dir);
90:
91: // do the damage
92: T_Damage (tr.ent, self, self, dir, point, vec3_origin, damage, kick/2, DAMAGE_NO_KNOCKBACK, MOD_HIT);
93:
94: if (!(tr.ent->svflags & SVF_MONSTER) && (!tr.ent->client))
95: return false;
96:
97: // do our special form of knockback here
98: VectorMA (self->enemy->absmin, 0.5, self->enemy->size, v);
99: VectorSubtract (v, point, v);
100: VectorNormalize (v);
101: VectorMA (self->enemy->velocity, kick, v, self->enemy->velocity);
102: if (self->enemy->velocity[2] > 0)
103: self->enemy->groundentity = NULL;
104: return true;
105: }
106:
107:
108: /*
109: =================
110: fire_lead
111:
112: This is an internal support routine used for bullet/pellet based weapons.
113: =================
114: */
115: static void fire_lead (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int te_impact, int hspread, int vspread, int mod)
116: {
117: trace_t tr;
118: vec3_t dir;
119: vec3_t forward, right, up;
120: vec3_t end;
121: float r;
122: float u;
123: vec3_t water_start;
124: qboolean water = false;
125: int content_mask = MASK_SHOT | MASK_WATER;
126:
127: tr = gi.trace (self->s.origin, NULL, NULL, start, self, MASK_SHOT);
128: if (!(tr.fraction < 1.0))
129: {
130: vectoangles (aimdir, dir);
131: AngleVectors (dir, forward, right, up);
132:
133: r = crandom()*hspread;
134: u = crandom()*vspread;
135: VectorMA (start, 8192, forward, end);
136: VectorMA (end, r, right, end);
137: VectorMA (end, u, up, end);
138:
139: if (gi.pointcontents (start) & MASK_WATER)
140: {
141: water = true;
142: VectorCopy (start, water_start);
143: content_mask &= ~MASK_WATER;
144: }
145:
146: tr = gi.trace (start, NULL, NULL, end, self, content_mask);
147:
148: // see if we hit water
149: if (tr.contents & MASK_WATER)
150: {
151: int color;
152:
153: water = true;
154: VectorCopy (tr.endpos, water_start);
155:
156: if (!VectorCompare (start, tr.endpos))
157: {
158: if (tr.contents & CONTENTS_WATER)
159: {
160: if (strcmp(tr.surface->name, "*brwater") == 0)
161: color = SPLASH_BROWN_WATER;
162: else
163: color = SPLASH_BLUE_WATER;
164: }
165: else if (tr.contents & CONTENTS_SLIME)
166: color = SPLASH_SLIME;
167: else if (tr.contents & CONTENTS_LAVA)
168: color = SPLASH_LAVA;
169: else
170: color = SPLASH_UNKNOWN;
171:
172: if (color != SPLASH_UNKNOWN)
173: {
174: gi.WriteByte (svc_temp_entity);
175: gi.WriteByte (TE_SPLASH);
176: gi.WriteByte (8);
177: gi.WritePosition (tr.endpos);
178: gi.WriteDir (tr.plane.normal);
179: gi.WriteByte (color);
180: gi.multicast (tr.endpos, MULTICAST_PVS);
181: }
182:
183: // change bullet's course when it enters water
184: VectorSubtract (end, start, dir);
185: vectoangles (dir, dir);
186: AngleVectors (dir, forward, right, up);
187: r = crandom()*hspread*2;
188: u = crandom()*vspread*2;
189: VectorMA (water_start, 8192, forward, end);
190: VectorMA (end, r, right, end);
191: VectorMA (end, u, up, end);
192: }
193:
194: // re-trace ignoring water this time
195: tr = gi.trace (water_start, NULL, NULL, end, self, MASK_SHOT);
196: }
197: }
198:
199: // send gun puff / flash
200: if (!((tr.surface) && (tr.surface->flags & SURF_SKY)))
201: {
202: if (tr.fraction < 1.0)
203: {
204: if (tr.ent->takedamage)
205: {
206: T_Damage (tr.ent, self, self, aimdir, tr.endpos, tr.plane.normal, damage, kick, DAMAGE_BULLET, mod);
207: }
208: else
209: {
210: if (strncmp (tr.surface->name, "sky", 3) != 0)
211: {
212: gi.WriteByte (svc_temp_entity);
213: gi.WriteByte (te_impact);
214: gi.WritePosition (tr.endpos);
215: gi.WriteDir (tr.plane.normal);
216: gi.multicast (tr.endpos, MULTICAST_PVS);
217:
218: if (self->client)
219: PlayerNoise(self, tr.endpos, PNOISE_IMPACT);
220: }
221: }
222: }
223: }
224:
225: // if went through water, determine where the end and make a bubble trail
226: if (water)
227: {
228: vec3_t pos;
229:
230: VectorSubtract (tr.endpos, water_start, dir);
231: VectorNormalize (dir);
232: VectorMA (tr.endpos, -2, dir, pos);
233: if (gi.pointcontents (pos) & MASK_WATER)
234: VectorCopy (pos, tr.endpos);
235: else
236: tr = gi.trace (pos, NULL, NULL, water_start, tr.ent, MASK_WATER);
237:
238: VectorAdd (water_start, tr.endpos, pos);
239: VectorScale (pos, 0.5, pos);
240:
241: gi.WriteByte (svc_temp_entity);
242: gi.WriteByte (TE_BUBBLETRAIL);
243: gi.WritePosition (water_start);
244: gi.WritePosition (tr.endpos);
245: gi.multicast (pos, MULTICAST_PVS);
246: }
247: }
248:
249:
250: /*
251: =================
252: fire_bullet
253:
254: Fires a single round. Used for machinegun and chaingun. Would be fine for
255: pistols, rifles, etc....
256: =================
257: */
258: void fire_bullet (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int hspread, int vspread, int mod)
259: {
260: fire_lead (self, start, aimdir, damage, kick, TE_GUNSHOT, hspread, vspread, mod);
261: }
262:
263:
264: /*
265: =================
266: fire_shotgun
267:
268: Shoots shotgun pellets. Used by shotgun and super shotgun.
269: =================
270: */
271: void fire_shotgun (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int hspread, int vspread, int count, int mod)
272: {
273: int i;
274:
275: for (i = 0; i < count; i++)
276: fire_lead (self, start, aimdir, damage, kick, TE_SHOTGUN, hspread, vspread, mod);
277: }
278:
279:
280: /*
281: =================
282: fire_blaster
283:
284: Fires a single blaster bolt. Used by the blaster and hyper blaster.
285: =================
286: */
287: void blaster_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
288: {
289: int mod;
290:
291: if (other == self->owner)
292: return;
293:
294: if (surf && (surf->flags & SURF_SKY))
295: {
296: G_FreeEdict (self);
297: return;
298: }
299:
300: if (self->owner->client)
301: PlayerNoise(self->owner, self->s.origin, PNOISE_IMPACT);
302:
303: if (other->takedamage)
304: {
305: if (self->spawnflags & 1)
306: mod = MOD_HYPERBLASTER;
307: else
308: mod = MOD_BLASTER;
309: T_Damage (other, self, self->owner, self->velocity, self->s.origin, plane->normal, self->dmg, 1, DAMAGE_ENERGY, mod);
310: }
311: else
312: {
313: gi.WriteByte (svc_temp_entity);
314: // RAFAEL
315: //if (self->s.effects & TE_BLUEHYPERBLASTER)
316: // gi.WriteByte (TE_BLUEHYPERBLASTER);
317: //else
318: gi.WriteByte (TE_BLASTER);
319: gi.WritePosition (self->s.origin);
320: if (!plane)
321: gi.WriteDir (vec3_origin);
322: else
323: gi.WriteDir (plane->normal);
324: gi.multicast (self->s.origin, MULTICAST_PVS);
325: }
326:
327: G_FreeEdict (self);
328: }
329:
330: void fire_blaster (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int effect, qboolean hyper)
331: {
332: edict_t *bolt;
333: trace_t tr;
334:
335: VectorNormalize (dir);
336:
337: bolt = G_Spawn();
338: bolt->svflags = SVF_DEADMONSTER;
339: // yes, I know it looks weird that projectiles are deadmonsters
340: // what this means is that when prediction is used against the object
341: // (blaster/hyperblaster shots), the player won't be solid clipped against
342: // the object. Right now trying to run into a firing hyperblaster
343: // is very jerky since you are predicted 'against' the shots.
344: VectorCopy (start, bolt->s.origin);
345: VectorCopy (start, bolt->s.old_origin);
346: vectoangles (dir, bolt->s.angles);
347: VectorScale (dir, speed, bolt->velocity);
348: bolt->movetype = MOVETYPE_FLYMISSILE;
349: bolt->clipmask = MASK_SHOT;
350: bolt->solid = SOLID_BBOX;
351: bolt->s.effects |= effect;
352: VectorClear (bolt->mins);
353: VectorClear (bolt->maxs);
354: bolt->s.modelindex = gi.modelindex ("models/objects/laser/tris.md2");
355: bolt->s.sound = gi.soundindex ("misc/lasfly.wav");
356: bolt->owner = self;
357: bolt->touch = blaster_touch;
358: bolt->nextthink = level.time + 2;
359: bolt->think = G_FreeEdict;
360: bolt->dmg = damage;
361: bolt->classname = "bolt";
362: if (hyper)
363: bolt->spawnflags = 1;
364: gi.linkentity (bolt);
365:
366: if (self->client)
367: check_dodge (self, bolt->s.origin, dir, speed);
368:
369: tr = gi.trace (self->s.origin, NULL, NULL, bolt->s.origin, bolt, MASK_SHOT);
370: if (tr.fraction < 1.0)
371: {
372: VectorMA (bolt->s.origin, -10, dir, bolt->s.origin);
373: bolt->touch (bolt, tr.ent, NULL, NULL);
374: }
375: }
376:
377: // RAFAEL
378: void fire_blueblaster (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int effect)
379: {
380: edict_t *bolt;
381: trace_t tr;
382:
383: VectorNormalize (dir);
384:
385: bolt = G_Spawn ();
386: VectorCopy (start, bolt->s.origin);
387: VectorCopy (start, bolt->s.old_origin);
388: vectoangles (dir, bolt->s.angles);
389: VectorScale (dir, speed, bolt->velocity);
390: bolt->movetype = MOVETYPE_FLYMISSILE;
391: bolt->clipmask = MASK_SHOT;
392: bolt->solid = SOLID_BBOX;
393: bolt->s.effects |= effect;
394: VectorClear (bolt->mins);
395: VectorClear (bolt->maxs);
396:
397: bolt->s.modelindex = gi.modelindex ("models/objects/blaser/tris.md2");
398: bolt->s.sound = gi.soundindex ("misc/lasfly.wav");
399: bolt->owner = self;
400: bolt->touch = blaster_touch;
401: bolt->nextthink = level.time + 2;
402: bolt->think = G_FreeEdict;
403: bolt->dmg = damage;
404: bolt->classname = "bolt";
405: gi.linkentity (bolt);
406:
407: if (self->client)
408: check_dodge (self, bolt->s.origin, dir, speed);
409:
410: tr = gi.trace (self->s.origin, NULL, NULL, bolt->s.origin, bolt, MASK_SHOT);
411:
412: if (tr.fraction < 1.0)
413: {
414: VectorMA (bolt->s.origin, -10, dir, bolt->s.origin);
415: bolt->touch (bolt, tr.ent, NULL, NULL);
416: }
417:
418: }
419:
420: /*
421: =================
422: fire_grenade
423: =================
424: */
425: static void Grenade_Explode (edict_t *ent)
426: {
427: vec3_t origin;
428: int mod;
429:
430: if (ent->owner->client)
431: PlayerNoise(ent->owner, ent->s.origin, PNOISE_IMPACT);
432:
433: //FIXME: if we are onground then raise our Z just a bit since we are a point?
434: if (ent->enemy)
435: {
436: float points;
437: vec3_t v;
438: vec3_t dir;
439:
440: VectorAdd (ent->enemy->mins, ent->enemy->maxs, v);
441: VectorMA (ent->enemy->s.origin, 0.5, v, v);
442: VectorSubtract (ent->s.origin, v, v);
443: points = ent->dmg - 0.5 * VectorLength (v);
444: VectorSubtract (ent->enemy->s.origin, ent->s.origin, dir);
445: if (ent->spawnflags & 1)
446: mod = MOD_HANDGRENADE;
447: else
448: mod = MOD_GRENADE;
449: T_Damage (ent->enemy, ent, ent->owner, dir, ent->s.origin, vec3_origin, (int)points, (int)points, DAMAGE_RADIUS, mod);
450: }
451:
452: if (ent->spawnflags & 2)
453: mod = MOD_HELD_GRENADE;
454: else if (ent->spawnflags & 1)
455: mod = MOD_HG_SPLASH;
456: else
457: mod = MOD_G_SPLASH;
458: T_RadiusDamage(ent, ent->owner, ent->dmg, ent->enemy, ent->dmg_radius, mod);
459:
460: VectorMA (ent->s.origin, -0.02, ent->velocity, origin);
461: gi.WriteByte (svc_temp_entity);
462: if (ent->waterlevel)
463: {
464: if (ent->groundentity)
465: gi.WriteByte (TE_GRENADE_EXPLOSION_WATER);
466: else
467: gi.WriteByte (TE_ROCKET_EXPLOSION_WATER);
468: }
469: else
470: {
471: if (ent->groundentity)
472: gi.WriteByte (TE_GRENADE_EXPLOSION);
473: else
474: gi.WriteByte (TE_ROCKET_EXPLOSION);
475: }
476: gi.WritePosition (origin);
477: gi.multicast (ent->s.origin, MULTICAST_PHS);
478:
479: G_FreeEdict (ent);
480: }
481:
482: static void Grenade_Touch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
483: {
484: if (other == ent->owner)
485: return;
486:
487: if (surf && (surf->flags & SURF_SKY))
488: {
489: G_FreeEdict (ent);
490: return;
491: }
492:
493: if (!other->takedamage)
494: {
495: if (ent->spawnflags & 1)
496: {
497: if (random() > 0.5)
498: gi.sound (ent, CHAN_VOICE, gi.soundindex ("weapons/hgrenb1a.wav"), 1, ATTN_NORM, 0);
499: else
500: gi.sound (ent, CHAN_VOICE, gi.soundindex ("weapons/hgrenb2a.wav"), 1, ATTN_NORM, 0);
501: }
502: else
503: {
504: gi.sound (ent, CHAN_VOICE, gi.soundindex ("weapons/grenlb1b.wav"), 1, ATTN_NORM, 0);
505: }
506: return;
507: }
508:
509: ent->enemy = other;
510: Grenade_Explode (ent);
511: }
512:
513: void fire_grenade (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, float timer, float damage_radius)
514: {
515: edict_t *grenade;
516: vec3_t dir;
517: vec3_t forward, right, up;
518:
519: vectoangles (aimdir, dir);
520: AngleVectors (dir, forward, right, up);
521:
522: grenade = G_Spawn();
523: VectorCopy (start, grenade->s.origin);
524: VectorScale (aimdir, speed, grenade->velocity);
525: VectorMA (grenade->velocity, 200 + crandom() * 10.0, up, grenade->velocity);
526: VectorMA (grenade->velocity, crandom() * 10.0, right, grenade->velocity);
527: VectorSet (grenade->avelocity, 300, 300, 300);
528: grenade->movetype = MOVETYPE_BOUNCE;
529: grenade->clipmask = MASK_SHOT;
530: grenade->solid = SOLID_BBOX;
531: grenade->s.effects |= EF_GRENADE;
532: VectorClear (grenade->mins);
533: VectorClear (grenade->maxs);
534: grenade->s.modelindex = gi.modelindex ("models/objects/grenade/tris.md2");
535: grenade->owner = self;
536: grenade->touch = Grenade_Touch;
537: grenade->nextthink = level.time + timer;
538: grenade->think = Grenade_Explode;
539: grenade->dmg = damage;
540: grenade->dmg_radius = damage_radius;
541: grenade->classname = "grenade";
542:
543: gi.linkentity (grenade);
544: }
545:
546: void fire_grenade2 (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, float timer, float damage_radius, qboolean held)
547: {
548: edict_t *grenade;
549: vec3_t dir;
550: vec3_t forward, right, up;
551:
552: vectoangles (aimdir, dir);
553: AngleVectors (dir, forward, right, up);
554:
555: grenade = G_Spawn();
556: VectorCopy (start, grenade->s.origin);
557: VectorScale (aimdir, speed, grenade->velocity);
558: VectorMA (grenade->velocity, 200 + crandom() * 10.0, up, grenade->velocity);
559: VectorMA (grenade->velocity, crandom() * 10.0, right, grenade->velocity);
560: VectorSet (grenade->avelocity, 300, 300, 300);
561: grenade->movetype = MOVETYPE_BOUNCE;
562: grenade->clipmask = MASK_SHOT;
563: grenade->solid = SOLID_BBOX;
564: grenade->s.effects |= EF_GRENADE;
565: VectorClear (grenade->mins);
566: VectorClear (grenade->maxs);
567: grenade->s.modelindex = gi.modelindex ("models/objects/grenade2/tris.md2");
568: grenade->owner = self;
569: grenade->touch = Grenade_Touch;
570: grenade->nextthink = level.time + timer;
571: grenade->think = Grenade_Explode;
572: grenade->dmg = damage;
573: grenade->dmg_radius = damage_radius;
574: grenade->classname = "hgrenade";
575: if (held)
576: grenade->spawnflags = 3;
577: else
578: grenade->spawnflags = 1;
579: grenade->s.sound = gi.soundindex("weapons/hgrenc1b.wav");
580:
581: if (timer <= 0.0)
582: Grenade_Explode (grenade);
583: else
584: {
585: gi.sound (self, CHAN_WEAPON, gi.soundindex ("weapons/hgrent1a.wav"), 1, ATTN_NORM, 0);
586: gi.linkentity (grenade);
587: }
588: }
589:
590:
591: /*
592: =================
593: fire_rocket
594: =================
595: */
596: void rocket_touch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
597: {
598: vec3_t origin;
599: int n;
600:
601: if (other == ent->owner)
602: return;
603:
604: if (surf && (surf->flags & SURF_SKY))
605: {
606: G_FreeEdict (ent);
607: return;
608: }
609:
610: if (ent->owner->client)
611: PlayerNoise(ent->owner, ent->s.origin, PNOISE_IMPACT);
612:
613: // calculate position for the explosion entity
614: VectorMA (ent->s.origin, -0.02, ent->velocity, origin);
615:
616: if (other->takedamage)
617: {
618: T_Damage (other, ent, ent->owner, ent->velocity, ent->s.origin, plane->normal, ent->dmg, 0, 0, MOD_ROCKET);
619: }
620: else
621: {
622: // don't throw any debris in net games
623: if (!deathmatch->value && !coop->value)
624: {
625: if ((surf) && !(surf->flags & (SURF_WARP|SURF_TRANS33|SURF_TRANS66|SURF_FLOWING)))
626: {
627: n = rand() % 5;
628: while(n--)
629: ThrowDebris (ent, "models/objects/debris2/tris.md2", 2, ent->s.origin);
630: }
631: }
632: }
633:
634: T_RadiusDamage(ent, ent->owner, ent->radius_dmg, other, ent->dmg_radius, MOD_R_SPLASH);
635:
636: gi.WriteByte (svc_temp_entity);
637: if (ent->waterlevel)
638: gi.WriteByte (TE_ROCKET_EXPLOSION_WATER);
639: else
640: gi.WriteByte (TE_ROCKET_EXPLOSION);
641: gi.WritePosition (origin);
642: gi.multicast (ent->s.origin, MULTICAST_PHS);
643:
644: G_FreeEdict (ent);
645: }
646:
647: void fire_rocket (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius, int radius_damage)
648: {
649: edict_t *rocket;
650:
651: rocket = G_Spawn();
652: VectorCopy (start, rocket->s.origin);
653: VectorCopy (dir, rocket->movedir);
654: vectoangles (dir, rocket->s.angles);
655: VectorScale (dir, speed, rocket->velocity);
656: rocket->movetype = MOVETYPE_FLYMISSILE;
657: rocket->clipmask = MASK_SHOT;
658: rocket->solid = SOLID_BBOX;
659: rocket->s.effects |= EF_ROCKET;
660: VectorClear (rocket->mins);
661: VectorClear (rocket->maxs);
662: rocket->s.modelindex = gi.modelindex ("models/objects/rocket/tris.md2");
663: rocket->owner = self;
664: rocket->touch = rocket_touch;
665: rocket->nextthink = level.time + 8000/speed;
666: rocket->think = G_FreeEdict;
667: rocket->dmg = damage;
668: rocket->radius_dmg = radius_damage;
669: rocket->dmg_radius = damage_radius;
670: rocket->s.sound = gi.soundindex ("weapons/rockfly.wav");
671: rocket->classname = "rocket";
672:
673: if (self->client)
674: check_dodge (self, rocket->s.origin, dir, speed);
675:
676: gi.linkentity (rocket);
677: }
678:
679:
680: /*
681: =================
682: fire_rail
683: =================
684: */
685: void fire_rail (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick)
686: {
687: vec3_t from;
688: vec3_t end;
689: trace_t tr;
690: edict_t *ignore;
691: int mask;
692: qboolean water;
693:
694: VectorMA (start, 8192, aimdir, end);
695: VectorCopy (start, from);
696: ignore = self;
697: water = false;
698: mask = MASK_SHOT|CONTENTS_SLIME|CONTENTS_LAVA;
699: while (ignore)
700: {
701: tr = gi.trace (from, NULL, NULL, end, ignore, mask);
702:
703: if (tr.contents & (CONTENTS_SLIME|CONTENTS_LAVA))
704: {
705: mask &= ~(CONTENTS_SLIME|CONTENTS_LAVA);
706: water = true;
707: }
708: else
709: {
710: if ((tr.ent->svflags & SVF_MONSTER) || (tr.ent->client))
711: ignore = tr.ent;
712: else
713: ignore = NULL;
714:
715: if ((tr.ent != self) && (tr.ent->takedamage))
716: T_Damage (tr.ent, self, self, aimdir, tr.endpos, tr.plane.normal, damage, kick, 0, MOD_RAILGUN);
717: }
718:
719: VectorCopy (tr.endpos, from);
720: }
721:
722: // send gun puff / flash
723: gi.WriteByte (svc_temp_entity);
724: gi.WriteByte (TE_RAILTRAIL);
725: gi.WritePosition (start);
726: gi.WritePosition (tr.endpos);
727: gi.multicast (self->s.origin, MULTICAST_PHS);
728: // gi.multicast (start, MULTICAST_PHS);
729: if (water)
730: {
731: gi.WriteByte (svc_temp_entity);
732: gi.WriteByte (TE_RAILTRAIL);
733: gi.WritePosition (start);
734: gi.WritePosition (tr.endpos);
735: gi.multicast (tr.endpos, MULTICAST_PHS);
736: }
737:
738: if (self->client)
739: PlayerNoise(self, tr.endpos, PNOISE_IMPACT);
740: }
741:
742:
743: /*
744: =================
745: fire_bfg
746: =================
747: */
748: void bfg_explode (edict_t *self)
749: {
750: edict_t *ent;
751: float points;
752: vec3_t v;
753: float dist;
754:
755: if (self->s.frame == 0)
756: {
757: // the BFG effect
758: ent = NULL;
759: while ((ent = findradius(ent, self->s.origin, self->dmg_radius)) != NULL)
760: {
761: if (!ent->takedamage)
762: continue;
763: if (ent == self->owner)
764: continue;
765: if (!CanDamage (ent, self))
766: continue;
767: if (!CanDamage (ent, self->owner))
768: continue;
769:
770: VectorAdd (ent->mins, ent->maxs, v);
771: VectorMA (ent->s.origin, 0.5, v, v);
772: VectorSubtract (self->s.origin, v, v);
773: dist = VectorLength(v);
774: points = self->radius_dmg * (1.0 - sqrt(dist/self->dmg_radius));
775: if (ent == self->owner)
776: points = points * 0.5;
777:
778: gi.WriteByte (svc_temp_entity);
779: gi.WriteByte (TE_BFG_EXPLOSION);
780: gi.WritePosition (ent->s.origin);
781: gi.multicast (ent->s.origin, MULTICAST_PHS);
782: T_Damage (ent, self, self->owner, self->velocity, ent->s.origin, vec3_origin, (int)points, 0, DAMAGE_ENERGY, MOD_BFG_EFFECT);
783: }
784: }
785:
786: self->nextthink = level.time + FRAMETIME;
787: self->s.frame++;
788: if (self->s.frame == 5)
789: self->think = G_FreeEdict;
790: }
791:
792: void bfg_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
793: {
794: if (other == self->owner)
795: return;
796:
797: if (surf && (surf->flags & SURF_SKY))
798: {
799: G_FreeEdict (self);
800: return;
801: }
802:
803: if (self->owner->client)
804: PlayerNoise(self->owner, self->s.origin, PNOISE_IMPACT);
805:
806: // core explosion - prevents firing it into the wall/floor
807: if (other->takedamage)
808: T_Damage (other, self, self->owner, self->velocity, self->s.origin, plane->normal, 200, 0, 0, MOD_BFG_BLAST);
809: T_RadiusDamage(self, self->owner, 200, other, 100, MOD_BFG_BLAST);
810:
811: gi.sound (self, CHAN_VOICE, gi.soundindex ("weapons/bfg__x1b.wav"), 1, ATTN_NORM, 0);
812: self->solid = SOLID_NOT;
813: self->touch = NULL;
814: VectorMA (self->s.origin, -1 * FRAMETIME, self->velocity, self->s.origin);
815: VectorClear (self->velocity);
816: self->s.modelindex = gi.modelindex ("sprites/s_bfg3.sp2");
817: self->s.frame = 0;
818: self->s.sound = 0;
819: self->s.effects &= ~EF_ANIM_ALLFAST;
820: self->think = bfg_explode;
821: self->nextthink = level.time + FRAMETIME;
822: self->enemy = other;
823:
824: gi.WriteByte (svc_temp_entity);
825: gi.WriteByte (TE_BFG_BIGEXPLOSION);
826: gi.WritePosition (self->s.origin);
827: gi.multicast (self->s.origin, MULTICAST_PVS);
828: }
829:
830:
831: void bfg_think (edict_t *self)
832: {
833: edict_t *ent;
834: edict_t *ignore;
835: vec3_t point;
836: vec3_t dir;
837: vec3_t start;
838: vec3_t end;
839: int dmg;
840: trace_t tr;
841:
842: if (deathmatch->value)
843: dmg = 5;
844: else
845: dmg = 10;
846:
847: ent = NULL;
848: while ((ent = findradius(ent, self->s.origin, 256)) != NULL)
849: {
850: if (ent == self)
851: continue;
852:
853: if (ent == self->owner)
854: continue;
855:
856: if (!ent->takedamage)
857: continue;
858:
859: if (!(ent->svflags & SVF_MONSTER) && (!ent->client) && (strcmp(ent->classname, "misc_explobox") != 0))
860: continue;
861:
862: VectorMA (ent->absmin, 0.5, ent->size, point);
863:
864: VectorSubtract (point, self->s.origin, dir);
865: VectorNormalize (dir);
866:
867: ignore = self;
868: VectorCopy (self->s.origin, start);
869: VectorMA (start, 2048, dir, end);
870: while(1)
871: {
872: tr = gi.trace (start, NULL, NULL, end, ignore, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_DEADMONSTER);
873:
874: if (!tr.ent)
875: break;
876:
877: // hurt it if we can
878: if ((tr.ent->takedamage) && !(tr.ent->flags & FL_IMMUNE_LASER) && (tr.ent != self->owner))
879: T_Damage (tr.ent, self, self->owner, dir, tr.endpos, vec3_origin, dmg, 1, DAMAGE_ENERGY, MOD_BFG_LASER);
880:
881: // if we hit something that's not a monster or player we're done
882: if (!(tr.ent->svflags & SVF_MONSTER) && (!tr.ent->client))
883: {
884: gi.WriteByte (svc_temp_entity);
885: gi.WriteByte (TE_LASER_SPARKS);
886: gi.WriteByte (4);
887: gi.WritePosition (tr.endpos);
888: gi.WriteDir (tr.plane.normal);
889: gi.WriteByte (self->s.skinnum);
890: gi.multicast (tr.endpos, MULTICAST_PVS);
891: break;
892: }
893:
894: ignore = tr.ent;
895: VectorCopy (tr.endpos, start);
896: }
897:
898: gi.WriteByte (svc_temp_entity);
899: gi.WriteByte (TE_BFG_LASER);
900: gi.WritePosition (self->s.origin);
901: gi.WritePosition (tr.endpos);
902: gi.multicast (self->s.origin, MULTICAST_PHS);
903: }
904:
905: self->nextthink = level.time + FRAMETIME;
906: }
907:
908:
909: void fire_bfg (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius)
910: {
911: edict_t *bfg;
912:
913: bfg = G_Spawn();
914: VectorCopy (start, bfg->s.origin);
915: VectorCopy (dir, bfg->movedir);
916: vectoangles (dir, bfg->s.angles);
917: VectorScale (dir, speed, bfg->velocity);
918: bfg->movetype = MOVETYPE_FLYMISSILE;
919: bfg->clipmask = MASK_SHOT;
920: bfg->solid = SOLID_BBOX;
921: bfg->s.effects |= EF_BFG | EF_ANIM_ALLFAST;
922: VectorClear (bfg->mins);
923: VectorClear (bfg->maxs);
924: bfg->s.modelindex = gi.modelindex ("sprites/s_bfg1.sp2");
925: bfg->owner = self;
926: bfg->touch = bfg_touch;
927: bfg->nextthink = level.time + 8000/speed;
928: bfg->think = G_FreeEdict;
929: bfg->radius_dmg = damage;
930: bfg->dmg_radius = damage_radius;
931: bfg->classname = "bfg blast";
932: bfg->s.sound = gi.soundindex ("weapons/bfg__l1a.wav");
933:
934: bfg->think = bfg_think;
935: bfg->nextthink = level.time + FRAMETIME;
936: bfg->teammaster = bfg;
937: bfg->teamchain = NULL;
938:
939: if (self->client)
940: check_dodge (self, bfg->s.origin, dir, speed);
941:
942: gi.linkentity (bfg);
943: }
944:
945:
946: // RAFAEL
947:
948: /*
949: fire_ionripper
950: */
951:
952: void ionripper_sparks (edict_t *self)
953: {
954: gi.WriteByte (svc_temp_entity);
955: gi.WriteByte (TE_WELDING_SPARKS);
956: gi.WriteByte (0);
957: gi.WritePosition (self->s.origin);
958: gi.WriteDir (vec3_origin);
959: gi.WriteByte (0xe4 + (rand()&3));
960: gi.multicast (self->s.origin, MULTICAST_PVS);
961:
962: G_FreeEdict (self);
963: }
964:
965: // RAFAEL
966: void ionripper_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
967: {
968: if (other == self->owner)
969: return;
970:
971: if (surf && (surf->flags & SURF_SKY))
972: {
973: G_FreeEdict (self);
974: return;
975: }
976:
977: if (self->owner->client)
978: PlayerNoise (self->owner, self->s.origin, PNOISE_IMPACT);
979:
980: if (other->takedamage)
981: {
982: T_Damage (other, self, self->owner, self->velocity, self->s.origin, plane->normal, self->dmg, 1, DAMAGE_ENERGY, MOD_RIPPER);
983:
984: }
985: else
986: {
987: return;
988: }
989:
990: G_FreeEdict (self);
991: }
992:
993:
994: // RAFAEL
995: void fire_ionripper (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int effect)
996: {
997: edict_t *ion;
998: trace_t tr;
999:
1000: VectorNormalize (dir);
1001:
1002: ion = G_Spawn ();
1003: VectorCopy (start, ion->s.origin);
1004: VectorCopy (start, ion->s.old_origin);
1005: vectoangles (dir, ion->s.angles);
1006: VectorScale (dir, speed, ion->velocity);
1007:
1008: ion->movetype = MOVETYPE_WALLBOUNCE;
1009: ion->clipmask = MASK_SHOT;
1010: ion->solid = SOLID_BBOX;
1011: ion->s.effects |= effect;
1012:
1013: ion->s.renderfx |= RF_FULLBRIGHT;
1014:
1015: VectorClear (ion->mins);
1016: VectorClear (ion->maxs);
1017: ion->s.modelindex = gi.modelindex ("models/objects/boomrang/tris.md2");
1018: ion->s.sound = gi.soundindex ("misc/lasfly.wav");
1019: ion->owner = self;
1020: ion->touch = ionripper_touch;
1021: ion->nextthink = level.time + 3;
1022: ion->think = ionripper_sparks;
1023: ion->dmg = damage;
1024: ion->dmg_radius = 100;
1025: gi.linkentity (ion);
1026:
1027: if (self->client)
1028: check_dodge (self, ion->s.origin, dir, speed);
1029:
1030: tr = gi.trace (self->s.origin, NULL, NULL, ion->s.origin, ion, MASK_SHOT);
1031: if (tr.fraction < 1.0)
1032: {
1033: VectorMA (ion->s.origin, -10, dir, ion->s.origin);
1034: ion->touch (ion, tr.ent, NULL, NULL);
1035: }
1036:
1037: }
1038:
1039:
1040: // RAFAEL
1041: /*
1042: fire_heat
1043: */
1044:
1045:
1046: void heat_think (edict_t *self)
1047: {
1048: edict_t *target = NULL;
1049: edict_t *aquire = NULL;
1050: vec3_t vec;
1051: vec3_t oldang;
1052: int len;
1053: int oldlen = 0;
1054:
1055: VectorClear (vec);
1056:
1057: // aquire new target
1058: while (( target = findradius (target, self->s.origin, 1024)) != NULL)
1059: {
1060:
1061: if (self->owner == target)
1062: continue;
1063: if (!target->svflags & SVF_MONSTER)
1064: continue;
1065: if (!target->client)
1066: continue;
1067: if (target->health <= 0)
1068: continue;
1069: if (!visible (self, target))
1070: continue;
1071:
1072: // if we need to reduce the tracking cone
1073: /*
1074: {
1075: vec3_t vec;
1076: float dot;
1077: vec3_t forward;
1078:
1079: AngleVectors (self->s.angles, forward, NULL, NULL);
1080: VectorSubtract (target->s.origin, self->s.origin, vec);
1081: VectorNormalize (vec);
1082: dot = DotProduct (vec, forward);
1083:
1084: if (dot > 0.6)
1085: continue;
1086: }
1087: */
1088:
1089: if (!infront (self, target))
1090: continue;
1091:
1092: VectorSubtract (self->s.origin, target->s.origin, vec);
1093: len = VectorLength (vec);
1094:
1095: if (aquire == NULL || len < oldlen)
1096: {
1097: aquire = target;
1098: self->target_ent = aquire;
1099: oldlen = len;
1100: }
1101: }
1102:
1103: if (aquire != NULL)
1104: {
1105: VectorCopy (self->s.angles, oldang);
1106: VectorSubtract (aquire->s.origin, self->s.origin, vec);
1107:
1108: vectoangles (vec, self->s.angles);
1109:
1110: VectorNormalize (vec);
1111: VectorCopy (vec, self->movedir);
1112: VectorScale (vec, 500, self->velocity);
1113: }
1114:
1115: self->nextthink = level.time + 0.1;
1116: }
1117:
1118: // RAFAEL
1119: void fire_heat (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius, int radius_damage)
1120: {
1121: edict_t *heat;
1122:
1123: heat = G_Spawn();
1124: VectorCopy (start, heat->s.origin);
1125: VectorCopy (dir, heat->movedir);
1126: vectoangles (dir, heat->s.angles);
1127: VectorScale (dir, speed, heat->velocity);
1128: heat->movetype = MOVETYPE_FLYMISSILE;
1129: heat->clipmask = MASK_SHOT;
1130: heat->solid = SOLID_BBOX;
1131: heat->s.effects |= EF_ROCKET;
1132: VectorClear (heat->mins);
1133: VectorClear (heat->maxs);
1134: heat->s.modelindex = gi.modelindex ("models/objects/rocket/tris.md2");
1135: heat->owner = self;
1136: heat->touch = rocket_touch;
1137:
1138: heat->nextthink = level.time + 0.1;
1139: heat->think = heat_think;
1140:
1141: heat->dmg = damage;
1142: heat->radius_dmg = radius_damage;
1143: heat->dmg_radius = damage_radius;
1144: heat->s.sound = gi.soundindex ("weapons/rockfly.wav");
1145:
1146: if (self->client)
1147: check_dodge (self, heat->s.origin, dir, speed);
1148:
1149: gi.linkentity (heat);
1150: }
1151:
1152:
1153:
1154: // RAFAEL
1155:
1156: /*
1157: fire_plasma
1158: */
1159:
1160: void plasma_touch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
1161: {
1162: vec3_t origin;
1163:
1164: if (other == ent->owner)
1165: return;
1166:
1167: if (surf && (surf->flags & SURF_SKY))
1168: {
1169: G_FreeEdict (ent);
1170: return;
1171: }
1172:
1173: if (ent->owner->client)
1174: PlayerNoise(ent->owner, ent->s.origin, PNOISE_IMPACT);
1175:
1176: // calculate position for the explosion entity
1177: VectorMA (ent->s.origin, -0.02, ent->velocity, origin);
1178:
1179: if (other->takedamage)
1180: {
1181: T_Damage (other, ent, ent->owner, ent->velocity, ent->s.origin, plane->normal, ent->dmg, 0, 0, MOD_PHALANX);
1182: }
1183:
1184: T_RadiusDamage(ent, ent->owner, ent->radius_dmg, other, ent->dmg_radius, MOD_PHALANX);
1185:
1186: gi.WriteByte (svc_temp_entity);
1187: gi.WriteByte (TE_PLASMA_EXPLOSION);
1188: gi.WritePosition (origin);
1189: gi.multicast (ent->s.origin, MULTICAST_PVS);
1190:
1191: G_FreeEdict (ent);
1192: }
1193:
1194:
1195: // RAFAEL
1196: void fire_plasma (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius, int radius_damage)
1197: {
1198: edict_t *plasma;
1199:
1200: plasma = G_Spawn();
1201: VectorCopy (start, plasma->s.origin);
1202: VectorCopy (dir, plasma->movedir);
1203: vectoangles (dir, plasma->s.angles);
1204: VectorScale (dir, speed, plasma->velocity);
1205: plasma->movetype = MOVETYPE_FLYMISSILE;
1206: plasma->clipmask = MASK_SHOT;
1207: plasma->solid = SOLID_BBOX;
1208:
1209: VectorClear (plasma->mins);
1210: VectorClear (plasma->maxs);
1211:
1212: plasma->owner = self;
1213: plasma->touch = plasma_touch;
1214: plasma->nextthink = level.time + 8000/speed;
1215: plasma->think = G_FreeEdict;
1216: plasma->dmg = damage;
1217: plasma->radius_dmg = radius_damage;
1218: plasma->dmg_radius = damage_radius;
1219: plasma->s.sound = gi.soundindex ("weapons/rockfly.wav");
1220:
1221: plasma->s.modelindex = gi.modelindex ("sprites/s_photon.sp2");
1222: plasma->s.effects |= EF_PLASMA | EF_ANIM_ALLFAST;
1223:
1224: if (self->client)
1225: check_dodge (self, plasma->s.origin, dir, speed);
1226:
1227: gi.linkentity (plasma);
1228:
1229:
1230: }
1231:
1232: // RAFAEL
1233: extern void SP_item_foodcube (edict_t *best);
1234: // RAFAEL
1235: static void Trap_Think (edict_t *ent)
1236: {
1237: edict_t *target = NULL;
1238: edict_t *best = NULL;
1239: vec3_t vec;
1240: int len, i;
1241: int oldlen = 8000;
1242: vec3_t forward, right, up;
1243:
1244: if (ent->timestamp < level.time)
1245: {
1246: BecomeExplosion1(ent);
1247: // note to self
1248: // cause explosion damage???
1249: return;
1250: }
1251:
1252: ent->nextthink = level.time + 0.1;
1253:
1254: if (!ent->groundentity)
1255: return;
1256:
1257: // ok lets do the blood effect
1258: if (ent->s.frame > 4)
1259: {
1260: if (ent->s.frame == 5)
1261: {
1262: if (ent->wait == 64)
1263: gi.sound(ent, CHAN_VOICE, gi.soundindex ("weapons/trapdown.wav"), 1, ATTN_IDLE, 0);
1264:
1265: ent->wait -= 2;
1266: ent->delay += level.time;
1267:
1268: for (i=0; i<3; i++)
1269: {
1270:
1271: best = G_Spawn();
1272:
1273: if (strcmp (ent->enemy->classname, "monster_gekk") == 0)
1274: {
1275: best->s.modelindex = gi.modelindex ("models/objects/gekkgib/torso/tris.md2");
1276: best->s.effects |= TE_GREENBLOOD;
1277: }
1278: else if (ent->mass > 200)
1279: {
1280: best->s.modelindex = gi.modelindex ("models/objects/gibs/chest/tris.md2");
1281: best->s.effects |= TE_BLOOD;
1282: }
1283: else
1284: {
1285: best->s.modelindex = gi.modelindex ("models/objects/gibs/sm_meat/tris.md2");
1286: best->s.effects |= TE_BLOOD;
1287: }
1288:
1289: AngleVectors (ent->s.angles, forward, right, up);
1290:
1291: RotatePointAroundVector( vec, up, right, ((360.0/3)* i)+ent->delay);
1292: VectorMA (vec, ent->wait/2, vec, vec);
1293: VectorAdd(vec, ent->s.origin, vec);
1294: VectorAdd(vec, forward, best->s.origin);
1295:
1296: best->s.origin[2] = ent->s.origin[2] + ent->wait;
1297:
1298: VectorCopy (ent->s.angles, best->s.angles);
1299:
1300: best->solid = SOLID_NOT;
1301: best->s.effects |= EF_GIB;
1302: best->takedamage = DAMAGE_YES;
1303:
1304: best->movetype = MOVETYPE_TOSS;
1305: best->svflags |= SVF_MONSTER;
1306: best->deadflag = DEAD_DEAD;
1307:
1308: VectorClear (best->mins);
1309: VectorClear (best->maxs);
1310:
1311: best->watertype = gi.pointcontents(best->s.origin);
1312: if (best->watertype & MASK_WATER)
1313: best->waterlevel = 1;
1314:
1315: best->nextthink = level.time + 0.1;
1316: best->think = G_FreeEdict;
1317: gi.linkentity (best);
1318: }
1319:
1320: if (ent->wait < 19)
1321: ent->s.frame ++;
1322:
1323: return;
1324: }
1325: ent->s.frame ++;
1326: if (ent->s.frame == 8)
1327: {
1328: ent->nextthink = level.time + 1.0;
1329: ent->think = G_FreeEdict;
1330:
1331: best = G_Spawn ();
1332: SP_item_foodcube (best);
1333: VectorCopy (ent->s.origin, best->s.origin);
1334: best->s.origin[2]+= 16;
1335: best->velocity[2] = 400;
1336: best->count = ent->mass;
1337: gi.linkentity (best);
1338: return;
1339: }
1340: return;
1341: }
1342:
1343: ent->s.effects &= ~EF_TRAP;
1344: if (ent->s.frame >= 4)
1345: {
1346: ent->s.effects |= EF_TRAP;
1347: VectorClear (ent->mins);
1348: VectorClear (ent->maxs);
1349:
1350: }
1351:
1352: if (ent->s.frame < 4)
1353: ent->s.frame++;
1354:
1355: while ((target = findradius(target, ent->s.origin, 256)) != NULL)
1356: {
1357: if (target == ent)
1358: continue;
1359: if (!(target->svflags & SVF_MONSTER) && !target->client)
1360: continue;
1361: // if (target == ent->owner)
1362: // continue;
1363: if (target->health <= 0)
1364: continue;
1365: if (!visible (ent, target))
1366: continue;
1367: if (!best)
1368: {
1369: best = target;
1370: continue;
1371: }
1372: VectorSubtract (ent->s.origin, target->s.origin, vec);
1373: len = VectorLength (vec);
1374: if (len < oldlen)
1375: {
1376: oldlen = len;
1377: best = target;
1378: }
1379: }
1380:
1381: // pull the enemy in
1382: if (best)
1383: {
1384: vec3_t forward;
1385:
1386: if (best->groundentity)
1387: {
1388: best->s.origin[2] += 1;
1389: best->groundentity = NULL;
1390: }
1391: VectorSubtract (ent->s.origin, best->s.origin, vec);
1392: len = VectorLength (vec);
1393: if (best->client)
1394: {
1395: VectorNormalize (vec);
1396: VectorMA (best->velocity, 250, vec, best->velocity);
1397: }
1398: else
1399: {
1400: best->ideal_yaw = vectoyaw(vec);
1401: M_ChangeYaw (best);
1402: AngleVectors (best->s.angles, forward, NULL, NULL);
1403: VectorScale (forward, 256, best->velocity);
1404: }
1405:
1406: gi.sound(ent, CHAN_VOICE, gi.soundindex ("weapons/trapsuck.wav"), 1, ATTN_IDLE, 0);
1407:
1408: if (len < 32)
1409: {
1410: if (best->mass < 400)
1411: {
1412: T_Damage (best, ent, ent->owner, vec3_origin, best->s.origin, vec3_origin, 100000, 1, 0, MOD_TRAP);
1413: ent->enemy = best;
1414: ent->wait = 64;
1415: VectorCopy (ent->s.origin, ent->s.old_origin);
1416: ent->timestamp = level.time + 30;
1417: if (deathmatch->value)
1418: ent->mass = best->mass/4;
1419: else
1420: ent->mass = best->mass/10;
1421: // ok spawn the food cube
1422: ent->s.frame = 5;
1423: }
1424: else
1425: {
1426: BecomeExplosion1(ent);
1427: // note to self
1428: // cause explosion damage???
1429: return;
1430: }
1431:
1432: }
1433: }
1434:
1435:
1436: }
1437:
1438:
1439: // RAFAEL
1440: void fire_trap (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, float timer, float damage_radius, qboolean held)
1441: {
1442: edict_t *trap;
1443: vec3_t dir;
1444: vec3_t forward, right, up;
1445:
1446: vectoangles (aimdir, dir);
1447: AngleVectors (dir, forward, right, up);
1448:
1449: trap = G_Spawn();
1450: VectorCopy (start, trap->s.origin);
1451: VectorScale (aimdir, speed, trap->velocity);
1452: VectorMA (trap->velocity, 200 + crandom() * 10.0, up, trap->velocity);
1453: VectorMA (trap->velocity, crandom() * 10.0, right, trap->velocity);
1454: VectorSet (trap->avelocity, 0, 300, 0);
1455: trap->movetype = MOVETYPE_BOUNCE;
1456: trap->clipmask = MASK_SHOT;
1457: trap->solid = SOLID_BBOX;
1458: // VectorClear (trap->mins);
1459: // VectorClear (trap->maxs);
1460: VectorSet (trap->mins, -4, -4, 0);
1461: VectorSet (trap->maxs, 4, 4, 8);
1462: trap->s.modelindex = gi.modelindex ("models/weapons/z_trap/tris.md2");
1463: trap->owner = self;
1464: trap->nextthink = level.time + 1.0;
1465: trap->think = Trap_Think;
1466: trap->dmg = damage;
1467: trap->dmg_radius = damage_radius;
1468: trap->classname = "htrap";
1469: // RAFAEL 16-APR-98
1470: trap->s.sound = gi.soundindex ("weapons/traploop.wav");
1471: // END 16-APR-98
1472: if (held)
1473: trap->spawnflags = 3;
1474: else
1475: trap->spawnflags = 1;
1476:
1477: if (timer <= 0.0)
1478: Grenade_Explode (trap);
1479: else
1480: {
1481: // gi.sound (self, CHAN_WEAPON, gi.soundindex ("weapons/trapdown.wav"), 1, ATTN_NORM, 0);
1482: gi.linkentity (trap);
1483: }
1484:
1485: trap->timestamp = level.time + 30;
1486:
1487: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.