home *** CD-ROM | disk | FTP | other *** search
/ Qu-ake / Qu-ake.iso / qu_ke / patches / 012 / DEMOCAM.QC < prev    next >
Encoding:
Text File  |  1996-10-17  |  8.9 KB  |  314 lines

  1. /*
  2. DemoCam QC mod by Harlequin (dtebben@alumni.caltech.edu).  See the
  3. democam.txt file for info on how to use -- it's a bit confusing.
  4. The intermission and top-dog cams are broken and possibly not fixable.
  5. If you have any luck, please drop me a line.
  6. */
  7.  
  8. float SVC_SETVIEWPORT    = 5;
  9. void() W_SetCurrentAmmo;
  10.  
  11. //#Harlequin#  Turns off the democam (back to first-person in the demo)
  12. void(entity CamClient) DemoCamStop =
  13. {
  14.     if (!CamClient.HAS_DEMOCAM)
  15.         return;
  16.  
  17.     msg_entity = CamClient;
  18.     WriteByte(MSG_ONE, SVC_SETVIEWPORT);
  19.     WriteEntity(MSG_ONE, CamClient);
  20.     CamClient.HAS_DEMOCAM = 0;
  21.     CamClient.VIEW_ON_DEMOCAM = 0;
  22.     W_SetCurrentAmmo();
  23. };
  24.  
  25.  
  26. //#Harlequin#  FindTopDog returns the player with the most frags.
  27. entity(entity oldtopdog) FindTopDog =
  28. {
  29.     local entity topdog, searchent;
  30.  
  31.     topdog = oldtopdog;
  32.     searchent = findradius(oldtopdog.origin, 100000);
  33.     while (searchent)
  34.     {
  35.         if (searchent.classname == "player")
  36.         {
  37.             if (searchent.frags > topdog.frags)
  38.                 topdog = searchent;
  39.         }
  40.         searchent = searchent.chain;
  41.     }
  42.     return topdog;
  43. };
  44.  
  45. //#Harlequin#  FindIntermissionCam returns the intermission spot with
  46. //the most players in view.
  47. entity() FindIntermissionCam =
  48. {
  49.     local entity newintercam, searchent, searchent2;
  50.     local float playercount, bestplayercount;
  51.  
  52.     searchent = find(world, classname, "info_intermission");
  53.     while (searchent)
  54.     {
  55.         searchent2 = find(world, classname, "player");
  56.         while (searchent2)
  57.         {
  58.             traceline(searchent.origin, searchent2.origin, TRUE, searchent);
  59.             if (trace_fraction == 1)
  60.                 playercount = playercount + 1;
  61.             searchent2 = find(searchent2, classname, "player");
  62.         }
  63.         if (playercount > bestplayercount)
  64.         {
  65.             newintercam = searchent;
  66.             bestplayercount = playercount;
  67.         }
  68.         playercount = 0;
  69.         searchent = find(searchent, classname, "info_intermission");
  70.     }
  71.  
  72. //#Harlequin#  If there are no players within LOS of an intermission
  73. //camera, switching to it screws everything up.  Therefore wait until
  74. //someone can be seen before switching.
  75.     if (bestplayercount > 0)
  76.         return newintercam;
  77.     else
  78.         return world;
  79.  
  80.  
  81. //#Harlequin#  If no intermission spots, look for player_start
  82.     searchent = find(world, classname, "info_player_start");
  83.     if (searchent)
  84.         return searchent;
  85.  
  86. //#Harlequin#  For funky maps with no player_start
  87.     searchent = find(world, classname, "testplayerstart");
  88.     if (searchent)
  89.         return searchent;
  90.  
  91. //#Harlequin#  This shouldn't ever happen
  92.     objerror ("FindIntermissionCam: no spot");
  93. };
  94.  
  95.  
  96. //#Harlequin#  The think routine for intermission cams.
  97. void() IntermissionCamThink =
  98. {
  99.     local entity newintercam;
  100.  
  101. //#Harlequin#  Finds a new spot every 10 seconds.
  102.     self.nextthink = time + 0.1;
  103.  
  104.     if (self.INTER_TIME < time)
  105.     {
  106.         newintercam = FindIntermissionCam();
  107.  
  108.         if (newintercam != world)
  109.         {
  110.             setorigin(self, newintercam.origin);
  111.             self.INTER_TIME = time + 10;
  112.             self.angles = self.v_angle = newintercam.mangle;
  113.         }
  114.     }
  115. };
  116.  
  117.  
  118. //#Harlequin#  Chase cam tracking code lifted wholesale from Eli
  119. //(apathas@mailhost.primenet.com)'s excellent ChaseCam mod in kuaqe2.
  120. //Only minor changes (except the TopDog stuff).
  121. void() DemoCamTrack =
  122. {
  123.   local vector spot2,
  124.                dir;
  125.   local float  dist,
  126.                cap;
  127.   local entity topdogtest;
  128.     
  129. //#Harlequin#  Stop recording in intermissions, or else funny things
  130. //will happen to the demo.  Anybody know how to fix this?
  131. //#Harlequin#  Note that self.owner is whoever it's following, but
  132. //self.DEMOCAM is the person recording the demo.  Here, top_dog_time
  133. //is actually a brief delay so the scores are included in the demo.
  134.   if ((self.owner.movetype == MOVETYPE_NONE) && (self.owner.health > 0))
  135.   {
  136.     if ((self.TOP_DOG_TIME > time + 3) && (self.TOP_DOG_TIME < time + 10))
  137.     {
  138.         stuffcmd(self.DEMOCAM, "stop\n");
  139.         DemoCamStop(self.DEMOCAM);
  140.     }
  141.     else if (self.TOP_DOG_TIME < time + 3)
  142.         self.TOP_DOG_TIME = time + 12;
  143.   }
  144.  
  145.   self.nextthink = time + 0.1;
  146.  
  147. //#Harlequin#  The basic routine for TopDogChaseCams.  It only checks
  148. //every 2 seconds because: 1) it could get confusing otherwise and
  149. //2) very frequent calls of FindRadius can slow down the server.
  150. //Note that self.owner is just who it happens to be following.
  151.   if ((self.TOP_DOG_TIME) && (self.TOP_DOG_TIME < time))
  152.   {
  153.     self.TOP_DOG_TIME = time + 2;
  154.     topdogtest = FindTopDog(self.owner);
  155.     if (topdogtest != self.owner)
  156.     {
  157.         self.owner = topdogtest;
  158.         self.origin = self.owner.origin;
  159.     }
  160.   }
  161.  
  162.   makevectors (self.owner.v_angle);
  163.  
  164.   // Set initial spot before clipping, compensating for looking up
  165.   // and down so the player doesn't block the view
  166.   spot2 = self.owner.origin - (v_forward * self.ammo_shells);
  167.   spot2_z = spot2_z + 16;
  168.  
  169.   if (self.owner.v_angle_x < 0)
  170.     spot2 = spot2 - self.owner.v_angle_x * 0.6 * v_up;
  171.   if (self.owner.v_angle_x > 0)
  172.     spot2 = spot2 + self.owner.v_angle_x * 0.6 * v_up;
  173.  
  174.   traceline (self.owner.origin, spot2, TRUE, self.owner);
  175.   self.ammo_shells = vlen (trace_endpos - self.owner.origin);
  176.   spot2 = trace_endpos + (v_forward * 2);
  177.  
  178.   traceline (spot2, spot2 + '0 0 32', TRUE, self.owner );
  179.   if (trace_fraction < 1 )
  180.     spot2 = trace_endpos - '0 0 32';
  181.  
  182.   dir = normalize (spot2 - self.origin);
  183.   dist = vlen (spot2 - self.origin);
  184.  
  185.   traceline (self.origin, spot2, TRUE, self.owner);
  186.   if (trace_fraction == 1)
  187.   {
  188.     self.angles = self.owner.angles;
  189.     cap = dist * 0.2;
  190.  
  191.     if (cap > 5.2)
  192.       self.velocity = dir * dist * 5.2;
  193.     else if (cap > 1)
  194.       self.velocity = dir * dist * cap;
  195.     else
  196.       self.velocity = dir * dist;
  197.  
  198.     if ((vlen(self.owner.origin - self.origin)) < 30)
  199.     {
  200.       self.velocity = self.velocity * 2;
  201.     }
  202.   }
  203.   else
  204.     setorigin (self, spot2);
  205.    
  206.   self.ammo_shells = self.ammo_shells + 4;
  207.  
  208.   if (self.ammo_shells > 72)
  209.     self.ammo_shells = 72;
  210.  
  211.   // respawn if missile ent. get's hung up
  212.   if (self.oldorigin == self.origin)
  213.   {
  214.     if (dist > 30)
  215.       self.ammo_nails = self.ammo_nails + 1;
  216.   }
  217.  
  218.   if (self.ammo_nails > 3)
  219.   {
  220.     self.origin = self.owner.origin;
  221.     return;
  222.   }
  223.  
  224.   self.oldorigin = self.origin;
  225. };
  226.  
  227. //#Harlequin#  The next function initializes the DemoCam.  Also taken
  228. //mostly from Eli's code.  CamClient is the person activating it.
  229. void(entity CamClient, float camtype) DemoCamStart =
  230. {
  231.     local entity DemoCam;
  232.  
  233.     msg_entity = CamClient;
  234.  
  235. //#Harlequin#  Get rid of the old democam, if it exists
  236.     if(CamClient.HAS_DEMOCAM)
  237.     {
  238.         WriteByte(MSG_ONE, SVC_SETVIEWPORT);  
  239.         WriteEntity(MSG_ONE, CamClient);
  240.         remove(CamClient.DEMOCAM);
  241.         CamClient.HAS_DEMOCAM = 0;
  242.         CamClient.VIEW_ON_DEMOCAM = 0;
  243.     }
  244.     DemoCam = spawn();
  245.     DemoCam.solid = SOLID_NOT;
  246.     DemoCam.movetype = MOVETYPE_FLYMISSILE;
  247.     DemoCam.owner = CamClient;
  248.     DemoCam.angles = DemoCam.owner.angles;
  249.  
  250. //#Harlequin#  This is confusing, but it just gives the camera & client
  251. //references to one another.
  252.     DemoCam.owner.DEMOCAM = DemoCam;
  253.     DemoCam.DEMOCAM = CamClient;
  254.  
  255.     DemoCam.owner.HAS_DEMOCAM = 1;
  256.     setmodel(DemoCam, "progs/s_bubble.spr");
  257. //#Harlequin#  Uncomment the next line to use the null sprite instead,
  258. //but remember to uncomment the precaching line in weapons.qc also
  259. //    setmodel(DemoCam, "null.spr");
  260.     setsize(DemoCam, '0 0 0', '0 0 0');
  261.     setorigin(DemoCam, DemoCam.owner.origin);
  262.     DemoCam.nextthink = time; 
  263.     if (camtype != 3) //#Harlequin#  All except intermission cam
  264.         DemoCam.think = DemoCamTrack;
  265.     else
  266.         DemoCam.think = IntermissionCamThink;
  267.     if (camtype == 2)
  268.         DemoCam.TOP_DOG_TIME = time;
  269.  
  270. //#Harlequin#  Switch the view to cam & back rapidly.  The aliases
  271. //are to mark the demo -- read the readme!
  272.     WriteByte(MSG_ONE, SVC_SETVIEWPORT); 
  273.     WriteEntity(MSG_ONE, DemoCam);
  274.     stuffcmd(CamClient, "alias disconnect\n");
  275.     WriteByte(MSG_ONE, SVC_SETVIEWPORT);  
  276.     WriteEntity(MSG_ONE, DemoCam.owner);
  277.     stuffcmd(CamClient, "alias disconnect\n");
  278.     if (!CamClient.SHOW_WEAPONMODELS)
  279.         CamClient.weaponmodel = string_null;
  280. };
  281.  
  282.  
  283. //#Harlequin#  DemoCamViewOn works only if the player is within line-of-
  284. //sight of his democam.  It does not continue to check for LOS after
  285. //activation, but being unable to see your own character is unlikely to
  286. //provide any advantage in a deathmatch :-).
  287. void(entity CamClient) DemoCamViewOn =
  288. {
  289.     if (!CamClient.HAS_DEMOCAM)
  290.         return;
  291.  
  292. //    traceline(CamClient.origin, CamClient.DEMOCAM.origin, TRUE, CamClient);
  293. //    if (trace_fraction == 1)
  294.     {
  295.         msg_entity = CamClient;
  296.         WriteByte(MSG_ONE, SVC_SETVIEWPORT);  
  297.         WriteEntity(MSG_ONE, CamClient.DEMOCAM);
  298.         CamClient.VIEW_ON_DEMOCAM = 1;
  299.     }
  300. };
  301.  
  302. //#Harlequin#  Similar to the same code in the start function.  The
  303. //aliasing stuff marks the demo.
  304. void(entity CamClient) DemoCamViewOff =
  305. {
  306.     msg_entity = CamClient;
  307.     WriteByte(MSG_ONE, SVC_SETVIEWPORT);  
  308.     WriteEntity(MSG_ONE, CamClient.DEMOCAM);
  309.     stuffcmd(CamClient, "alias disconnect\n");
  310.     WriteByte(MSG_ONE, SVC_SETVIEWPORT);  
  311.     WriteEntity(MSG_ONE, CamClient);
  312.     stuffcmd(CamClient, "alias disconnect\n");
  313.     CamClient.VIEW_ON_DEMOCAM = 0;
  314. };