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