1 #include "g_local.h"
2 
3 
4 /*
5 ==============================================================================
6 
7 PLAYER TRAIL
8 
9 ==============================================================================
10 
11 This is a circular list containing the a list of points of where
12 the player has been recently.  It is used by monsters for pursuit.
13 
14 .origin		the spot
15 .owner		forward link
16 .aiment		backward link
17 */
18 
19 
20 #define	TRAIL_LENGTH	8
21 
22 edict_t		*trail[TRAIL_LENGTH];
23 int			trail_head;
24 qboolean	trail_active = false;
25 
26 #define NEXT(n)		(((n) + 1) & (TRAIL_LENGTH - 1))
27 #define PREV(n)		(((n) - 1) & (TRAIL_LENGTH - 1))
28 
29 
PlayerTrail_Init(void)30 void PlayerTrail_Init (void)
31 {
32 	int		n;
33 
34 	if (deathmatch->value /* FIXME || coop */)
35 		return;
36 
37 	for (n = 0; n < TRAIL_LENGTH; n++)
38 	{
39 		trail[n] = G_Spawn();
40 		trail[n]->classname = "player_trail";
41 	}
42 
43 	trail_head = 0;
44 	trail_active = true;
45 }
46 
47 
PlayerTrail_Add(vec3_t spot)48 void PlayerTrail_Add (vec3_t spot)
49 {
50 	vec3_t	temp;
51 
52 	if (!trail_active)
53 		return;
54 
55 	VectorCopy (spot, trail[trail_head]->s.origin);
56 
57 	trail[trail_head]->timestamp = level.time;
58 
59 	VectorSubtract (spot, trail[PREV(trail_head)]->s.origin, temp);
60 	trail[trail_head]->s.angles[1] = vectoyaw (temp);
61 
62 	trail_head = NEXT(trail_head);
63 }
64 
65 
PlayerTrail_New(vec3_t spot)66 void PlayerTrail_New (vec3_t spot)
67 {
68 	if (!trail_active)
69 		return;
70 
71 	PlayerTrail_Init ();
72 	PlayerTrail_Add (spot);
73 }
74 
75 
PlayerTrail_PickFirst(edict_t * self)76 edict_t *PlayerTrail_PickFirst (edict_t *self)
77 {
78 	int		marker;
79 	int		n;
80 
81 	if (!trail_active)
82 		return NULL;
83 
84 	for (marker = trail_head, n = TRAIL_LENGTH; n; n--)
85 	{
86 		if(trail[marker]->timestamp <= self->monsterinfo.trail_time)
87 			marker = NEXT(marker);
88 		else
89 			break;
90 	}
91 
92 	if (visible(self, trail[marker]))
93 	{
94 		return trail[marker];
95 	}
96 
97 	if (visible(self, trail[PREV(marker)]))
98 	{
99 		return trail[PREV(marker)];
100 	}
101 
102 	return trail[marker];
103 }
104 
PlayerTrail_PickNext(edict_t * self)105 edict_t *PlayerTrail_PickNext (edict_t *self)
106 {
107 	int		marker;
108 	int		n;
109 
110 	if (!trail_active)
111 		return NULL;
112 
113 	for (marker = trail_head, n = TRAIL_LENGTH; n; n--)
114 	{
115 		if(trail[marker]->timestamp <= self->monsterinfo.trail_time)
116 			marker = NEXT(marker);
117 		else
118 			break;
119 	}
120 
121 	return trail[marker];
122 }
123 
PlayerTrail_LastSpot(void)124 edict_t *PlayerTrail_LastSpot (void)
125 {
126 	return trail[PREV(trail_head)];
127 }
128