home *** CD-ROM | disk | FTP | other *** search
/ Qu-ake / Qu-ake.iso / qu_ke / patches / 006 / CHASECAM.QC next >
Encoding:
Text File  |  1996-11-16  |  26.0 KB  |  1,244 lines

  1. /*
  2.  #####################
  3.  ### chase cam mod ###
  4.  Rob Albin, 09 Sep 96
  5.  
  6.  orig functions modified:
  7.     WEAPONS.QC
  8.         W_SetCurrentAmmo
  9.         ImpulseCommands
  10.     CLIENT.QC
  11.         SetChangeParms
  12.         SetNewParms
  13.         DecodeLevelParms
  14.         PutClientInServer
  15. */
  16.  
  17. // message protocol defines
  18. float SVC_SETVIEWPORT    = 5;
  19. float SVC_SETVIEWANGLES    = 10;
  20.  
  21. // free player entity variable
  22. // '.float speed'  bit-flag defines:
  23. float CHSCAM_MONSTER  = 8;
  24. float CHSCAM_ON       = 4;
  25. float LASERTARG_LIT   = 2;
  26. float LASERTARG_ON    = 1;
  27.  
  28.  
  29. void() Keep_cam_chasing_owner;
  30. void( float opt ) Remove_chase_cam;
  31.  
  32. // defaults reset every time level starts
  33. float chasecam_dist = 118, chasecam_zofs = 24;
  34.  
  35.  
  36. // Resets weapon model after changing view
  37. // called by chase cam or player entities
  38. void( entity player_ent ) Chase_cam_setweapon =
  39. {
  40.     local entity e;
  41.  
  42.     e = self;
  43.     self = player_ent;
  44.     W_SetCurrentAmmo ();
  45.     self = e;
  46. };
  47.  
  48. // called either by player or chase cam entities (to restart)
  49. void( entity cam_owner ) Start_chase_cam =
  50. {
  51.  
  52.     local entity    chase_cam;
  53.  
  54.     chase_cam = spawn();
  55.  
  56.     chase_cam.owner=cam_owner;
  57.  
  58.     // turn on bit-flag
  59.     chase_cam.owner.speed = chase_cam.owner.speed | CHSCAM_ON;
  60.  
  61.     chase_cam.solid = SOLID_NOT;
  62.     chase_cam.movetype = MOVETYPE_FLY;
  63.  
  64.  
  65.     chase_cam.angles = chase_cam.owner.angles;
  66.  
  67.     setmodel (chase_cam, "progs/eyes.mdl" );
  68.     setsize (chase_cam, '0 0 0', '0 0 0');
  69.     setorigin( chase_cam, chase_cam.owner.origin );
  70.     chase_cam.classname = "chase_cam";
  71.  
  72.     chase_cam.nextthink = time + 0.1;
  73.     chase_cam.think = Keep_cam_chasing_owner;
  74.  
  75.     msg_entity = chase_cam.owner;                         // target of message
  76.     WriteByte (MSG_ONE, SVC_SETVIEWPORT);
  77.     WriteEntity (MSG_ONE, chase_cam);           // view port
  78.  
  79.     Chase_cam_setweapon( cam_owner );
  80.  
  81.     // distance clipping
  82.     chase_cam.ammo_shells = chasecam_dist / 3; // chasecam_dist;
  83.  
  84. };
  85.  
  86. // secondary think for cam entities
  87. void() Reable_chase_cam =
  88. {
  89.     self.nextthink = time + 0.1;
  90.  
  91.     // debug
  92.     // sprint( self.owner, "Reable_chase_cam was called\n" );
  93.  
  94.     // clears bug of not being able to hit fire to restart
  95.     // after dying in water
  96.     if (self.owner.health <= 0)
  97.     {
  98.         remove( self );
  99.         return;
  100.     }
  101.  
  102.     if (self.owner.waterlevel)
  103.         return;
  104.  
  105.     Start_chase_cam( self.owner );
  106.     remove( self );
  107.  
  108. };
  109.  
  110. // called only by chase cam entities
  111. // opt values
  112. // TRUE = remove completely
  113. // FALSE = remove view but keep alive with Reable_chase_cam();
  114. void( float opt ) Remove_chase_cam =
  115. {
  116.     // turn off bit-flag
  117.     if ( (self.owner.speed & CHSCAM_ON) )
  118.         self.owner.speed = self.owner.speed - CHSCAM_ON;
  119.  
  120.     // makes entity appear gone even if going into keep alive state
  121.     setmodel( self, "" );
  122.     self.velocity = '0 0 0';
  123.  
  124.     // set view-point back to normal
  125.     msg_entity = self.owner;      // target of message
  126.     WriteByte (MSG_ONE, SVC_SETVIEWPORT);
  127.     WriteEntity (MSG_ONE, self.owner);           // view port
  128.  
  129.     Chase_cam_setweapon( self.owner );
  130.  
  131.     if ( !opt )
  132.     {
  133.         self.nextthink = time + 0.1;
  134.         self.think = Reable_chase_cam;
  135.     }
  136.     else
  137.         remove( self );
  138.  
  139. };
  140.  
  141. // main think function for cam entities
  142. //  self.ammo_shells = distance clipping
  143. //  self.ammo_nails = hang-up flag
  144.  
  145. void() Keep_cam_chasing_owner =
  146. {
  147.     local vector goal, dir;
  148.     local float  dist, cap,
  149.                      f_f;
  150.     //debug var
  151.     local string s;
  152.  
  153.     self.nextthink = time + 0.1;
  154.  
  155.     // check if player toggled
  156.     // or in water
  157.     if (! (self.owner.speed & CHSCAM_ON))
  158.     {
  159.         Remove_chase_cam( TRUE );
  160.         return;
  161.     }
  162.  
  163.     if ( self.owner.waterlevel )
  164.     {
  165.         if (self.owner.health > 0)
  166.         {
  167.             Remove_chase_cam( FALSE );
  168.             return;
  169.         }
  170.     }
  171.  
  172.     // get player velocity relative to player's
  173.     // current yaw
  174.     // f_f (based on running calcs (maxspeed = 400)
  175.     //  (back ~= 640, forward ~= 0)
  176.     dir_y = self.owner.v_angle_y;
  177.     makevectors( dir );
  178.     f_f = vlen( (v_forward * 320) - self.owner.velocity );
  179.  
  180.     // held for use after second makevectors call for
  181.     // v_forward based only on yaw
  182.     dir = v_forward;
  183.  
  184. //   local string s;
  185. //   sprint( self.owner, "\n\n f_f = " );
  186. //   s = ftos( f_f );
  187. //   sprint( self.owner, s );
  188. //   sprint( self.owner, "\n f_r = " );
  189. //   s = ftos( f_r );
  190. //   sprint( self.owner, s );
  191. //   sprint( self.owner, "\n" );
  192.  
  193.     makevectors( self.owner.v_angle );
  194.  
  195.     // set spot before clipping
  196.     goal = self.owner.origin - (v_forward * self.ammo_shells);
  197.     /*
  198.         sprint( self.owner, "shells: " );
  199.         s = ftos( self.ammo_shells );
  200.         sprint( self.owner, s );
  201.         sprint( self.owner, "vang_x: " );
  202.         s = ftos( self.owner.v_angle_x );
  203.         sprint( self.owner, s );
  204.         sprint( self.owner, "\n" );
  205.     */
  206.  
  207.     if (self.owner.v_angle_x > 16)
  208.     {
  209.         // dir is first v_forward based on yaw only
  210.         goal = goal + (dir * (self.owner.v_angle_x - 16) );
  211.         cap = chasecam_zofs - ((self.owner.v_angle_x - 16) );// * 0.8);
  212.         //if (cap < 0) cap = 0;
  213.         goal_z = goal_z + cap;
  214.         if (goal_z < self.owner.origin_z + 20)
  215.             goal_z = self.owner.origin_z + 20;
  216.     }
  217.     else
  218.         goal_z = goal_z + chasecam_zofs;
  219.  
  220.  
  221.     traceline (self.owner.origin, goal, FALSE, self.owner);
  222.  
  223.     // for fading from walls and up-aim auto rising
  224.     if (trace_fraction < 1 || self.owner.v_angle_x < -16)
  225.         self.ammo_shells = 8 + vlen(trace_endpos - self.owner.origin);
  226.  
  227.     // avoids most hang-ups along walls
  228.     goal = trace_endpos + ( v_forward * 2 );
  229.  
  230.  
  231.  
  232.     // clip from ceiling if too close
  233.     traceline (goal, goal + '0 0 32', FALSE, self.owner );
  234.     if (trace_fraction < 1 )
  235.     {
  236.         dir = trace_endpos - '0 0 32';
  237.  
  238.         traceline (goal, goal - '0 0 32', FALSE, self.owner );
  239.         if (trace_fraction == 1)
  240.             goal = dir;
  241.     }
  242.  
  243.  
  244.     dir = normalize(goal - self.origin);
  245.     dist = vlen(goal - self.origin);
  246.  
  247.  
  248.     // traceline( self.origin, goal, FALSE, self.owner );
  249.     // if ( trace_fraction == 1 )
  250.     if ( visible(self.owner) )
  251.     {
  252.         self.angles = self.owner.angles;
  253.  
  254.         cap = dist * 0.2;
  255.  
  256.         if (cap > 5.2)
  257.             self.velocity = dir * dist * 5.2;
  258.         else if (cap > 1)
  259.             self.velocity = dir * dist * cap;
  260.         else
  261.             self.velocity = dir * dist;
  262.  
  263.         // tighten up if owner running backwards
  264.         if ( f_f > 560)
  265.         {
  266.             self.velocity = self.velocity * 2;
  267.         }
  268.  
  269.     }
  270.     else
  271.         setorigin( self, goal );
  272.  
  273.     // fade back from walls
  274.     self.ammo_shells = self.ammo_shells + 4.5;
  275.     if (self.ammo_shells > chasecam_dist)
  276.         self.ammo_shells = chasecam_dist;
  277.  
  278.     // respawn if missile ent. get's hung up
  279.     if( self.oldorigin == self.origin )
  280.     {
  281.         if( dist > 30 )
  282.             self.ammo_nails = self.ammo_nails + 1;
  283.         if( self.ammo_nails > 2 )
  284.         {
  285.             Start_chase_cam( self.owner );
  286.             remove( self );
  287.             return;
  288.         }
  289.  
  290.     }
  291.     self.oldorigin = self.origin;
  292.  
  293. };
  294.  
  295.  
  296. // called by player only
  297. void() Toggle_chase_cam =
  298. {
  299.  
  300.     if (self.waterlevel)
  301.         return;
  302.  
  303.     if( (self.speed & CHSCAM_ON) )
  304.     {
  305.         // will be noticed by next think
  306.         // of player's chase cam entity
  307.         self.speed = self.speed - CHSCAM_ON;
  308.     }
  309.     else
  310.         Start_chase_cam( self );
  311.  
  312. };
  313.  
  314. ////////////////////////////////////////////
  315. // laser targeter functions
  316.  
  317. // targeter ent. think function
  318.  
  319. void() LaserTargeterTrack = {
  320.     local vector src;
  321.  
  322.     if (! (self.owner.speed & LASERTARG_ON))
  323.     {
  324.         if( (self.owner.speed & LASERTARG_LIT) )
  325.         {
  326.             self.owner.speed = self.owner.speed | LASERTARG_ON;
  327.             self.effects = self.effects | EF_DIMLIGHT;
  328.         }
  329.         else
  330.         {
  331.             remove( self );
  332.             return;
  333.         }
  334.     }
  335.  
  336.     makevectors( self.owner.v_angle );
  337.  
  338.     src = self.owner.origin + v_forward * 10;
  339.     src_z = self.owner.absmin_z + self.owner.size_z * 0.7;
  340.  
  341.     traceline( src,  src + v_forward * 2048, FALSE, self.owner);
  342.  
  343.     setorigin( self, (0.1 * src + 0.9 * trace_endpos) );
  344.  
  345.     self.nextthink = time + 0.05;
  346.  
  347. };
  348.  
  349. void( entity targ_owner ) LaserTargeterToggle =
  350. {
  351.  
  352.     local entity e;
  353.  
  354.     if( (targ_owner.speed & LASERTARG_ON) )
  355.     {
  356.         if( (targ_owner.speed & LASERTARG_LIT) )
  357.             targ_owner.speed = targ_owner.speed - LASERTARG_LIT;
  358.         else
  359.             targ_owner.speed = targ_owner.speed | LASERTARG_LIT;
  360.  
  361.         targ_owner.speed = targ_owner.speed - LASERTARG_ON;
  362.     }
  363.     else
  364.     {
  365.         targ_owner.speed = targ_owner.speed | LASERTARG_ON;
  366.  
  367.         e = spawn();
  368.         e.owner = targ_owner;
  369.  
  370.         e.movetype = MOVETYPE_NONE;
  371.         e.solid = SOLID_NOT;
  372.  
  373.         setmodel( e, "progs/s_bubble.spr" );
  374.         setsize( e, VEC_ORIGIN, VEC_ORIGIN );
  375.         setorigin( e, e.owner.origin );
  376.  
  377.         if( (e.owner.speed & LASERTARG_LIT) )
  378.             e.effects = e.effects | EF_DIMLIGHT;
  379.  
  380.         e.nextthink = time + 0.1;
  381.         e.think = LaserTargeterTrack;
  382.  
  383.     }
  384.  
  385. };
  386. ////////////////////////////////////////////
  387.  
  388.  
  389. void() Chase_cam_lvlstart_think =
  390. {
  391.  
  392.     if ( (self.owner.speed & CHSCAM_ON) )
  393.         Start_chase_cam( self.owner );
  394.  
  395.     if ( (self.owner.speed & LASERTARG_ON) )
  396.     {
  397.         self.owner.speed = self.owner.speed - LASERTARG_ON;
  398.         LaserTargeterToggle( self.owner );
  399.     }
  400.  
  401.     remove( self );
  402.  
  403. };
  404.  
  405.  
  406. // called in CLIENT.QC by void() PutClientInServer
  407. // player.speed is set and saved between levels using parm16
  408. // in CLIENT.QC
  409. void() Chase_cam_level_start =
  410. {
  411.  
  412.     local entity e;
  413.  
  414.         e = spawn();
  415.         e.owner = self;
  416.  
  417.         e.movetype = MOVETYPE_NONE;
  418.         e.solid = SOLID_NOT;
  419.  
  420.         setmodel( e, "" );
  421.         setsize( e, VEC_ORIGIN, VEC_ORIGIN );
  422.         setorigin( e, e.owner.origin );
  423.  
  424.         e.nextthink = time + 0.2;
  425.         e.think = Chase_cam_lvlstart_think;
  426.  
  427. };
  428.  
  429. // opt:
  430. // 0 = minus
  431. // 1 = plus
  432. void(float opt) Chase_cam_change_dist =
  433. {
  434.     local string s;
  435.  
  436.     if (!opt)
  437.     {
  438.         chasecam_dist = chasecam_dist - 2;
  439.         if (chasecam_dist < 10)
  440.             chasecam_dist = 10;
  441.     }
  442.     else
  443.     {
  444.         chasecam_dist = chasecam_dist + 2;
  445.     }
  446.     sprint( self, "chasecam distance = " );
  447.     s = ftos( chasecam_dist );
  448.     sprint( self, s );
  449.     sprint( self, "\n" );
  450.  
  451.  
  452. };
  453.  
  454. // ### chase view spy mod ###
  455. // uses free player variable .vector dest1 to hold current
  456. // origin for switching back.
  457.  
  458. void() MKeep_cam_chasing_owner;
  459.  
  460. float    modelindex_eyes, modelindex_player;
  461.  
  462. void() MFake_player_think =
  463. {
  464.     self.nextthink = time + 0.1;
  465.  
  466.     if ((self.owner.speed & CHSCAM_ON))
  467.         return;
  468.  
  469.     self.solid = SOLID_NOT;
  470.  
  471.     // player appear
  472.     self.owner.solid = SOLID_SLIDEBOX;
  473.     self.owner.movetype = MOVETYPE_WALK;
  474.     setmodel (self.owner, "progs/eyes.mdl");
  475.     modelindex_eyes = self.owner.modelindex;
  476.     setmodel (self.owner, "progs/player.mdl");
  477.     modelindex_player = self.owner.modelindex;
  478.     setsize (self.owner, VEC_HULL_MIN, VEC_HULL_MAX);
  479.         //setorigin( self.owner, self.owner.dest1 );
  480.     setorigin( self.owner, self.origin );
  481.     ////////////////
  482.  
  483.     if ((self.owner.flags & FL_NOTARGET))
  484.         self.owner.flags = self.owner.flags - FL_NOTARGET;
  485.  
  486.     remove( self );
  487.  
  488. };
  489.  
  490. /*
  491. void() MFake_player_pain =
  492. {
  493.     local float d;
  494.  
  495.     if (self.owner.health > self.health)
  496.     {
  497.         d = self.owner.health - self.health;
  498.         T_Damage(self.owner, self, self, d);
  499.     }
  500.  
  501. };
  502.  
  503. void() MFake_player_die =
  504. {
  505.     if ((self.owner.speed & CHSCAM_ON))
  506.         self.owner.speed = self.owner.speed - CHSCAM_ON;
  507.     MFake_player_pain();
  508.     MFake_player_think();
  509.  
  510. };
  511. */
  512.  
  513. void( entity cam_owner, vector cam_pos ) MFake_player_appear =
  514. {
  515.     local entity e;
  516.     local vector plr_pos;
  517.  
  518.     plr_pos = cam_owner.origin;
  519.  
  520.     // player vanish
  521.         //cam_owner.dest1 = cam_owner.origin;
  522.     cam_owner.flags = cam_owner.flags | FL_NOTARGET;
  523.     cam_owner.solid = SOLID_NOT;
  524.     cam_owner.movetype = MOVETYPE_NONE;
  525.     setmodel (cam_owner, "");
  526.     modelindex_eyes = cam_owner.modelindex;
  527.     modelindex_player = cam_owner.modelindex;
  528.  
  529.     cam_owner.angles = cam_owner.goalentity.angles;
  530.     cam_owner.fixangle = 1;
  531.         // position player to chase view's location
  532.     setsize (cam_owner, VEC_ORIGIN, VEC_ORIGIN);
  533.     setorigin( cam_owner, cam_pos );
  534.     ////////////////
  535.  
  536.  
  537.     e = spawn();
  538.     e.owner = cam_owner;
  539.  
  540.     e.classname = "fake_player";
  541.     e.solid = SOLID_BBOX;
  542.     e.movetype = MOVETYPE_STEP;
  543.     e.health = cam_owner.health;
  544.     e.takedamage = DAMAGE_AIM;
  545.     e.angles = cam_owner.angles;
  546.  
  547.     e.nextthink = time + 0.1;
  548.     e.think = MFake_player_think;
  549.     //e.th_pain = MFake_player_pain;
  550.     //e.th_die = MFake_player_die;
  551.  
  552.     setmodel (e, "progs/player.mdl");
  553.     setsize (e, VEC_HULL_MIN, VEC_HULL_MAX);
  554.     // position fake player on player's original spot
  555.     setorigin( e, plr_pos );
  556.  
  557.  
  558. };
  559.  
  560. // called either by player or chase cam entities (to restart)
  561. //opt:
  562. // 0 = don't make fake player
  563. // 1 = make fake player
  564. void( entity cam_owner, entity g_e, float opt ) MStart_chase_cam =
  565. {
  566.  
  567.     local entity    chase_cam;
  568.  
  569.     cam_owner.goalentity = g_e;
  570.  
  571.     chase_cam = spawn();
  572.  
  573.     chase_cam.owner = cam_owner;
  574.  
  575.     // turn on bit-flags
  576.     chase_cam.owner.speed = chase_cam.owner.speed | CHSCAM_ON;
  577.     chase_cam.owner.speed = chase_cam.owner.speed | CHSCAM_MONSTER;
  578.  
  579.     chase_cam.solid = SOLID_NOT;
  580.     chase_cam.movetype = MOVETYPE_FLY;
  581.  
  582.     chase_cam.angles = cam_owner.goalentity.angles;
  583.  
  584.     setmodel (chase_cam, "progs/eyes.mdl" );
  585.     setsize (chase_cam, VEC_ORIGIN, VEC_ORIGIN);
  586.     setorigin( chase_cam, cam_owner.goalentity.origin );
  587.  
  588.     if (opt > 0)
  589.         MFake_player_appear( cam_owner, chase_cam.origin );
  590.  
  591.     chase_cam.classname = "chase_cam";
  592.  
  593.     chase_cam.nextthink = time + 0.1;
  594.     chase_cam.think = MKeep_cam_chasing_owner;
  595.  
  596.     msg_entity = chase_cam.owner;                         // target of message
  597.     WriteByte (MSG_ONE, SVC_SETVIEWPORT);
  598.     WriteEntity (MSG_ONE, chase_cam);           // view port
  599.  
  600.     Chase_cam_setweapon( cam_owner );
  601.  
  602.     // distance clipping
  603.     chase_cam.ammo_shells = chasecam_dist / 3; // chasecam_dist;
  604.  
  605. };
  606.  
  607. // called only by chase cam entities
  608. // opt values
  609. // TRUE = remove completely
  610. // FALSE = remove view but keep alive with Reable_chase_cam();
  611. void( float opt ) MRemove_chase_cam =
  612. {
  613.     // turn off bit-flag
  614.     if ( (self.owner.speed & CHSCAM_ON) )
  615.         self.owner.speed = self.owner.speed - CHSCAM_ON;
  616.     if ( (self.owner.speed & CHSCAM_MONSTER) )
  617.         self.owner.speed = self.owner.speed - CHSCAM_MONSTER;
  618.  
  619.     // makes entity appear gone even if going into keep alive state
  620.     setmodel( self, "" );
  621.     self.velocity = '0 0 0';
  622.  
  623.  
  624.     // set view-point back to normal
  625.     msg_entity = self.owner;      // target of message
  626.     WriteByte (MSG_ONE, SVC_SETVIEWPORT);
  627.     WriteEntity (MSG_ONE, self.owner);           // view port
  628.  
  629.  
  630.     if (deathmatch || coop)
  631.     {
  632.         sprint( self.owner.goalentity, self.owner.netname );
  633.         sprint( self.owner.goalentity, " quit tracking\n" );
  634.     }
  635.  
  636.     Chase_cam_setweapon( self.owner );
  637.  
  638.  
  639.     remove( self );
  640.  
  641. };
  642.  
  643. // main think function for cam entities
  644. //  self.ammo_shells = distance clipping
  645. //  self.ammo_nails = hang-up flag
  646.  
  647. void() MKeep_cam_chasing_owner =
  648. {
  649.     local vector goal, dir;
  650.     local float  dist, cap,
  651.                      f_f;
  652.     //debug var
  653.     local string s;
  654.  
  655.     self.nextthink = time + 0.1;
  656.  
  657.     // check if player toggled
  658.     // or in water
  659.     if (! (self.owner.speed & CHSCAM_ON))
  660.     {
  661.         MRemove_chase_cam( TRUE );
  662.         return;
  663.     }
  664.  
  665.     makevectors( self.owner.goalentity.angles );
  666.  
  667.     // set spot before clipping
  668.     goal = self.owner.goalentity.origin - (v_forward * self.ammo_shells);
  669.     goal_z = goal_z + chasecam_zofs;
  670.  
  671.  
  672.     traceline (self.owner.goalentity.origin, goal, FALSE, self.owner.goalentity);
  673.  
  674.     // for fading from walls and up-aim auto rising
  675.     if (trace_fraction < 1)
  676.         self.ammo_shells = 8 + vlen(trace_endpos - self.owner.goalentity.origin);
  677.  
  678.     // avoids most hang-ups along walls
  679.     goal = trace_endpos + ( v_forward * 2 );
  680.  
  681.     // clip from ceiling if too close
  682.     traceline (goal, goal + '0 0 32', FALSE, self.owner.goalentity );
  683.     if (trace_fraction < 1 )
  684.     {
  685.         dir = trace_endpos - '0 0 32';
  686.  
  687.         traceline (goal, goal - '0 0 32', FALSE, self.owner.goalentity );
  688.         if (trace_fraction == 1)
  689.             goal = dir;
  690.     }
  691.  
  692.     dir = normalize(goal - self.origin);
  693.     dist = vlen(goal - self.origin);
  694.  
  695.  
  696.     if ( visible(self.owner.goalentity) )
  697.     {
  698.         self.angles = self.owner.goalentity.angles;
  699.  
  700.         cap = dist * 0.2;
  701.  
  702.         if (cap > 5.2)
  703.             self.velocity = dir * dist * 5.2;
  704.         else if (cap > 1)
  705.             self.velocity = dir * dist * cap;
  706.         else
  707.             self.velocity = dir * dist;
  708.     }
  709.     else
  710.         setorigin( self, goal );
  711.  
  712.     setorigin( self.owner, self.origin );
  713.  
  714.     // fade back from walls
  715.     self.ammo_shells = self.ammo_shells + 4.5;
  716.     if (self.ammo_shells > chasecam_dist)
  717.         self.ammo_shells = chasecam_dist;
  718.  
  719.     // respawn if missile ent. get's hung up
  720.     if( self.oldorigin == self.origin )
  721.     {
  722.         if( dist > 30 )
  723.             self.ammo_nails = self.ammo_nails + 1;
  724.         if( self.ammo_nails > 2 )
  725.         {
  726.             MStart_chase_cam( self.owner, self.owner.goalentity, 0 );
  727.             remove( self );
  728.             return;
  729.         }
  730.  
  731.     }
  732.     self.oldorigin = self.origin;
  733.  
  734. };
  735.  
  736.  
  737. float Mcam_monster_count = 0;
  738. float Mcam_monster_maxcount;
  739.  
  740. entity() MChasecam_get_maxcount =
  741. {
  742.     local entity e, ret_e;
  743.     local float flg2;
  744.  
  745.     e = world;
  746.     ret_e = world;
  747.     Mcam_monster_maxcount = 0;
  748.  
  749.     if (deathmatch || coop)
  750.     {
  751.         do
  752.         {
  753.             e = nextent( e );
  754.             if (e)
  755.             {
  756.                 if (e.health > 0)
  757.                 {
  758.                     flg2 = 0;
  759.                     if (e.classname == "player")
  760.                     {
  761.                         if (e.netname != self.netname) flg2 = 1;
  762.                     }
  763.  
  764.                     if (flg2 == 1)
  765.                     {
  766.                         Mcam_monster_maxcount = Mcam_monster_maxcount + 1;
  767.                         if (Mcam_monster_count == Mcam_monster_maxcount)
  768.                             ret_e = e;
  769.                     }
  770.                 }
  771.             }
  772.         }while (e);
  773.  
  774.         return ret_e;
  775.     }
  776.  
  777.     do
  778.     {
  779.         e = nextent( e );
  780.         if (e)
  781.         {
  782.             if (e.health > 0)
  783.             {
  784.                 flg2 = 0;
  785.                 if (e.classname == "monster_oldone") flg2 = 1;
  786.                 if (e.classname == "monster_boss")       flg2 = 1;
  787.                 if (e.classname == "monster_ogre")       flg2 = 1;
  788.                 if (e.classname == "monster_knight")     flg2 = 1;
  789.                 if (e.classname == "monster_shambler")   flg2 = 1;
  790.                 if (e.classname == "monster_demon1")     flg2 = 1;
  791.                 if (e.classname == "monster_wizard")     flg2 = 1;
  792.                 if (e.classname == "monster_zombie")     flg2 = 1;
  793.                 if (e.classname == "monster_dog")        flg2 = 1;
  794.                 if (e.classname == "monster_hell_knight") flg2 = 1;
  795.                 if (e.classname == "monster_tarbaby")    flg2 = 1;
  796.                 if (e.classname == "monster_vomit")      flg2 = 1;
  797.                 if (e.classname == "monster_enforcer")   flg2 = 1;
  798.                 if (e.classname == "monster_army")       flg2 = 1;
  799.                 if (e.classname == "monster_shalrath")   flg2 = 1;
  800.  
  801.                 if (flg2 == 1)
  802.                 {
  803.                     Mcam_monster_maxcount = Mcam_monster_maxcount + 1;
  804.                     if (Mcam_monster_count == Mcam_monster_maxcount)
  805.                         ret_e = e;
  806.                 }
  807.             }
  808.         }
  809.     }while (e);
  810.  
  811.     return ret_e;
  812.  
  813. };
  814.  
  815.  
  816. //opt:
  817. //0 = back
  818. //1 = forward
  819. void(float opt) Chasecam_find_monster =
  820. {
  821.     local entity e;
  822.     local string s;
  823.  
  824.     if( (self.speed & CHSCAM_ON) )
  825.     {
  826.         // will be noticed by next think
  827.         // of player's chase cam and fake player entities
  828.         self.speed = self.speed - CHSCAM_ON;
  829.  
  830.  
  831.         return;
  832.     }
  833.  
  834.     // don't run unless on the ground
  835.     if (! (self.flags & FL_ONGROUND) )
  836.         return;
  837.  
  838.  
  839.     e = MChasecam_get_maxcount();
  840.     if (opt == 0)
  841.     {
  842.         Mcam_monster_count = Mcam_monster_count - 1;
  843.         if (Mcam_monster_count < 1)
  844.             Mcam_monster_count = Mcam_monster_maxcount;
  845.     }
  846.     else
  847.         Mcam_monster_count = Mcam_monster_count + 1;
  848.  
  849.     if (Mcam_monster_count > Mcam_monster_maxcount)
  850.         Mcam_monster_count = 1;
  851.     e = MChasecam_get_maxcount();
  852.  
  853.     if (e != world)
  854.     {
  855.         s = ftos( Mcam_monster_count );
  856.         sprint( self, s );
  857.         sprint( self, " of " );
  858.         s = ftos( Mcam_monster_maxcount );
  859.         sprint( self, s );
  860.         sprint( self, ": " );
  861.         if (deathmatch || coop)
  862.         {
  863.             sprint( e, "You are being tracked by " );
  864.             sprint( e, self.netname );
  865.             sprint( e, "\n" );
  866.  
  867.             sprint( self, e.netname );
  868.         }
  869.         else
  870.         {
  871.             sprint( self, e.classname );
  872.         }
  873.         sprint( self, "\n" );
  874.  
  875.         MStart_chase_cam( self, e, 1 );
  876.     }
  877.     else
  878.     {
  879.         if (deathmatch || coop)
  880.             sprint( self, "No other living players in level...\n" );
  881.         else
  882.             sprint( self, "No living monsters found...\n" );
  883.     }
  884.  
  885. };
  886.  
  887. // ### chase cam mod ###
  888. // #####################
  889.  
  890.  
  891.  
  892. /*
  893.  ######################
  894.  ### Multiskin v1.1 ###
  895.  
  896.  Orig. functions modifyed:
  897.     WEAPONS.QC
  898.         ImpulseCommands
  899.     CLIENT.QC
  900.         PutClientInServer
  901. */
  902.  
  903. // opt:
  904. // 0 = up
  905. // 1 = down
  906. void( float opt ) Choose_multiskin =
  907. {
  908.    if (opt == 0)
  909.    {
  910.         self.skin = self.skin + 1;
  911.         if (self.skin == 19)
  912.          self.skin = 0;
  913.    }
  914.    else
  915.    {
  916.         self.skin = self.skin - 1;
  917.       if (self.skin == -1)
  918.          self.skin = 18;
  919.    }
  920.  
  921.    if (self.skin == 0)
  922.         centerprint(self, "SKIN: the Good Guy Himself (1)");
  923.     else if (self.skin == 1)
  924.       centerprint(self, "SKIN: Duke Nukem 3d (2)");
  925.    else if (self.skin == 2)
  926.       centerprint(self, "SKIN: Mr. Toad (3)");
  927.    else if (self.skin == 3)
  928.       centerprint(self, "SKIN: the Stormtrooper (4)");
  929.    else if (self.skin == 4)
  930.       centerprint(self, "SKIN: Max (5)");
  931.    else if (self.skin == 5)
  932.       centerprint(self, "SKIN: the Terminator (6)");
  933.    else if (self.skin == 6)
  934.       centerprint(self, "SKIN: Judge Dredd (7)");
  935.    else if (self.skin == 7)
  936.       centerprint(self, "SKIN: Camouflaged soldier (8)");
  937.    else if (self.skin == 8)
  938.       centerprint(self, "SKIN: Captain Picard (9)");
  939.    else if (self.skin == 9)
  940.       centerprint(self, "SKIN: the Wizzard (10)");
  941.    else if (self.skin == 10)
  942.       centerprint(self,"SKIN: the Predator (11)");
  943.    else if (self.skin == 11)
  944.       centerprint(self,"SKIN: Skeleton (12)");
  945.    else if (self.skin == 12)
  946.       centerprint(self,"SKIN: Wan-Fu (13)");
  947.    else if (self.skin == 13)
  948.       centerprint(self,"SKIN: Henry Rollins (14)");
  949.    else if (self.skin == 14)
  950.       centerprint(self,"SKIN: He-Man (15)");
  951.    else if (self.skin == 15)
  952.       centerprint(self,"SKIN: Boba (16)");
  953.    else if (self.skin == 16)
  954.       centerprint(self,"SKIN: Superman (17)");
  955.    else if (self.skin == 17)
  956.       centerprint(self,"SKIN: NYPD Cop (18)");
  957.    else if (self.skin == 18)
  958.       centerprint(self,"SKIN: Red/Yellow women dude (19)");
  959. };
  960.  
  961. // ### Multiskin v1.1 ###
  962. // ######################
  963.  
  964. /*
  965.  #######################
  966.  ### Hot Key Weapons ###
  967.  
  968.  Rob Albin, Oct 7 96
  969.  
  970.  Orig. functions modifyed:
  971.     WEAPONS.QC
  972.         ImpulseCommands
  973.  
  974.  Abstract:
  975.     Provides hot-key impulses for axe, grenade, and rocket launcher
  976.     that return to previous weapon.
  977.     New cycle weapons impulses that don't select these weapons.
  978.  
  979.     uses free entity variable (float point of vector) dest_x
  980.     (only used for doors)
  981.  
  982.  
  983.  CFG file use:
  984.  
  985.  alias +axe_hotkey "impulse 41; +attack"
  986.  alias -axe_hotkey "impulse 40; -attack"
  987.  
  988.  alias +grenade_hotkey "impulse 42; +attack"
  989.  alias -grenade_hotkey "impulse 40; -attack"
  990.  
  991.  alias +rocket_hotkey "impulse 43; +attack"
  992.  alias -rocket_hotkey "impulse 40; -attack"
  993.  
  994.  bind "<key>" "+axe_hotkey"
  995.  bind "<key>" "+grenade_hotkey"
  996.  bind "<key>" "+rocket_hotkey"
  997.  
  998.  // new weapons cycle commands (skips hot-key weapons)
  999.  bind "<key>" "impulse 44"
  1000.  bind "<key>" "impulse 45"
  1001.  
  1002. */
  1003.  
  1004.  
  1005. // opt:
  1006. // 1 = axe
  1007. // 2 = grenade launcher
  1008. // 3 = rocket launcher
  1009. void( float opt ) HotKey_weapon =
  1010. {
  1011.     local float w;
  1012.  
  1013.     if (self.weapon != IT_GRENADE_LAUNCHER &&
  1014.          self.weapon != IT_ROCKET_LAUNCHER  &&
  1015.        self.weapon != IT_AXE)
  1016.         self.dest_x = self.weapon;
  1017.  
  1018.    if (opt == 1)
  1019.    {
  1020.       w = IT_AXE;
  1021.    }
  1022.    else if (opt == 2)
  1023.    {
  1024.       if (! (self.items & IT_GRENADE_LAUNCHER) )
  1025.          return;
  1026.       w = IT_GRENADE_LAUNCHER;
  1027.    }
  1028.    else
  1029.    {
  1030.       if (! (self.items & IT_ROCKET_LAUNCHER) )
  1031.          return;
  1032.       w = IT_ROCKET_LAUNCHER;
  1033.    }
  1034.  
  1035.    self.weapon = w;
  1036.    W_SetCurrentAmmo();
  1037. };
  1038.  
  1039. void() HotKey_previous_weapon =
  1040. {
  1041.    if (! self.dest_x)
  1042.       return;
  1043.  
  1044.    self.weapon = self.dest_x;
  1045.    W_SetCurrentAmmo();
  1046. };
  1047.  
  1048. void() HotKey_CycleWeaponCommand =
  1049. {
  1050.    local float w, it, am, c;
  1051.    local string s;
  1052.  
  1053.    s = " ";
  1054.    c = 0;
  1055.    w = self.weapon;
  1056.  
  1057.    it = self.items;
  1058.     self.impulse = 0;
  1059.     
  1060.     while (1)
  1061.     {
  1062.         am = 0;
  1063.  
  1064.       if (w == IT_LIGHTNING)
  1065.         {
  1066.          s = "Shotgun";
  1067.          w = IT_SHOTGUN;
  1068.             if (self.ammo_shells < 1)
  1069.                 am = 1;
  1070.         }
  1071.       else if (w == IT_AXE)
  1072.         {
  1073.          s = "Shotgun";
  1074.          w = IT_SHOTGUN;
  1075.             if (self.ammo_shells < 1)
  1076.                 am = 1;
  1077.         }
  1078.       else if (w == IT_SHOTGUN)
  1079.         {
  1080.          s = "Super Shotgun";
  1081.          w = IT_SUPER_SHOTGUN;
  1082.             if (self.ammo_shells < 2)
  1083.                 am = 1;
  1084.         }        
  1085.       else if (w == IT_SUPER_SHOTGUN)
  1086.         {
  1087.          s = "Nailgun";
  1088.          w = IT_NAILGUN;
  1089.             if (self.ammo_nails < 1)
  1090.                 am = 1;
  1091.         }
  1092.       else if (w == IT_NAILGUN)
  1093.         {
  1094.          s = "Super Nailgun";
  1095.          w = IT_SUPER_NAILGUN;
  1096.             if (self.ammo_nails < 2)
  1097.                 am = 1;
  1098.         }
  1099.       else if (w == IT_SUPER_NAILGUN)
  1100.         {
  1101.          s = "Lightning Gun";
  1102.          w = IT_LIGHTNING;
  1103.             if (self.ammo_cells < 1)
  1104.                 am = 1;
  1105.         }
  1106.         else if (w == IT_GRENADE_LAUNCHER)
  1107.         {
  1108.             s = "Lightning Gun";
  1109.             w = IT_LIGHTNING;
  1110.             if (self.ammo_cells < 1)
  1111.                 am = 1;
  1112.         }
  1113.         else if (w == IT_ROCKET_LAUNCHER)
  1114.         {
  1115.             s = "Lightning Gun";
  1116.             w = IT_LIGHTNING;
  1117.             if (self.ammo_cells < 1)
  1118.                 am = 1;
  1119.         }
  1120.  
  1121.         if ( (it & w) && am == 0)
  1122.         {
  1123.             self.weapon = w;
  1124.             W_SetCurrentAmmo ();
  1125.  
  1126.             if ( (self.speed & CHSCAM_ON) )
  1127.                 centerprint( self, s );
  1128.  
  1129.             return;
  1130.         }
  1131.  
  1132.         if (c > 8) return;
  1133.         c = c + 1;
  1134.     }
  1135.  
  1136. };
  1137.  
  1138.  
  1139. void() HotKey_CycleWeaponReverseCommand =
  1140. {
  1141.     local float w, it, am, c;
  1142.     local string s;
  1143.  
  1144.     s = " ";
  1145.     c = 0;
  1146.     w = self.weapon;
  1147.  
  1148.     it = self.items;
  1149.     self.impulse = 0;
  1150.  
  1151.     while (1)
  1152.     {
  1153.         am = 0;
  1154.  
  1155.         if (w == IT_LIGHTNING)
  1156.         {
  1157.             s = "Super Nailgun";
  1158.             w = IT_SUPER_NAILGUN;
  1159.             if (self.ammo_nails < 2)
  1160.                 am = 1;
  1161.         }
  1162.         else if (w == IT_ROCKET_LAUNCHER)
  1163.         {
  1164.             s = "Super Nailgun";
  1165.             w = IT_SUPER_NAILGUN;
  1166.             if (self.ammo_nails < 2)
  1167.                 am = 1;
  1168.         }
  1169.         else if (w == IT_GRENADE_LAUNCHER)
  1170.         {
  1171.             s = "Super Nailgun";
  1172.             w = IT_SUPER_NAILGUN;
  1173.             if (self.ammo_nails < 2)
  1174.                 am = 1;
  1175.         }
  1176.         else if (w == IT_SUPER_NAILGUN)
  1177.         {
  1178.             s = "Nailgun";
  1179.             w = IT_NAILGUN;
  1180.             if (self.ammo_nails < 1)
  1181.                 am = 1;
  1182.         }
  1183.         else if (w == IT_NAILGUN)
  1184.         {
  1185.             s = "Super Shotgun";
  1186.             w = IT_SUPER_SHOTGUN;
  1187.             if (self.ammo_shells < 2)
  1188.                 am = 1;
  1189.         }
  1190.         else if (w == IT_SUPER_SHOTGUN)
  1191.         {
  1192.             s = "Shotgun";
  1193.             w = IT_SHOTGUN;
  1194.             if (self.ammo_shells < 1)
  1195.                 am = 1;
  1196.         }
  1197.         else if (w == IT_SHOTGUN)
  1198.         {
  1199.             s = "Lightning Gun";
  1200.             w = IT_LIGHTNING;
  1201.             if (self.ammo_cells < 1)
  1202.                 am = 1;
  1203.         }
  1204.         else if (w == IT_AXE)
  1205.         {
  1206.             s = "Lightning Gun";
  1207.             w = IT_LIGHTNING;
  1208.             if (self.ammo_cells < 1)
  1209.                 am = 1;
  1210.         }
  1211.  
  1212.         if ( (it & w) && am == 0)
  1213.         {
  1214.             self.weapon = w;
  1215.             W_SetCurrentAmmo ();
  1216.             if ( (self.speed & CHSCAM_ON) )
  1217.                 centerprint( self, s );
  1218.             return;
  1219.         }
  1220.  
  1221.         if (c > 8) return;
  1222.         c = c + 1;
  1223.     }
  1224.  
  1225. };
  1226.  
  1227. // ### Hot Key Weapons mod ###
  1228. // ###########################
  1229.  
  1230.  
  1231. // ######################
  1232. // ### rune cheat mod ###
  1233.  
  1234. void() GiveFirstThreeRunes =
  1235. {
  1236.     serverflags = serverflags | 14;
  1237.  
  1238. };
  1239.  
  1240. // ### rune cheat mod ###
  1241. // ######################
  1242.  
  1243.  
  1244.