1 // dm_tag
2 // pmack
3 // june 1998
4 
5 #include "g_local.h"
6 
7 extern edict_t *SelectFarthestDeathmatchSpawnPoint (void);
8 extern void	SelectSpawnPoint (edict_t *ent, vec3_t origin, vec3_t angles);
9 
10 void SP_dm_tag_token (edict_t *self);
11 
12 // ***********************
13 // Tag Specific Stuff
14 // ***********************
15 
16 edict_t		*tag_token;
17 edict_t		*tag_owner;
18 int			tag_count;
19 
20 //=================
21 //=================
Tag_PlayerDeath(edict_t * targ,edict_t * inflictor,edict_t * attacker)22 void Tag_PlayerDeath(edict_t *targ, edict_t *inflictor, edict_t *attacker)
23 {
24 //	gi.dprintf("%s killed %s\n", attacker->classname, targ->classname);
25 //	gi.dprintf("%x killed %x\n", attacker, targ);
26 
27 	if(tag_token && targ && (targ == tag_owner))
28 	{
29 //		gi.dprintf("owner died/suicided. dropping\n");
30 		Tag_DropToken(targ, FindItem( "Tag Token" ));
31 		tag_owner = NULL;
32 		tag_count = 0;
33 	}
34 //	else
35 //		gi.dprintf("unrelated slaying\n");
36 }
37 
38 //=================
39 //=================
Tag_KillItBonus(edict_t * self)40 void Tag_KillItBonus (edict_t *self)
41 {
42 	edict_t			*armor;
43 
44 	// if the player is hurt, boost them up to max.
45 	if(self->health < self->max_health)
46 	{
47 		self->health += 200;
48 		if(self->health > self->max_health)
49 			self->health = self->max_health;
50 	}
51 
52 	// give the player a body armor
53 	armor = G_Spawn();
54 	armor->spawnflags |= DROPPED_ITEM;
55 	armor->item = FindItem("Body Armor");
56 	Touch_Item(armor, self, NULL, NULL);
57 	if(armor->inuse)
58 		G_FreeEdict(armor);
59 }
60 
61 //=================
62 //=================
Tag_PlayerDisconnect(edict_t * self)63 void Tag_PlayerDisconnect (edict_t *self)
64 {
65 	if(tag_token && self && (self == tag_owner))
66 	{
67 //		gi.dprintf("owner died/suicided. dropping\n");
68 		Tag_DropToken(self, FindItem( "Tag Token" ));
69 		tag_owner = NULL;
70 		tag_count = 0;
71 	}
72 }
73 
74 //=================
75 //=================
Tag_Score(edict_t * attacker,edict_t * victim,int scoreChange)76 void Tag_Score (edict_t *attacker, edict_t *victim, int scoreChange)
77 {
78 	gitem_t		*quad;
79 	int			mod;
80 
81 	mod = meansOfDeath & ~MOD_FRIENDLY_FIRE;
82 
83 //	gi.dprintf("%s killed %s\n", attacker->classname, victim->classname);
84 //	gi.dprintf("%x killed %x\n", attacker, victim);
85 	if(tag_token && tag_owner)
86 	{
87 		// owner killed somone else
88 		if((scoreChange > 0) && tag_owner == attacker)
89 		{
90 			scoreChange = 3;
91 			tag_count++;
92 //			gi.dprintf("tag total: %d\n", tag_count);
93 			if(tag_count == 5)
94 			{
95 //				gi.dprintf("going to quad\n");
96 				quad = FindItem ("Quad Damage");
97 				attacker->client->pers.inventory[ITEM_INDEX(quad)]++;
98 				quad->use (attacker, quad);
99 				tag_count = 0;
100 			}
101 		}
102 		// owner got killed. 5 points and switch owners
103 		else if(tag_owner == victim && tag_owner != attacker)
104 		{
105 //			gi.dprintf("owner killed by another player.\n");
106 			scoreChange = 5;
107 			if ((mod == MOD_HUNTER_SPHERE) || (mod == MOD_DOPPLE_EXPLODE) ||
108 				(mod == MOD_DOPPLE_VENGEANCE) || (mod == MOD_DOPPLE_HUNTER) ||
109 				(attacker->health <= 0))
110 			{
111 				Tag_DropToken(tag_owner, FindItem( "Tag Token" ));
112 				tag_owner = NULL;
113 				tag_count = 0;
114 			}
115 			else
116 			{
117 				Tag_KillItBonus(attacker);
118 				tag_owner = attacker;
119 				tag_count = 0;
120 			}
121 		}
122 //		else
123 //			gi.dprintf("unaffected slaying\n");
124 	}
125 //	else
126 //		gi.dprintf("no tag token?\n");
127 
128 	attacker->client->resp.score += scoreChange;
129 }
130 
131 //=================
132 //=================
Tag_PickupToken(edict_t * ent,edict_t * other)133 qboolean Tag_PickupToken (edict_t *ent, edict_t *other)
134 {
135 	if(gamerules && (gamerules->value != 2))
136 	{
137 		return false;
138 	}
139 
140 //	gi.dprintf("tag token picked up by %x\n", other);
141 	// sanity checking is good.
142 	if(tag_token != ent)
143 		tag_token = ent;
144 
145 	other->client->pers.inventory[ITEM_INDEX(ent->item)]++;
146 
147 	tag_owner = other;
148 	tag_count = 0;
149 
150 	Tag_KillItBonus (other);
151 
152 	return true;
153 }
154 
155 //=================
156 //=================
Tag_Respawn(edict_t * ent)157 void Tag_Respawn (edict_t *ent)
158 {
159 	edict_t	*spot;
160 
161 	spot = SelectFarthestDeathmatchSpawnPoint();
162 	if(spot == NULL)
163 	{
164 //		gi.dprintf("No open spawn point, waiting...\n");
165 		ent->nextthink = level.time + 1;
166 		return;
167 	}
168 
169 //	gi.dprintf("Relocating\n");
170 
171 	VectorCopy(spot->s.origin, ent->s.origin);
172 	gi.linkentity(ent);
173 }
174 
175 //=================
176 //=================
Tag_MakeTouchable(edict_t * ent)177 void Tag_MakeTouchable (edict_t *ent)
178 {
179 	ent->touch = Touch_Item;
180 
181 	tag_token->think = Tag_Respawn;
182 
183 	// check here to see if it's in lava or slime. if so, do a respawn sooner
184 	if(gi.pointcontents(ent->s.origin) & (CONTENTS_LAVA|CONTENTS_SLIME))
185 	{
186 //		gi.dprintf("spawned in slime or lava. quick relocate\n");
187 		tag_token->nextthink = level.time + 3;
188 	}
189 	else
190 	{
191 //		gi.dprintf("spawned in the clear. regular relocate\n");
192 		tag_token->nextthink = level.time + 30;
193 	}
194 }
195 
196 //=================
197 //=================
Tag_DropToken(edict_t * ent,gitem_t * item)198 void Tag_DropToken (edict_t *ent, gitem_t *item)
199 {
200 	trace_t	trace;
201 	vec3_t	forward, right;
202 	vec3_t	offset;
203 
204 //	if(ent->client)
205 //		gi.dprintf("%s dropped the tag token\n", ent->client->pers.netname);
206 //	else
207 //		gi.dprintf("non-client dropped the tag token  (%s)\n", ent->classname);
208 
209 	// reset the score count for next player
210 	tag_count = 0;
211 	tag_owner = NULL;
212 
213 	tag_token = G_Spawn();
214 
215 	tag_token->classname = item->classname;
216 	tag_token->item = item;
217 	tag_token->spawnflags = DROPPED_ITEM;
218 	tag_token->s.effects = EF_ROTATE | EF_TAGTRAIL;
219 	tag_token->s.renderfx = RF_GLOW;
220 	VectorSet (tag_token->mins, -15, -15, -15);
221 	VectorSet (tag_token->maxs, 15, 15, 15);
222 	gi.setmodel (tag_token, tag_token->item->world_model);
223 	tag_token->solid = SOLID_TRIGGER;
224 	tag_token->movetype = MOVETYPE_TOSS;
225 	tag_token->touch = NULL;
226 	tag_token->owner = ent;
227 
228 	AngleVectors (ent->client->v_angle, forward, right, NULL);
229 	VectorSet(offset, 24, 0, -16);
230 	G_ProjectSource (ent->s.origin, offset, forward, right, tag_token->s.origin);
231 	trace = gi.trace (ent->s.origin, tag_token->mins, tag_token->maxs,
232 		tag_token->s.origin, ent, CONTENTS_SOLID);
233 	VectorCopy (trace.endpos, tag_token->s.origin);
234 
235 	VectorScale (forward, 100, tag_token->velocity);
236 	tag_token->velocity[2] = 300;
237 
238 	tag_token->think = Tag_MakeTouchable;
239 	tag_token->nextthink = level.time + 1;
240 
241 	gi.linkentity (tag_token);
242 
243 //	tag_token = Drop_Item (ent, item);
244 	ent->client->pers.inventory[ITEM_INDEX(item)]--;
245 	ValidateSelectedItem (ent);
246 }
247 
248 //=================
249 //=================
Tag_PlayerEffects(edict_t * ent)250 void Tag_PlayerEffects (edict_t *ent)
251 {
252 	if(ent == tag_owner)
253 		ent->s.effects |= EF_TAGTRAIL;
254 }
255 
256 //=================
257 //=================
Tag_DogTag(edict_t * ent,edict_t * killer,char ** pic)258 void Tag_DogTag (edict_t *ent, edict_t *killer, char **pic)
259 {
260 	if(ent == tag_owner)
261 			(*pic)="tag3";
262 }
263 
264 //=================
265 // Tag_ChangeDamage - damage done that does not involve the tag owner
266 //		is at 75% original to encourage folks to go after the tag owner.
267 //=================
Tag_ChangeDamage(edict_t * targ,edict_t * attacker,int damage,int mod)268 int	Tag_ChangeDamage (edict_t *targ, edict_t *attacker, int damage, int mod)
269 {
270 	if((targ != tag_owner) && (attacker != tag_owner))
271 		return (damage * 3 / 4);
272 
273 	return damage;
274 }
275 
276 //=================
277 //=================
Tag_GameInit(void)278 void Tag_GameInit (void)
279 {
280 	tag_token = NULL;
281 	tag_owner = NULL;
282 	tag_count = 0;
283 }
284 
285 //=================
286 //=================
Tag_PostInitSetup(void)287 void Tag_PostInitSetup (void)
288 {
289 	edict_t		*e;
290 	vec3_t		origin, angles;
291 
292 	// automatic spawning of tag token if one is not present on map.
293 	e = G_Find (NULL, FOFS(classname), "dm_tag_token");
294 	if(e == NULL)
295 	{
296 		e = G_Spawn();
297 		e->classname = "dm_tag_token";
298 
299 		SelectSpawnPoint (e, origin, angles);
300 		VectorCopy(origin, e->s.origin);
301 		VectorCopy(origin, e->s.old_origin);
302 		VectorCopy(angles, e->s.angles);
303 		SP_dm_tag_token (e);
304 	}
305 }
306 
307 /*QUAKED dm_tag_token (.3 .3 1) (-16 -16 -16) (16 16 16)
308 The tag token for deathmatch tag games.
309 */
SP_dm_tag_token(edict_t * self)310 void SP_dm_tag_token (edict_t *self)
311 {
312 	if(!(deathmatch->value))
313 	{
314 		G_FreeEdict(self);
315 		return;
316 	}
317 
318 	if(gamerules && (gamerules->value != 2))
319 	{
320 		G_FreeEdict(self);
321 		return;
322 	}
323 
324 	// store the tag token edict pointer for later use.
325 	tag_token = self;
326 	tag_count = 0;
327 
328 	self->classname = "dm_tag_token";
329 	self->model = "models/items/tagtoken/tris.md2";
330 	self->count = 1;
331 	SpawnItem (self, FindItem ("Tag Token"));
332 }
333 
334