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