home *** CD-ROM | disk | FTP | other *** search
/ Quake 'em / QUAKEEM.BIN / quake / programs / camera / nezu_cam.qc < prev    next >
Encoding:
Text File  |  1996-08-05  |  9.3 KB  |  284 lines

  1. //
  2. //      Nezu Camera V1.0    4/8/96
  3. //
  4. // A simple implementation of the infamous Duke3D Camera for Quake v1.01
  5. // Made possible thanx to the DEM spec, that tell everything about
  6. // messages from server to client.
  7. //   
  8. /* 
  9. **
  10. ** Example of Camera Usage
  11. **
  12. ** Modify file weapons.qc
  13. **
  14. void() ImpulseCommands =
  15. {
  16.   ...
  17. //------------------------- Patch by Nezu 4/8/96 ---------------------------    
  18. // New impulse 240 = Camera
  19.     if (self.impulse == 240)
  20.         NezuCamera( self);
  21. // New impulse 242 = CameraCycle
  22.         if (self.impulse == 242)
  23.                 NezuCameraCycle(self);
  24. //------------------------------- End Patch -------------------------------
  25.   ...
  26. };
  27. **  
  28. **
  29. */
  30. //--------------------------------------------------------
  31. //
  32. // Function prototypes, for dealing with camera
  33. //
  34. //--------------------------------------------------------
  35. //
  36. void(entity me, entity camera)     NezuSetViewPoint;
  37. void(entity me, vector viewangles) NezuSetViewAngle;
  38. void(entity me)                    NezuCamera;
  39. //
  40. float SVC_SETVIEWPORT = 5;    // Net.Protocol 0x05
  41. float SVC_SETVIEWANGLES = 10; // Net.Protocol 0x0A
  42. float SVC_UPDATEENTITY = 128; // Net.Protocol 0x80
  43. //
  44. //--------------------------------------------------------
  45. // NezuSetViewPoint( me, camera);
  46. //   me     = player entity
  47. //   camera = entity that is playing the camera for me
  48. // Make a player see through a given entity (the camera).
  49. //--------------------------------------------------------
  50. //
  51. // Dependencies:
  52. //      msg_entity is modified
  53. //
  54. void(entity me, entity camera) NezuSetViewPoint =
  55. {
  56.   // Set view point
  57.   msg_entity = me;                         // target of message
  58.   WriteByte (MSG_ONE, SVC_SETVIEWPORT);    // 5 = SVC_SETVIEWPORT;  
  59.   WriteEntity (MSG_ONE, camera);           // view port
  60.   // Also set angles, otherwise it feels strange
  61.   // NezuSetViewAngle(me, camera.angles);
  62.   WriteByte (MSG_ONE, SVC_SETVIEWANGLES);  // 10 = SVC_SETVIEWANGLES
  63.   WriteAngle(MSG_ONE, camera.angles_x);    // tilt 
  64.   WriteAngle(MSG_ONE, camera.angles_y);    // yaw
  65.   WriteAngle(MSG_ONE, camera.angles_z);    // flip
  66. };
  67. //
  68. //--------------------------------------------------------
  69. // NezuSetViewAngle( me, angles);
  70. //   me     = player entity
  71. //   angles = new orientation angles for me
  72. // Change the view angles of a player.
  73. // Note: setting me.angles doesn't work for players.
  74. //--------------------------------------------------------
  75. //
  76. // Dependencies:
  77. //      msg_entity is modified
  78. //
  79. void(entity me, vector viewangles) NezuSetViewAngle =
  80. {
  81.   msg_entity = me;                         // target of message
  82.   WriteByte(MSG_ONE, SVC_SETVIEWANGLES);   // 10 = SVC_SETVIEWANGLES
  83.   WriteAngle(MSG_ONE, viewangles_x);       // tilt 
  84.   WriteAngle(MSG_ONE, viewangles_y);       // yaw
  85.   WriteAngle(MSG_ONE, viewangles_z);       // flip
  86. };
  87. //
  88. //--------------------------------------------------------
  89. // NezuUpdateCamera( me, camera);
  90. //   me     = player entity
  91. //   camera = entity that might be unknown to the client
  92. // Declare an entity position to the client. That's useful because if a client
  93. // doesn't know where an entity is, it assumes it's in '0 0 0' (usually wrong...)
  94. //--------------------------------------------------------
  95. //
  96. // Dependencies: 
  97. //      msg_entity is modified
  98. //
  99. void(entity me, entity camera) NezuUpdateCamera =
  100. {
  101.   msg_entity = me;                         // target of message
  102.   //0x0080 = SVC_UPDATEENTITY
  103.   // |   1 = extended mask
  104.   // |   2 = position_x
  105.   // |   4 = position_y
  106.   // |   8 = position_z
  107.   // |  10 = angles_y (yaw)
  108.   // |  20 = new
  109.   // |  40 = frame
  110.   WriteByte (MSG_ONE, SVC_UPDATEENTITY|15); // 0x80|1|2|4|8
  111.   //0x00XX =
  112.   // |01xx = angles_x (tilt)
  113.   // |02xx = angles_z (flip)
  114.   // |04xx = modelindex
  115.   // |08xx = colormap
  116.   // |10xx = skin
  117.   // |20xx = attack state
  118.   // |40xx = entity as short, not byte
  119.   WriteByte (MSG_ONE, 64); // 0x40
  120.   // mask &0x4000:  ReadShort   
  121.   WriteEntity(MSG_ONE,camera);
  122.   // origin[0] = mask & 0x0002 ? ReadCoord : default
  123.   WriteCoord(MSG_ONE,camera.origin_x);
  124.   // origin[1] = mask & 0x0004 ? ReadCoord : default
  125.   WriteCoord(MSG_ONE,camera.origin_y);
  126.   // origin[2] = mask & 0x0008 ? ReadCoord : default
  127.   WriteCoord(MSG_ONE,camera.origin_z);
  128. };
  129. //
  130. //
  131. //--------------------------------------------------------
  132. // entity = NezuFindClosest( scenter, srange);
  133. //   scenter = center of sphere
  134. //   srange  = size of sphere
  135. // Find the entity that is closest to the center of the sphere
  136. // Returns world if none was found 
  137. //--------------------------------------------------------
  138. //
  139. // Dependencies: entity.chain is modified by findradius
  140. //
  141. entity(vector scenter, float srange) NezuFindClosest =
  142. {
  143.   local float  dist;
  144.   local float  edist;
  145.   local entity e;
  146.   local entity best;
  147.   dist = srange;
  148.   e = findradius( scenter, srange); 
  149.   while(e)  // e != world
  150.   { 
  151.     edist= vlen(e.origin - scenter);
  152.     if(edist<dist)
  153.     { 
  154.       if(e.classname != "path_corner") // avoid those entities
  155.       {
  156.         dist = edist;
  157.         best = e;
  158.       }
  159.     }
  160.     e = e.chain;
  161.   }
  162.   return best;
  163. };
  164.  
  165.  
  166. //
  167. //--------------------------------------------------------
  168. // NezuCamera( me);
  169. //   me     = player entity
  170. //   me.aflag = camera status (0=off 666=on 777=ready)
  171. //              this is a hack: self.aflag is used by doors only.
  172. //  Fire a line ahead. If an entity is touched, it becomes the camera.
  173. //  Next time this function is called, the view is restored to the player
  174. //--------------------------------------------------------
  175. // 
  176. // Dependencies:
  177. //   entity.trigger_field is used for the current camera
  178. //   entity.aflag   is used to toggle the camera status for each player
  179. //   trace_fraction, trace_ent  are modified by traceline()
  180. //
  181. // Rule:  me.aflag==666  means the camera is active.
  182. //
  183. void(entity me) NezuCamera = 
  184. {
  185.   local entity camera;
  186.   local    vector me_src;
  187.   local vector me_targ;
  188.   local vector me_fire;
  189.   if(me.aflag!=666)                // camera is on, set it off
  190.   { 
  191.     camera=me;
  192.     NezuSetViewPoint(me, me);      // restore player position
  193.     sprint(me,"Camera off\n");
  194.     me.aflag=666;                  // camera is ready
  195.     //do not change me.trigger_field  for the NezuCameraCycle
  196.   }
  197.   else                             // camera is off, try to set it on
  198.   { 
  199.     me_fire = aim(me, 200);        // slow missile speed
  200.     // makevectors(me.angles);     // set v_forward  
  201.     me_src = me.origin + '0 0 16';
  202.     me_targ = me_src  + me_fire*10000;
  203.     //
  204.     // Fire a line 10000 ahead. 
  205.     //
  206.     traceline (me_src, me_targ , FALSE, me);
  207.     //
  208.     // Find the entity hit
  209.     // 
  210.     if (trace_fraction >= 1.0) return;  // Nothing was hit
  211.     camera = trace_ent;
  212.     if (camera == world)                // hit the walls or floors
  213.     { 
  214.       camera = NezuFindClosest(trace_endpos, 100);
  215.       if(camera == world) return;          // found nothing
  216.     } 
  217.     //
  218.     // Set camera viewpoint
  219.     //    
  220.     NezuSetViewPoint(me, camera);       // Restore player position
  221.     sprint(me,"Camera set to ");      // Message for player
  222.     sprint(me,camera.classname);      // Bastard string concatenation from hell
  223.     sprint(me,"\n");                  // End the message,and print it
  224.     me.aflag=0;                       // Camera is on
  225.     me.trigger_field = camera;        // for the NezuCameraCycle
  226.   }
  227. };
  228. //
  229. //--------------------------------------------------------
  230. // NezuCameraCycle( me);
  231. //   me     = player entity
  232. //   me.aflag = camera status (0=off 666=on 777=ready)
  233. //              this is a hack: self.aflag is used by doors only.
  234. //   me.trigger_field = current camera
  235. //              this is a hack: self.trigger_field is used by doors only.
  236. //  Cycle player through all entities of a specific kind
  237. //  Next time this function is called, the view is restored to the player
  238. //--------------------------------------------------------
  239. // 
  240. //
  241. // Dependencies:
  242. //   entity.trigger_field is used for the current camera
  243. //   entity.aflag   is used to toggle the camera status for each player
  244. //   trace_fraction, trace_ent  are modified by traceline()
  245. //
  246. void(entity me) NezuCameraCycle = 
  247. {
  248.   local entity camera;
  249.   local string stufftofind;
  250.   
  251.   //
  252.   // cycle through entities, never come back to me
  253.   //
  254.   camera=me.trigger_field; 
  255.   do
  256.   {
  257.     camera = nextent(camera);
  258.     if(me.aflag & 1) // might not exist in level     
  259.       stufftofind = "item_shells"; 
  260.     else // must exist in level!
  261.       stufftofind = "info_player_deathmatch"; 
  262.     camera = find(camera, classname, stufftofind);
  263.     if(!camera) // cycle of 2 steps
  264.       me.aflag = (me.aflag + 1) & 1;
  265.   }while(!camera);
  266.   //
  267.   // Send to client an update of camera position
  268.   // Otherwise the camera is beleived to be in the void
  269.   //
  270.   NezuUpdateCamera(me, camera);
  271.   //
  272.   // Set camera viewpoint
  273.   //    
  274.   NezuSetViewPoint(me, camera);       // Restore player position
  275. // Removed the printing of coordinates, because fairly annoying 
  276. //  stufftofind= vtos(camera.origin);
  277. //  sprint(me,"Camera set to ");        // Message for player
  278. //  sprint(me, stufftofind);            // Bastard string concatenation from hell
  279. //  sprint(me,"\n");                    // End the message,and print it
  280.   me.trigger_field = camera;          // Current Camera
  281. };
  282. //
  283. // That's all there is to it. Enjoy!
  284. //