home *** CD-ROM | disk | FTP | other *** search
/ Quake 'em / QUAKEEM.BIN / quake / programs / dropdead / client.qc < prev    next >
Encoding:
Text File  |  1996-08-21  |  37.2 KB  |  1,644 lines

  1. // prototypes
  2. void() W_WeaponFrame;
  3. void() W_SetCurrentAmmo;
  4. void() player_pain;
  5. void() player_stand1;
  6. void (vector org) spawn_tfog;
  7. void (vector org, entity death_owner) spawn_tdeath;
  8.  
  9. float    modelindex_eyes, modelindex_player;
  10.  
  11. // DM code
  12. entity connect_player;
  13.  
  14. /*
  15. =============================================================================
  16.  
  17.                 LEVEL CHANGING / INTERMISSION
  18.  
  19. =============================================================================
  20. */
  21.  
  22. float    intermission_running;
  23. float    intermission_exittime;
  24. float button_pressed;
  25.  
  26. /*QUAKED info_intermission (1 0.5 0.5) (-16 -16 -16) (16 16 16)
  27. This is the camera point for the intermission.
  28. Use mangle instead of angle, so you can set pitch or roll as well as yaw.  'pitch roll yaw'
  29. */
  30. void() info_intermission =
  31. {
  32. };
  33.  
  34.  
  35. void() ResetParms =
  36. {
  37.     parm1 = IT_SHOTGUN | IT_AXE;
  38.     parm2 = 100;
  39.     parm3 = 0;
  40.     parm4 = 25;
  41.     parm5 = 0;
  42.     parm6 = 0;
  43.     parm6 = 0;
  44.     parm8 = 1;
  45.     parm9 = 0;
  46.     // DM code
  47.     parm10 = self.skin;
  48.     parm11 = self.start_team;
  49. };
  50.  
  51. void() SetChangeParms =
  52. {
  53. // remove items
  54.     self.items = self.items - (self.items & 
  55.     (IT_KEY1 | IT_KEY2 | IT_INVISIBILITY | IT_INVULNERABILITY | IT_SUIT | IT_QUAD) );
  56.     
  57. // cap super health
  58.     if (self.health > 100)
  59.         self.health = 100;
  60.     if (self.health < 50)
  61.         self.health = 50;
  62.     parm1 = self.items;
  63.     parm2 = self.health;
  64.     parm3 = self.armorvalue;
  65.     if (self.ammo_shells < 25)
  66.         parm4 = 25;
  67.     else
  68.         parm4 = self.ammo_shells;
  69.     parm5 = self.ammo_nails;
  70.     parm6 = self.ammo_rockets;
  71.     parm7 = self.ammo_cells;
  72.     parm8 = self.weapon;
  73.     parm9 = self.armortype * 100;
  74.     // DM code
  75.     parm10 = self.skin;
  76.     parm11 = self.start_team;
  77. };
  78.  
  79. void() SetNewParms =
  80. {
  81.     parm1 = IT_SHOTGUN | IT_AXE;
  82.     parm2 = 100;
  83.     parm3 = 0;
  84.     parm4 = 25;
  85.     parm5 = 0;
  86.     parm6 = 0;
  87.     parm6 = 0;
  88.     parm8 = 1;
  89.     parm9 = 0;
  90.     // DM code
  91.     parm10 = 0;
  92.     parm11 = 0;
  93. };
  94.  
  95. void() DecodeLevelParms =
  96. {
  97.     if (serverflags)
  98.     {
  99.         if (world.model == "maps/start.bsp")
  100.             ResetParms ();        // take away all stuff on starting new episode
  101.     }
  102.     
  103.     self.items = parm1;
  104.     self.health = parm2;
  105.     self.armorvalue = parm3;
  106.     self.ammo_shells = parm4;
  107.     self.ammo_nails = parm5;
  108.     self.ammo_rockets = parm6;
  109.     self.ammo_cells = parm7;
  110.     self.weapon = parm8;
  111.     self.armortype = parm9 * 0.01;
  112.     self.skin = parm10;
  113.     self.start_team = parm11;
  114. };
  115.  
  116. /*
  117. ============
  118. FindIntermission
  119.  
  120. Returns the entity to view from
  121. ============
  122. */
  123. entity() FindIntermission =
  124. {
  125.     local    entity spot;
  126.     local    float cyc;
  127.  
  128. // look for info_intermission first
  129.     spot = find (world, classname, "info_intermission");
  130.     if (spot)
  131.     {    // pick a random one
  132.         cyc = random() * 4;
  133.         while (cyc > 1)
  134.         {
  135.             spot = find (spot, classname, "info_intermission");
  136.             if (!spot)
  137.                 spot = find (spot, classname, "info_intermission");
  138.             cyc = cyc - 1;
  139.         }
  140.         return spot;
  141.     }
  142.  
  143. // then look for the start position
  144.     spot = find (world, classname, "info_player_start");
  145.     if (spot)
  146.         return spot;
  147.     
  148. // testinfo_player_start is only found in regioned levels
  149.     spot = find (world, classname, "testplayerstart");
  150.     if (spot)
  151.         return spot;
  152.     
  153.     objerror ("FindIntermission: no spot");
  154. };
  155.  
  156.  
  157. string nextmap;
  158. void() GotoNextMap =
  159. {
  160.     if (cvar("samelevel"))    // if samelevel is set, stay on same level
  161.         changelevel (mapname);
  162.     else
  163.         changelevel (nextmap);
  164. };
  165.  
  166.  
  167. void() ExitIntermission =
  168. {
  169. // skip any text in deathmatch
  170.     if (deathmatch)
  171.     {
  172.         GotoNextMap ();
  173.         return;
  174.     }
  175.     
  176.     intermission_exittime = time + 1;
  177.     intermission_running = intermission_running + 1;
  178.  
  179. //
  180. // run some text if at the end of an episode
  181. //
  182.     if (intermission_running == 2)
  183.     {
  184.         if (world.model == "maps/e1m7.bsp")
  185.         {
  186.             WriteByte (MSG_ALL, SVC_CDTRACK);
  187.             WriteByte (MSG_ALL, 2);
  188.             WriteByte (MSG_ALL, 3);
  189.             if (!cvar("registered"))
  190.             {
  191.                 WriteByte (MSG_ALL, SVC_FINALE);
  192.                 WriteString (MSG_ALL, "As the corpse of the monstrous entity\nChthon sinks back into the lava whence\nit rose, you grip the Rune of Earth\nMagic tightly. Now that you have\nconquered the Dimension of the Doomed,\nrealm of Earth Magic, you are ready to\ncomplete your task in the other three\nhaunted lands of Quake. Or are you? If\nyou don't register Quake, you'll never\nknow what awaits you in the Realm of\nBlack Magic, the Netherworld, and the\nElder World!");
  193.             }
  194.             else
  195.             {
  196.                 WriteByte (MSG_ALL, SVC_FINALE);
  197.                 WriteString (MSG_ALL, "As the corpse of the monstrous entity\nChthon sinks back into the lava whence\nit rose, you grip the Rune of Earth\nMagic tightly. Now that you have\nconquered the Dimension of the Doomed,\nrealm of Earth Magic, you are ready to\ncomplete your task. A Rune of magic\npower lies at the end of each haunted\nland of Quake. Go forth, seek the\ntotality of the four Runes!");
  198.             }
  199.             return;
  200.         }
  201.         else if (world.model == "maps/e2m6.bsp")
  202.         {
  203.             WriteByte (MSG_ALL, SVC_CDTRACK);
  204.             WriteByte (MSG_ALL, 2);
  205.             WriteByte (MSG_ALL, 3);
  206.  
  207.             WriteByte (MSG_ALL, SVC_FINALE);
  208.             WriteString (MSG_ALL, "The Rune of Black Magic throbs evilly in\nyour hand and whispers dark thoughts\ninto your brain. You learn the inmost\nlore of the Hell-Mother; Shub-Niggurath!\nYou now know that she is behind all the\nterrible plotting which has led to so\nmuch death and horror. But she is not\ninviolate! Armed with this Rune, you\nrealize that once all four Runes are\ncombined, the gate to Shub-Niggurath's\nPit will open, and you can face the\nWitch-Goddess herself in her frightful\notherworld cathedral.");
  209.             return;
  210.         }
  211.         else if (world.model == "maps/e3m6.bsp")
  212.         {
  213.             WriteByte (MSG_ALL, SVC_CDTRACK);
  214.             WriteByte (MSG_ALL, 2);
  215.             WriteByte (MSG_ALL, 3);
  216.  
  217.             WriteByte (MSG_ALL, SVC_FINALE);
  218.             WriteString (MSG_ALL, "The charred viscera of diabolic horrors\nbubble viscously as you seize the Rune\nof Hell Magic. Its heat scorches your\nhand, and its terrible secrets blight\nyour mind. Gathering the shreds of your\ncourage, you shake the devil's shackles\nfrom your soul, and become ever more\nhard and determined to destroy the\nhideous creatures whose mere existence\nthreatens the souls and psyches of all\nthe population of Earth.");
  219.             return;
  220.         }
  221.         else if (world.model == "maps/e4m7.bsp")
  222.         {
  223.             WriteByte (MSG_ALL, SVC_CDTRACK);
  224.             WriteByte (MSG_ALL, 2);
  225.             WriteByte (MSG_ALL, 3);
  226.  
  227.             WriteByte (MSG_ALL, SVC_FINALE);
  228.             WriteString (MSG_ALL, "Despite the awful might of the Elder\nWorld, you have achieved the Rune of\nElder Magic, capstone of all types of\narcane wisdom. Beyond good and evil,\nbeyond life and death, the Rune\npulsates, heavy with import. Patient and\npotent, the Elder Being Shub-Niggurath\nweaves her dire plans to clear off all\nlife from the Earth, and bring her own\nfoul offspring to our world! For all the\ndwellers in these nightmare dimensions\nare her descendants! Once all Runes of\nmagic power are united, the energy\nbehind them will blast open the Gateway\nto Shub-Niggurath, and you can travel\nthere to foil the Hell-Mother's plots\nin person.");
  229.             return;
  230.         }
  231.  
  232.         GotoNextMap();
  233.     }
  234.     
  235.     if (intermission_running == 3)
  236.     {
  237.         if (!cvar("registered"))
  238.         {    // shareware episode has been completed, go to sell screen
  239.             WriteByte (MSG_ALL, SVC_SELLSCREEN);
  240.             return;
  241.         }
  242.         
  243.         if ( (serverflags&15) == 15)
  244.         {
  245.             WriteByte (MSG_ALL, SVC_FINALE);
  246.             WriteString (MSG_ALL, "Now, you have all four Runes. You sense\ntremendous invisible forces moving to\nunseal ancient barriers. Shub-Niggurath\nhad hoped to use the Runes Herself to\nclear off the Earth, but now instead,\nyou will use them to enter her home and\nconfront her as an avatar of avenging\nEarth-life. If you defeat her, you will\nbe remembered forever as the savior of\nthe planet. If she conquers, it will be\nas if you had never been born.");
  247.             return;
  248.         }
  249.         
  250.     }
  251.  
  252.     GotoNextMap();
  253. };
  254.  
  255. /*
  256. ============
  257. IntermissionThink
  258.  
  259. When the player presses attack or jump, change to the next level
  260. ============
  261. */
  262. void() IntermissionThink =
  263. {
  264.     if (time < intermission_exittime)
  265.         return;
  266.  
  267.     if (time < intermission_exittime + 10)
  268.     {
  269.         if (!button_pressed)
  270.         {
  271.             if (self.button0 || self.button1 || self.button2)
  272.                 button_pressed = 1;
  273.             return;
  274.         }
  275.         else
  276.         {
  277.             if (self.button0 || self.button1 || self.button2)
  278.                 return;
  279.         }
  280.     }
  281.     
  282.     ExitIntermission ();
  283. };
  284.  
  285. void() execute_changelevel =
  286. {
  287.     local entity    pos;
  288.  
  289.     intermission_running = 1;
  290.     
  291. // enforce a wait time before allowing changelevel
  292.     if (deathmatch)
  293.         intermission_exittime = time + 5;
  294.     else
  295.         intermission_exittime = time + 2;
  296.     button_pressed = 0;
  297.  
  298.     WriteByte (MSG_ALL, SVC_CDTRACK);
  299.     WriteByte (MSG_ALL, 3);
  300.     WriteByte (MSG_ALL, 3);
  301.     
  302.     pos = FindIntermission ();
  303.  
  304.     other = find (world, classname, "player");
  305.     while (other != world)
  306.     {
  307.         other.view_ofs = '0 0 0';
  308.         other.angles = other.v_angle = pos.mangle;
  309.         other.fixangle = TRUE;        // turn this way immediately
  310.         other.nextthink = time + 0.5;
  311.         other.takedamage = DAMAGE_NO;
  312.         other.solid = SOLID_NOT;
  313.         other.movetype = MOVETYPE_NONE;
  314.         other.modelindex = 0;
  315.         setorigin (other, pos.origin);
  316.         other = find (other, classname, "player");
  317.     }    
  318.  
  319.     WriteByte (MSG_ALL, SVC_INTERMISSION);
  320. };
  321.  
  322.  
  323. void() changelevel_touch =
  324. {
  325.     // DM code
  326.     if ( teamplay && (deathmatch || coop) )
  327.         connect_player.check_team_time = time + 0.5;
  328.  
  329.     if (other.classname != "player")
  330.         return;
  331.  
  332.     if (cvar("noexit"))
  333.     {
  334.         T_Damage (other, self, self, 50000);
  335.         return;
  336.     }
  337.  
  338.     bprint (other.netname);
  339.     bprint (" exited the level\n");
  340.     
  341.     nextmap = self.map;
  342.  
  343.     SUB_UseTargets ();
  344.  
  345.     if ( (self.spawnflags & 1) && (deathmatch == 0) )
  346.     {    // NO_INTERMISSION
  347.         GotoNextMap();
  348.         return;
  349.     }
  350.     
  351.     self.touch = SUB_Null;
  352.  
  353. // we can't move people right now, because touch functions are called
  354. // in the middle of C movement code, so set a think time to do it
  355.     self.think = execute_changelevel;
  356.     self.nextthink = time + 0.1;
  357. };
  358.  
  359. /* QUAKED trigger_changelevel (0.5 0.5 0.5) ? NO_INTERMISSION
  360. When the player touches this, he gets sent to the map listed in the "map"
  361. variable.  Unless the NO_INTERMISSION flag is set, the view will go to the
  362. info_intermission spot and display stats.
  363. */
  364. void() trigger_changelevel =
  365. {
  366.     if (!self.map)
  367.         objerror ("changelevel trigger doesn't have map");
  368.     
  369.     InitTrigger ();
  370.     self.touch = changelevel_touch;
  371. };
  372.  
  373.  
  374. /*
  375. =============================================================================
  376.  
  377.                 PLAYER GAME EDGE FUNCTIONS
  378.  
  379. =============================================================================
  380. */
  381.  
  382. void() set_suicide_frame;
  383.  
  384. // called by ClientKill and DeadThink
  385. void() respawn =
  386. {
  387.     if (coop)
  388.     {
  389.         // make a copy of the dead body for appearances sake
  390.         CopyToBodyQue (self);
  391.         // get the spawn parms as they were at level start
  392.         setspawnparms (self);
  393.         // respawn        
  394.         PutClientInServer ();
  395.     }
  396.     else if (deathmatch)
  397.     {
  398.         // make a copy of the dead body for appearances sake
  399.         CopyToBodyQue (self);
  400.         // DM code
  401.         ResetParms ();
  402.         // respawn        
  403.         PutClientInServer ();
  404.     }
  405.     else
  406.     {    // restart the entire server
  407.         localcmd ("restart\n");
  408.     }
  409. };
  410.  
  411.  
  412. /*
  413. ============
  414. ClientKill
  415.  
  416. Player entered the suicide command
  417. ============
  418. */
  419. void() ClientKill =
  420. {
  421.     bprint (self.netname);
  422.     bprint (" suicides\n");
  423.     set_suicide_frame ();
  424.     self.modelindex = modelindex_player;
  425.     self.frags = self.frags - 2;    // extra penalty
  426.     respawn ();
  427. };
  428.  
  429. float(vector v) CheckSpawnPoint =
  430. {
  431.     return FALSE;
  432. };
  433.  
  434. /*
  435. ============
  436. SelectSpawnPoint
  437.  
  438. Returns the entity to spawn at
  439. ============
  440. */
  441. entity() SelectSpawnPoint =
  442. {
  443.     local    entity spot;
  444.     
  445. // testinfo_player_start is only found in regioned levels
  446.     spot = find (world, classname, "testplayerstart");
  447.     if (spot)
  448.         return spot;
  449.         
  450. // choose a info_player_deathmatch point
  451.     if (coop)
  452.     {
  453.         lastspawn = find(lastspawn, classname, "info_player_coop");
  454.         if (lastspawn == world)
  455.             lastspawn = find (lastspawn, classname, "info_player_start");
  456.         if (lastspawn != world)
  457.             return lastspawn;
  458.     }
  459.     else if (deathmatch)
  460.     {
  461.         lastspawn = find(lastspawn, classname, "info_player_deathmatch");
  462.         if (lastspawn == world)
  463.             lastspawn = find (lastspawn, classname, "info_player_deathmatch");
  464.         if (lastspawn != world)
  465.             return lastspawn;
  466.     }
  467.  
  468.     if (serverflags)
  469.     {    // return with a rune to start
  470.         spot = find (world, classname, "info_player_start2");
  471.         if (spot)
  472.             return spot;
  473.     }
  474.     
  475.     spot = find (world, classname, "info_player_start");
  476.     if (!spot)
  477.         error ("PutClientInServer: no info_player_start on level");
  478.     
  479.     return spot;
  480. };
  481.  
  482. /*
  483. ===========
  484. PutClientInServer
  485.  
  486. called each time a player is spawned
  487. ============
  488. */
  489. void() PlayerDie;
  490. // DM function.
  491. void() PlayerTouch;
  492.  
  493.  
  494. void() PutClientInServer =
  495. {
  496.     local    entity spot;
  497.  
  498.     self.classname = "player";
  499.     self.health = 100;
  500.     self.takedamage = DAMAGE_AIM;
  501.     self.solid = SOLID_SLIDEBOX;
  502.     self.movetype = MOVETYPE_WALK;
  503.     self.show_hostile = 0;
  504.     self.max_health = 100;
  505.     self.flags = FL_CLIENT;
  506.     self.air_finished = time + 12;
  507.     self.dmg = 2;           // initial water damage
  508.     self.super_damage_finished = 0;
  509.     self.radsuit_finished = 0;
  510.     self.invisible_finished = 0;
  511.     self.invincible_finished = 0;
  512.     self.effects = 0;
  513.     self.invincible_time = 0;
  514.  
  515.     DecodeLevelParms ();
  516.  
  517.     W_SetCurrentAmmo ();
  518.  
  519.     self.attack_finished = time;
  520.     self.th_pain = player_pain;
  521.     self.th_die = PlayerDie;
  522.  
  523.     // DM code.
  524.     self.touch = PlayerTouch;
  525.  
  526.     self.deadflag = DEAD_NO;
  527. // paustime is set by teleporters to keep the player from moving a while
  528.     self.pausetime = 0;
  529.     
  530.     spot = SelectSpawnPoint ();
  531.  
  532.     self.origin = spot.origin + '0 0 1';
  533.     self.angles = spot.angles;
  534.     self.fixangle = TRUE;        // turn this way immediately
  535.  
  536. // oh, this is a hack!
  537.     setmodel (self, "progs/eyes.mdl");
  538.     modelindex_eyes = self.modelindex;
  539.  
  540.     setmodel (self, "progs/player.mdl");
  541.     modelindex_player = self.modelindex;
  542.  
  543.     setsize (self, VEC_HULL_MIN, VEC_HULL_MAX);
  544.     
  545.     self.view_ofs = '0 0 22';
  546.  
  547.     player_stand1 ();
  548.     
  549.     if (deathmatch || coop)
  550.     {
  551.         makevectors(self.angles);
  552.         spawn_tfog (self.origin + v_forward*20);
  553.     }
  554.  
  555.     spawn_tdeath (self.origin, self);
  556.  
  557. /* Code used only for skin testing.
  558. local entity test;
  559. test = spawn();
  560. test.skin = 18;
  561. test.health = 100;
  562. test.takedamage = DAMAGE_AIM;
  563. test.solid = SOLID_SLIDEBOX;
  564. test.movetype = MOVETYPE_STEP;
  565. test.show_hostile = 0;
  566. test.max_health = 100;
  567. test.th_pain = player_pain;
  568. test.th_die = PlayerDie;
  569. setmodel (test, "progs/player.mdl");
  570. setsize (test, VEC_HULL_MIN, VEC_HULL_MAX);
  571. setorigin (test, self.origin + '40 80 0');
  572. test.velocity = '0 0 0';
  573. test.nextthink = -1;
  574. test.think = SUB_Null;
  575. test.classname = "";
  576. test.frame = 0;
  577. test.cnt = 0;
  578. */
  579. };
  580.  
  581.  
  582. /*
  583. =============================================================================
  584.  
  585.                 QUAKED FUNCTIONS
  586.  
  587. =============================================================================
  588. */
  589.  
  590.  
  591. /*QUAKED info_player_start (1 0 0) (-16 -16 -24) (16 16 24)
  592. The normal starting point for a level.
  593. */
  594. void() info_player_start =
  595. {
  596. };
  597.  
  598.  
  599. /*QUAKED info_player_start2 (1 0 0) (-16 -16 -24) (16 16 24)
  600. Only used on start map for the return point from an episode.
  601. */
  602. void() info_player_start2 =
  603. {
  604. };
  605.  
  606.  
  607. /*
  608. saved out by quaked in region mode
  609. */
  610. void() testplayerstart =
  611. {
  612. };
  613.  
  614. /*QUAKED info_player_deathmatch (1 0 1) (-16 -16 -24) (16 16 24)
  615. potential spawning position for deathmatch games
  616. */
  617. void() info_player_deathmatch =
  618. {
  619. };
  620.  
  621. /*QUAKED info_player_coop (1 0 1) (-16 -16 -24) (16 16 24)
  622. potential spawning position for coop games
  623. */
  624. void() info_player_coop =
  625. {
  626. };
  627.  
  628. /*
  629. ===============================================================================
  630.  
  631. RULES
  632.  
  633. ===============================================================================
  634. */
  635.  
  636. void(entity c) PrintClientScore =
  637. {
  638.     if (c.frags > -10 && c.frags < 0)
  639.         bprint (" ");
  640.     else if (c.frags >= 0)
  641.     {
  642.         if (c.frags < 100)
  643.             bprint (" ");
  644.         if (c.frags < 10)
  645.             bprint (" ");
  646.     }
  647.     bprint (ftos(c.frags));
  648.     bprint (" ");
  649.     bprint (c.netname);
  650.     bprint ("\n");
  651. };
  652.  
  653. void() DumpScore =
  654. {
  655.     local entity    e, sort, walk;
  656.  
  657.     if (world.chain)
  658.         error ("DumpScore: world.chain is set");
  659.  
  660. // build a sorted lis
  661.     e = find(world, classname, "player");
  662.     sort = world;
  663.     while (e)
  664.     {
  665.         if (!sort)
  666.         {
  667.             sort = e;
  668.             e.chain = world;
  669.         }
  670.         else
  671.         {
  672.             if (e.frags > sort.frags)
  673.             {
  674.                 e.chain = sort;
  675.                 sort = e;
  676.             }
  677.             else
  678.             {
  679.                 walk = sort;
  680.                 do
  681.                 {
  682.                     if (!walk.chain)
  683.                     {
  684.                         e.chain = world;
  685.                         walk.chain = e;
  686.                     }
  687.                     else if (walk.chain.frags < e.frags)
  688.                     {
  689.                         e.chain = walk.chain;
  690.                         walk.chain = e;
  691.                     }
  692.                     else
  693.                         walk = walk.chain;
  694.                 } while (walk.chain != e);
  695.             }
  696.         }
  697.         
  698.         e = find(e, classname, "player");
  699.     }
  700.  
  701. // print the list
  702.     
  703.     bprint ("\n");    
  704.     while (sort)
  705.     {
  706.         PrintClientScore (sort);
  707.         sort = sort.chain;
  708.     }
  709.     bprint ("\n");
  710. };
  711.  
  712. /*
  713. go to the next level for deathmatch
  714. */
  715. void() NextLevel =
  716. {
  717.     local entity o;
  718.  
  719. // find a trigger changelevel
  720.     o = find(world, classname, "trigger_changelevel");
  721.     if (!o || mapname == "start")
  722.     {    // go back to same map if no trigger_changelevel
  723.         o = spawn();
  724.         o.map = mapname;
  725.     }
  726.  
  727.     nextmap = o.map;
  728.     
  729.     if (o.nextthink < time)
  730.     {
  731.         o.think = execute_changelevel;
  732.         o.nextthink = time + 0.1;
  733.     }
  734. };
  735.  
  736. /*
  737. ============
  738. CheckRules
  739.  
  740. Exit deathmatch games upon conditions
  741. ============
  742. */
  743. void() CheckRules =
  744. {
  745.     local    float        timelimit;
  746.     local    float        fraglimit;
  747.  
  748.     if (gameover)    // someone else quit the game already
  749.         return;
  750.  
  751.     timelimit = cvar("timelimit") * 60;
  752.     fraglimit = cvar("fraglimit");
  753.  
  754.     if (timelimit && time >= timelimit)
  755.     {
  756. NextLevel ();
  757. /*
  758.         gameover = TRUE;
  759.         bprint ("\n\n\n==============================\n");
  760.         bprint ("game exited after ");
  761.         bprint (ftos(timelimit/60));
  762.         bprint (" minutes\n");
  763.         DumpScore ();
  764.         localcmd ("killserver\n");
  765. */
  766.         return;
  767.     }
  768.     
  769.     if (fraglimit && self.frags >= fraglimit)
  770.     {
  771. NextLevel ();
  772. /*
  773.         gameover = TRUE;
  774.         bprint ("\n\n\n==============================\n");
  775.         bprint ("game exited after ");
  776.         bprint (ftos(self.frags));
  777.         bprint (" frags\n");
  778.         DumpScore ();
  779.         localcmd ("killserver\n");
  780. */
  781.         return;
  782.     }    
  783. };
  784.  
  785. //============================================================================
  786.  
  787. void() PlayerDeathThink =
  788. {
  789.     local entity    old_self;
  790.     local float        forward;
  791.  
  792.     if ((self.flags & FL_ONGROUND))
  793.     {
  794.         forward = vlen (self.velocity);
  795.         forward = forward - 20;
  796.         if (forward <= 0)
  797.             self.velocity = '0 0 0';
  798.         else    
  799.             self.velocity = forward * normalize(self.velocity);
  800.     }
  801.  
  802. // wait for all buttons released
  803.     if (self.deadflag == DEAD_DEAD)
  804.     {
  805.         if (self.button2 || self.button1 || self.button0)
  806.             return;
  807.         self.deadflag = DEAD_RESPAWNABLE;
  808.         button_pressed = 0;
  809.         return;
  810.     }
  811.  
  812.     // Wait for any button to be pressed and released.
  813.     if (!button_pressed)
  814.     {
  815.         if (self.button2 || self.button1 || self.button0)
  816.             button_pressed = 1;
  817.         return;
  818.     }
  819.     else
  820.     {
  821.         if (self.button2 || self.button1 || self.button0)
  822.             return;
  823.     }
  824.  
  825.     // DM code
  826.     if (teamplay >= 5 && self.team == actual_team2)
  827.     {
  828.         sprint(self, "You're still IT!\n");
  829.         IT_time = time;
  830.     }
  831.     respawn();
  832. };
  833.  
  834.  
  835. void() PlayerJump =
  836. {
  837.     local vector start, end;
  838.     
  839.     if (self.flags & FL_WATERJUMP)
  840.         return;
  841.  
  842.     if (self.waterlevel >= 2)
  843.     {
  844.         if (self.watertype == CONTENT_WATER)
  845.             self.velocity_z = 100;
  846.         else if (self.watertype == CONTENT_SLIME)
  847.             self.velocity_z = 80;
  848.         else
  849.             self.velocity_z = 50;
  850.  
  851. // play swiming sound
  852.         if (self.swim_flag < time)
  853.         {
  854.             self.swim_flag = time + 1;
  855.             if (random() < 0.5)
  856.                 sound (self, CHAN_BODY, "misc/water1.wav", 1, ATTN_NORM);
  857.             else
  858.                 sound (self, CHAN_BODY, "misc/water2.wav", 1, ATTN_NORM);
  859.         }
  860.  
  861.         return;
  862.     }
  863.  
  864.     if ( !(self.flags & FL_ONGROUND) && self.velocity_z )
  865.         return;
  866.  
  867.     if ( !(self.flags & FL_JUMPRELEASED) )
  868.         return;        // don't pogo stick
  869.  
  870.     self.flags = self.flags - (self.flags & FL_JUMPRELEASED);
  871.  
  872.     self.flags = self.flags - FL_ONGROUND;    // don't stairwalk
  873.     
  874.     self.button2 = 0;
  875. // player jumping sound
  876.     sound (self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM);
  877.     self.velocity_z = self.velocity_z + 270;
  878. };
  879.  
  880.  
  881. /*
  882. ===========
  883. WaterMove
  884.  
  885. ============
  886. */
  887. .float    dmgtime;
  888.  
  889. void() WaterMove =
  890. {
  891. //dprint (ftos(self.waterlevel));
  892.     if (self.movetype == MOVETYPE_NOCLIP)
  893.         return;
  894.     if (self.health < 0)
  895.         return;
  896.  
  897.     if (self.waterlevel != 3)
  898.     {
  899.         if (self.air_finished < time)
  900.             sound (self, CHAN_VOICE, "player/gasp2.wav", 1, ATTN_NORM);
  901.         else if (self.air_finished < time + 9)
  902.             sound (self, CHAN_VOICE, "player/gasp1.wav", 1, ATTN_NORM);
  903.         self.air_finished = time + 12;
  904.         self.dmg = 2;
  905.     }
  906.     else if (self.air_finished < time)
  907.     {    // drown!
  908.         if (self.pain_finished < time)
  909.         {
  910.             self.dmg = self.dmg + 2;
  911.             if (self.dmg > 15)
  912.                 self.dmg = 10;
  913.             T_Damage (self, world, world, self.dmg);
  914.             self.pain_finished = time + 1;
  915.         }
  916.     }
  917.     
  918.     if (!self.waterlevel)
  919.     {
  920.         if (self.flags & FL_INWATER)
  921.         {    
  922.             // play leave water sound
  923.             sound (self, CHAN_BODY, "misc/outwater.wav", 1, ATTN_NORM);
  924.             self.flags = self.flags - FL_INWATER;
  925.         }
  926.         return;
  927.     }
  928.  
  929.     if (self.watertype == CONTENT_LAVA)
  930.     {    // do damage
  931.         if (self.dmgtime < time)
  932.         {
  933.             if (self.radsuit_finished > time)
  934.                 self.dmgtime = time + 1;
  935.             else
  936.                 self.dmgtime = time + 0.2;
  937.  
  938.             T_Damage (self, world, world, 10*self.waterlevel);
  939.         }
  940.     }
  941.     else if (self.watertype == CONTENT_SLIME)
  942.     {    // do damage
  943.         if (self.dmgtime < time && self.radsuit_finished < time)
  944.         {
  945.             self.dmgtime = time + 1;
  946.             T_Damage (self, world, world, 4*self.waterlevel);
  947.         }
  948.     }
  949.     
  950.     if ( !(self.flags & FL_INWATER) )
  951.     {    
  952.  
  953. // player enter water sound
  954.  
  955.         if (self.watertype == CONTENT_LAVA)
  956.             sound (self, CHAN_BODY, "player/inlava.wav", 1, ATTN_NORM);
  957.         if (self.watertype == CONTENT_WATER)
  958.             sound (self, CHAN_BODY, "player/inh2o.wav", 1, ATTN_NORM);
  959.         if (self.watertype == CONTENT_SLIME)
  960.             sound (self, CHAN_BODY, "player/slimbrn2.wav", 1, ATTN_NORM);
  961.  
  962.         self.flags = self.flags + FL_INWATER;
  963.         self.dmgtime = 0;
  964.     }
  965.     
  966.     if (! (self.flags & FL_WATERJUMP) )
  967.         self.velocity = self.velocity - 0.8*self.waterlevel*frametime*self.velocity;
  968. };
  969.  
  970. void() CheckWaterJump =
  971. {
  972.     local vector start, end;
  973.  
  974. // check for a jump-out-of-water
  975.     makevectors (self.angles);
  976.     start = self.origin;
  977.     start_z = start_z + 8; 
  978.     v_forward_z = 0;
  979.     normalize(v_forward);
  980.     end = start + v_forward*24;
  981.     traceline (start, end, TRUE, self);
  982.     if (trace_fraction < 1)
  983.     {    // solid at waist
  984.         start_z = start_z + self.maxs_z - 8;
  985.         end = start + v_forward*24;
  986.         self.movedir = trace_plane_normal * -50;
  987.         traceline (start, end, TRUE, self);
  988.         if (trace_fraction == 1)
  989.         {    // open at eye level
  990.             self.flags = self.flags | FL_WATERJUMP;
  991.             self.velocity_z = 225;
  992.             self.flags = self.flags - (self.flags & FL_JUMPRELEASED);
  993.             self.teleport_time = time + 2;    // safety net
  994.             return;
  995.         }
  996.     }
  997. };
  998.  
  999.  
  1000. /*
  1001. ================
  1002. PlayerPreThink
  1003.  
  1004. Called every frame before physics are run
  1005. ================
  1006. */
  1007. void() PlayerPreThink =
  1008. {
  1009.     if (intermission_running)
  1010.     {
  1011.         IntermissionThink ();    // otherwise a button could be missed between
  1012.         return;                    // the think tics
  1013.     }
  1014.  
  1015.     if (self.view_ofs == '0 0 0')
  1016.         return;        // intermission or finale
  1017.  
  1018.     makevectors (self.v_angle);        // is this still used
  1019.  
  1020.     CheckRules ();
  1021.     WaterMove ();
  1022.  
  1023.     if (self.waterlevel == 2)
  1024.         CheckWaterJump ();
  1025.  
  1026.     if (self.deadflag >= DEAD_DEAD)
  1027.     {
  1028.         PlayerDeathThink ();
  1029.         return;
  1030.     }
  1031.     
  1032.     if (self.deadflag == DEAD_DYING)
  1033.         return;    // dying, so do nothing
  1034.  
  1035.     // DM code - 
  1036.     // Assign new player to a team and
  1037.     // don't allow a player to change teams!
  1038.     if (self.check_team_time && time >= self.check_team_time)
  1039.     {
  1040.         if (self.start_team == 0)  // New player?
  1041.             self.impulse = 200;
  1042.         else if (self.team != self.start_team)  // Attempt to change sides?
  1043.             self.impulse = 200;
  1044.         else if (teamplay >= 5)  // Game of tag?
  1045.         {
  1046.             if (self.start_team == actual_team2  // Is player IT and alive?
  1047.                     && !self.deadflag)
  1048.             {
  1049.                 if (time == IT_time + 30)
  1050.                 {
  1051.                     sprint(self, "You're still IT!");
  1052.                     IT_time = IT_time - 0.1;
  1053.                 }
  1054.                 if (!IT_time)
  1055.                     IT_time = time;
  1056.                 else if (time >= IT_time + 60)  // Has a minute as IT passed?
  1057.                 {
  1058.                     bprint(self.netname);
  1059.                     bprint(" earned a bonus survival frag.\n");
  1060.                     self.frags = self.frags + 1;
  1061.                     IT_time = time;
  1062.                 }
  1063.             }
  1064.         }
  1065.     }
  1066.         
  1067.     if (self.button2)
  1068.     {
  1069.         PlayerJump ();
  1070.     }
  1071.     else
  1072.         self.flags = self.flags | FL_JUMPRELEASED;
  1073.  
  1074. // teleporters can force a non-moving pause time    
  1075.     if (time < self.pausetime)
  1076.         self.velocity = '0 0 0';
  1077. };
  1078.     
  1079. /*
  1080. ================
  1081. CheckPowerups
  1082.  
  1083. Check for turning off powerups
  1084. ================
  1085. */
  1086. void() CheckPowerups =
  1087. {
  1088.     if (self.health <= 0)
  1089.         return;
  1090.  
  1091. // invisibility
  1092.     if (self.invisible_finished)
  1093.     {
  1094. // sound and screen flash when items starts to run out
  1095.         if (self.invisible_sound < time)
  1096.         {
  1097.             sound (self, CHAN_AUTO, "items/inv3.wav", 0.5, ATTN_IDLE);
  1098.             self.invisible_sound = time + ((random() * 3) + 1);
  1099.         }
  1100.  
  1101.  
  1102.         if (self.invisible_finished < time + 3)
  1103.         {
  1104.             if (self.invisible_time == 1)
  1105.             {
  1106.                 sprint (self, "Ring of Shadows magic is fading\n");
  1107.                 stuffcmd (self, "bf\n");
  1108.                 sound (self, CHAN_AUTO, "items/inv2.wav", 1, ATTN_NORM);
  1109.                 self.invisible_time = time + 1;
  1110.             }
  1111.             
  1112.             if (self.invisible_time < time)
  1113.             {
  1114.                 self.invisible_time = time + 1;
  1115.                 stuffcmd (self, "bf\n");
  1116.             }
  1117.         }
  1118.  
  1119.         if (self.invisible_finished < time)
  1120.         {    // just stopped
  1121.             self.items = self.items - IT_INVISIBILITY;
  1122.             self.invisible_finished = 0;
  1123.             self.invisible_time = 0;
  1124.         }
  1125.         
  1126.     // use the eyes
  1127.         self.frame = 0;
  1128.         self.modelindex = modelindex_eyes;
  1129.     }
  1130.     else
  1131.         self.modelindex = modelindex_player;    // don't use eyes
  1132.  
  1133. // invincibility
  1134.     if (self.invincible_finished)
  1135.     {
  1136. // sound and screen flash when items starts to run out
  1137.         if (self.invincible_finished < time + 3)
  1138.         {
  1139.             if (self.invincible_time == 1)
  1140.             {
  1141.                 sprint (self, "Protection is almost burned out\n");
  1142.                 stuffcmd (self, "bf\n");
  1143.                 sound (self, CHAN_AUTO, "items/protect2.wav", 1, ATTN_NORM);
  1144.                 self.invincible_time = time + 1;
  1145.             }
  1146.             
  1147.             if (self.invincible_time < time)
  1148.             {
  1149.                 self.invincible_time = time + 1;
  1150.                 stuffcmd (self, "bf\n");
  1151.             }
  1152.         }
  1153.         
  1154.         if (self.invincible_finished < time)
  1155.         {    // just stopped
  1156.             self.items = self.items - IT_INVULNERABILITY;
  1157.             self.invincible_time = 0;
  1158.             self.invincible_finished = 0;
  1159.         }
  1160.         if (self.invincible_finished > time)
  1161.             self.effects = self.effects | EF_DIMLIGHT;
  1162.         else
  1163.             self.effects = self.effects - (self.effects & EF_DIMLIGHT);
  1164.     }
  1165.  
  1166. // super damage
  1167.     if (self.super_damage_finished)
  1168.     {
  1169.  
  1170. // sound and screen flash when items starts to run out
  1171.  
  1172.         if (self.super_damage_finished < time + 3)
  1173.         {
  1174.             if (self.super_time == 1)
  1175.             {
  1176.                 sprint (self, "Quad Damage is wearing off\n");
  1177.                 stuffcmd (self, "bf\n");
  1178.                 sound (self, CHAN_AUTO, "items/damage2.wav", 1, ATTN_NORM);
  1179.                 self.super_time = time + 1;
  1180.             }      
  1181.             
  1182.             if (self.super_time < time)
  1183.             {
  1184.                 self.super_time = time + 1;
  1185.                 stuffcmd (self, "bf\n");
  1186.             }
  1187.         }
  1188.  
  1189.         if (self.super_damage_finished < time)
  1190.         {    // just stopped
  1191.             self.items = self.items - IT_QUAD;
  1192.             self.super_damage_finished = 0;
  1193.             self.super_time = 0;
  1194.         }
  1195.         if (self.super_damage_finished > time)
  1196.             self.effects = self.effects | EF_DIMLIGHT;
  1197.         else
  1198.             self.effects = self.effects - (self.effects & EF_DIMLIGHT);
  1199.     }    
  1200.  
  1201. // suit    
  1202.     if (self.radsuit_finished)
  1203.     {
  1204.         self.air_finished = time + 12;        // don't drown
  1205.  
  1206. // sound and screen flash when items starts to run out
  1207.         if (self.radsuit_finished < time + 3)
  1208.         {
  1209.             if (self.rad_time == 1)
  1210.             {
  1211.                 sprint (self, "Air supply in Biosuit expiring\n");
  1212.                 stuffcmd (self, "bf\n");
  1213.                 sound (self, CHAN_AUTO, "items/suit2.wav", 1, ATTN_NORM);
  1214.                 self.rad_time = time + 1;
  1215.             }
  1216.             
  1217.             if (self.rad_time < time)
  1218.             {
  1219.                 self.rad_time = time + 1;
  1220.                 stuffcmd (self, "bf\n");
  1221.             }
  1222.         }
  1223.  
  1224.         if (self.radsuit_finished < time)
  1225.         {    // just stopped
  1226.             self.items = self.items - IT_SUIT;
  1227.             self.rad_time = 0;
  1228.             self.radsuit_finished = 0;
  1229.         }
  1230.     }    
  1231. };
  1232.  
  1233.  
  1234. /*
  1235. ================
  1236. PlayerPostThink
  1237.  
  1238. Called every frame after physics are run
  1239. ================
  1240. */
  1241. void() PlayerPostThink =
  1242. {
  1243.     if (self.view_ofs == '0 0 0')
  1244.         return;        // intermission or finale
  1245.     if (self.deadflag)
  1246.         return;
  1247.  
  1248. // do weapon stuff
  1249.  
  1250.     W_WeaponFrame ();
  1251.  
  1252. // check to see if player landed and play landing sound    
  1253.     if ((self.jump_flag < -300) && (self.flags & FL_ONGROUND) && (self.health > 0))
  1254.     {
  1255.         if (self.watertype == CONTENT_WATER)
  1256.             sound (self, CHAN_BODY, "player/h2ojump.wav", 1, ATTN_NORM);
  1257.         else if (self.jump_flag < -650)
  1258.         {
  1259.             T_Damage (self, world, world, 5); 
  1260.             sound (self, CHAN_VOICE, "player/land2.wav", 1, ATTN_NORM);
  1261.             self.deathtype = "falling";
  1262.         }
  1263.         else
  1264.             sound (self, CHAN_VOICE, "player/land.wav", 1, ATTN_NORM);
  1265.  
  1266.         self.jump_flag = 0;
  1267.     }
  1268.  
  1269.     if (!(self.flags & FL_ONGROUND))
  1270.         self.jump_flag = self.velocity_z;
  1271.  
  1272.     CheckPowerups ();
  1273. };
  1274.  
  1275.  
  1276. /*
  1277. ===========
  1278. ClientConnect
  1279.  
  1280. called when a player connects to a server
  1281. ============
  1282. */
  1283. void() ClientConnect =
  1284. {
  1285.     // DM code
  1286.     connect_player = self;
  1287.  
  1288.     bprint (self.netname);
  1289.     bprint (" entered the game\n");
  1290.  
  1291. // a client connecting during an intermission can cause problems
  1292.     if (intermission_running)
  1293.         ExitIntermission ();
  1294. };
  1295.  
  1296.  
  1297. /*
  1298. ===========
  1299. ClientDisconnect
  1300.  
  1301. called when a player disconnects from a server
  1302. ============
  1303. */
  1304. void() ClientDisconnect =
  1305. {
  1306.     if (gameover)
  1307.         return;
  1308.     // if the level end trigger has been activated, just return
  1309.     // since they aren't *really* leaving
  1310.  
  1311.     // let everyone else know
  1312.     bprint (self.netname);
  1313.     bprint (" left the game with ");
  1314.     bprint (ftos(self.frags));
  1315.     bprint (" frags\n");
  1316.     sound (self, CHAN_BODY, "player/tornoff2.wav", 1, ATTN_NONE);
  1317.     set_suicide_frame ();
  1318.  
  1319.     // DM code
  1320.     if (teamplay >= 5)
  1321.     {
  1322.         local float team1;
  1323.         local float team2;
  1324.         local entity first;
  1325.         local entity it;
  1326.  
  1327.         // Tag a new player IT only if there are two or more players remaining.
  1328.         team1 = 0;
  1329.         team2 = 0;
  1330.         other = find (world, classname, "player");
  1331.         while (other != world)
  1332.         {
  1333.             if (other != self)
  1334.             {
  1335.                 if (other.team == actual_team1)
  1336.                 {
  1337.                     if (team1 == 0)
  1338.                         first = other;
  1339.                     team1 = team1 + 1;
  1340.                 }
  1341.                 else  // IT!
  1342.                 {
  1343.                     it = other;
  1344.                     team2 = team2 + 1;
  1345.                 }
  1346.             }
  1347.             other = find (other, classname, "player");
  1348.         }
  1349.         if (self.start_team == actual_team2)  // Was exiting player IT?
  1350.         {
  1351.             // Make certain there are still two or more players.
  1352.             if (team1 > 1)
  1353.             {
  1354.                 ConfigTeam(2, 0);
  1355.                 stuffcmd(first, color_team);
  1356.                 first.start_team = assigned_team;
  1357.                 first.team = assigned_team;
  1358.                 first.skin = skin_team;
  1359.  
  1360.                 bprint(first.netname);
  1361.                 bprint(" is now IT!\n");
  1362.                 IT_time = time;
  1363.             }
  1364.         }
  1365.         else if (team1 == 0 && team2)  // Remove IT if no more players hunting.
  1366.         {
  1367.             ConfigTeam(1, 0);
  1368.             stuffcmd(it, color_team);
  1369.             it.start_team = assigned_team;
  1370.             it.team = assigned_team;
  1371.             it.skin = skin_team;
  1372.  
  1373.             sprint(it, "You're no longer IT as there are no players left to tag you.\n");
  1374.             IT_time = 0;
  1375.         }
  1376.     }
  1377. };
  1378.  
  1379. /*
  1380. ===========
  1381. ClientObituary
  1382.  
  1383. called when a player dies
  1384. ============
  1385. */
  1386. void(entity targ, entity attacker) ClientObituary =
  1387. {
  1388.     local    float rnum;
  1389.     local    string deathstring, deathstring2;
  1390.     rnum = random();
  1391.  
  1392.     if (targ.classname == "player")
  1393.     {
  1394.         local float targ_value;
  1395.         targ_value = 1;
  1396.         if (teamplay >= 5)  // Game of tag?
  1397.         {
  1398.             if (targ.start_team == actual_team2)  // Was target IT?
  1399.                 targ_value = 3;
  1400.         }
  1401.         if (attacker.classname == "teledeath")
  1402.         {
  1403.             bprint (targ.netname);
  1404.             bprint (" was telefragged by ");
  1405.             bprint (attacker.owner.netname);
  1406.             bprint ("\n");
  1407.  
  1408.             attacker.owner.frags = attacker.owner.frags + targ_value;
  1409.             return;
  1410.         }
  1411.  
  1412.         if (attacker.classname == "teledeath2")
  1413.         {
  1414.             bprint ("Satan's power deflects ");
  1415.             bprint (targ.netname);
  1416.             bprint ("'s telefrag\n");
  1417.  
  1418.             targ.frags = targ.frags - 1;
  1419.             return;
  1420.         }
  1421.  
  1422.         if (attacker.classname == "player")
  1423.         {
  1424.             if (targ == attacker)
  1425.             {
  1426.                 // killed self
  1427.                 attacker.frags = attacker.frags - 1;
  1428.                 bprint (targ.netname);
  1429.                 
  1430.                 if (targ.weapon == 64 && targ.waterlevel > 1)
  1431.                 {
  1432.                     bprint (" discharges into the water.\n");
  1433.                     return;
  1434.                 }
  1435.                 if (targ.weapon == 16)
  1436.                     bprint (" tries to put the pin back in\n");
  1437.                 else if (rnum < 0.5)
  1438.                     bprint (" becomes bored with life\n");
  1439.                 else
  1440.                     bprint (" checks if his weapon is loaded\n");
  1441.                 return;
  1442.             }
  1443.             else
  1444.             {
  1445.                 attacker.frags = attacker.frags + targ_value;
  1446.  
  1447.                 rnum = attacker.weapon;
  1448.                 if (rnum == IT_AXE)
  1449.                 {
  1450.                     deathstring = " was ax-murdered by ";
  1451.                     deathstring2 = "\n";
  1452.                 }
  1453.                 if (rnum == IT_SHOTGUN)
  1454.                 {
  1455.                     deathstring = " chewed on ";
  1456.                     deathstring2 = "'s boomstick\n";
  1457.                 }
  1458.                 if (rnum == IT_SUPER_SHOTGUN)
  1459.                 {
  1460.                     deathstring = " ate 2 loads of ";
  1461.                     deathstring2 = "'s buckshot\n";
  1462.                 }
  1463.                 if (rnum == IT_NAILGUN)
  1464.                 {
  1465.                     deathstring = " was nailed by ";
  1466.                     deathstring2 = "\n";
  1467.                 }
  1468.                 if (rnum == IT_SUPER_NAILGUN)
  1469.                 {
  1470.                     deathstring = " was punctured by ";
  1471.                     deathstring2 = "\n";
  1472.                 }
  1473.                 if (rnum == IT_GRENADE_LAUNCHER)
  1474.                 {
  1475.                     if (targ.health < -40)
  1476.                     {
  1477.                         deathstring = " was gibbed by ";
  1478.                         deathstring2 = "'s grenade\n";
  1479.                     }
  1480.                     else
  1481.                     {
  1482.                         deathstring = " eats ";
  1483.                         deathstring2 = "'s pineapple\n";
  1484.                     }
  1485.                 }
  1486.                 if (rnum == IT_ROCKET_LAUNCHER)
  1487.                 {
  1488.                     if (targ.health < -40)
  1489.                     {
  1490.                         deathstring = " was gibbed by ";
  1491.                         deathstring2 = "'s rocket\n" ;
  1492.                     }
  1493.                     else
  1494.                     {
  1495.                         deathstring = " rides ";
  1496.                         deathstring2 = "'s rocket\n";
  1497.                     }
  1498.                 }
  1499.                 if (rnum == IT_LIGHTNING)
  1500.                 {
  1501.                     deathstring = " accepts ";
  1502.                     if (attacker.waterlevel > 1)
  1503.                         deathstring2 = "'s discharge\n";
  1504.                     else
  1505.                         deathstring2 = "'s shaft\n";
  1506.                 }
  1507.                 bprint (targ.netname);
  1508.                 bprint (deathstring);
  1509.                 bprint (attacker.netname);
  1510.                 bprint (deathstring2);
  1511.  
  1512.                 // DM code
  1513.                 if (teamplay >= 5)
  1514.                 {
  1515.                     // Remove IT from killed player.
  1516.                     ConfigTeam(1, 0);
  1517.                     stuffcmd(targ, color_team);
  1518.                     targ.start_team = assigned_team;
  1519.                     targ.team = assigned_team;
  1520.                     targ.skin = skin_team;
  1521.                     ConfigTeam(2, 0);
  1522.                     stuffcmd(attacker, color_team);
  1523.                     attacker.start_team = assigned_team;
  1524.                     attacker.team = assigned_team;
  1525.                     attacker.skin = skin_team;
  1526.  
  1527.                     bprint("Tag!  ");
  1528.                     bprint(attacker.netname);
  1529.                     bprint(" is now IT!\n");
  1530.                     IT_time = time;
  1531.                 }
  1532.             }
  1533.             return;
  1534.         }
  1535.         else
  1536.         {
  1537.             targ.frags = targ.frags - 1;        // killed self
  1538.             rnum = targ.watertype;
  1539.  
  1540.             bprint (targ.netname);
  1541.             if (rnum == -3)
  1542.             {
  1543.                 if (random() < 0.5)
  1544.                     bprint (" sleeps with the fishes\n");
  1545.                 else
  1546.                     bprint (" sucks it down\n");
  1547.                 return;
  1548.             }
  1549.             else if (rnum == -4)
  1550.             {
  1551.                 if (random() < 0.5)
  1552.                     bprint (" gulped a load of slime\n");
  1553.                 else
  1554.                     bprint (" can't exist on slime alone\n");
  1555.                 return;
  1556.             }
  1557.             else if (rnum == -5)
  1558.             {
  1559.                 if (targ.health < -15)
  1560.                 {
  1561.                     bprint (" burst into flames\n");
  1562.                     return;
  1563.                 }
  1564.                 if (random() < 0.5)
  1565.                     bprint (" turned into hot slag\n");
  1566.                 else
  1567.                     bprint (" visits the Volcano God\n");
  1568.                 return;
  1569.             }
  1570.  
  1571.             if (attacker.flags & FL_MONSTER)
  1572.             {
  1573.                 if (attacker.classname == "monster_army")
  1574.                     bprint (" was shot by a Grunt\n");
  1575.                 if (attacker.classname == "monster_demon1")
  1576.                     bprint (" was eviscerated by a Fiend\n");
  1577.                 if (attacker.classname == "monster_dog")
  1578.                     bprint (" was mauled by a Rottweiler\n");
  1579.                 if (attacker.classname == "monster_dragon")
  1580.                     bprint (" was fried by a Dragon\n");
  1581.                 if (attacker.classname == "monster_enforcer")
  1582.                     bprint (" was blasted by an Enforcer\n");
  1583.                 if (attacker.classname == "monster_fish")
  1584.                     bprint (" was fed to the Rotfish\n");
  1585.                 if (attacker.classname == "monster_hell_knight")
  1586.                     bprint (" was slain by a Death Knight\n");
  1587.                 if (attacker.classname == "monster_knight")
  1588.                     bprint (" was slashed by a Knight\n");
  1589.                 if (attacker.classname == "monster_ogre")
  1590.                     bprint (" was destroyed by an Ogre\n");
  1591.                 if (attacker.classname == "monster_oldone")
  1592.                     bprint (" became one with Shub-Niggurath\n");
  1593.                 if (attacker.classname == "monster_shalrath")
  1594.                     bprint (" was exploded by a Vore\n");
  1595.                 if (attacker.classname == "monster_shambler")
  1596.                     bprint (" was smashed by a Shambler\n");
  1597.                 if (attacker.classname == "monster_tarbaby")
  1598.                     bprint (" was slimed by a Spawn\n");
  1599.                 if (attacker.classname == "monster_vomit")
  1600.                     bprint (" was vomited on by a Vomitus\n");
  1601.                 if (attacker.classname == "monster_wizard")
  1602.                     bprint (" was scragged by a Scrag\n");
  1603.                 if (attacker.classname == "monster_zombie")
  1604.                     bprint (" joins the Zombies\n");
  1605.  
  1606.                 return;
  1607.             }
  1608.             if (attacker.classname == "explo_box")
  1609.             {
  1610.                 bprint (" blew up\n");
  1611.                 return;
  1612.             }
  1613.             if (attacker.solid == SOLID_BSP && attacker != world)
  1614.             {    
  1615.                 bprint (" was squished\n");
  1616.                 return;
  1617.             }
  1618.             if (targ.deathtype == "falling")
  1619.             {
  1620.                 targ.deathtype = "";
  1621.                 bprint (" fell to his death\n");
  1622.                 return;
  1623.             }
  1624.             if (attacker.classname == "trap_shooter" || attacker.classname == "trap_spikeshooter")
  1625.             {
  1626.                 bprint (" was spiked\n");
  1627.                 return;
  1628.             }
  1629.             if (attacker.classname == "fireball")
  1630.             {
  1631.                 bprint (" ate a lavaball\n");
  1632.                 return;
  1633.             }
  1634.             if (attacker.classname == "trigger_changelevel")
  1635.             {
  1636.                 bprint (" tried to leave\n");
  1637.                 return;
  1638.             }
  1639.  
  1640.             bprint (" died\n");
  1641.         }
  1642.     }
  1643. };
  1644.