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