home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga 14 / MA_Cover_14.iso / source / c / q1source_amy / qw / progs / client.qc < prev    next >
Encoding:
Text File  |  1997-08-12  |  33.3 KB  |  1,499 lines

  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. };
  1499.