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