home *** CD-ROM | disk | FTP | other *** search
- //
- // Nezu Camera V1.0 4/8/96
- //
- // A simple implementation of the infamous Duke3D Camera for Quake v1.01
- // Made possible thanx to the DEM spec, that tell everything about
- // messages from server to client.
- //
- /*
- **
- ** Example of Camera Usage
- **
- ** Modify file weapons.qc
- **
- void() ImpulseCommands =
- {
- ...
- //------------------------- Patch by Nezu 4/8/96 ---------------------------
- // New impulse 240 = Camera
- if (self.impulse == 240)
- NezuCamera( self);
- // New impulse 242 = CameraCycle
- if (self.impulse == 242)
- NezuCameraCycle(self);
- //------------------------------- End Patch -------------------------------
- ...
- };
- **
- **
- */
- //--------------------------------------------------------
- //
- // Function prototypes, for dealing with camera
- //
- //--------------------------------------------------------
- //
- void(entity me, entity camera) NezuSetViewPoint;
- void(entity me, vector viewangles) NezuSetViewAngle;
- void(entity me) NezuCamera;
- //
- float SVC_SETVIEWPORT = 5; // Net.Protocol 0x05
- float SVC_SETVIEWANGLES = 10; // Net.Protocol 0x0A
- float SVC_UPDATEENTITY = 128; // Net.Protocol 0x80
- //
- //--------------------------------------------------------
- // NezuSetViewPoint( me, camera);
- // me = player entity
- // camera = entity that is playing the camera for me
- // Make a player see through a given entity (the camera).
- //--------------------------------------------------------
- //
- // Dependencies:
- // msg_entity is modified
- //
- void(entity me, entity camera) NezuSetViewPoint =
- {
- // Set view point
- msg_entity = me; // target of message
- WriteByte (MSG_ONE, SVC_SETVIEWPORT); // 5 = SVC_SETVIEWPORT;
- WriteEntity (MSG_ONE, camera); // view port
- // Also set angles, otherwise it feels strange
- // NezuSetViewAngle(me, camera.angles);
- WriteByte (MSG_ONE, SVC_SETVIEWANGLES); // 10 = SVC_SETVIEWANGLES
- WriteAngle(MSG_ONE, camera.angles_x); // tilt
- WriteAngle(MSG_ONE, camera.angles_y); // yaw
- WriteAngle(MSG_ONE, camera.angles_z); // flip
- };
- //
- //--------------------------------------------------------
- // NezuSetViewAngle( me, angles);
- // me = player entity
- // angles = new orientation angles for me
- // Change the view angles of a player.
- // Note: setting me.angles doesn't work for players.
- //--------------------------------------------------------
- //
- // Dependencies:
- // msg_entity is modified
- //
- void(entity me, vector viewangles) NezuSetViewAngle =
- {
- msg_entity = me; // target of message
- WriteByte(MSG_ONE, SVC_SETVIEWANGLES); // 10 = SVC_SETVIEWANGLES
- WriteAngle(MSG_ONE, viewangles_x); // tilt
- WriteAngle(MSG_ONE, viewangles_y); // yaw
- WriteAngle(MSG_ONE, viewangles_z); // flip
- };
- //
- //--------------------------------------------------------
- // NezuUpdateCamera( me, camera);
- // me = player entity
- // camera = entity that might be unknown to the client
- // Declare an entity position to the client. That's useful because if a client
- // doesn't know where an entity is, it assumes it's in '0 0 0' (usually wrong...)
- //--------------------------------------------------------
- //
- // Dependencies:
- // msg_entity is modified
- //
- void(entity me, entity camera) NezuUpdateCamera =
- {
- msg_entity = me; // target of message
- //0x0080 = SVC_UPDATEENTITY
- // | 1 = extended mask
- // | 2 = position_x
- // | 4 = position_y
- // | 8 = position_z
- // | 10 = angles_y (yaw)
- // | 20 = new
- // | 40 = frame
- WriteByte (MSG_ONE, SVC_UPDATEENTITY|15); // 0x80|1|2|4|8
- //0x00XX =
- // |01xx = angles_x (tilt)
- // |02xx = angles_z (flip)
- // |04xx = modelindex
- // |08xx = colormap
- // |10xx = skin
- // |20xx = attack state
- // |40xx = entity as short, not byte
- WriteByte (MSG_ONE, 64); // 0x40
- // mask &0x4000: ReadShort
- WriteEntity(MSG_ONE,camera);
- // origin[0] = mask & 0x0002 ? ReadCoord : default
- WriteCoord(MSG_ONE,camera.origin_x);
- // origin[1] = mask & 0x0004 ? ReadCoord : default
- WriteCoord(MSG_ONE,camera.origin_y);
- // origin[2] = mask & 0x0008 ? ReadCoord : default
- WriteCoord(MSG_ONE,camera.origin_z);
- };
- //
- //
- //--------------------------------------------------------
- // entity = NezuFindClosest( scenter, srange);
- // scenter = center of sphere
- // srange = size of sphere
- // Find the entity that is closest to the center of the sphere
- // Returns world if none was found
- //--------------------------------------------------------
- //
- // Dependencies: entity.chain is modified by findradius
- //
- entity(vector scenter, float srange) NezuFindClosest =
- {
- local float dist;
- local float edist;
- local entity e;
- local entity best;
- dist = srange;
- e = findradius( scenter, srange);
- while(e) // e != world
- {
- edist= vlen(e.origin - scenter);
- if(edist<dist)
- {
- if(e.classname != "path_corner") // avoid those entities
- {
- dist = edist;
- best = e;
- }
- }
- e = e.chain;
- }
- return best;
- };
-
-
- //
- //--------------------------------------------------------
- // NezuCamera( me);
- // me = player entity
- // me.aflag = camera status (0=off 666=on 777=ready)
- // this is a hack: self.aflag is used by doors only.
- // Fire a line ahead. If an entity is touched, it becomes the camera.
- // Next time this function is called, the view is restored to the player
- //--------------------------------------------------------
- //
- // Dependencies:
- // entity.trigger_field is used for the current camera
- // entity.aflag is used to toggle the camera status for each player
- // trace_fraction, trace_ent are modified by traceline()
- //
- // Rule: me.aflag==666 means the camera is active.
- //
- void(entity me) NezuCamera =
- {
- local entity camera;
- local vector me_src;
- local vector me_targ;
- local vector me_fire;
- if(me.aflag!=666) // camera is on, set it off
- {
- camera=me;
- NezuSetViewPoint(me, me); // restore player position
- sprint(me,"Camera off\n");
- me.aflag=666; // camera is ready
- //do not change me.trigger_field for the NezuCameraCycle
- }
- else // camera is off, try to set it on
- {
- me_fire = aim(me, 200); // slow missile speed
- // makevectors(me.angles); // set v_forward
- me_src = me.origin + '0 0 16';
- me_targ = me_src + me_fire*10000;
- //
- // Fire a line 10000 ahead.
- //
- traceline (me_src, me_targ , FALSE, me);
- //
- // Find the entity hit
- //
- if (trace_fraction >= 1.0) return; // Nothing was hit
- camera = trace_ent;
- if (camera == world) // hit the walls or floors
- {
- camera = NezuFindClosest(trace_endpos, 100);
- if(camera == world) return; // found nothing
- }
- //
- // Set camera viewpoint
- //
- NezuSetViewPoint(me, camera); // Restore player position
- sprint(me,"Camera set to "); // Message for player
- sprint(me,camera.classname); // Bastard string concatenation from hell
- sprint(me,"\n"); // End the message,and print it
- me.aflag=0; // Camera is on
- me.trigger_field = camera; // for the NezuCameraCycle
- }
- };
- //
- //--------------------------------------------------------
- // NezuCameraCycle( me);
- // me = player entity
- // me.aflag = camera status (0=off 666=on 777=ready)
- // this is a hack: self.aflag is used by doors only.
- // me.trigger_field = current camera
- // this is a hack: self.trigger_field is used by doors only.
- // Cycle player through all entities of a specific kind
- // Next time this function is called, the view is restored to the player
- //--------------------------------------------------------
- //
- //
- // Dependencies:
- // entity.trigger_field is used for the current camera
- // entity.aflag is used to toggle the camera status for each player
- // trace_fraction, trace_ent are modified by traceline()
- //
- void(entity me) NezuCameraCycle =
- {
- local entity camera;
- local string stufftofind;
-
- //
- // cycle through entities, never come back to me
- //
- camera=me.trigger_field;
- do
- {
- camera = nextent(camera);
- if(me.aflag & 1) // might not exist in level
- stufftofind = "item_shells";
- else // must exist in level!
- stufftofind = "info_player_deathmatch";
- camera = find(camera, classname, stufftofind);
- if(!camera) // cycle of 2 steps
- me.aflag = (me.aflag + 1) & 1;
- }while(!camera);
- //
- // Send to client an update of camera position
- // Otherwise the camera is beleived to be in the void
- //
- NezuUpdateCamera(me, camera);
- //
- // Set camera viewpoint
- //
- NezuSetViewPoint(me, camera); // Restore player position
- // Removed the printing of coordinates, because fairly annoying
- // stufftofind= vtos(camera.origin);
- // sprint(me,"Camera set to "); // Message for player
- // sprint(me, stufftofind); // Bastard string concatenation from hell
- // sprint(me,"\n"); // End the message,and print it
- me.trigger_field = camera; // Current Camera
- };
- //
- // That's all there is to it. Enjoy!
- //