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