1  /*begin of jet.c*/
2 
3 #include "g_local.h"
4 
5 
6 /*we get silly velocity-effects when we are on ground and try to
7   accelerate, so lift us a little bit if possible*/
Jet_AvoidGround(edict_t * ent)8 qboolean Jet_AvoidGround( edict_t *ent )
9 {
10   vec3_t                new_origin;
11   trace_t       trace;
12   qboolean      success;
13 
14   /*Check if there is enough room above us before we change origin[2]*/
15   new_origin[0] = ent->s.origin[0];
16   new_origin[1] = ent->s.origin[1];
17   new_origin[2] = ent->s.origin[2] + 0.5;
18   trace = gi.trace( ent->s.origin, ent->mins, ent->maxs, new_origin, ent, MASK_MONSTERSOLID );
19 
20   if ( success=(trace.plane.normal[2]==0) )     /*no ceiling?*/
21     ent->s.origin[2] += 0.5;                    /*then make sure off ground*/
22 
23   return success;
24 }
25 
26 
27 /*This function returns true if the jet is activated
28   (surprise, surprise)*/
Jet_Active(edict_t * ent)29 qboolean Jet_Active( edict_t *ent )
30 {
31   return ( ent->client->Jet_framenum >= level.framenum );
32 }
33 
34 
35 /*If a player dies with activated jetpack this function will be called
36   and produces a little explosion*/
Jet_BecomeExplosion(edict_t * ent,int damage)37 void Jet_BecomeExplosion( edict_t *ent, int damage )
38 {
39   int   n;
40 
41   gi.WriteByte( svc_temp_entity );
42   gi.WriteByte( TE_EXPLOSION1 );   /*TE_EXPLOSION2 is possible too*/
43   gi.WritePosition( ent->s.origin );
44   gi.multicast( ent->s.origin, MULTICAST_PVS );
45   gi.sound( ent, CHAN_BODY, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0 );
46 
47   /*throw some gib*/
48   for ( n=0; n<4; n++ )
49     ThrowGib( ent, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC );
50   ThrowClientHead( ent, damage );
51   ent->takedamage = DAMAGE_NO;
52 
53 }
54 
55 
56 /*The lifting effect is done through changing the origin, it
57   gives the best results. Of course its a little dangerous because
58   if we dont take care, we can move into solid*/
Jet_ApplyLifting(edict_t * ent)59 void Jet_ApplyLifting( edict_t *ent )
60 {
61   float         delta;
62   vec3_t        new_origin;
63   trace_t       trace;
64   int           time = 24;     /*must be >0, time/10 = time in sec for a
65                                  complete cycle (up/down)*/
66   float         amplitude = 2.0;
67 
68   /*calculate the z-distance to lift in this step*/
69   delta = sin( (float)((level.framenum%time)*(360/time))/180*M_PI ) * amplitude;
70   delta = (float)((int)(delta*8))/8; /*round to multiples of 0.125*/
71 
72   VectorCopy( ent->s.origin, new_origin );
73   new_origin[2] += delta;
74 
75   if( VectorLength(ent->velocity) == 0 )
76   {
77      /*i dont know the reason yet, but there is some floating so we
78        have to compensate that here (only if there is no velocity left)*/
79      new_origin[0] -= 0.125;
80      new_origin[1] -= 0.125;
81      new_origin[2] -= 0.125;
82   }
83 
84   /*before we change origin, its important to check that we dont go
85     into solid*/
86   trace = gi.trace( ent->s.origin, ent->mins, ent->maxs, new_origin, ent, MASK_MONSTERSOLID );
87   if ( trace.plane.normal[2] == 0 )
88     VectorCopy( new_origin, ent->s.origin );
89 }
90 
91 
92 /*This function applys some sparks to your jetpack, this part is
93   exactly copied from Muce's and SumFuka's JetPack-tutorial and does a
94   very nice effect.*/
Jet_ApplySparks(edict_t * ent)95 void Jet_ApplySparks ( edict_t *ent )
96 {
97   vec3_t  forward, right;
98   vec3_t  pack_pos, jet_vector;
99 
100   AngleVectors(ent->client->v_angle, forward, right, NULL);
101   VectorScale (forward, -7, pack_pos);
102   VectorAdd (pack_pos, ent->s.origin, pack_pos);
103   pack_pos[2] += (ent->viewheight);
104   VectorScale (forward, -50, jet_vector);
105 
106   gi.WriteByte (svc_temp_entity);
107   gi.WriteByte (TE_SPARKS);
108   gi.WritePosition (pack_pos);
109   gi.WriteDir (jet_vector);
110   gi.multicast (pack_pos, MULTICAST_PVS);
111 }
112 
113 
114 /*if the angle of the velocity vector is different to the viewing
115   angle (flying curves or stepping left/right) we get a dotproduct
116   which is here used for rolling*/
Jet_ApplyRolling(edict_t * ent,vec3_t right)117 void Jet_ApplyRolling( edict_t *ent, vec3_t right )
118 {
119   float roll,
120         value = 0.05,
121         sign = -1;    /*set this to +1 if you want to roll contrariwise*/
122 
123   roll = DotProduct( ent->velocity, right ) * value * sign;
124   ent->client->kick_angles[ROLL] = roll;
125 }
126 
127 
128 /*Now for the main movement code. The steering is a lot like in water, that
129   means your viewing direction is your moving direction. You have three
130   direction Boosters: the big Main Booster and the smaller up-down and
131   left-right Boosters.
132   There are only 2 adds to the code of the first tutorial: the Jet_next_think
133   and the rolling.
134   The other modifications results in the use of the built-in quake functions,
135   there is no change in moving behavior (reinventing the wheel is a lot of
136   "fun" and a BIG waste of time ;-))*/
Jet_ApplyJet(edict_t * ent,usercmd_t * ucmd)137 void Jet_ApplyJet( edict_t *ent, usercmd_t *ucmd )
138 {
139   float direction;
140   vec3_t acc;
141   vec3_t forward, right;
142   int    i;
143 
144   /*clear gravity so we dont have to compensate it with the Boosters*/
145   ent->client->ps.pmove.gravity = 0;
146 
147   /*calculate the direction vectors dependent on viewing direction
148     (length of the vectors forward/right is always 1, the coordinates of
149     the vectors are values of how much youre looking in a specific direction
150     [if youre looking up to the top, the x/y values are nearly 0 the
151     z value is nearly 1])*/
152   AngleVectors( ent->client->v_angle, forward, right, NULL );
153 
154   /*Run jet only 10 times a second so movement dont depends on fps
155     because ClientThink is called as often as possible
156     (fps<10 still is a problem ?)*/
157   if ( ent->client->Jet_next_think <= level.framenum )
158   {
159     ent->client->Jet_next_think = level.framenum + 1;
160 
161     /*clear acceleration-vector*/
162     VectorClear( acc );
163 
164     /*if we are moving forward or backward add MainBooster acceleration
165       (60)*/
166     if ( ucmd->forwardmove )
167     {
168       /*are we accelerating backward or forward?*/
169       direction = (ucmd->forwardmove<0) ? -1.0 : 1.0;
170 
171       /*add the acceleration for each direction*/
172       acc[0] += direction * forward[0] * 60;
173       acc[1] += direction * forward[1] * 60;
174       acc[2] += direction * forward[2] * 60;
175     }
176 
177     /*if we sidestep add Left-Right-Booster acceleration (40)*/
178     if ( ucmd->sidemove )
179     {
180       /*are we accelerating left or right*/
181       direction = (ucmd->sidemove<0) ? -1.0 : 1.0;
182 
183       /*add only to x and y acceleration*/
184       acc[0] += right[0] * direction * 40;
185       acc[1] += right[1] * direction * 40;
186     }
187 
188     /*if we crouch or jump add Up-Down-Booster acceleration (30)*/
189     if ( ucmd->upmove )
190       acc[2] += ucmd->upmove > 0 ? 30 : -30;
191 
192     /*now apply some friction dependent on velocity (higher velocity results
193       in higher friction), without acceleration this will reduce the velocity
194       to 0 in a few steps*/
195     ent->velocity[0] += -(ent->velocity[0]/6.0);
196     ent->velocity[1] += -(ent->velocity[1]/6.0);
197     ent->velocity[2] += -(ent->velocity[2]/7.0);
198 
199     /*then accelerate with the calculated values. If the new acceleration for
200       a direction is smaller than an earlier, the friction will reduce the speed
201       in that direction to the new value in a few steps, so if youre flying
202       curves or around corners youre floating a little bit in the old direction*/
203     VectorAdd( ent->velocity, acc, ent->velocity );
204 
205     /*round velocitys (is this necessary?)*/
206     ent->velocity[0] = (float)((int)(ent->velocity[0]*8))/8;
207     ent->velocity[1] = (float)((int)(ent->velocity[1]*8))/8;
208     ent->velocity[2] = (float)((int)(ent->velocity[2]*8))/8;
209 
210     /*Bound velocitys so that friction and acceleration dont need to be
211       synced on maxvelocitys*/
212     for ( i=0 ; i<2 ; i++) /*allow z-velocity to be greater*/
213     {
214       if (ent->velocity[i] > 300)
215         ent->velocity[i] = 300;
216       else if (ent->velocity[i] < -300)
217         ent->velocity[i] = -300;
218     }
219 
220     /*add some gentle up and down when idle (not accelerating)*/
221     if( VectorLength(acc) == 0 )
222       Jet_ApplyLifting( ent );
223 
224   }//if ( ent->client->Jet_next_think...
225 
226   /*add rolling when we fly curves or boost left/right*/
227   Jet_ApplyRolling( ent, right );
228 
229   /*last but not least add some smoke*/
230   Jet_ApplySparks( ent );
231 
232 }
233 
234 /*end of jet.c*/
235 
236 
237 
238 /*
239 =================
240 ApplyThrust
241 
242 MUCE:
243 To add thrusting velocity to player
244 =================
245 */
246 
ApplyThrust(edict_t * ent)247 void ApplyThrust (edict_t *ent)
248 {
249 
250         vec3_t forward, right;
251         vec3_t pack_pos, jet_vector;
252 
253         //MUCE:  add thrust to character
254 
255         if (ent->velocity[2] < -500)
256                 ent->velocity[2]+=((ent->velocity[2])/(-5));
257         else if (ent->velocity[2] < 0)
258                 ent->velocity[2] += 100;
259         else
260                 ent->velocity[2]+=((1000-ent->velocity[2])/8);
261 
262         //MUCE:  add sparks
263 
264         AngleVectors(ent->client->v_angle, forward, right, NULL);
265         VectorScale (forward, -7, pack_pos);
266         VectorAdd (pack_pos, ent->s.origin, pack_pos);
267         pack_pos[2] += (ent->viewheight);
268 
269         VectorScale (forward, -50, jet_vector);
270 
271         gi.WriteByte (svc_temp_entity);
272         gi.WriteByte (TE_SPARKS);
273         gi.WritePosition (pack_pos);
274         gi.WriteDir (jet_vector);
275         gi.multicast (pack_pos, MULTICAST_PVS);
276 
277         //MUCE: add sound
278 
279         if (ent->client->next_thrust_sound < level.time)
280         {
281                 gi.sound (ent, CHAN_BODY, gi.soundindex("weapons/rockfly.wav"), 1, ATTN_NORM, 0);
282                 ent->client->next_thrust_sound=level.time+1.0;
283         }
284 }
285 
286