1 #include "g_local.h"
2 
3 void ChasecamTrack (edict_t *ent);
4 
5 /*  The ent is the owner of the chasecam  */
ChasecamStart(edict_t * ent)6 void ChasecamStart (edict_t *ent) {
7 	/* This creates a tempory entity we can manipulate within this function */
8 	edict_t *chasecam;
9 
10 	/* Tell everything that looks at the toggle that our chasecam is on and working
11 */
12 	ent->client->chasetoggle = 1;
13 
14 	/* Make out gun model "non-existent" so it's more realistic to the player using
15 the chasecam */
16 	ent->client->ps.gunindex = 0;
17 
18 	chasecam = G_Spawn ();
19 	chasecam->owner = ent;
20 	chasecam->solid = SOLID_NOT;
21 
22 	chasecam->movetype = MOVETYPE_FLYMISSILE;
23 	// Added by WarZone - Begin
24 	ent->client->ps.pmove.pm_flags |= PMF_NO_PREDICTION; // this turns off Quake2's inclination to predict where the camera is going,
25 
26 
27 // making a much smoother ride
28 	ent->svflags |= SVF_NOCLIENT; // this line tells Quake2 not to send the unnecessary info about the camera to other players
29 
30 	// Added by WarZone - End
31 	/* Now, make the angles of the player model, (!NOT THE HUMAN VIEW!) be	 copied
32 to the same angle of the chasecam entity */
33 	VectorCopy (ent->s.angles, chasecam->s.angles);
34 
35 	/* Clear the size of the entity, so it DOES technically have a size, but that
36 of '0 0 0'-'0 0 0'. (xyz, xyz). mins = Minimum size, maxs = Maximum size */
37 	VectorClear (chasecam->mins);
38 	VectorClear (chasecam->maxs);
39 
40 	/* Make the chasecam's origin (position) be the same as the player entity's
41 because as the camera starts, it will force itself out slowly backwards from the
42 player model */
43 	VectorCopy (ent->s.origin, chasecam->s.origin);
44 
45 	chasecam->classname = "chasecam";
46 	chasecam->prethink = ChasecamTrack;
47 	ent->client->chasecam = chasecam;
48 	ent->client->oldplayer = G_Spawn();
49 }
50 
51 /* Here, the "ent" is referring to the client, the player that owns the
52 chasecam, and the "opt" string is telling the function whether to totally get
53 rid of the camera, or to put it into the background while it checks if the
54 player is out of the water or not. The "opt" could have easily been a string,
55 and might have used less memory, but it is easier to have a string as it is
56 clearer to the reader */
57 
ChasecamRemove(edict_t * ent)58 void ChasecamRemove (edict_t *ent){
59 	if (ent->client->chasetoggle == 0) {
60 		ent->client->ps.gunindex =
61 gi.modelindex(ent->client->pers.weapon->view_model);
62 		ent->s.modelindex = ent->client->oldplayer->s.modelindex;
63 		VectorClear (ent->client->chasecam->velocity);
64 
65 	      // Added by WarZone - Begin
66             ent->svflags &= ~SVF_NOCLIENT;
67             // Added by WarZone - End
68 
69 		free(ent->client->oldplayer->client);
70 		G_FreeEdict (ent->client->oldplayer);
71 		G_FreeEdict (ent->client->chasecam);
72 	}
73 	else {
74 		ent->client->chasetoggle = 2;
75 	}
76 }
77 
78 /* The "ent" is the chasecam */
ChasecamTrack(edict_t * ent)79 void ChasecamTrack (edict_t *ent) {
80 	/* Create tempory vectors and trace variables */
81 	trace_t tr;
82 	vec3_t spot2, headorg, angle;
83 	vec3_t forward, right, up;
84 	float dist;
85 
86 	ent->nextthink = level.time + 0.100;
87 
88 	VectorCopy(ent->owner->s.origin, headorg);
89 	if(!(ent->owner->client->ps.pmove.pm_flags & PMF_DUCKED))
90 		headorg[2] += 25;
91 	else
92 		headorg[2] += 10;
93 
94 	if(ent->owner->client->chasedist1 <= 0)
95 		ent->owner->client->chasedist1 = 80;
96 
97 	VectorCopy(ent->owner->client->v_angle, angle);
98 	/* get the CLIENT's viewangle, and break it down into direction vectors, of forward, right, and up. VERY useful */
99 	AngleVectors (ent->owner->client->ps.viewangles, forward, right, up);
100 
101 	dist = ent->chasedist2 / ent->owner->client->chasedist1;
102 
103 	VectorScale(forward, -ent->owner->client->chasedist1, spot2);  // Find the max distance
104 
105 	spot2[2] += 5.00;
106 	VectorScale(spot2, dist, spot2);  // Calculate the current distance
107 
108 	VectorAdd(headorg, spot2, spot2);
109 	tr = gi.trace (headorg, NULL, NULL, spot2, ent->owner, true);
110 	VectorSubtract(spot2, headorg, spot2);
111 
112 	VectorScale(spot2, tr.fraction - 0.05, spot2); // Scale the distance if the trace hit a wall
113 
114 
115 	VectorAdd(spot2, headorg, spot2);
116 	VectorCopy(spot2, ent->s.origin);
117 	VectorCopy(angle, ent->s.angles);
118 
119 	/* Copy the position of the chasecam now, and stick it to the movedir variable,
120 for position
121 		checking when we rethink this function */
122 	VectorCopy (ent->s.origin, ent->movedir);
123 
124 	if(ent->owner->client->chasetoggle == 2){ // If the cam is supposed to turn off, zoom in
125 		ent->chasedist2 -= 6;
126 		if (ent->chasedist2 <= 0){ // If it has finished zooming in remove the camera
127 			ent->chasedist2 = 0;
128 			ent->owner->client->chasetoggle = 0;
129 			ChasecamRemove(ent->owner);
130 		}
131 	}
132 	else if (ent->chasedist2 < ent->owner->client->chasedist1){
133 		ent->chasedist2 += 6;
134 		if (ent->chasedist2 > ent->owner->client->chasedist1)
135 			ent->chasedist2 = ent->owner->client->chasedist1;
136 	}
137 	else if (ent->chasedist2 > ent->owner->client->chasedist1){
138 		ent->chasedist2 -= 6;
139 		if (ent->chasedist2 < ent->owner->client->chasedist1)
140 			ent->chasedist2 = ent->owner->client->chasedist1;
141 	}
142 }
143 
Cmd_Chasecam_Toggle(edict_t * ent)144 void Cmd_Chasecam_Toggle (edict_t *ent) {
145 	if (ent->client->chasetoggle > 0)
146 		ChasecamRemove (ent);
147 	else
148 		ChasecamStart (ent);
149 }
150 
Cmd_Chasecam_Zoom(edict_t * ent,char * opt)151 void Cmd_Chasecam_Zoom(edict_t *ent, char *opt) {
152 	if(!strcmp(opt, "out") && ent->client->chasetoggle > 0)
153 		ent->client->chasedist1 += 10;
154 	else if(ent->client->chasetoggle > 0)
155 		ent->client->chasedist1 -= 10;
156 
157 	if(ent->client->chasedist1 <= 0)
158 		ent->client->chasedist1 = 80;
159 
160 	gi.bprintf(PRINT_HIGH, "Zoom Amount: %f\n", ent->client->chasedist1);
161 }
162 
Cmd_Chasecam_Viewlock(edict_t * ent)163 void Cmd_Chasecam_Viewlock(edict_t *ent) {
164 	if(ent->client->chasetoggle == 1)
165 		ent->client->chasetoggle = 3;
166 	else if(ent->client->chasetoggle == 3)
167 		ent->client->chasetoggle = 1;
168 	else if(ent->client->chasetoggle == 0){
169 		ChasecamStart (ent);
170 		ent->client->chasetoggle = 3;
171 	}
172 }
173 
CheckChasecam_Viewent(edict_t * ent)174 void CheckChasecam_Viewent (edict_t *ent) {
175 	// Added by WarZone - Begin
176 	gclient_t *cl;
177 	if (!ent->client->oldplayer->client) {
178 		cl = (gclient_t *)
179 		malloc(sizeof(gclient_t));
180 		ent->client->oldplayer->client = cl;
181 	}
182 	// Added by WarZone - End
183 
184 	if ((ent->client->chasetoggle >= 1) && (ent->client->oldplayer)) {
185 		ent->client->oldplayer->s.frame = ent->s.frame;
186 		/* Copy the origin, the speed, and the model angle, NOT
187 			literal angle to the display entity */
188 		VectorCopy (ent->s.origin, ent->client->oldplayer->s.origin);
189 		VectorCopy (ent->velocity, ent->client->oldplayer->velocity);
190 		VectorCopy (ent->s.angles, ent->client->oldplayer->s.angles);
191 		/* Make sure we are using the same model + skin as selected, as well
192 			as the weapon model the player model is holding. For customized
193 			deathmatch weapon displaying, you can use the modelindex2 for
194 			different weapon changing, as you can read in forthcoming tutorials */
195 		// Added by WarZone - Begin
196 		ent->client->oldplayer->s = ent->s;
197 		// copies over all of the important player related information
198 		// Added by WarZone - End
199 		gi.linkentity (ent->client->oldplayer);
200 	}
201 }
202 
203