|
|
1.1 root 1: // g_newdm.c
2: // pmack
3: // june 1998
4:
5: #include "g_local.h"
6: #include "m_player.h"
7:
8: dm_game_rt DMGame;
9:
10: // ****************************
11: // General DM Stuff
12: // ****************************
13:
14: void InitGameRules(void)
15: {
16: int gameNum;
17:
18: // clear out the game rule structure before we start
19: memset(&DMGame, 0, sizeof(dm_game_rt));
20:
21: if(gamerules && gamerules->value)
22: {
23: gameNum = gamerules->value;
24: switch(gameNum)
25: {
26: case RDM_TAG:
27: DMGame.GameInit = Tag_GameInit;
28: DMGame.PostInitSetup = Tag_PostInitSetup;
29: DMGame.PlayerDeath = Tag_PlayerDeath;
30: DMGame.Score = Tag_Score;
31: DMGame.PlayerEffects = Tag_PlayerEffects;
32: DMGame.DogTag = Tag_DogTag;
33: DMGame.PlayerDisconnect = Tag_PlayerDisconnect;
34: DMGame.ChangeDamage = Tag_ChangeDamage;
35: break;
36: /*
37: case RDM_DEATHBALL:
38: DMGame.GameInit = DBall_GameInit;
39: DMGame.ChangeKnockback = DBall_ChangeKnockback;
40: DMGame.ChangeDamage = DBall_ChangeDamage;
41: DMGame.ClientBegin = DBall_ClientBegin;
42: DMGame.SelectSpawnPoint = DBall_SelectSpawnPoint;
43: DMGame.PostInitSetup = DBall_PostInitSetup;
44: DMGame.CheckDMRules = DBall_CheckDMRules;
45: break;
46: */
47: // reset gamerules if it's not a valid number
48: default:
49: gamerules->value = 0;
50: break;
51: }
52: }
53:
54: // if we're set up to play, initialize the game as needed.
55: if(DMGame.GameInit)
56: DMGame.GameInit();
57: }
58:
59: //=================
60: //=================
61: #define IT_TYPE_MASK (IT_WEAPON|IT_AMMO|IT_POWERUP|IT_ARMOR|IT_KEY)
62:
63: extern void ED_CallSpawn (edict_t *ent);
64: extern qboolean Pickup_Health (edict_t *ent, edict_t *other);
65: extern qboolean Pickup_Adrenaline (edict_t *ent, edict_t *other);
66: extern qboolean Pickup_Armor (edict_t *ent, edict_t *other);
67: extern qboolean Pickup_PowerArmor (edict_t *ent, edict_t *other);
68:
69: char *FindSubstituteItem (edict_t *ent)
70: {
71: int i;
72: int itflags, myflags;
73: float rnd;
74: int count;
75: int pick;
76: gitem_t *it;
77:
78: // there are only two classes of power armor, and we don't want
79: // to give out power screens. therefore, power shields should
80: // remain power shields. (powerscreens shouldn't be there at all...)
81: if (ent->item->pickup == Pickup_PowerArmor)
82: return NULL;
83:
84: // health is special case
85: if ((ent->item->pickup == Pickup_Health) || (ent->item->pickup == Pickup_Adrenaline))
86: {
87: // health pellets stay health pellets
88: if(!strcmp(ent->classname, "item_health_small"))
89: return NULL;
90:
91: rnd = random();
92: if(rnd < 0.6)
93: return "item_health";
94: else if(rnd < 0.9)
95: return "item_health_large";
96: else if(rnd < 0.99)
97: return "item_adrenaline";
98: else
99: return "item_health_mega";
100: }
101: // armor is also special case
102: else if(ent->item->pickup == Pickup_Armor)
103: {
104: // armor shards stay armor shards
105: if (ent->item->tag == ARMOR_SHARD)
106: return NULL;
107:
108: rnd = random();
109: if(rnd < 0.6)
110: return "item_armor_jacket";
111: else if(rnd < 0.9)
112: return "item_armor_combat";
113: else
114: return "item_armor_body";
115: }
116:
117:
118: // we want to stay within the item class
119: myflags = ent->item->flags & IT_TYPE_MASK;
120: if ((myflags & IT_AMMO) && (myflags & IT_WEAPON))
121: myflags = IT_AMMO;
122:
123: count = 0;
124:
125: // first pass, count the matching items
126: it = itemlist;
127: for (i=0 ; i<game.num_items ; i++, it++)
128: {
129: itflags = it->flags;
130:
131: if (!itflags || (itflags & IT_NOT_GIVEABLE))
132: continue;
133:
134: // prox,grenades,etc should count as ammo.
135: if ((itflags & IT_AMMO) && (itflags & IT_WEAPON))
136: itflags = IT_AMMO;
137:
138: if ( ((int)dmflags->value & DF_NO_NUKES) && !strcmp(ent->classname, "ammo_nuke") )
139: continue;
140:
141: if ( ((int)dmflags->value & DF_NO_MINES) &&
142: (!strcmp(ent->classname, "ammo_prox") || !strcmp(ent->classname, "ammo_tesla")))
143: continue;
144:
145: if ((itflags & IT_TYPE_MASK) == (myflags & IT_TYPE_MASK))
146: count++;
147: }
148:
149: if(!count)
150: return NULL;
151:
152: pick = ceil(random() * count);
153: count = 0;
154:
155: // second pass, pick one.
156: it = itemlist;
157: for (i=0 ; i<game.num_items ; i++, it++)
158: {
159: itflags = it->flags;
160:
161: if (!itflags || (itflags & IT_NOT_GIVEABLE))
162: continue;
163:
164: // prox,grenades,etc should count as ammo.
165: if ((itflags & IT_AMMO) && (itflags & IT_WEAPON))
166: itflags = IT_AMMO;
167:
168: if ( ((int)dmflags->value & DF_NO_NUKES) && !strcmp(ent->classname, "ammo_nuke") )
169: continue;
170:
171: if ( ((int)dmflags->value & DF_NO_MINES) &&
172: (!strcmp(ent->classname, "ammo_prox") || !strcmp(ent->classname, "ammo_tesla")))
173: continue;
174:
175: if ((itflags & IT_TYPE_MASK) == (myflags & IT_TYPE_MASK))
176: {
177: count++;
178: if(pick == count)
179: return it->classname;
180: }
181: }
182:
183: return NULL;
184: }
185:
186: //=================
187: //=================
188: edict_t *DoRandomRespawn (edict_t *ent)
189: {
190: edict_t *newEnt;
191: char *classname;
192:
193: classname = FindSubstituteItem (ent);
194: if (classname == NULL)
195: return NULL;
196:
197: gi.unlinkentity (ent);
198:
199: newEnt = G_Spawn();
200: newEnt->classname = classname;
201: VectorCopy (ent->s.origin, newEnt->s.origin);
202: VectorCopy (ent->s.old_origin, newEnt->s.old_origin);
203: VectorCopy (ent->mins, newEnt->mins);
204: VectorCopy (ent->maxs, newEnt->maxs);
205:
206: VectorSet (newEnt->gravityVector, 0, 0, -1);
207:
208: ED_CallSpawn (newEnt);
209:
210: newEnt->s.renderfx |= RF_IR_VISIBLE;
211:
212: return newEnt;
213: }
214:
215: //=================
216: //=================
217: void PrecacheForRandomRespawn (void)
218: {
219: gitem_t *it;
220: int i;
221: int itflags;
222:
223: it = itemlist;
224: for (i=0 ; i<game.num_items ; i++, it++)
225: {
226: itflags = it->flags;
227:
228: if (!itflags || (itflags & IT_NOT_GIVEABLE))
229: continue;
230:
231: PrecacheItem(it);
232: }
233: }
234:
235: // ***************************
236: // DOPPLEGANGER
237: // ***************************
238:
239: extern edict_t *Sphere_Spawn (edict_t *owner, int spawnflags);
240:
241: void fire_doppleganger (edict_t *ent, vec3_t start, vec3_t aimdir);
242: void doppleganger_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point);
243:
244: void doppleganger_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
245: {
246: edict_t *sphere;
247: float dist;
248: vec3_t dir;
249:
250: if((self->enemy) && (self->enemy != self->teammaster))
251: {
252: VectorSubtract(self->enemy->s.origin, self->s.origin, dir);
253: dist = VectorLength(dir);
254:
255: if(dist > 768)
256: {
257: sphere = Sphere_Spawn (self, SPHERE_HUNTER | SPHERE_DOPPLEGANGER);
258: sphere->pain(sphere, attacker, 0, 0);
259: }
260: else //if(dist > 256)
261: {
262: sphere = Sphere_Spawn (self, SPHERE_VENGEANCE | SPHERE_DOPPLEGANGER);
263: sphere->pain(sphere, attacker, 0, 0);
264: }
265: // else
266: // {
267: // T_RadiusClassDamage (self, self->teammaster, 175, "doppleganger", 384, MOD_DOPPLE_EXPLODE);
268: // }
269: }
270:
271: if(self->teamchain)
272: BecomeExplosion1(self->teamchain);
273: BecomeExplosion1(self);
274: }
275:
276: void doppleganger_pain (edict_t *self, edict_t *other, float kick, int damage)
277: {
278: self->enemy = other;
279: }
280:
281: void doppleganger_timeout (edict_t *self)
282: {
283: // T_RadiusClassDamage (self, self->teammaster, 140, "doppleganger", 256, MOD_DOPPLE_EXPLODE);
284:
285: if(self->teamchain)
286: BecomeExplosion1(self->teamchain);
287: BecomeExplosion1(self);
288: }
289:
290: void body_think (edict_t *self)
291: {
292: float r;
293:
294: if(abs(self->ideal_yaw - anglemod(self->s.angles[YAW])) < 2)
295: {
296: if(self->timestamp < level.time)
297: {
298: r = random();
299: if(r < 0.10)
300: {
301: self->ideal_yaw = random() * 350.0;
302: self->timestamp = level.time + 1;
303: }
304: }
305: }
306: else
307: M_ChangeYaw(self);
308:
309: self->s.frame ++;
310: if (self->s.frame > FRAME_stand40)
311: self->s.frame = FRAME_stand01;
312:
313: self->nextthink = level.time + 0.1;
314: }
315:
316: void fire_doppleganger (edict_t *ent, vec3_t start, vec3_t aimdir)
317: {
318: edict_t *base;
319: edict_t *body;
320: vec3_t dir;
321: vec3_t forward, right, up;
322: int number;
323:
324: vectoangles2 (aimdir, dir);
325: AngleVectors (dir, forward, right, up);
326:
327: base = G_Spawn();
328: VectorCopy (start, base->s.origin);
329: VectorCopy (dir, base->s.angles);
330: VectorClear (base->velocity);
331: VectorClear (base->avelocity);
332: base->movetype = MOVETYPE_TOSS;
333: base->solid = SOLID_BBOX;
334: base->s.renderfx |= RF_IR_VISIBLE;
335: base->s.angles[PITCH]=0;
336: VectorSet (base->mins, -16, -16, -24);
337: VectorSet (base->maxs, 16, 16, 32);
338: // base->s.modelindex = gi.modelindex ("models/objects/dopplebase/tris.md2");
339: base->s.modelindex = 0;
340: base->teammaster = ent;
341: base->svflags |= SVF_DAMAGEABLE;
342: base->takedamage = DAMAGE_AIM;
343: base->health = 30;
344: base->pain = doppleganger_pain;
345: base->die = doppleganger_die;
346:
347: // FIXME - remove with style
348: base->nextthink = level.time + 30;
349: base->think = doppleganger_timeout;
350:
351: base->classname = "doppleganger";
352:
353: gi.linkentity (base);
354:
355: body = G_Spawn();
356: number = body->s.number;
357: body->s = ent->s;
358: body->s.sound = 0;
359: body->s.event = 0;
360: // body->s.modelindex2 = 0; // no attached items (CTF flag, etc)
361: body->s.number = number;
362: body->yaw_speed = 30;
363: body->ideal_yaw = 0;
364: VectorCopy (start, body->s.origin);
365: body->s.origin[2] += 8;
366: body->think = body_think;
367: body->nextthink = level.time + FRAMETIME;
368: gi.linkentity (body);
369:
370: base->teamchain = body;
371: body->teammaster = base;
372: }
373:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.