|
|
1.1 root 1:
2: // prototypes
3: void () W_WeaponFrame;
4: void() W_SetCurrentAmmo;
5: void() player_pain;
6: void() player_stand1;
7: void (vector org) spawn_tfog;
8: void (vector org, entity death_owner) spawn_tdeath;
9:
10: float modelindex_eyes, modelindex_player;
11:
12: /*
13: =============================================================================
14:
15: LEVEL CHANGING / INTERMISSION
16:
17: =============================================================================
18: */
19:
20: string nextmap;
21:
22: float intermission_running;
23: float intermission_exittime;
24:
25: /*QUAKED info_intermission (1 0.5 0.5) (-16 -16 -16) (16 16 16)
26: This is the camera point for the intermission.
27: Use mangle instead of angle, so you can set pitch or roll as well as yaw. 'pitch roll yaw'
28: */
29: void() info_intermission =
30: {
31: self.angles = self.mangle; // so C can get at it
32: };
33:
34:
35:
36: void() SetChangeParms =
37: {
38: if (self.health <= 0)
39: {
40: SetNewParms ();
41: return;
42: }
43:
44: // remove items
45: self.items = self.items - (self.items &
46: (IT_KEY1 | IT_KEY2 | IT_INVISIBILITY | IT_INVULNERABILITY | IT_SUIT | IT_QUAD) );
47:
48: // cap super health
49: if (self.health > 100)
50: self.health = 100;
51: if (self.health < 50)
52: self.health = 50;
53: parm1 = self.items;
54: parm2 = self.health;
55: parm3 = self.armorvalue;
56: if (self.ammo_shells < 25)
57: parm4 = 25;
58: else
59: parm4 = self.ammo_shells;
60: parm5 = self.ammo_nails;
61: parm6 = self.ammo_rockets;
62: parm7 = self.ammo_cells;
63: parm8 = self.weapon;
64: parm9 = self.armortype * 100;
65: };
66:
67: void() SetNewParms =
68: {
69: parm1 = IT_SHOTGUN | IT_AXE;
70: parm2 = 100;
71: parm3 = 0;
72: parm4 = 25;
73: parm5 = 0;
74: parm6 = 0;
75: parm7 = 0;
76: parm8 = 1;
77: parm9 = 0;
78: };
79:
80: void() DecodeLevelParms =
81: {
82: if (serverflags)
83: {
84: if (world.model == "maps/start.bsp")
85: SetNewParms (); // take away all stuff on starting new episode
86: }
87:
88: self.items = parm1;
89: self.health = parm2;
90: self.armorvalue = parm3;
91: self.ammo_shells = parm4;
92: self.ammo_nails = parm5;
93: self.ammo_rockets = parm6;
94: self.ammo_cells = parm7;
95: self.weapon = parm8;
96: self.armortype = parm9 * 0.01;
97: };
98:
99: /*
100: ============
101: FindIntermission
102:
103: Returns the entity to view from
104: ============
105: */
106: entity() FindIntermission =
107: {
108: local entity spot;
109: local float cyc;
110:
111: // look for info_intermission first
112: spot = find (world, classname, "info_intermission");
113: if (spot)
114: { // pick a random one
115: cyc = random() * 4;
116: while (cyc > 1)
117: {
118: spot = find (spot, classname, "info_intermission");
119: if (!spot)
120: spot = find (spot, classname, "info_intermission");
121: cyc = cyc - 1;
122: }
123: return spot;
124: }
125:
126: // then look for the start position
127: spot = find (world, classname, "info_player_start");
128: if (spot)
129: return spot;
130:
131: objerror ("FindIntermission: no spot");
132: };
133:
134:
135: void() GotoNextMap =
136: {
137: local string newmap;
138:
139: //ZOID: 12-13-96, samelevel is overloaded, only 1 works for same level
140:
141: if (cvar("samelevel") == 1) // if samelevel is set, stay on same level
142: changelevel (mapname);
143: else {
144: // configurable map lists, see if the current map exists as a
145: // serverinfo/localinfo var
146: newmap = infokey(world, mapname);
147: if (newmap != "")
148: changelevel (newmap);
149: else
150: changelevel (nextmap);
151: }
152: };
153:
154:
155:
156: /*
157: ============
158: IntermissionThink
159:
160: When the player presses attack or jump, change to the next level
161: ============
162: */
163: void() IntermissionThink =
164: {
165: if (time < intermission_exittime)
166: return;
167:
168: if (!self.button0 && !self.button1 && !self.button2)
169: return;
170:
171: GotoNextMap ();
172: };
173:
174: /*
175: ============
176: execute_changelevel
177:
178: The global "nextmap" has been set previously.
179: Take the players to the intermission spot
180: ============
181: */
182: void() execute_changelevel =
183: {
184: local entity pos;
185:
186: intermission_running = 1;
187:
188: // enforce a wait time before allowing changelevel
189: intermission_exittime = time + 5;
190:
191: pos = FindIntermission ();
192:
193: // play intermission music
194: WriteByte (MSG_ALL, SVC_CDTRACK);
195: WriteByte (MSG_ALL, 3);
196:
197: WriteByte (MSG_ALL, SVC_INTERMISSION);
198: WriteCoord (MSG_ALL, pos.origin_x);
199: WriteCoord (MSG_ALL, pos.origin_y);
200: WriteCoord (MSG_ALL, pos.origin_z);
201: WriteAngle (MSG_ALL, pos.mangle_x);
202: WriteAngle (MSG_ALL, pos.mangle_y);
203: WriteAngle (MSG_ALL, pos.mangle_z);
204:
205: other = find (world, classname, "player");
206: while (other != world)
207: {
208: other.takedamage = DAMAGE_NO;
209: other.solid = SOLID_NOT;
210: other.movetype = MOVETYPE_NONE;
211: other.modelindex = 0;
212: other = find (other, classname, "player");
213: }
214:
215: };
216:
217:
218: void() changelevel_touch =
219: {
220: local entity pos;
221:
222: if (other.classname != "player")
223: return;
224:
225: // if "noexit" is set, blow up the player trying to leave
226: //ZOID, 12-13-96, noexit isn't supported in QW. Overload samelevel
227: // if ((cvar("noexit") == 1) || ((cvar("noexit") == 2) && (mapname != "start")))
228: if ((cvar("samelevel") == 2) || ((cvar("samelevel") == 3) && (mapname != "start")))
229: {
230: T_Damage (other, self, self, 50000);
231: return;
232: }
233:
234: bprint (PRINT_HIGH, other.netname);
235: bprint (PRINT_HIGH," exited the level\n");
236:
237: nextmap = self.map;
238:
239: SUB_UseTargets ();
240:
241: self.touch = SUB_Null;
242:
243: // we can't move people right now, because touch functions are called
244: // in the middle of C movement code, so set a think time to do it
245: self.think = execute_changelevel;
246: self.nextthink = time + 0.1;
247: };
248:
249: /*QUAKED trigger_changelevel (0.5 0.5 0.5) ? NO_INTERMISSION
250: When the player touches this, he gets sent to the map listed in the "map" variable. Unless the NO_INTERMISSION flag is set, the view will go to the info_intermission spot and display stats.
251: */
252: void() trigger_changelevel =
253: {
254: if (!self.map)
255: objerror ("chagnelevel trigger doesn't have map");
256:
257: InitTrigger ();
258: self.touch = changelevel_touch;
259: };
260:
261:
262: /*
263: =============================================================================
264:
265: PLAYER GAME EDGE FUNCTIONS
266:
267: =============================================================================
268: */
269:
270: void() set_suicide_frame;
271:
272: // called by ClientKill and DeadThink
273: void() respawn =
274: {
275: // make a copy of the dead body for appearances sake
276: CopyToBodyQue (self);
277: // set default spawn parms
278: SetNewParms ();
279: // respawn
280: PutClientInServer ();
281: };
282:
283:
284: /*
285: ============
286: ClientKill
287:
288: Player entered the suicide command
289: ============
290: */
291: void() ClientKill =
292: {
293: bprint (PRINT_MEDIUM, self.netname);
294: bprint (PRINT_MEDIUM, " suicides\n");
295: set_suicide_frame ();
296: self.modelindex = modelindex_player;
297: logfrag (self, self);
298: self.frags = self.frags - 2; // extra penalty
299: respawn ();
300: };
301:
302: float(vector v) CheckSpawnPoint =
303: {
304: return FALSE;
305: };
306:
307: /*
308: ============
309: SelectSpawnPoint
310:
311: Returns the entity to spawn at
312: ============
313: */
314: entity() SelectSpawnPoint =
315: {
316: local entity spot, newspot, thing;
317: local float numspots, totalspots;
318: local float rnum, pcount;
319: local float rs;
320: local entity spots;
321:
322: numspots = 0;
323: totalspots = 0;
324:
325: // testinfo_player_start is only found in regioned levels
326: spot = find (world, classname, "testplayerstart");
327: if (spot)
328: return spot;
329:
330: // choose a info_player_deathmatch point
331:
332: // ok, find all spots that don't have players nearby
333:
334: spots = world;
335: spot = find (world, classname, "info_player_deathmatch");
336: while (spot)
337: {
338: totalspots = totalspots + 1;
339:
340: thing=findradius(spot.origin, 84);
341: pcount=0;
342: while (thing)
343: {
344: if (thing.classname == "player")
345: pcount=pcount + 1;
346: thing=thing.chain;
347: }
348: if (pcount == 0) {
349: spot.goalentity = spots;
350: spots = spot;
351: numspots = numspots + 1;
352: }
353:
354: // Get the next spot in the chain
355: spot = find (spot, classname, "info_player_deathmatch");
356: }
357: totalspots=totalspots - 1;
358: if (!numspots) {
359: // ack, they are all full, just pick one at random
360: // bprint (PRINT_HIGH, "Ackk! All spots are full. Selecting random spawn spot\n");
361: totalspots = rint((random() * totalspots));
362: spot = find (world, classname, "info_player_deathmatch");
363: while (totalspots > 0) {
364: totalspots = totalspots - 1;
365: spot = find (spot, classname, "info_player_deathmatch");
366: }
367: return spot;
368: }
369:
370: // We now have the number of spots available on the map in numspots
371:
372: // Generate a random number between 1 and numspots
373:
374: numspots = numspots - 1;
375:
376: numspots = rint((random() * numspots ) );
377:
378: spot = spots;
379: while (numspots > 0) {
380: spot = spot.goalentity;
381: numspots = numspots - 1;
382: }
383: return spot;
384:
385: };
386: void() DecodeLevelParms;
387: void() PlayerDie;
388:
389: /*
390: ===========
391: ValidateUser
392:
393:
394: ============
395: */
396: float(entity e) ValidateUser =
397: {
398: /*
399: local string s;
400: local string userclan;
401: local float rank, rankmin, rankmax;
402:
403: //
404: // if the server has set "clan1" and "clan2", then it
405: // is a clan match that will allow only those two clans in
406: //
407: s = serverinfo("clan1");
408: if (s)
409: {
410: userclan = masterinfo(e,"clan");
411: if (s == userclan)
412: return true;
413: s = serverinfo("clan2");
414: if (s == userclan)
415: return true;
416: return false;
417: }
418:
419: //
420: // if the server has set "rankmin" and/or "rankmax" then
421: // the users rank must be between those two values
422: //
423: s = masterinfo (e, "rank");
424: rank = stof (s);
425:
426: s = serverinfo("rankmin");
427: if (s)
428: {
429: rankmin = stof (s);
430: if (rank < rankmin)
431: return false;
432: }
433: s = serverinfo("rankmax");
434: if (s)
435: {
436: rankmax = stof (s);
437: if (rankmax < rank)
438: return false;
439: }
440:
441: return true;
442: */
443: };
444:
445:
446: /*
447: ===========
448: PutClientInServer
449:
450: called each time a player enters a new level
451: ============
452: */
453: void() PutClientInServer =
454: {
455: local entity spot;
456: local string s;
457:
458: self.classname = "player";
459: self.health = 100;
460: self.takedamage = DAMAGE_AIM;
461: self.solid = SOLID_SLIDEBOX;
462: self.movetype = MOVETYPE_WALK;
463: self.show_hostile = 0;
464: self.max_health = 100;
465: self.flags = FL_CLIENT;
466: self.air_finished = time + 12;
467: self.dmg = 2; // initial water damage
468: self.super_damage_finished = 0;
469: self.radsuit_finished = 0;
470: self.invisible_finished = 0;
471: self.invincible_finished = 0;
472: self.effects = 0;
473: self.invincible_time = 0;
474:
475: DecodeLevelParms ();
476:
477: W_SetCurrentAmmo ();
478:
479: self.attack_finished = time;
480: self.th_pain = player_pain;
481: self.th_die = PlayerDie;
482:
483: self.deadflag = DEAD_NO;
484: // paustime is set by teleporters to keep the player from moving a while
485: self.pausetime = 0;
486:
487: spot = SelectSpawnPoint ();
488:
489: self.origin = spot.origin + '0 0 1';
490: self.angles = spot.angles;
491: self.fixangle = TRUE; // turn this way immediately
492:
493: // oh, this is a hack!
494: setmodel (self, "progs/eyes.mdl");
495: modelindex_eyes = self.modelindex;
496:
497: setmodel (self, "progs/player.mdl");
498: modelindex_player = self.modelindex;
499:
500: setsize (self, VEC_HULL_MIN, VEC_HULL_MAX);
501:
502: self.view_ofs = '0 0 22';
503:
504: // Mod - Xian (May.20.97)
505: // Bug where player would have velocity from their last kill
506:
507: self.velocity = '0 0 0';
508:
509: player_stand1 ();
510:
511: makevectors(self.angles);
512: spawn_tfog (self.origin + v_forward*20);
513:
514: spawn_tdeath (self.origin, self);
515:
516: // Set Rocket Jump Modifiers
517: if (stof(infokey(world, "rj")) != 0)
518: {
519: rj = stof(infokey(world, "rj"));
520: }
521:
522: if (deathmatch == 4)
523: {
524: self.ammo_shells = 0;
525: if (stof(infokey(world, "axe")) == 0)
526: {
527: self.ammo_nails = 255;
528: self.ammo_shells = 255;
529: self.ammo_rockets = 255;
530: self.ammo_cells = 255;
531: self.items = self.items | IT_NAILGUN;
532: self.items = self.items | IT_SUPER_NAILGUN;
533: self.items = self.items | IT_SUPER_SHOTGUN;
534: self.items = self.items | IT_ROCKET_LAUNCHER;
535: // self.items = self.items | IT_GRENADE_LAUNCHER;
536: self.items = self.items | IT_LIGHTNING;
537: }
538: self.items = self.items - (self.items & (IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3)) + IT_ARMOR3;
539: self.armorvalue = 200;
540: self.armortype = 0.8;
541: self.health = 250;
542: self.items = self.items | IT_INVULNERABILITY;
543: self.invincible_time = 1;
544: self.invincible_finished = time + 3;
545: }
546:
547: if (deathmatch == 5)
548: {
549: self.ammo_nails = 80;
550: self.ammo_shells = 30;
551: self.ammo_rockets = 10;
552: self.ammo_cells = 30;
553: self.items = self.items | IT_NAILGUN;
554: self.items = self.items | IT_SUPER_NAILGUN;
555: self.items = self.items | IT_SUPER_SHOTGUN;
556: self.items = self.items | IT_ROCKET_LAUNCHER;
557: self.items = self.items | IT_GRENADE_LAUNCHER;
558: self.items = self.items | IT_LIGHTNING;
559: self.items = self.items - (self.items & (IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3)) + IT_ARMOR3;
560: self.armorvalue = 200;
561: self.armortype = 0.8;
562: self.health = 200;
563: self.items = self.items | IT_INVULNERABILITY;
564: self.invincible_time = 1;
565: self.invincible_finished = time + 3;
566: }
567:
568:
569: };
570:
571:
572: /*
573: =============================================================================
574:
575: QUAKED FUNCTIONS
576:
577: =============================================================================
578: */
579:
580:
581: /*QUAKED info_player_start (1 0 0) (-16 -16 -24) (16 16 24)
582: The normal starting point for a level.
583: */
584: void() info_player_start =
585: {
586: };
587:
588:
589: /*QUAKED info_player_start2 (1 0 0) (-16 -16 -24) (16 16 24)
590: Only used on start map for the return point from an episode.
591: */
592: void() info_player_start2 =
593: {
594: };
595:
596: /*QUAKED info_player_deathmatch (1 0 1) (-16 -16 -24) (16 16 24)
597: potential spawning position for deathmatch games
598: */
599: void() info_player_deathmatch =
600: {
601: };
602:
603: /*QUAKED info_player_coop (1 0 1) (-16 -16 -24) (16 16 24)
604: potential spawning position for coop games
605: */
606: void() info_player_coop =
607: {
608: };
609:
610: /*
611: ===============================================================================
612:
613: RULES
614:
615: ===============================================================================
616: */
617:
618: /*
619: go to the next level for deathmatch
620: */
621: void() NextLevel =
622: {
623: local entity o;
624: local string newmap;
625:
626: if (nextmap != "")
627: return; // already done
628:
629: if (mapname == "start")
630: {
631: if (!cvar("registered"))
632: {
633: mapname = "e1m1";
634: }
635: else if (!(serverflags & 1))
636: {
637: mapname = "e1m1";
638: serverflags = serverflags | 1;
639: }
640: else if (!(serverflags & 2))
641: {
642: mapname = "e2m1";
643: serverflags = serverflags | 2;
644: }
645: else if (!(serverflags & 4))
646: {
647: mapname = "e3m1";
648: serverflags = serverflags | 4;
649: }
650: else if (!(serverflags & 8))
651: {
652: mapname = "e4m1";
653: serverflags = serverflags - 7;
654: }
655:
656: o = spawn();
657: o.map = mapname;
658: }
659: else
660: {
661: // find a trigger changelevel
662: o = find(world, classname, "trigger_changelevel");
663: if (!o || mapname == "start")
664: { // go back to same map if no trigger_changelevel
665: o = spawn();
666: o.map = mapname;
667: }
668: }
669:
670: nextmap = o.map;
671:
672: if (o.nextthink < time)
673: {
674: o.think = execute_changelevel;
675: o.nextthink = time + 0.1;
676: }
677: };
678:
679: /*
680: ============
681: CheckRules
682:
683: Exit deathmatch games upon conditions
684: ============
685: */
686: void() CheckRules =
687: {
688: if (timelimit && time >= timelimit)
689: NextLevel ();
690:
691: if (fraglimit && self.frags >= fraglimit)
692: NextLevel ();
693: };
694:
695: //============================================================================
696:
697: void() PlayerDeathThink =
698: {
699: local entity old_self;
700: local float forward;
701:
702: if ((self.flags & FL_ONGROUND))
703: {
704: forward = vlen (self.velocity);
705: forward = forward - 20;
706: if (forward <= 0)
707: self.velocity = '0 0 0';
708: else
709: self.velocity = forward * normalize(self.velocity);
710: }
711:
712: // wait for all buttons released
713: if (self.deadflag == DEAD_DEAD)
714: {
715: if (self.button2 || self.button1 || self.button0)
716: return;
717: self.deadflag = DEAD_RESPAWNABLE;
718: return;
719: }
720:
721: // wait for any button down
722: if (!self.button2 && !self.button1 && !self.button0)
723: return;
724:
725: self.button0 = 0;
726: self.button1 = 0;
727: self.button2 = 0;
728: respawn();
729: };
730:
731:
732: void() PlayerJump =
733: {
734: local vector start, end;
735:
736: if (self.flags & FL_WATERJUMP)
737: return;
738:
739: if (self.waterlevel >= 2)
740: {
741: // play swiming sound
742: if (self.swim_flag < time)
743: {
744: self.swim_flag = time + 1;
745: if (random() < 0.5)
746: sound (self, CHAN_BODY, "misc/water1.wav", 1, ATTN_NORM);
747: else
748: sound (self, CHAN_BODY, "misc/water2.wav", 1, ATTN_NORM);
749: }
750:
751: return;
752: }
753:
754: if (!(self.flags & FL_ONGROUND))
755: return;
756:
757: if ( !(self.flags & FL_JUMPRELEASED) )
758: return; // don't pogo stick
759:
760: self.flags = self.flags - (self.flags & FL_JUMPRELEASED);
761: self.button2 = 0;
762:
763: // player jumping sound
764: sound (self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM);
765: };
766:
767:
768: /*
769: ===========
770: WaterMove
771:
772: ============
773: */
774: .float dmgtime;
775:
776: void() WaterMove =
777: {
778: //dprint (ftos(self.waterlevel));
779: if (self.movetype == MOVETYPE_NOCLIP)
780: return;
781: if (self.health < 0)
782: return;
783:
784: if (self.waterlevel != 3)
785: {
786: if (self.air_finished < time)
787: sound (self, CHAN_VOICE, "player/gasp2.wav", 1, ATTN_NORM);
788: else if (self.air_finished < time + 9)
789: sound (self, CHAN_VOICE, "player/gasp1.wav", 1, ATTN_NORM);
790: self.air_finished = time + 12;
791: self.dmg = 2;
792: }
793: else if (self.air_finished < time)
794: { // drown!
795: if (self.pain_finished < time)
796: {
797: self.dmg = self.dmg + 2;
798: if (self.dmg > 15)
799: self.dmg = 10;
800: T_Damage (self, world, world, self.dmg);
801: self.pain_finished = time + 1;
802: }
803: }
804:
805: if (!self.waterlevel)
806: {
807: if (self.flags & FL_INWATER)
808: {
809: // play leave water sound
810: sound (self, CHAN_BODY, "misc/outwater.wav", 1, ATTN_NORM);
811: self.flags = self.flags - FL_INWATER;
812: }
813: return;
814: }
815:
816: if (self.watertype == CONTENT_LAVA)
817: { // do damage
818: if (self.dmgtime < time)
819: {
820: if (self.radsuit_finished > time)
821: self.dmgtime = time + 1;
822: else
823: self.dmgtime = time + 0.2;
824:
825: T_Damage (self, world, world, 10*self.waterlevel);
826: }
827: }
828: else if (self.watertype == CONTENT_SLIME)
829: { // do damage
830: if (self.dmgtime < time && self.radsuit_finished < time)
831: {
832: self.dmgtime = time + 1;
833: T_Damage (self, world, world, 4*self.waterlevel);
834: }
835: }
836:
837: if ( !(self.flags & FL_INWATER) )
838: {
839:
840: // player enter water sound
841:
842: if (self.watertype == CONTENT_LAVA)
843: sound (self, CHAN_BODY, "player/inlava.wav", 1, ATTN_NORM);
844: if (self.watertype == CONTENT_WATER)
845: sound (self, CHAN_BODY, "player/inh2o.wav", 1, ATTN_NORM);
846: if (self.watertype == CONTENT_SLIME)
847: sound (self, CHAN_BODY, "player/slimbrn2.wav", 1, ATTN_NORM);
848:
849: self.flags = self.flags + FL_INWATER;
850: self.dmgtime = 0;
851: }
852: };
853:
854: void() CheckWaterJump =
855: {
856: local vector start, end;
857:
858: // check for a jump-out-of-water
859: makevectors (self.angles);
860: start = self.origin;
861: start_z = start_z + 8;
862: v_forward_z = 0;
863: normalize(v_forward);
864: end = start + v_forward*24;
865: traceline (start, end, TRUE, self);
866: if (trace_fraction < 1)
867: { // solid at waist
868: start_z = start_z + self.maxs_z - 8;
869: end = start + v_forward*24;
870: self.movedir = trace_plane_normal * -50;
871: traceline (start, end, TRUE, self);
872: if (trace_fraction == 1)
873: { // open at eye level
874: self.flags = self.flags | FL_WATERJUMP;
875: self.velocity_z = 225;
876: self.flags = self.flags - (self.flags & FL_JUMPRELEASED);
877: self.teleport_time = time + 2; // safety net
878: return;
879: }
880: }
881: };
882:
883: /*
884: ================
885: PlayerPreThink
886:
887: Called every frame before physics are run
888: ================
889: */
890: void() PlayerPreThink =
891: {
892: local float mspeed, aspeed;
893: local float r;
894:
895: if (intermission_running)
896: {
897: IntermissionThink (); // otherwise a button could be missed between
898: return; // the think tics
899: }
900:
901: if (self.view_ofs == '0 0 0')
902: return; // intermission or finale
903:
904: makevectors (self.v_angle); // is this still used
905:
906: self.deathtype = "";
907:
908: CheckRules ();
909: WaterMove ();
910: /*
911: if (self.waterlevel == 2)
912: CheckWaterJump ();
913: */
914:
915: if (self.deadflag >= DEAD_DEAD)
916: {
917: PlayerDeathThink ();
918: return;
919: }
920:
921: if (self.deadflag == DEAD_DYING)
922: return; // dying, so do nothing
923:
924: if (self.button2)
925: {
926: PlayerJump ();
927: }
928: else
929: self.flags = self.flags | FL_JUMPRELEASED;
930:
931: // teleporters can force a non-moving pause time
932: if (time < self.pausetime)
933: self.velocity = '0 0 0';
934:
935: if(time > self.attack_finished && self.currentammo == 0 && self.weapon != IT_AXE)
936: {
937: self.weapon = W_BestWeapon ();
938: W_SetCurrentAmmo ();
939: }
940: };
941:
942: /*
943: ================
944: CheckPowerups
945:
946: Check for turning off powerups
947: ================
948: */
949: void() CheckPowerups =
950: {
951: if (self.health <= 0)
952: return;
953:
954: // invisibility
955: if (self.invisible_finished)
956: {
957: // sound and screen flash when items starts to run out
958: if (self.invisible_sound < time)
959: {
960: sound (self, CHAN_AUTO, "items/inv3.wav", 0.5, ATTN_IDLE);
961: self.invisible_sound = time + ((random() * 3) + 1);
962: }
963:
964:
965: if (self.invisible_finished < time + 3)
966: {
967: if (self.invisible_time == 1)
968: {
969: sprint (self, PRINT_HIGH, "Ring of Shadows magic is fading\n");
970: stuffcmd (self, "bf\n");
971: sound (self, CHAN_AUTO, "items/inv2.wav", 1, ATTN_NORM);
972: self.invisible_time = time + 1;
973: }
974:
975: if (self.invisible_time < time)
976: {
977: self.invisible_time = time + 1;
978: stuffcmd (self, "bf\n");
979: }
980: }
981:
982: if (self.invisible_finished < time)
983: { // just stopped
984: self.items = self.items - IT_INVISIBILITY;
985: self.invisible_finished = 0;
986: self.invisible_time = 0;
987: }
988:
989: // use the eyes
990: self.frame = 0;
991: self.modelindex = modelindex_eyes;
992: }
993: else
994: self.modelindex = modelindex_player; // don't use eyes
995:
996: // invincibility
997: if (self.invincible_finished)
998: {
999: // sound and screen flash when items starts to run out
1000: if (self.invincible_finished < time + 3)
1001: {
1002: if (self.invincible_time == 1)
1003: {
1004: sprint (self, PRINT_HIGH, "Protection is almost burned out\n");
1005: stuffcmd (self, "bf\n");
1006: sound (self, CHAN_AUTO, "items/protect2.wav", 1, ATTN_NORM);
1007: self.invincible_time = time + 1;
1008: }
1009:
1010: if (self.invincible_time < time)
1011: {
1012: self.invincible_time = time + 1;
1013: stuffcmd (self, "bf\n");
1014: }
1015: }
1016:
1017: if (self.invincible_finished < time)
1018: { // just stopped
1019: self.items = self.items - IT_INVULNERABILITY;
1020: self.invincible_time = 0;
1021: self.invincible_finished = 0;
1022: }
1023: if (self.invincible_finished > time)
1024: {
1025: self.effects = self.effects | EF_DIMLIGHT;
1026: self.effects = self.effects | EF_RED;
1027: }
1028: else
1029: {
1030: self.effects = self.effects - (self.effects & EF_DIMLIGHT);
1031: self.effects = self.effects - (self.effects & EF_RED);
1032: }
1033: }
1034:
1035: // super damage
1036: if (self.super_damage_finished)
1037: {
1038:
1039: // sound and screen flash when items starts to run out
1040:
1041: if (self.super_damage_finished < time + 3)
1042: {
1043: if (self.super_time == 1)
1044: {
1045: if (deathmatch == 4)
1046: sprint (self, PRINT_HIGH, "OctaPower is wearing off\n");
1047: else
1048: sprint (self, PRINT_HIGH, "Quad Damage is wearing off\n");
1049: stuffcmd (self, "bf\n");
1050: sound (self, CHAN_AUTO, "items/damage2.wav", 1, ATTN_NORM);
1051: self.super_time = time + 1;
1052: }
1053:
1054: if (self.super_time < time)
1055: {
1056: self.super_time = time + 1;
1057: stuffcmd (self, "bf\n");
1058: }
1059: }
1060:
1061: if (self.super_damage_finished < time)
1062: { // just stopped
1063: self.items = self.items - IT_QUAD;
1064: if (deathmatch == 4)
1065: {
1066: self.ammo_cells = 255;
1067: self.armorvalue = 1;
1068: self.armortype = 0.8;
1069: self.health = 100;
1070: }
1071: self.super_damage_finished = 0;
1072: self.super_time = 0;
1073: }
1074: if (self.super_damage_finished > time)
1075: {
1076: self.effects = self.effects | EF_DIMLIGHT;
1077: self.effects = self.effects | EF_BLUE;
1078: }
1079: else
1080: {
1081: self.effects = self.effects - (self.effects & EF_DIMLIGHT);
1082: self.effects = self.effects - (self.effects & EF_BLUE);
1083: }
1084: }
1085:
1086: // suit
1087: if (self.radsuit_finished)
1088: {
1089: self.air_finished = time + 12; // don't drown
1090:
1091: // sound and screen flash when items starts to run out
1092: if (self.radsuit_finished < time + 3)
1093: {
1094: if (self.rad_time == 1)
1095: {
1096: sprint (self, PRINT_HIGH, "Air supply in Biosuit expiring\n");
1097: stuffcmd (self, "bf\n");
1098: sound (self, CHAN_AUTO, "items/suit2.wav", 1, ATTN_NORM);
1099: self.rad_time = time + 1;
1100: }
1101:
1102: if (self.rad_time < time)
1103: {
1104: self.rad_time = time + 1;
1105: stuffcmd (self, "bf\n");
1106: }
1107: }
1108:
1109: if (self.radsuit_finished < time)
1110: { // just stopped
1111: self.items = self.items - IT_SUIT;
1112: self.rad_time = 0;
1113: self.radsuit_finished = 0;
1114: }
1115: }
1116:
1117: };
1118:
1119:
1120: /*
1121: ================
1122: PlayerPostThink
1123:
1124: Called every frame after physics are run
1125: ================
1126: */
1127: void() PlayerPostThink =
1128: {
1129: local float mspeed, aspeed;
1130: local float r;
1131:
1132: //dprint ("post think\n");
1133: if (self.view_ofs == '0 0 0')
1134: return; // intermission or finale
1135: if (self.deadflag)
1136: return;
1137:
1138: // check to see if player landed and play landing sound
1139: if ((self.jump_flag < -300) && (self.flags & FL_ONGROUND) )
1140: {
1141: if (self.watertype == CONTENT_WATER)
1142: sound (self, CHAN_BODY, "player/h2ojump.wav", 1, ATTN_NORM);
1143: else if (self.jump_flag < -650)
1144: {
1145: self.deathtype = "falling";
1146: T_Damage (self, world, world, 5);
1147: sound (self, CHAN_VOICE, "player/land2.wav", 1, ATTN_NORM);
1148: }
1149: else
1150: sound (self, CHAN_VOICE, "player/land.wav", 1, ATTN_NORM);
1151: }
1152:
1153: self.jump_flag = self.velocity_z;
1154:
1155: CheckPowerups ();
1156:
1157: W_WeaponFrame ();
1158:
1159: };
1160:
1161:
1162: /*
1163: ===========
1164: ClientConnect
1165:
1166: called when a player connects to a server
1167: ============
1168: */
1169: void() ClientConnect =
1170: {
1171: bprint (PRINT_HIGH, self.netname);
1172: bprint (PRINT_HIGH, " entered the game\n");
1173:
1174: // a client connecting during an intermission can cause problems
1175: if (intermission_running)
1176: GotoNextMap ();
1177: };
1178:
1179:
1180: /*
1181: ===========
1182: ClientDisconnect
1183:
1184: called when a player disconnects from a server
1185: ============
1186: */
1187: void() ClientDisconnect =
1188: {
1189: // let everyone else know
1190: bprint (PRINT_HIGH, self.netname);
1191: bprint (PRINT_HIGH, " left the game with ");
1192: bprint (PRINT_HIGH, ftos(self.frags));
1193: bprint (PRINT_HIGH, " frags\n");
1194: sound (self, CHAN_BODY, "player/tornoff2.wav", 1, ATTN_NONE);
1195: set_suicide_frame ();
1196: };
1197:
1198: /*
1199: ===========
1200: ClientObituary
1201:
1202: called when a player dies
1203: ============
1204: */
1205:
1206: void(entity targ, entity attacker) ClientObituary =
1207: {
1208: local float rnum;
1209: local string deathstring, deathstring2;
1210: local string s;
1211: local string attackerteam, targteam;
1212:
1213: rnum = random();
1214: //ZOID 12-13-96: self.team doesn't work in QW. Use keys
1215: attackerteam = infokey(attacker, "team");
1216: targteam = infokey(targ, "team");
1217:
1218: if (targ.classname == "player")
1219: {
1220:
1221: if (deathmatch > 3)
1222: {
1223: if (targ.deathtype == "selfwater")
1224: {
1225: bprint (PRINT_MEDIUM, targ.netname);
1226: bprint (PRINT_MEDIUM," electrocutes himself.\n ");
1227: targ.frags = targ.frags - 1;
1228: return;
1229: }
1230: }
1231:
1232: if (attacker.classname == "teledeath")
1233: {
1234: bprint (PRINT_MEDIUM,targ.netname);
1235: bprint (PRINT_MEDIUM," was telefragged by ");
1236: bprint (PRINT_MEDIUM,attacker.owner.netname);
1237: bprint (PRINT_MEDIUM,"\n");
1238: logfrag (attacker.owner, targ);
1239:
1240: attacker.owner.frags = attacker.owner.frags + 1;
1241: return;
1242: }
1243:
1244: if (attacker.classname == "teledeath2")
1245: {
1246: bprint (PRINT_MEDIUM,"Satan's power deflects ");
1247: bprint (PRINT_MEDIUM,targ.netname);
1248: bprint (PRINT_MEDIUM,"'s telefrag\n");
1249:
1250: targ.frags = targ.frags - 1;
1251: logfrag (targ, targ);
1252: return;
1253: }
1254:
1255: // double 666 telefrag (can happen often in deathmatch 4)
1256: if (attacker.classname == "teledeath3")
1257: {
1258: bprint (PRINT_MEDIUM,targ.netname);
1259: bprint (PRINT_MEDIUM," was telefragged by ");
1260: bprint (PRINT_MEDIUM,attacker.owner.netname);
1261: bprint (PRINT_MEDIUM, "'s Satan's power\n");
1262: targ.frags = targ.frags - 1;
1263: logfrag (targ, targ);
1264: return;
1265: }
1266:
1267:
1268: if (targ.deathtype == "squish")
1269: {
1270: if (teamplay && targteam == attackerteam && attackerteam != "" && targ != attacker)
1271: {
1272: logfrag (attacker, attacker);
1273: attacker.frags = attacker.frags - 1;
1274: bprint (PRINT_MEDIUM,attacker.netname);
1275: bprint (PRINT_MEDIUM," squished a teammate\n");
1276: return;
1277: }
1278: else if (attacker.classname == "player" && attacker != targ)
1279: {
1280: bprint (PRINT_MEDIUM, attacker.netname);
1281: bprint (PRINT_MEDIUM," squishes ");
1282: bprint (PRINT_MEDIUM,targ.netname);
1283: bprint (PRINT_MEDIUM,"\n");
1284: logfrag (attacker, targ);
1285: attacker.frags = attacker.frags + 1;
1286: return;
1287: }
1288: else
1289: {
1290: logfrag (targ, targ);
1291: targ.frags = targ.frags - 1; // killed self
1292: bprint (PRINT_MEDIUM,targ.netname);
1293: bprint (PRINT_MEDIUM," was squished\n");
1294: return;
1295: }
1296: }
1297:
1298: if (attacker.classname == "player")
1299: {
1300: if (targ == attacker)
1301: {
1302: // killed self
1303: logfrag (attacker, attacker);
1304: attacker.frags = attacker.frags - 1;
1305: bprint (PRINT_MEDIUM,targ.netname);
1306: if (targ.deathtype == "grenade")
1307: bprint (PRINT_MEDIUM," tries to put the pin back in\n");
1308: else if (targ.deathtype == "rocket")
1309: bprint (PRINT_MEDIUM," becomes bored with life\n");
1310: else if (targ.weapon == 64 && targ.waterlevel > 1)
1311: {
1312: if (targ.watertype == CONTENT_SLIME)
1313: bprint (PRINT_MEDIUM," discharges into the slime\n");
1314: else if (targ.watertype == CONTENT_LAVA)
1315: bprint (PRINT_MEDIUM," discharges into the lava\n");
1316: else
1317: bprint (PRINT_MEDIUM," discharges into the water.\n");
1318: }
1319: else
1320: bprint (PRINT_MEDIUM," becomes bored with life\n");
1321: return;
1322: }
1323: else if ( (teamplay == 2) && (targteam == attackerteam) &&
1324: (attackerteam != "") )
1325: {
1326: if (rnum < 0.25)
1327: deathstring = " mows down a teammate\n";
1328: else if (rnum < 0.50)
1329: deathstring = " checks his glasses\n";
1330: else if (rnum < 0.75)
1331: deathstring = " gets a frag for the other team\n";
1332: else
1333: deathstring = " loses another friend\n";
1334: bprint (PRINT_MEDIUM, attacker.netname);
1335: bprint (PRINT_MEDIUM, deathstring);
1336: attacker.frags = attacker.frags - 1;
1337: //ZOID 12-13-96: killing a teammate logs as suicide
1338: logfrag (attacker, attacker);
1339: return;
1340: }
1341: else
1342: {
1343: logfrag (attacker, targ);
1344: attacker.frags = attacker.frags + 1;
1345:
1346: rnum = attacker.weapon;
1347: if (targ.deathtype == "nail")
1348: {
1349: deathstring = " was nailed by ";
1350: deathstring2 = "\n";
1351: }
1352: else if (targ.deathtype == "supernail")
1353: {
1354: deathstring = " was punctured by ";
1355: deathstring2 = "\n";
1356: }
1357: else if (targ.deathtype == "grenade")
1358: {
1359: deathstring = " eats ";
1360: deathstring2 = "'s pineapple\n";
1361: if (targ.health < -40)
1362: {
1363: deathstring = " was gibbed by ";
1364: deathstring2 = "'s grenade\n";
1365: }
1366: }
1367: else if (targ.deathtype == "rocket")
1368: {
1369: if (attacker.super_damage_finished > 0 && targ.health < -40)
1370: {
1371: rnum = random();
1372: if (rnum < 0.3)
1373: deathstring = " was brutalized by ";
1374: else if (rnum < 0.6)
1375: deathstring = " was smeared by ";
1376: else
1377: {
1378: bprint (PRINT_MEDIUM, attacker.netname);
1379: bprint (PRINT_MEDIUM, " rips ");
1380: bprint (PRINT_MEDIUM, targ.netname);
1381: bprint (PRINT_MEDIUM, " a new one\n");
1382: return;
1383: }
1384: deathstring2 = "'s quad rocket\n";
1385: }
1386: else
1387: {
1388: deathstring = " rides ";
1389: deathstring2 = "'s rocket\n";
1390: if (targ.health < -40)
1391: {
1392: deathstring = " was gibbed by ";
1393: deathstring2 = "'s rocket\n" ;
1394: }
1395: }
1396: }
1397: else if (rnum == IT_AXE)
1398: {
1399: deathstring = " was ax-murdered by ";
1400: deathstring2 = "\n";
1401: }
1402: else if (rnum == IT_SHOTGUN)
1403: {
1404: deathstring = " chewed on ";
1405: deathstring2 = "'s boomstick\n";
1406: }
1407: else if (rnum == IT_SUPER_SHOTGUN)
1408: {
1409: deathstring = " ate 2 loads of ";
1410: deathstring2 = "'s buckshot\n";
1411: }
1412: else if (rnum == IT_LIGHTNING)
1413: {
1414: deathstring = " accepts ";
1415: if (attacker.waterlevel > 1)
1416: deathstring2 = "'s discharge\n";
1417: else
1418: deathstring2 = "'s shaft\n";
1419: }
1420: bprint (PRINT_MEDIUM,targ.netname);
1421: bprint (PRINT_MEDIUM,deathstring);
1422: bprint (PRINT_MEDIUM,attacker.netname);
1423: bprint (PRINT_MEDIUM,deathstring2);
1424: }
1425: return;
1426: }
1427: else
1428: {
1429: logfrag (targ, targ);
1430: targ.frags = targ.frags - 1; // killed self
1431: rnum = targ.watertype;
1432:
1433: bprint (PRINT_MEDIUM,targ.netname);
1434: if (rnum == -3)
1435: {
1436: if (random() < 0.5)
1437: bprint (PRINT_MEDIUM," sleeps with the fishes\n");
1438: else
1439: bprint (PRINT_MEDIUM," sucks it down\n");
1440: return;
1441: }
1442: else if (rnum == -4)
1443: {
1444: if (random() < 0.5)
1445: bprint (PRINT_MEDIUM," gulped a load of slime\n");
1446: else
1447: bprint (PRINT_MEDIUM," can't exist on slime alone\n");
1448: return;
1449: }
1450: else if (rnum == -5)
1451: {
1452: if (targ.health < -15)
1453: {
1454: bprint (PRINT_MEDIUM," burst into flames\n");
1455: return;
1456: }
1457: if (random() < 0.5)
1458: bprint (PRINT_MEDIUM," turned into hot slag\n");
1459: else
1460: bprint (PRINT_MEDIUM," visits the Volcano God\n");
1461: return;
1462: }
1463:
1464: if (attacker.classname == "explo_box")
1465: {
1466: bprint (PRINT_MEDIUM," blew up\n");
1467: return;
1468: }
1469: if (targ.deathtype == "falling")
1470: {
1471: bprint (PRINT_MEDIUM," fell to his death\n");
1472: return;
1473: }
1474: if (targ.deathtype == "nail" || targ.deathtype == "supernail")
1475: {
1476: bprint (PRINT_MEDIUM," was spiked\n");
1477: return;
1478: }
1479: if (targ.deathtype == "laser")
1480: {
1481: bprint (PRINT_MEDIUM," was zapped\n");
1482: return;
1483: }
1484: if (attacker.classname == "fireball")
1485: {
1486: bprint (PRINT_MEDIUM," ate a lavaball\n");
1487: return;
1488: }
1489: if (attacker.classname == "trigger_changelevel")
1490: {
1491: bprint (PRINT_MEDIUM," tried to leave\n");
1492: return;
1493: }
1494:
1495: bprint (PRINT_MEDIUM," died\n");
1496: }
1497: }
1498: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.