home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 113 / EnigmaAmiga113CD.iso / software / sviluppo / quakeworld_src / client / cl_cam.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-17  |  13.9 KB  |  575 lines

  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the included (GNU.txt) GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. /* ZOID
  21.  *
  22.  * Player camera tracking in Spectator mode
  23.  *
  24.  * This takes over player controls for spectator automatic camera.
  25.  * Player moves as a spectator, but the camera tracks and enemy player
  26.  */
  27.  
  28. #include "quakedef.h"
  29. #include "winquake.h"
  30.  
  31. #define PM_SPECTATORMAXSPEED  500
  32. #define PM_STOPSPEED  100
  33. #define PM_MAXSPEED     320
  34. #define BUTTON_JUMP 2
  35. #define BUTTON_ATTACK 1
  36. #define MAX_ANGLE_TURN 10
  37.  
  38. static vec3_t desired_position; // where the camera wants to be
  39. static qboolean locked = false;
  40. static int oldbuttons;
  41.  
  42. // track high fragger
  43. cvar_t cl_hightrack = {"cl_hightrack", "0" };
  44.  
  45. cvar_t cl_chasecam = {"cl_chasecam", "0"};
  46.  
  47. //cvar_t cl_camera_maxpitch = {"cl_camera_maxpitch", "10" };
  48. //cvar_t cl_camera_maxyaw = {"cl_camera_maxyaw", "30" };
  49.  
  50. qboolean cam_forceview;
  51. vec3_t cam_viewangles;
  52. double cam_lastviewtime;
  53.  
  54. int spec_track = 0; // player# of who we are tracking
  55. int autocam = CAM_NONE;
  56.  
  57. static void vectoangles(vec3_t vec, vec3_t ang)
  58. {
  59.   float forward;
  60.   float yaw, pitch;
  61.   
  62.   if (vec[1] == 0 && vec[0] == 0)
  63.   {
  64.     yaw = 0;
  65.     if (vec[2] > 0)
  66.       pitch = 90;
  67.     else
  68.       pitch = 270;
  69.   }
  70.   else
  71.   {
  72.     yaw = (int) (atan2(vec[1], vec[0]) * 180 / M_PI);
  73.     if (yaw < 0)
  74.       yaw += 360;
  75.  
  76.     forward = sqrt (vec[0]*vec[0] + vec[1]*vec[1]);
  77.     pitch = (int) (atan2(vec[2], forward) * 180 / M_PI);
  78.     if (pitch < 0)
  79.       pitch += 360;
  80.   }
  81.  
  82.   ang[0] = pitch;
  83.   ang[1] = yaw;
  84.   ang[2] = 0;
  85. }
  86.  
  87. static float vlen(vec3_t v)
  88. {
  89.   return sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
  90. }
  91.  
  92. // returns true if weapon model should be drawn in camera mode
  93. qboolean Cam_DrawViewModel(void)
  94. {
  95.   if (!cl.spectator)
  96.     return true;
  97.  
  98.   if (autocam && locked && cl_chasecam.value)
  99.     return true;
  100.   return false;
  101. }
  102.  
  103. // returns true if we should draw this player, we don't if we are chase camming
  104. qboolean Cam_DrawPlayer(int playernum)
  105. {
  106.   if (cl.spectator && autocam && locked && cl_chasecam.value && 
  107.     spec_track == playernum)
  108.     return false;
  109.   return true;
  110. }
  111.  
  112. void Cam_Unlock(void)
  113. {
  114.   if (autocam) {
  115.     MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
  116.     MSG_WriteString (&cls.netchan.message, "ptrack");
  117.     autocam = CAM_NONE;
  118.     locked = false;
  119.     Sbar_Changed();
  120.   }
  121. }
  122.  
  123. void Cam_Lock(int playernum)
  124. {
  125.   char st[40];
  126.  
  127.   sprintf(st, "ptrack %i", playernum);
  128.   MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
  129.   MSG_WriteString (&cls.netchan.message, st);
  130.   spec_track = playernum;
  131.   cam_forceview = true;
  132.   locked = false;
  133.   Sbar_Changed();
  134. }
  135.  
  136. pmtrace_t Cam_DoTrace(vec3_t vec1, vec3_t vec2)
  137. {
  138. #if 0
  139.   memset(&pmove, 0, sizeof(pmove));
  140.  
  141.   pmove.numphysent = 1;
  142.   VectorCopy (vec3_origin, pmove.physents[0].origin);
  143.   pmove.physents[0].model = cl.worldmodel;
  144. #endif
  145.  
  146.   VectorCopy (vec1, pmove.origin);
  147.   return PM_PlayerMove(pmove.origin, vec2);
  148. }
  149.   
  150. // Returns distance or 9999 if invalid for some reason
  151. static float Cam_TryFlyby(player_state_t *self, player_state_t *player, vec3_t vec, qboolean checkvis)
  152. {
  153.   vec3_t v;
  154.   pmtrace_t trace;
  155.   float len;
  156.  
  157.   vectoangles(vec, v);
  158. //  v[0] = -v[0];
  159.   VectorCopy (v, pmove.angles);
  160.   VectorNormalize(vec);
  161.   VectorMA(player->origin, 800, vec, v);
  162.   // v is endpos
  163.   // fake a player move
  164.   trace = Cam_DoTrace(player->origin, v);
  165.   if (/*trace.inopen ||*/ trace.inwater)
  166.     return 9999;
  167.   VectorCopy(trace.endpos, vec);
  168.   VectorSubtract(trace.endpos, player->origin, v);
  169.   len = sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
  170.   if (len < 32 || len > 800)
  171.     return 9999;
  172.   if (checkvis) {
  173.     VectorSubtract(trace.endpos, self->origin, v);
  174.     len = sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
  175.  
  176.     trace = Cam_DoTrace(self->origin, vec);
  177.     if (trace.fraction != 1 || trace.inwater)
  178.       return 9999;
  179.   }
  180.   return len;
  181. }
  182.  
  183. // Is player visible?
  184. static qboolean Cam_IsVisible(player_state_t *player, vec3_t vec)
  185. {
  186.   pmtrace_t trace;
  187.   vec3_t v;
  188.   float d;
  189.  
  190.   trace = Cam_DoTrace(player->origin, vec);
  191.   if (trace.fraction != 1 || /*trace.inopen ||*/ trace.inwater)
  192.     return false;
  193.   // check distance, don't let the player get too far away or too close
  194.   VectorSubtract(player->origin, vec, v);
  195.   d = vlen(v);
  196.   if (d < 16)
  197.     return false;
  198.   return true;
  199. }
  200.  
  201. static qboolean InitFlyby(player_state_t *self, player_state_t *player, int checkvis) 
  202. {
  203.     float f, max;
  204.     vec3_t vec, vec2;
  205.   vec3_t forward, right, up;
  206.  
  207.   VectorCopy(player->viewangles, vec);
  208.     vec[0] = 0;
  209.   AngleVectors (vec, forward, right, up);
  210. //  for (i = 0; i < 3; i++)
  211. //    forward[i] *= 3;
  212.  
  213.     max = 1000;
  214.   VectorAdd(forward, up, vec2);
  215.   VectorAdd(vec2, right, vec2);
  216.     if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < max) {
  217.         max = f;
  218.     VectorCopy(vec2, vec);
  219.     }
  220.   VectorAdd(forward, up, vec2);
  221.   VectorSubtract(vec2, right, vec2);
  222.     if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < max) {
  223.         max = f;
  224.     VectorCopy(vec2, vec);
  225.     }
  226.   VectorAdd(forward, right, vec2);
  227.     if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < max) {
  228.         max = f;
  229.     VectorCopy(vec2, vec);
  230.     }
  231.   VectorSubtract(forward, right, vec2);
  232.     if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < max) {
  233.         max = f;
  234.     VectorCopy(vec2, vec);
  235.     }
  236.   VectorAdd(forward, up, vec2);
  237.     if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < max) {
  238.         max = f;
  239.     VectorCopy(vec2, vec);
  240.     }
  241.   VectorSubtract(forward, up, vec2);
  242.     if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < max) {
  243.         max = f;
  244.     VectorCopy(vec2, vec);
  245.     }
  246.   VectorAdd(up, right, vec2);
  247.   VectorSubtract(vec2, forward, vec2);
  248.     if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < max) {
  249.         max = f;
  250.     VectorCopy(vec2, vec);
  251.     }
  252.   VectorSubtract(up, right, vec2);
  253.   VectorSubtract(vec2, forward, vec2);
  254.     if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < max) {
  255.         max = f;
  256.     VectorCopy(vec2, vec);
  257.     }
  258.   // invert
  259.   VectorSubtract(vec3_origin, forward, vec2);
  260.     if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < max) {
  261.         max = f;
  262.     VectorCopy(vec2, vec);
  263.     }
  264.   VectorCopy(forward, vec2);
  265.     if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < max) {
  266.         max = f;
  267.     VectorCopy(vec2, vec);
  268.     }
  269.   // invert
  270.   VectorSubtract(vec3_origin, right, vec2);
  271.     if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < max) {
  272.         max = f;
  273.     VectorCopy(vec2, vec);
  274.     }
  275.   VectorCopy(right, vec2);
  276.     if ((f = Cam_TryFlyby(self, player, vec2, checkvis)) < max) {
  277.         max = f;
  278.     VectorCopy(vec2, vec);
  279.     }
  280.  
  281.   // ack, can't find him
  282.     if (max >= 1000) {
  283. //    Cam_Unlock();
  284.     return false;
  285.   }
  286.   locked = true;
  287.   VectorCopy(vec, desired_position); 
  288.   return true;
  289. }
  290.  
  291. static void Cam_CheckHighTarget(void)
  292. {
  293.   int i, j, max;
  294.   player_info_t *s;
  295.  
  296.   j = -1;
  297.   for (i = 0, max = -9999; i < MAX_CLIENTS; i++) {
  298.     s = &cl.players[i];
  299.     if (s->name[0] && !s->spectator && s->frags > max) {
  300.       max = s->frags;
  301.       j = i;
  302.     }
  303.   }
  304.   if (j >= 0) {
  305.     if (!locked || cl.players[j].frags > cl.players[spec_track].frags)
  306.       Cam_Lock(j);
  307.   } else
  308.     Cam_Unlock();
  309. }
  310.   
  311. // ZOID
  312. //
  313. // Take over the user controls and track a player.
  314. // We find a nice position to watch the player and move there
  315. void Cam_Track(usercmd_t *cmd)
  316. {
  317.   player_state_t *player, *self;
  318.   frame_t *frame;
  319.   vec3_t vec;
  320.   float len;
  321.  
  322.   if (!cl.spectator)
  323.     return;
  324.   
  325.   if (cl_hightrack.value && !locked)
  326.     Cam_CheckHighTarget();
  327.  
  328.   if (!autocam || cls.state != ca_active)
  329.     return;
  330.  
  331.   if (locked && (!cl.players[spec_track].name[0] || cl.players[spec_track].spectator)) {
  332.     locked = false;
  333.     if (cl_hightrack.value)
  334.       Cam_CheckHighTarget();
  335.     else
  336.       Cam_Unlock();
  337.     return;
  338.   }
  339.  
  340.   frame = &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK];
  341.   player = frame->playerstate + spec_track;
  342.   self = frame->playerstate + cl.playernum;
  343.  
  344.   if (!locked || !Cam_IsVisible(player, desired_position)) {
  345.     if (!locked || realtime - cam_lastviewtime > 0.1) {
  346.       if (!InitFlyby(self, player, true))
  347.         InitFlyby(self, player, false);
  348.       cam_lastviewtime = realtime;
  349.     }
  350.   } else
  351.     cam_lastviewtime = realtime;
  352.   
  353.   // couldn't track for some reason
  354.   if (!locked || !autocam)
  355.     return;
  356.  
  357.   if (cl_chasecam.value) {
  358.     cmd->forwardmove = cmd->sidemove = cmd->upmove = 0;
  359.  
  360.     VectorCopy(player->viewangles, cl.viewangles);
  361.     VectorCopy(player->origin, desired_position);
  362.     if (memcmp(&desired_position, &self->origin, sizeof(desired_position)) != 0) {
  363.       MSG_WriteByte (&cls.netchan.message, clc_tmove);
  364.       MSG_WriteCoord (&cls.netchan.message, desired_position[0]);
  365.       MSG_WriteCoord (&cls.netchan.message, desired_position[1]);
  366.       MSG_WriteCoord (&cls.netchan.message, desired_position[2]);
  367.       // move there locally immediately
  368.       VectorCopy(desired_position, self->origin);
  369.     }
  370.     self->weaponframe = player->weaponframe;
  371.  
  372.   } else {
  373.     // Ok, move to our desired position and set our angles to view
  374.     // the player
  375.     VectorSubtract(desired_position, self->origin, vec);
  376.     len = vlen(vec);
  377.     cmd->forwardmove = cmd->sidemove = cmd->upmove = 0;
  378.     if (len > 16) { // close enough?
  379.       MSG_WriteByte (&cls.netchan.message, clc_tmove);
  380.       MSG_WriteCoord (&cls.netchan.message, desired_position[0]);
  381.       MSG_WriteCoord (&cls.netchan.message, desired_position[1]);
  382.       MSG_WriteCoord (&cls.netchan.message, desired_position[2]);
  383.     }
  384.  
  385.     // move there locally immediately
  386.     VectorCopy(desired_position, self->origin);
  387.                      
  388.     VectorSubtract(player->origin, desired_position, vec);
  389.     vectoangles(vec, cl.viewangles);
  390.     cl.viewangles[0] = -cl.viewangles[0];
  391.   }
  392. }
  393.  
  394. #if 0
  395. static float adjustang(float current, float ideal, float speed)
  396. {
  397.   float move;
  398.  
  399.   current = anglemod(current);
  400.   ideal = anglemod(ideal);
  401.  
  402.   if (current == ideal)
  403.     return current;
  404.  
  405.   move = ideal - current;
  406.   if (ideal > current)
  407.   {
  408.     if (move >= 180)
  409.       move = move - 360;
  410.   }
  411.   else
  412.   {
  413.     if (move <= -180)
  414.       move = move + 360;
  415.   }
  416.   if (move > 0)
  417.   {
  418.     if (move > speed)
  419.       move = speed;
  420.   }
  421.   else
  422.   {
  423.     if (move < -speed)
  424.       move = -speed;
  425.   }
  426.  
  427. //Con_Printf("c/i: %4.2f/%4.2f move: %4.2f\n", current, ideal, move);
  428.   return anglemod (current + move);
  429. }
  430. #endif
  431.  
  432. #if 0
  433. void Cam_SetView(void)
  434. {
  435.   return;
  436.   player_state_t *player, *self;
  437.   frame_t *frame;
  438.   vec3_t vec, vec2;
  439.  
  440.   if (cls.state != ca_active || !cl.spectator || 
  441.     !autocam || !locked)
  442.     return;
  443.  
  444.   frame = &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK];
  445.   player = frame->playerstate + spec_track;
  446.   self = frame->playerstate + cl.playernum;
  447.  
  448.   VectorSubtract(player->origin, cl.simorg, vec);
  449.   if (cam_forceview) {
  450.     cam_forceview = false;
  451.     vectoangles(vec, cam_viewangles);
  452.     cam_viewangles[0] = -cam_viewangles[0];
  453.   } else {
  454.     vectoangles(vec, vec2);
  455.     vec2[PITCH] = -vec2[PITCH];
  456.  
  457.     cam_viewangles[PITCH] = adjustang(cam_viewangles[PITCH], vec2[PITCH], cl_camera_maxpitch.value);
  458.     cam_viewangles[YAW] = adjustang(cam_viewangles[YAW], vec2[YAW], cl_camera_maxyaw.value);
  459.   }
  460.   VectorCopy(cam_viewangles, cl.viewangles);
  461.   VectorCopy(cl.viewangles, cl.simangles);
  462. }
  463. #endif
  464.  
  465. void Cam_FinishMove(usercmd_t *cmd)
  466. {
  467.   int i;
  468.   player_info_t *s;
  469.   int end;
  470.  
  471.   if (cls.state != ca_active)
  472.     return;
  473.  
  474.   if (!cl.spectator) // only in spectator mode
  475.     return;
  476.  
  477. #if 0
  478.   if (autocam && locked) {
  479.     frame = &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK];
  480.     player = frame->playerstate + spec_track;
  481.     self = frame->playerstate + cl.playernum;
  482.  
  483.     VectorSubtract(player->origin, self->origin, vec);
  484.     if (cam_forceview) {
  485.       cam_forceview = false;
  486.       vectoangles(vec, cam_viewangles);
  487.       cam_viewangles[0] = -cam_viewangles[0];
  488.     } else {
  489.       vectoangles(vec, vec2);
  490.       vec2[PITCH] = -vec2[PITCH];
  491.  
  492.       cam_viewangles[PITCH] = adjustang(cam_viewangles[PITCH], vec2[PITCH], cl_camera_maxpitch.value);
  493.       cam_viewangles[YAW] = adjustang(cam_viewangles[YAW], vec2[YAW], cl_camera_maxyaw.value);
  494.     }
  495.     VectorCopy(cam_viewangles, cl.viewangles);
  496.   }
  497. #endif
  498.  
  499.   if (cmd->buttons & BUTTON_ATTACK) {
  500.     if (!(oldbuttons & BUTTON_ATTACK)) {
  501.  
  502.       oldbuttons |= BUTTON_ATTACK;
  503.       autocam++;
  504.  
  505.       if (autocam > CAM_TRACK) {
  506.         Cam_Unlock();
  507.         VectorCopy(cl.viewangles, cmd->angles);
  508.         return;
  509.       }
  510.     } else
  511.       return;
  512.   } else {
  513.     oldbuttons &= ~BUTTON_ATTACK;
  514.     if (!autocam)
  515.       return;
  516.   }
  517.  
  518.   if (autocam && cl_hightrack.value) {
  519.     Cam_CheckHighTarget();
  520.     return;
  521.   }
  522.  
  523.   if (locked) {
  524.     if ((cmd->buttons & BUTTON_JUMP) && (oldbuttons & BUTTON_JUMP))
  525.       return;   // don't pogo stick
  526.  
  527.     if (!(cmd->buttons & BUTTON_JUMP)) {
  528.       oldbuttons &= ~BUTTON_JUMP;
  529.       return;
  530.     }
  531.     oldbuttons |= BUTTON_JUMP;  // don't jump again until released
  532.   }
  533.  
  534. //  Con_Printf("Selecting track target...\n");
  535.  
  536.   if (locked && autocam)
  537.     end = (spec_track + 1) % MAX_CLIENTS;
  538.   else
  539.     end = spec_track;
  540.   i = end;
  541.   do {
  542.     s = &cl.players[i];
  543.     if (s->name[0] && !s->spectator) {
  544.       Cam_Lock(i);
  545.       return;
  546.     }
  547.     i = (i + 1) % MAX_CLIENTS;
  548.   } while (i != end);
  549.   // stay on same guy?
  550.   i = spec_track;
  551.   s = &cl.players[i];
  552.   if (s->name[0] && !s->spectator) {
  553.     Cam_Lock(i);
  554.     return;
  555.   }
  556.   Con_Printf("No target found ...\n");
  557.   autocam = locked = false;
  558. }
  559.  
  560. void Cam_Reset(void)
  561. {
  562.   autocam = CAM_NONE;
  563.   spec_track = 0;
  564. }
  565.  
  566. void CL_InitCam(void)
  567. {
  568.   Cvar_RegisterVariable (&cl_hightrack);
  569.   Cvar_RegisterVariable (&cl_chasecam);
  570. //  Cvar_RegisterVariable (&cl_camera_maxpitch);
  571. //  Cvar_RegisterVariable (&cl_camera_maxyaw);
  572. }
  573.  
  574.  
  575.