FighterNPC.c 55 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752
  1. // leave this line at the top for all g_xxxx.cpp files...
  2. #include "g_headers.h"
  3. //seems to be a compiler bug, it doesn't clean out the #ifdefs between dif-compiles
  4. //or something, so the headers spew errors on these defs from the previous compile.
  5. //this fixes that. -rww
  6. #ifdef _JK2MP
  7. //get rid of all the crazy defs we added for this file
  8. #undef currentAngles
  9. #undef currentOrigin
  10. #undef mins
  11. #undef maxs
  12. #undef legsAnimTimer
  13. #undef torsoAnimTimer
  14. #undef bool
  15. #undef false
  16. #undef true
  17. #undef sqrtf
  18. #undef Q_flrand
  19. #undef MOD_EXPLOSIVE
  20. #endif
  21. #ifdef _JK2 //SP does not have this preprocessor for game like MP does
  22. #ifndef _JK2MP
  23. #define _JK2MP
  24. #endif
  25. #endif
  26. #ifndef _JK2MP //if single player
  27. #ifndef QAGAME //I don't think we have a QAGAME define
  28. #define QAGAME //but define it cause in sp we're always in the game
  29. #endif
  30. #endif
  31. #ifdef QAGAME //including game headers on cgame is FORBIDDEN ^_^
  32. #include "g_local.h"
  33. #elif defined _JK2MP
  34. #include "bg_public.h"
  35. #endif
  36. #ifndef _JK2MP
  37. #include "g_functions.h"
  38. #include "g_vehicles.h"
  39. #else
  40. #include "bg_vehicles.h"
  41. #endif
  42. #ifdef _JK2MP
  43. //this is really horrible, but it works! just be sure not to use any locals or anything
  44. //with these names (exluding bool, false, true). -rww
  45. #define currentAngles r.currentAngles
  46. #define currentOrigin r.currentOrigin
  47. #define mins r.mins
  48. #define maxs r.maxs
  49. #define legsAnimTimer legsTimer
  50. #define torsoAnimTimer torsoTimer
  51. #define bool qboolean
  52. #define false qfalse
  53. #define true qtrue
  54. #define sqrtf sqrt
  55. #define Q_flrand flrand
  56. #define MOD_EXPLOSIVE MOD_SUICIDE
  57. #else
  58. #define bgEntity_t gentity_t
  59. #endif
  60. extern float DotToSpot( vec3_t spot, vec3_t from, vec3_t fromAngles );
  61. #ifdef QAGAME //SP or gameside MP
  62. extern vmCvar_t cg_thirdPersonAlpha;
  63. extern vec3_t playerMins;
  64. extern vec3_t playerMaxs;
  65. extern cvar_t *g_speederControlScheme;
  66. extern void ChangeWeapon( gentity_t *ent, int newWeapon );
  67. extern void PM_SetAnim(pmove_t *pm,int setAnimParts,int anim,int setAnimFlags, int blendTime);
  68. extern int PM_AnimLength( int index, animNumber_t anim );
  69. extern void G_VehicleTrace( trace_t *results, const vec3_t start, const vec3_t tMins, const vec3_t tMaxs, const vec3_t end, int passEntityNum, int contentmask );
  70. #endif
  71. extern qboolean BG_UnrestrainedPitchRoll( playerState_t *ps, Vehicle_t *pVeh );
  72. #ifdef _JK2MP
  73. #include "../namespace_begin.h"
  74. extern void BG_SetAnim(playerState_t *ps, animation_t *animations, int setAnimParts,int anim,int setAnimFlags, int blendTime);
  75. extern int BG_GetTime(void);
  76. #endif
  77. extern void BG_ExternThisSoICanRecompileInDebug( Vehicle_t *pVeh, playerState_t *riderPS );
  78. //this stuff has got to be predicted, so..
  79. bool BG_FighterUpdate(Vehicle_t *pVeh, const usercmd_t *pUcmd, vec3_t trMins, vec3_t trMaxs, float gravity,
  80. void (*traceFunc)( trace_t *results, const vec3_t start, const vec3_t lmins, const vec3_t lmaxs, const vec3_t end, int passEntityNum, int contentMask ))
  81. {
  82. vec3_t bottom;
  83. playerState_t *parentPS;
  84. qboolean isDead = qfalse;
  85. #ifdef QAGAME //don't do this on client
  86. // Make sure the riders are not visible or collidable.
  87. pVeh->m_pVehicleInfo->Ghost( pVeh, pVeh->m_pPilot );
  88. #endif
  89. #ifdef _JK2MP
  90. parentPS = pVeh->m_pParentEntity->playerState;
  91. #else
  92. parentPS = &pVeh->m_pParentEntity->client->ps;
  93. #endif
  94. if (!parentPS)
  95. {
  96. Com_Error(ERR_DROP, "NULL PS in BG_FighterUpdate (%s)", pVeh->m_pVehicleInfo->name);
  97. return false;
  98. }
  99. // If we have a pilot, take out gravity (it's a flying craft...).
  100. if ( pVeh->m_pPilot )
  101. {
  102. parentPS->gravity = 0;
  103. #ifndef _JK2MP //don't need this flag in mp, I.. guess
  104. pVeh->m_pParentEntity->svFlags |= SVF_CUSTOM_GRAVITY;
  105. #endif
  106. }
  107. else
  108. {
  109. #ifndef _JK2MP //don't need this flag in mp, I.. guess
  110. pVeh->m_pParentEntity->svFlags &= ~SVF_CUSTOM_GRAVITY;
  111. #else //in MP set grav back to normal gravity
  112. if (pVeh->m_pVehicleInfo->gravity)
  113. {
  114. parentPS->gravity = pVeh->m_pVehicleInfo->gravity;
  115. }
  116. else
  117. { //it doesn't have gravity specified apparently
  118. parentPS->gravity = gravity;
  119. }
  120. #endif
  121. }
  122. #ifdef _JK2MP
  123. isDead = (qboolean)((parentPS->eFlags&EF_DEAD)!=0);
  124. #else
  125. isDead = (parentPS->stats[STAT_HEALTH] <= 0 );
  126. #endif
  127. /*
  128. if ( isDead ||
  129. (pVeh->m_pVehicleInfo->surfDestruction &&
  130. pVeh->m_iRemovedSurfaces ) )
  131. {//can't land if dead or spiralling out of control
  132. pVeh->m_LandTrace.fraction = 1.0f;
  133. pVeh->m_LandTrace.contents = pVeh->m_LandTrace.surfaceFlags = 0;
  134. VectorClear( pVeh->m_LandTrace.plane.normal );
  135. pVeh->m_LandTrace.allsolid = qfalse;
  136. pVeh->m_LandTrace.startsolid = qfalse;
  137. }
  138. else
  139. {
  140. */
  141. //argh, no, I need to have a way to see when they impact the ground while damaged. -rww
  142. // Check to see if the fighter has taken off yet (if it's a certain height above ground).
  143. VectorCopy( parentPS->origin, bottom );
  144. bottom[2] -= pVeh->m_pVehicleInfo->landingHeight;
  145. traceFunc( &pVeh->m_LandTrace, parentPS->origin, trMins, trMaxs, bottom, pVeh->m_pParentEntity->s.number, (MASK_NPCSOLID&~CONTENTS_BODY) );
  146. //}
  147. return true;
  148. }
  149. #ifdef QAGAME //ONLY in SP or on server, not cgame
  150. // Like a think or move command, this updates various vehicle properties.
  151. static bool Update( Vehicle_t *pVeh, const usercmd_t *pUcmd )
  152. {
  153. assert(pVeh->m_pParentEntity);
  154. if (!BG_FighterUpdate(pVeh, pUcmd, ((gentity_t *)pVeh->m_pParentEntity)->mins,
  155. ((gentity_t *)pVeh->m_pParentEntity)->maxs,
  156. #ifdef _JK2MP
  157. g_gravity.value,
  158. #else
  159. g_gravity->value,
  160. #endif
  161. G_VehicleTrace))
  162. {
  163. return false;
  164. }
  165. if ( !g_vehicleInfo[VEHICLE_BASE].Update( pVeh, pUcmd ) )
  166. {
  167. return false;
  168. }
  169. return true;
  170. }
  171. // Board this Vehicle (get on). The first entity to board an empty vehicle becomes the Pilot.
  172. static bool Board( Vehicle_t *pVeh, bgEntity_t *pEnt )
  173. {
  174. if ( !g_vehicleInfo[VEHICLE_BASE].Board( pVeh, pEnt ) )
  175. return false;
  176. // Set the board wait time (they won't be able to do anything, including getting off, for this amount of time).
  177. pVeh->m_iBoarding = level.time + 1500;
  178. return true;
  179. }
  180. // Eject an entity from the vehicle.
  181. static bool Eject( Vehicle_t *pVeh, bgEntity_t *pEnt, qboolean forceEject )
  182. {
  183. if ( g_vehicleInfo[VEHICLE_BASE].Eject( pVeh, pEnt, forceEject ) )
  184. {
  185. return true;
  186. }
  187. return false;
  188. }
  189. #endif //end game-side only
  190. //method of decrementing the given angle based on the given taking variable frame times into account
  191. static float PredictedAngularDecrement(float scale, float timeMod, float originalAngle)
  192. {
  193. float fixedBaseDec = originalAngle*0.05f;
  194. float r = 0.0f;
  195. if (fixedBaseDec < 0.0f)
  196. {
  197. fixedBaseDec = -fixedBaseDec;
  198. }
  199. fixedBaseDec *= (1.0f+(1.0f-scale));
  200. if (fixedBaseDec < 0.1f)
  201. { //don't increment in incredibly small fractions, it would eat up unnecessary bandwidth.
  202. fixedBaseDec = 0.1f;
  203. }
  204. fixedBaseDec *= (timeMod*0.1f);
  205. if (originalAngle > 0.0f)
  206. { //subtract
  207. r = (originalAngle-fixedBaseDec);
  208. if (r < 0.0f)
  209. {
  210. r = 0.0f;
  211. }
  212. }
  213. else if (originalAngle < 0.0f)
  214. { //add
  215. r = (originalAngle+fixedBaseDec);
  216. if (r > 0.0f)
  217. {
  218. r = 0.0f;
  219. }
  220. }
  221. return r;
  222. }
  223. #ifdef QAGAME//only do this check on GAME side, because if it's CGAME, it's being predicted, and it's only predicted if the local client is the driver
  224. qboolean FighterIsInSpace( gentity_t *gParent )
  225. {
  226. if ( gParent
  227. && gParent->client
  228. && gParent->client->inSpaceIndex
  229. && gParent->client->inSpaceIndex < ENTITYNUM_WORLD )
  230. {
  231. return qtrue;
  232. }
  233. return qfalse;
  234. }
  235. #endif
  236. qboolean FighterOverValidLandingSurface( Vehicle_t *pVeh )
  237. {
  238. if ( pVeh->m_LandTrace.fraction < 1.0f //ground present
  239. && pVeh->m_LandTrace.plane.normal[2] >= MIN_LANDING_SLOPE )//flat enough
  240. //FIXME: also check for a certain surface flag ... "landing zones"?
  241. {
  242. return qtrue;
  243. }
  244. return qfalse;
  245. }
  246. qboolean FighterIsLanded( Vehicle_t *pVeh, playerState_t *parentPS )
  247. {
  248. if ( FighterOverValidLandingSurface( pVeh )
  249. && !parentPS->speed )//stopped
  250. {
  251. return qtrue;
  252. }
  253. return qfalse;
  254. }
  255. qboolean FighterIsLanding( Vehicle_t *pVeh, playerState_t *parentPS )
  256. {
  257. if ( FighterOverValidLandingSurface( pVeh )
  258. #ifdef QAGAME//only do this check on GAME side, because if it's CGAME, it's being predicted, and it's only predicted if the local client is the driver
  259. && pVeh->m_pVehicleInfo->Inhabited( pVeh )//has to have a driver in order to be capable of landing
  260. #endif
  261. && (pVeh->m_ucmd.forwardmove < 0||pVeh->m_ucmd.upmove<0) //decelerating or holding crouch button
  262. && parentPS->speed <= MIN_LANDING_SPEED )//going slow enough to start landing - was using pVeh->m_pVehicleInfo->speedIdle, but that's still too fast
  263. {
  264. return qtrue;
  265. }
  266. return qfalse;
  267. }
  268. qboolean FighterIsLaunching( Vehicle_t *pVeh, playerState_t *parentPS )
  269. {
  270. if ( FighterOverValidLandingSurface( pVeh )
  271. #ifdef QAGAME//only do this check on GAME side, because if it's CGAME, it's being predicted, and it's only predicted if the local client is the driver
  272. && pVeh->m_pVehicleInfo->Inhabited( pVeh )//has to have a driver in order to be capable of landing
  273. #endif
  274. && pVeh->m_ucmd.upmove > 0 //trying to take off
  275. && parentPS->speed <= 200.0f )//going slow enough to start landing - was using pVeh->m_pVehicleInfo->speedIdle, but that's still too fast
  276. {
  277. return qtrue;
  278. }
  279. return qfalse;
  280. }
  281. qboolean FighterSuspended( Vehicle_t *pVeh, playerState_t *parentPS )
  282. {
  283. #ifdef QAGAME//only do this check on GAME side, because if it's CGAME, it's being predicted, and it's only predicted if the local client is the driver
  284. if (!pVeh->m_pPilot//empty
  285. && !parentPS->speed//not moving
  286. && pVeh->m_ucmd.forwardmove <= 0//not trying to go forward for whatever reason
  287. && pVeh->m_pParentEntity != NULL
  288. && (((gentity_t *)pVeh->m_pParentEntity)->spawnflags&2) )//SUSPENDED spawnflag is on
  289. {
  290. return qtrue;
  291. }
  292. return qfalse;
  293. #elif CGAME
  294. return qfalse;
  295. #endif
  296. }
  297. #ifdef CGAME
  298. extern void trap_S_StartSound( vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfx ); //cg_syscalls.c
  299. extern sfxHandle_t trap_S_RegisterSound( const char *sample); //cg_syscalls.c
  300. #endif
  301. //MP RULE - ALL PROCESSMOVECOMMANDS FUNCTIONS MUST BE BG-COMPATIBLE!!!
  302. //If you really need to violate this rule for SP, then use ifdefs.
  303. //By BG-compatible, I mean no use of game-specific data - ONLY use
  304. //stuff available in the MP bgEntity (in SP, the bgEntity is #defined
  305. //as a gentity, but the MP-compatible access restrictions are based
  306. //on the bgEntity structure in the MP codebase) -rww
  307. // ProcessMoveCommands the Vehicle.
  308. #define FIGHTER_MIN_TAKEOFF_FRACTION 0.7f
  309. static void ProcessMoveCommands( Vehicle_t *pVeh )
  310. {
  311. /************************************************************************************/
  312. /* BEGIN Here is where we move the vehicle (forward or back or whatever). BEGIN */
  313. /************************************************************************************/
  314. //Client sets ucmds and such for speed alterations
  315. float speedInc, speedIdleDec, speedIdle, speedIdleAccel, speedMin, speedMax;
  316. bgEntity_t *parent = pVeh->m_pParentEntity;
  317. qboolean isLandingOrLaunching = qfalse;
  318. #ifndef _JK2MP//SP
  319. int curTime = level.time;
  320. #elif QAGAME//MP GAME
  321. int curTime = level.time;
  322. #elif CGAME//MP CGAME
  323. //FIXME: pass in ucmd? Not sure if this is reliable...
  324. int curTime = pm->cmd.serverTime;
  325. #endif
  326. #ifdef _JK2MP
  327. playerState_t *parentPS = parent->playerState;
  328. #else
  329. playerState_t *parentPS = &parent->client->ps;
  330. #endif
  331. #ifdef _JK2MP
  332. if ( parentPS->hyperSpaceTime
  333. && curTime - parentPS->hyperSpaceTime < HYPERSPACE_TIME )
  334. {//Going to Hyperspace
  335. //totally override movement
  336. float timeFrac = ((float)(curTime-parentPS->hyperSpaceTime))/HYPERSPACE_TIME;
  337. if ( timeFrac < HYPERSPACE_TELEPORT_FRAC )
  338. {//for first half, instantly jump to top speed!
  339. if ( !(parentPS->eFlags2&EF2_HYPERSPACE) )
  340. {//waiting to face the right direction, do nothing
  341. parentPS->speed = 0.0f;
  342. }
  343. else
  344. {
  345. if ( parentPS->speed < HYPERSPACE_SPEED )
  346. {//just started hyperspace
  347. //MIKE: This is going to play the sound twice for the predicting client, I suggest using
  348. //a predicted event or only doing it game-side. -rich
  349. #ifdef QAGAME//MP GAME-side
  350. //G_EntitySound( ((gentity_t *)(pVeh->m_pParentEntity)), CHAN_LOCAL, pVeh->m_pVehicleInfo->soundHyper );
  351. #elif CGAME//MP CGAME-side
  352. trap_S_StartSound( NULL, pm->ps->clientNum, CHAN_LOCAL, pVeh->m_pVehicleInfo->soundHyper );
  353. #endif
  354. }
  355. parentPS->speed = HYPERSPACE_SPEED;
  356. }
  357. }
  358. else
  359. {//slow from top speed to 200...
  360. parentPS->speed = 200.0f + ((1.0f-timeFrac)*(1.0f/HYPERSPACE_TELEPORT_FRAC)*(HYPERSPACE_SPEED-200.0f));
  361. //don't mess with acceleration, just pop to the high velocity
  362. if ( VectorLength( parentPS->velocity ) < parentPS->speed )
  363. {
  364. VectorScale( parentPS->moveDir, parentPS->speed, parentPS->velocity );
  365. }
  366. }
  367. return;
  368. }
  369. #endif
  370. if ( pVeh->m_iDropTime >= curTime )
  371. {//no speed, just drop
  372. parentPS->speed = 0.0f;
  373. parentPS->gravity = 800;
  374. return;
  375. }
  376. isLandingOrLaunching = (FighterIsLanding( pVeh, parentPS )||FighterIsLaunching( pVeh, parentPS ));
  377. // If we are hitting the ground, just allow the fighter to go up and down.
  378. if ( isLandingOrLaunching//going slow enough to start landing
  379. && (pVeh->m_ucmd.forwardmove<=0||pVeh->m_LandTrace.fraction<=FIGHTER_MIN_TAKEOFF_FRACTION) )//not trying to accelerate away already (or: you are trying to, but not high enough off the ground yet)
  380. {//FIXME: if start to move forward and fly over something low while still going relatively slow, you may try to land even though you don't mean to...
  381. //float fInvFrac = 1.0f - pVeh->m_LandTrace.fraction;
  382. if ( pVeh->m_ucmd.upmove > 0 )
  383. {
  384. #ifdef _JK2MP
  385. if ( parentPS->velocity[2] <= 0
  386. && pVeh->m_pVehicleInfo->soundTakeOff )
  387. {//taking off for the first time
  388. #ifdef QAGAME//MP GAME-side
  389. G_EntitySound( ((gentity_t *)(pVeh->m_pParentEntity)), CHAN_AUTO, pVeh->m_pVehicleInfo->soundTakeOff );
  390. #endif
  391. }
  392. #endif
  393. parentPS->velocity[2] += pVeh->m_pVehicleInfo->acceleration * pVeh->m_fTimeModifier;// * ( /*fInvFrac **/ 1.5f );
  394. }
  395. else if ( pVeh->m_ucmd.upmove < 0 )
  396. {
  397. parentPS->velocity[2] -= pVeh->m_pVehicleInfo->acceleration * pVeh->m_fTimeModifier;// * ( /*fInvFrac **/ 1.8f );
  398. }
  399. else if ( pVeh->m_ucmd.forwardmove < 0 )
  400. {
  401. if ( pVeh->m_LandTrace.fraction != 0.0f )
  402. {
  403. parentPS->velocity[2] -= pVeh->m_pVehicleInfo->acceleration * pVeh->m_fTimeModifier;
  404. }
  405. if ( pVeh->m_LandTrace.fraction <= FIGHTER_MIN_TAKEOFF_FRACTION )
  406. {
  407. //pVeh->m_pParentEntity->client->ps.velocity[0] *= pVeh->m_LandTrace.fraction;
  408. //pVeh->m_pParentEntity->client->ps.velocity[1] *= pVeh->m_LandTrace.fraction;
  409. //remember to always base this stuff on the time modifier! otherwise, you create
  410. //framerate-dependancy issues and break prediction in MP -rww
  411. //parentPS->velocity[2] *= pVeh->m_LandTrace.fraction;
  412. //it's not an angle, but hey
  413. parentPS->velocity[2] = PredictedAngularDecrement(pVeh->m_LandTrace.fraction, pVeh->m_fTimeModifier*5.0f, parentPS->velocity[2]);
  414. parentPS->speed = 0;
  415. }
  416. }
  417. // Make sure they don't pitch as they near the ground.
  418. //pVeh->m_vOrientation[PITCH] *= 0.7f;
  419. pVeh->m_vOrientation[PITCH] = PredictedAngularDecrement(0.7f, pVeh->m_fTimeModifier*10.0f, pVeh->m_vOrientation[PITCH]);
  420. return;
  421. }
  422. if ( (pVeh->m_ucmd.upmove > 0) && pVeh->m_pVehicleInfo->turboSpeed )
  423. {
  424. if ((curTime - pVeh->m_iTurboTime)>pVeh->m_pVehicleInfo->turboRecharge)
  425. {
  426. pVeh->m_iTurboTime = (curTime + pVeh->m_pVehicleInfo->turboDuration);
  427. if (pVeh->m_pVehicleInfo->iTurboStartFX)
  428. {
  429. int i;
  430. for (i=0; i<MAX_VEHICLE_EXHAUSTS; i++)
  431. {
  432. if (pVeh->m_iExhaustTag[i]==-1)
  433. {
  434. break;
  435. }
  436. #ifndef _JK2MP//SP
  437. G_PlayEffect(pVeh->m_pVehicleInfo->iTurboStartFX, pVeh->m_pParentEntity->playerModel, pVeh->m_iExhaustTag[i], pVeh->m_pParentEntity->s.number, pVeh->m_pParentEntity->currentOrigin );
  438. #else
  439. //TODO: MP Play Effect?
  440. #endif
  441. }
  442. }
  443. //NOTE: turbo sound can't be part of effect if effect is played on every muzzle!
  444. if ( pVeh->m_pVehicleInfo->soundTurbo )
  445. {
  446. #ifndef _JK2MP//SP
  447. G_SoundIndexOnEnt( pVeh->m_pParentEntity, CHAN_AUTO, pVeh->m_pVehicleInfo->soundTurbo );
  448. #elif QAGAME//MP GAME-side
  449. G_EntitySound( ((gentity_t *)(pVeh->m_pParentEntity)), CHAN_AUTO, pVeh->m_pVehicleInfo->soundTurbo );
  450. #elif CGAME//MP CGAME-side
  451. //trap_S_StartSound( NULL, pVeh->m_pParentEntity->s.number, CHAN_AUTO, pVeh->m_pVehicleInfo->soundTurbo );
  452. #endif
  453. }
  454. }
  455. }
  456. speedInc = pVeh->m_pVehicleInfo->acceleration * pVeh->m_fTimeModifier;
  457. if ( curTime < pVeh->m_iTurboTime )
  458. {//going turbo speed
  459. speedMax = pVeh->m_pVehicleInfo->turboSpeed;
  460. //double our acceleration
  461. speedInc *= 2.0f;
  462. //force us to move forward
  463. pVeh->m_ucmd.forwardmove = 127;
  464. #ifdef _JK2MP//SP can cheat and just check m_iTurboTime directly... :)
  465. //add flag to let cgame know to draw the iTurboFX effect
  466. parentPS->eFlags |= EF_JETPACK_ACTIVE;
  467. #endif
  468. }
  469. /*
  470. //FIXME: if turbotime is up and we're waiting for it to recharge, should our max speed drop while we recharge?
  471. else if ( (curTime - pVeh->m_iTurboTime)<3000 )
  472. {//still waiting for the recharge
  473. speedMax = pVeh->m_pVehicleInfo->speedMax*0.75;
  474. }
  475. */
  476. else
  477. {//normal max speed
  478. speedMax = pVeh->m_pVehicleInfo->speedMax;
  479. #ifdef _JK2MP//SP can cheat and just check m_iTurboTime directly... :)
  480. if ( (parentPS->eFlags&EF_JETPACK_ACTIVE) )
  481. {//stop cgame from playing the turbo exhaust effect
  482. parentPS->eFlags &= ~EF_JETPACK_ACTIVE;
  483. }
  484. #endif
  485. }
  486. speedIdleDec = pVeh->m_pVehicleInfo->decelIdle * pVeh->m_fTimeModifier;
  487. speedIdle = pVeh->m_pVehicleInfo->speedIdle;
  488. speedIdleAccel = pVeh->m_pVehicleInfo->accelIdle * pVeh->m_fTimeModifier;
  489. speedMin = pVeh->m_pVehicleInfo->speedMin;
  490. if ( (parentPS->brokenLimbs&(1<<SHIPSURF_DAMAGE_BACK_HEAVY)) )
  491. {//engine has taken heavy damage
  492. speedMax *= 0.8f;//at 80% speed
  493. }
  494. else if ( (parentPS->brokenLimbs&(1<<SHIPSURF_DAMAGE_BACK_LIGHT)) )
  495. {//engine has taken light damage
  496. speedMax *= 0.6f;//at 60% speed
  497. }
  498. if (pVeh->m_iRemovedSurfaces
  499. || parentPS->electrifyTime>=curTime)
  500. { //go out of control
  501. parentPS->speed += speedInc;
  502. //Why set forwardmove? PMove code doesn't use it... does it?
  503. pVeh->m_ucmd.forwardmove = 127;
  504. }
  505. #ifdef QAGAME //well, the thing is always going to be inhabited if it's being predicted!
  506. else if ( FighterSuspended( pVeh, parentPS ) )
  507. {
  508. parentPS->speed = 0;
  509. pVeh->m_ucmd.forwardmove = 0;
  510. }
  511. else if ( !pVeh->m_pVehicleInfo->Inhabited( pVeh )
  512. && parentPS->speed > 0 )
  513. {//pilot jumped out while we were moving forward (not landing or landed) so just keep the throttle locked
  514. //Why set forwardmove? PMove code doesn't use it... does it?
  515. pVeh->m_ucmd.forwardmove = 127;
  516. }
  517. #endif
  518. else if ( ( parentPS->speed || parentPS->groundEntityNum == ENTITYNUM_NONE ||
  519. pVeh->m_ucmd.forwardmove || pVeh->m_ucmd.upmove > 0 ) && pVeh->m_LandTrace.fraction >= 0.05f )
  520. {
  521. if ( pVeh->m_ucmd.forwardmove > 0 && speedInc )
  522. {
  523. parentPS->speed += speedInc;
  524. pVeh->m_ucmd.forwardmove = 127;
  525. }
  526. else if ( pVeh->m_ucmd.forwardmove < 0
  527. || pVeh->m_ucmd.upmove < 0 )
  528. {//decelerating or braking
  529. if ( pVeh->m_ucmd.upmove < 0 )
  530. {//braking (trying to land?), slow down faster
  531. if ( pVeh->m_ucmd.forwardmove )
  532. {//decelerator + brakes
  533. speedInc += pVeh->m_pVehicleInfo->braking;
  534. speedIdleDec += pVeh->m_pVehicleInfo->braking;
  535. }
  536. else
  537. {//just brakes
  538. speedInc = speedIdleDec = pVeh->m_pVehicleInfo->braking;
  539. }
  540. }
  541. if ( parentPS->speed > speedIdle )
  542. {
  543. parentPS->speed -= speedInc;
  544. }
  545. else if ( parentPS->speed > speedMin )
  546. {
  547. if ( FighterOverValidLandingSurface( pVeh ) )
  548. {//there's ground below us and we're trying to slow down, slow down faster
  549. parentPS->speed -= speedInc;
  550. }
  551. else
  552. {
  553. parentPS->speed -= speedIdleDec;
  554. if ( parentPS->speed < MIN_LANDING_SPEED )
  555. {//unless you can land, don't drop below the landing speed!!! This way you can't come to a dead stop in mid-air
  556. parentPS->speed = MIN_LANDING_SPEED;
  557. }
  558. }
  559. }
  560. if ( pVeh->m_pVehicleInfo->type == VH_FIGHTER )
  561. {
  562. pVeh->m_ucmd.forwardmove = 127;
  563. }
  564. else if ( speedMin >= 0 )
  565. {
  566. pVeh->m_ucmd.forwardmove = 0;
  567. }
  568. }
  569. //else not accel, decel or braking
  570. else if ( pVeh->m_pVehicleInfo->throttleSticks )
  571. {//we're using a throttle that sticks at current speed
  572. if ( parentPS->speed <= MIN_LANDING_SPEED )
  573. {//going less than landing speed
  574. if ( FighterOverValidLandingSurface( pVeh ) )
  575. {//close to ground and not going very fast
  576. //slow to a stop if within landing height and not accel/decel/braking
  577. if ( parentPS->speed > 0 )
  578. {//slow down
  579. parentPS->speed -= speedIdleDec;
  580. }
  581. else if ( parentPS->speed < 0 )
  582. {//going backwards, slow down
  583. parentPS->speed += speedIdleDec;
  584. }
  585. }
  586. else
  587. {//not over a valid landing surf, but going too slow
  588. //speed up to idle speed if not over a valid landing surf and not accel/decel/braking
  589. if ( parentPS->speed < speedIdle )
  590. {
  591. parentPS->speed += speedIdleAccel;
  592. if ( parentPS->speed > speedIdle )
  593. {
  594. parentPS->speed = speedIdle;
  595. }
  596. }
  597. }
  598. }
  599. }
  600. else
  601. {//then speed up or slow down to idle speed
  602. //accelerate to cruising speed only, otherwise, just coast
  603. // If they've launched, apply some constant motion.
  604. if ( (pVeh->m_LandTrace.fraction >= 1.0f //no ground
  605. || pVeh->m_LandTrace.plane.normal[2] < MIN_LANDING_SLOPE )//or can't land on ground below us
  606. && speedIdle > 0 )
  607. {//not above ground and have an idle speed
  608. //float fSpeed = pVeh->m_pParentEntity->client->ps.speed;
  609. if ( parentPS->speed < speedIdle )
  610. {
  611. parentPS->speed += speedIdleAccel;
  612. if ( parentPS->speed > speedIdle )
  613. {
  614. parentPS->speed = speedIdle;
  615. }
  616. }
  617. else if ( parentPS->speed > 0 )
  618. {//slow down
  619. parentPS->speed -= speedIdleDec;
  620. if ( parentPS->speed < speedIdle )
  621. {
  622. parentPS->speed = speedIdle;
  623. }
  624. }
  625. }
  626. else//either close to ground or no idle speed
  627. {//slow to a stop if no idle speed or within landing height and not accel/decel/braking
  628. if ( parentPS->speed > 0 )
  629. {//slow down
  630. parentPS->speed -= speedIdleDec;
  631. }
  632. else if ( parentPS->speed < 0 )
  633. {//going backwards, slow down
  634. parentPS->speed += speedIdleDec;
  635. }
  636. }
  637. }
  638. }
  639. else
  640. {
  641. if ( pVeh->m_ucmd.forwardmove < 0 )
  642. {
  643. pVeh->m_ucmd.forwardmove = 0;
  644. }
  645. if ( pVeh->m_ucmd.upmove < 0 )
  646. {
  647. pVeh->m_ucmd.upmove = 0;
  648. }
  649. #ifndef _JK2MP
  650. if ( !pVeh->m_pVehicleInfo->strafePerc || (!g_speederControlScheme->value && !pVeh->m_pParentEntity->s.number) )
  651. {//if in a strafe-capable vehicle, clear strafing unless using alternate control scheme
  652. pVeh->m_ucmd.rightmove = 0;
  653. }
  654. #endif
  655. }
  656. #if 1//This is working now, but there are some transitional jitters... Rich?
  657. //STRAFING==============================================================================
  658. if ( pVeh->m_pVehicleInfo->strafePerc
  659. #ifdef QAGAME//only do this check on GAME side, because if it's CGAME, it's being predicted, and it's only predicted if the local client is the driver
  660. && pVeh->m_pVehicleInfo->Inhabited( pVeh )//has to have a driver in order to be capable of landing
  661. #endif
  662. && !pVeh->m_iRemovedSurfaces
  663. && parentPS->electrifyTime<curTime
  664. && (pVeh->m_LandTrace.fraction >= 1.0f//no grounf
  665. ||pVeh->m_LandTrace.plane.normal[2] < MIN_LANDING_SLOPE//can't land here
  666. ||parentPS->speed>MIN_LANDING_SPEED)//going too fast to land
  667. && pVeh->m_ucmd.rightmove )
  668. {//strafe
  669. vec3_t vAngles, vRight;
  670. float strafeSpeed = (pVeh->m_pVehicleInfo->strafePerc*speedMax)*5.0f;
  671. VectorCopy( pVeh->m_vOrientation, vAngles );
  672. vAngles[PITCH] = vAngles[ROLL] = 0;
  673. AngleVectors( vAngles, NULL, vRight, NULL );
  674. if ( pVeh->m_ucmd.rightmove > 0 )
  675. {//strafe right
  676. //FIXME: this will probably make it possible to cheat and
  677. // go faster than max speed if you keep turning and strafing...
  678. if ( pVeh->m_fStrafeTime > -MAX_STRAFE_TIME )
  679. {//can strafe right for 2 seconds
  680. float curStrafeSpeed = DotProduct( parentPS->velocity, vRight );
  681. if ( curStrafeSpeed > 0.0f )
  682. {//if > 0, already strafing right
  683. strafeSpeed -= curStrafeSpeed;//so it doesn't add up
  684. }
  685. if ( strafeSpeed > 0 )
  686. {
  687. VectorMA( parentPS->velocity, strafeSpeed*pVeh->m_fTimeModifier, vRight, parentPS->velocity );
  688. }
  689. pVeh->m_fStrafeTime -= 50*pVeh->m_fTimeModifier;
  690. }
  691. }
  692. else
  693. {//strafe left
  694. if ( pVeh->m_fStrafeTime < MAX_STRAFE_TIME )
  695. {//can strafe left for 2 seconds
  696. float curStrafeSpeed = DotProduct( parentPS->velocity, vRight );
  697. if ( curStrafeSpeed < 0.0f )
  698. {//if < 0, already strafing left
  699. strafeSpeed += curStrafeSpeed;//so it doesn't add up
  700. }
  701. if ( strafeSpeed > 0 )
  702. {
  703. VectorMA( parentPS->velocity, -strafeSpeed*pVeh->m_fTimeModifier, vRight, parentPS->velocity );
  704. }
  705. pVeh->m_fStrafeTime += 50*pVeh->m_fTimeModifier;
  706. }
  707. }
  708. //strafing takes away from forward speed? If so, strafePerc above should use speedMax
  709. //parentPS->speed *= (1.0f-pVeh->m_pVehicleInfo->strafePerc);
  710. }
  711. else//if ( pVeh->m_fStrafeTime )
  712. {
  713. if ( pVeh->m_fStrafeTime > 0 )
  714. {
  715. pVeh->m_fStrafeTime -= 50*pVeh->m_fTimeModifier;
  716. if ( pVeh->m_fStrafeTime < 0 )
  717. {
  718. pVeh->m_fStrafeTime = 0.0f;
  719. }
  720. }
  721. else if ( pVeh->m_fStrafeTime < 0 )
  722. {
  723. pVeh->m_fStrafeTime += 50*pVeh->m_fTimeModifier;
  724. if ( pVeh->m_fStrafeTime > 0 )
  725. {
  726. pVeh->m_fStrafeTime = 0.0f;
  727. }
  728. }
  729. }
  730. //STRAFING==============================================================================
  731. #endif
  732. if ( parentPS->speed > speedMax )
  733. {
  734. parentPS->speed = speedMax;
  735. }
  736. else if ( parentPS->speed < speedMin )
  737. {
  738. parentPS->speed = speedMin;
  739. }
  740. #ifdef QAGAME//FIXME: get working in GAME and CGAME
  741. if ((pVeh->m_vOrientation[PITCH]*0.1f) > 10.0f)
  742. { //pitched downward, increase speed more and more based on our tilt
  743. if ( FighterIsInSpace( (gentity_t *)parent ) )
  744. {//in space, do nothing with speed base on pitch...
  745. }
  746. else
  747. {
  748. //really should only do this when on a planet
  749. float mult = pVeh->m_vOrientation[PITCH]*0.1f;
  750. if (mult < 1.0f)
  751. {
  752. mult = 1.0f;
  753. }
  754. parentPS->speed = PredictedAngularDecrement(mult, pVeh->m_fTimeModifier*10.0f, parentPS->speed);
  755. }
  756. }
  757. if (pVeh->m_iRemovedSurfaces
  758. || parentPS->electrifyTime>=curTime)
  759. { //going down
  760. if ( FighterIsInSpace( (gentity_t *)parent ) )
  761. {//we're in a valid trigger_space brush
  762. //simulate randomness
  763. if ( !(parent->s.number&3) )
  764. {//even multiple of 3, don't do anything
  765. parentPS->gravity = 0;
  766. }
  767. else if ( !(parent->s.number&2) )
  768. {//even multiple of 2, go up
  769. parentPS->gravity = -500.0f;
  770. parentPS->velocity[2] = 80.0f;
  771. }
  772. else
  773. {//odd number, go down
  774. parentPS->gravity = 500.0f;
  775. parentPS->velocity[2] = -80.0f;
  776. }
  777. }
  778. else
  779. {//over a planet
  780. parentPS->gravity = 500.0f;
  781. parentPS->velocity[2] = -80.0f;
  782. }
  783. }
  784. else if ( FighterSuspended( pVeh, parentPS ) )
  785. {
  786. parentPS->gravity = 0;
  787. }
  788. else if ( (!parentPS->speed||parentPS->speed < speedIdle) && pVeh->m_ucmd.upmove <= 0 )
  789. {//slowing down or stopped and not trying to take off
  790. if ( FighterIsInSpace( (gentity_t *)parent ) )
  791. {//we're in space, stopping doesn't make us drift downward
  792. if ( FighterOverValidLandingSurface( pVeh ) )
  793. {//well, there's something below us to land on, so go ahead and lower us down to it
  794. parentPS->gravity = (speedIdle - parentPS->speed)/4;
  795. }
  796. }
  797. else
  798. {//over a planet
  799. parentPS->gravity = (speedIdle - parentPS->speed)/4;
  800. }
  801. }
  802. else
  803. {
  804. parentPS->gravity = 0;
  805. }
  806. #else//FIXME: get above checks working in GAME and CGAME
  807. parentPS->gravity = 0;
  808. #endif
  809. /********************************************************************************/
  810. /* END Here is where we move the vehicle (forward or back or whatever). END */
  811. /********************************************************************************/
  812. }
  813. extern void BG_VehicleTurnRateForSpeed( Vehicle_t *pVeh, float speed, float *mPitchOverride, float *mYawOverride );
  814. static void FighterWingMalfunctionCheck( Vehicle_t *pVeh, playerState_t *parentPS )
  815. {
  816. float mPitchOverride = 1.0f;
  817. float mYawOverride = 1.0f;
  818. BG_VehicleTurnRateForSpeed( pVeh, parentPS->speed, &mPitchOverride, &mYawOverride );
  819. //check right wing damage
  820. if ( (parentPS->brokenLimbs&(1<<SHIPSURF_DAMAGE_RIGHT_HEAVY)) )
  821. {//right wing has taken heavy damage
  822. pVeh->m_vOrientation[ROLL] += (sin( pVeh->m_ucmd.serverTime*0.001 )+1.0f)*pVeh->m_fTimeModifier*mYawOverride*50.0f;
  823. }
  824. else if ( (parentPS->brokenLimbs&(1<<SHIPSURF_DAMAGE_RIGHT_LIGHT)) )
  825. {//right wing has taken light damage
  826. pVeh->m_vOrientation[ROLL] += (sin( pVeh->m_ucmd.serverTime*0.001 )+1.0f)*pVeh->m_fTimeModifier*mYawOverride*12.5f;
  827. }
  828. //check left wing damage
  829. if ( (parentPS->brokenLimbs&(1<<SHIPSURF_DAMAGE_LEFT_HEAVY)) )
  830. {//left wing has taken heavy damage
  831. pVeh->m_vOrientation[ROLL] -= (sin( pVeh->m_ucmd.serverTime*0.001 )+1.0f)*pVeh->m_fTimeModifier*mYawOverride*50.0f;
  832. }
  833. else if ( (parentPS->brokenLimbs&(1<<SHIPSURF_DAMAGE_LEFT_LIGHT)) )
  834. {//left wing has taken light damage
  835. pVeh->m_vOrientation[ROLL] -= (sin( pVeh->m_ucmd.serverTime*0.001 )+1.0f)*pVeh->m_fTimeModifier*mYawOverride*12.5f;
  836. }
  837. }
  838. static void FighterNoseMalfunctionCheck( Vehicle_t *pVeh, playerState_t *parentPS )
  839. {
  840. float mPitchOverride = 1.0f;
  841. float mYawOverride = 1.0f;
  842. BG_VehicleTurnRateForSpeed( pVeh, parentPS->speed, &mPitchOverride, &mYawOverride );
  843. //check nose damage
  844. if ( (parentPS->brokenLimbs&(1<<SHIPSURF_DAMAGE_FRONT_HEAVY)) )
  845. {//nose has taken heavy damage
  846. //pitch up and down over time
  847. pVeh->m_vOrientation[PITCH] += sin( pVeh->m_ucmd.serverTime*0.001 )*pVeh->m_fTimeModifier*mPitchOverride*50.0f;
  848. }
  849. else if ( (parentPS->brokenLimbs&(1<<SHIPSURF_DAMAGE_FRONT_LIGHT)) )
  850. {//nose has taken heavy damage
  851. //pitch up and down over time
  852. pVeh->m_vOrientation[PITCH] += sin( pVeh->m_ucmd.serverTime*0.001 )*pVeh->m_fTimeModifier*mPitchOverride*20.0f;
  853. }
  854. }
  855. static void FighterDamageRoutine( Vehicle_t *pVeh, bgEntity_t *parent, playerState_t *parentPS, playerState_t *riderPS, qboolean isDead )
  856. {
  857. if ( !pVeh->m_iRemovedSurfaces )
  858. {//still in one piece
  859. if ( pVeh->m_pParentEntity && isDead )
  860. {//death spiral
  861. pVeh->m_ucmd.upmove = 0;
  862. //FIXME: don't bias toward pitching down when not in space
  863. /*
  864. if ( FighterIsInSpace( pVeh->m_pParentEntity ) )
  865. {
  866. }
  867. else
  868. */
  869. if ( !(pVeh->m_pParentEntity->s.number%3) )
  870. {//NOT everyone should do this
  871. pVeh->m_vOrientation[PITCH] += pVeh->m_fTimeModifier;
  872. if ( !BG_UnrestrainedPitchRoll( riderPS, pVeh ) )
  873. {
  874. if ( pVeh->m_vOrientation[PITCH] > 60.0f )
  875. {
  876. pVeh->m_vOrientation[PITCH] = 60.0f;
  877. }
  878. }
  879. }
  880. else if ( !(pVeh->m_pParentEntity->s.number%2) )
  881. {
  882. pVeh->m_vOrientation[PITCH] -= pVeh->m_fTimeModifier;
  883. if ( !BG_UnrestrainedPitchRoll( riderPS, pVeh ) )
  884. {
  885. if ( pVeh->m_vOrientation[PITCH] > -60.0f )
  886. {
  887. pVeh->m_vOrientation[PITCH] = -60.0f;
  888. }
  889. }
  890. }
  891. if ( (pVeh->m_pParentEntity->s.number%2) )
  892. {
  893. pVeh->m_vOrientation[YAW] += pVeh->m_fTimeModifier;
  894. pVeh->m_vOrientation[ROLL] += pVeh->m_fTimeModifier*4.0f;
  895. }
  896. else
  897. {
  898. pVeh->m_vOrientation[YAW] -= pVeh->m_fTimeModifier;
  899. pVeh->m_vOrientation[ROLL] -= pVeh->m_fTimeModifier*4.0f;
  900. }
  901. }
  902. return;
  903. }
  904. //if we get into here we have at least one broken piece
  905. pVeh->m_ucmd.upmove = 0;
  906. //if you're off the ground and not suspended, pitch down
  907. //FIXME: not in space!
  908. if ( pVeh->m_LandTrace.fraction >= 0.1f )
  909. {
  910. if ( !FighterSuspended( pVeh, parentPS ) )
  911. {
  912. //pVeh->m_ucmd.forwardmove = 0;
  913. //FIXME: don't bias towards pitching down when in space...
  914. if ( !(pVeh->m_pParentEntity->s.number%2) )
  915. {//NOT everyone should do this
  916. pVeh->m_vOrientation[PITCH] += pVeh->m_fTimeModifier;
  917. if ( !BG_UnrestrainedPitchRoll( riderPS, pVeh ) )
  918. {
  919. if ( pVeh->m_vOrientation[PITCH] > 60.0f )
  920. {
  921. pVeh->m_vOrientation[PITCH] = 60.0f;
  922. }
  923. }
  924. }
  925. else if ( !(pVeh->m_pParentEntity->s.number%3) )
  926. {
  927. pVeh->m_vOrientation[PITCH] -= pVeh->m_fTimeModifier;
  928. if ( !BG_UnrestrainedPitchRoll( riderPS, pVeh ) )
  929. {
  930. if ( pVeh->m_vOrientation[PITCH] > -60.0f )
  931. {
  932. pVeh->m_vOrientation[PITCH] = -60.0f;
  933. }
  934. }
  935. }
  936. //else: just keep going forward
  937. }
  938. }
  939. #ifdef QAGAME
  940. if ( pVeh->m_LandTrace.fraction < 1.0f )
  941. { //if you land at all when pieces of your ship are missing, then die
  942. gentity_t *parent = (gentity_t *)pVeh->m_pParentEntity;
  943. gentity_t *killer = parent;
  944. #ifdef _JK2MP//only have this info in MP...
  945. if (parent->client->ps.otherKiller < ENTITYNUM_WORLD &&
  946. parent->client->ps.otherKillerTime > level.time)
  947. {
  948. gentity_t *potentialKiller = &g_entities[parent->client->ps.otherKiller];
  949. if (potentialKiller->inuse && potentialKiller->client)
  950. { //he's valid I guess
  951. killer = potentialKiller;
  952. }
  953. }
  954. #endif
  955. G_Damage(parent, killer, killer, vec3_origin, parent->client->ps.origin, 99999, DAMAGE_NO_ARMOR, MOD_SUICIDE);
  956. }
  957. #endif
  958. if ( ((pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_C) ||
  959. (pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_D)) &&
  960. ((pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_E) ||
  961. (pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_F)) )
  962. { //wings on both side broken
  963. float factor = 2.0f;
  964. if ((pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_E) &&
  965. (pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_F) &&
  966. (pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_C) &&
  967. (pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_D))
  968. { //all wings broken
  969. factor *= 2.0f;
  970. }
  971. if ( !(pVeh->m_pParentEntity->s.number%4)||!(pVeh->m_pParentEntity->s.number%5) )
  972. {//won't yaw, so increase roll factor
  973. factor *= 4.0f;
  974. }
  975. pVeh->m_vOrientation[ROLL] += (pVeh->m_fTimeModifier*factor); //do some spiralling
  976. }
  977. else if ((pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_C) ||
  978. (pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_D))
  979. { //left wing broken
  980. float factor = 2.0f;
  981. if ((pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_C) &&
  982. (pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_D))
  983. { //if both are broken..
  984. factor *= 2.0f;
  985. }
  986. if ( !(pVeh->m_pParentEntity->s.number%4)||!(pVeh->m_pParentEntity->s.number%5) )
  987. {//won't yaw, so increase roll factor
  988. factor *= 4.0f;
  989. }
  990. pVeh->m_vOrientation[ROLL] += factor*pVeh->m_fTimeModifier;
  991. }
  992. else if ((pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_E) ||
  993. (pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_F))
  994. { //right wing broken
  995. float factor = 2.0f;
  996. if ((pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_E) &&
  997. (pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_F))
  998. { //if both are broken..
  999. factor *= 2.0f;
  1000. }
  1001. if ( !(pVeh->m_pParentEntity->s.number%4)||!(pVeh->m_pParentEntity->s.number%5) )
  1002. {//won't yaw, so increase roll factor
  1003. factor *= 4.0f;
  1004. }
  1005. pVeh->m_vOrientation[ROLL] -= factor*pVeh->m_fTimeModifier;
  1006. }
  1007. }
  1008. #ifdef _JK2MP
  1009. void FighterYawAdjust(Vehicle_t *pVeh, playerState_t *riderPS, playerState_t *parentPS)
  1010. {
  1011. float angDif = AngleSubtract(pVeh->m_vOrientation[YAW], riderPS->viewangles[YAW]);
  1012. if (parentPS && parentPS->speed)
  1013. {
  1014. float s = parentPS->speed;
  1015. float maxDif = pVeh->m_pVehicleInfo->turningSpeed*0.8f; //magic number hackery
  1016. if (s < 0.0f)
  1017. {
  1018. s = -s;
  1019. }
  1020. angDif *= s/pVeh->m_pVehicleInfo->speedMax;
  1021. if (angDif > maxDif)
  1022. {
  1023. angDif = maxDif;
  1024. }
  1025. else if (angDif < -maxDif)
  1026. {
  1027. angDif = -maxDif;
  1028. }
  1029. pVeh->m_vOrientation[YAW] = AngleNormalize180(pVeh->m_vOrientation[YAW] - angDif*(pVeh->m_fTimeModifier*0.2f));
  1030. }
  1031. }
  1032. void FighterPitchAdjust(Vehicle_t *pVeh, playerState_t *riderPS, playerState_t *parentPS)
  1033. {
  1034. float angDif = AngleSubtract(pVeh->m_vOrientation[PITCH], riderPS->viewangles[PITCH]);
  1035. if (parentPS && parentPS->speed)
  1036. {
  1037. float s = parentPS->speed;
  1038. float maxDif = pVeh->m_pVehicleInfo->turningSpeed*0.8f; //magic number hackery
  1039. if (s < 0.0f)
  1040. {
  1041. s = -s;
  1042. }
  1043. angDif *= s/pVeh->m_pVehicleInfo->speedMax;
  1044. if (angDif > maxDif)
  1045. {
  1046. angDif = maxDif;
  1047. }
  1048. else if (angDif < -maxDif)
  1049. {
  1050. angDif = -maxDif;
  1051. }
  1052. pVeh->m_vOrientation[PITCH] = AngleNormalize360(pVeh->m_vOrientation[PITCH] - angDif*(pVeh->m_fTimeModifier*0.2f));
  1053. }
  1054. }
  1055. #endif
  1056. //MP RULE - ALL PROCESSORIENTCOMMANDS FUNCTIONS MUST BE BG-COMPATIBLE!!!
  1057. //If you really need to violate this rule for SP, then use ifdefs.
  1058. //By BG-compatible, I mean no use of game-specific data - ONLY use
  1059. //stuff available in the MP bgEntity (in SP, the bgEntity is #defined
  1060. //as a gentity, but the MP-compatible access restrictions are based
  1061. //on the bgEntity structure in the MP codebase) -rww
  1062. // ProcessOrientCommands the Vehicle.
  1063. static void ProcessOrientCommands( Vehicle_t *pVeh )
  1064. {
  1065. /********************************************************************************/
  1066. /* BEGIN Here is where make sure the vehicle is properly oriented. BEGIN */
  1067. /********************************************************************************/
  1068. bgEntity_t *parent = pVeh->m_pParentEntity;
  1069. playerState_t *parentPS, *riderPS;
  1070. float angleTimeMod;
  1071. #ifdef QAGAME
  1072. const float groundFraction = 0.1f;
  1073. #endif
  1074. float curRoll = 0.0f;
  1075. qboolean isDead = qfalse;
  1076. qboolean isLandingOrLanded = qfalse;
  1077. #ifndef _JK2MP//SP
  1078. int curTime = level.time;
  1079. #elif QAGAME//MP GAME
  1080. int curTime = level.time;
  1081. #elif CGAME//MP CGAME
  1082. //FIXME: pass in ucmd? Not sure if this is reliable...
  1083. int curTime = pm->cmd.serverTime;
  1084. #endif
  1085. #ifdef _JK2MP
  1086. bgEntity_t *rider = NULL;
  1087. if (parent->s.owner != ENTITYNUM_NONE)
  1088. {
  1089. rider = PM_BGEntForNum(parent->s.owner); //&g_entities[parent->r.ownerNum];
  1090. }
  1091. #else
  1092. gentity_t *rider = parent->owner;
  1093. #endif
  1094. #ifdef _JK2MP
  1095. if ( !rider )
  1096. #else
  1097. if ( !rider || !rider->client )
  1098. #endif
  1099. {
  1100. rider = parent;
  1101. }
  1102. #ifdef _JK2MP
  1103. parentPS = parent->playerState;
  1104. riderPS = rider->playerState;
  1105. isDead = (qboolean)((parentPS->eFlags&EF_DEAD)!=0);
  1106. #else
  1107. parentPS = &parent->client->ps;
  1108. riderPS = &rider->client->ps;
  1109. isDead = (parentPS->stats[STAT_HEALTH] <= 0 );
  1110. #endif
  1111. #ifdef _JK2MP
  1112. if ( parentPS->hyperSpaceTime
  1113. && (curTime - parentPS->hyperSpaceTime) < HYPERSPACE_TIME )
  1114. {//Going to Hyperspace
  1115. VectorCopy( riderPS->viewangles, pVeh->m_vOrientation );
  1116. VectorCopy( riderPS->viewangles, parentPS->viewangles );
  1117. return;
  1118. }
  1119. #endif
  1120. if ( pVeh->m_iDropTime >= curTime )
  1121. {//you can only YAW during this
  1122. parentPS->viewangles[YAW] = pVeh->m_vOrientation[YAW] = riderPS->viewangles[YAW];
  1123. return;
  1124. }
  1125. angleTimeMod = pVeh->m_fTimeModifier;
  1126. if ( isDead || parentPS->electrifyTime>=curTime ||
  1127. (pVeh->m_pVehicleInfo->surfDestruction &&
  1128. pVeh->m_iRemovedSurfaces &&
  1129. (pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_C) &&
  1130. (pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_D) &&
  1131. (pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_E) &&
  1132. (pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_F)) )
  1133. { //do some special stuff for when all the wings are torn off
  1134. FighterDamageRoutine(pVeh, parent, parentPS, riderPS, isDead);
  1135. pVeh->m_vOrientation[ROLL] = AngleNormalize180( pVeh->m_vOrientation[ROLL] );
  1136. return;
  1137. }
  1138. if ( !BG_UnrestrainedPitchRoll( riderPS, pVeh ) )
  1139. {
  1140. pVeh->m_vOrientation[ROLL] = PredictedAngularDecrement(0.95f, angleTimeMod*2.0f, pVeh->m_vOrientation[ROLL]);
  1141. }
  1142. isLandingOrLanded = (FighterIsLanding( pVeh, parentPS )||FighterIsLanded( pVeh, parentPS ));
  1143. if (!isLandingOrLanded)
  1144. { //don't do this stuff while landed.. I guess. I don't want ships spinning in place, looks silly.
  1145. int m = 0;
  1146. float aVelDif;
  1147. float dForVel;
  1148. FighterWingMalfunctionCheck( pVeh, parentPS );
  1149. while (m < 3)
  1150. {
  1151. aVelDif = pVeh->m_vFullAngleVelocity[m];
  1152. if (aVelDif != 0.0f)
  1153. {
  1154. dForVel = (aVelDif*0.1f)*pVeh->m_fTimeModifier;
  1155. if (dForVel > 1.0f || dForVel < -1.0f)
  1156. {
  1157. pVeh->m_vOrientation[m] += dForVel;
  1158. pVeh->m_vOrientation[m] = AngleNormalize180(pVeh->m_vOrientation[m]);
  1159. if (m == PITCH)
  1160. { //don't pitch downward into ground even more.
  1161. if (pVeh->m_vOrientation[m] > 90.0f && (pVeh->m_vOrientation[m]-dForVel) < 90.0f)
  1162. {
  1163. pVeh->m_vOrientation[m] = 90.0f;
  1164. pVeh->m_vFullAngleVelocity[m] = -pVeh->m_vFullAngleVelocity[m];
  1165. }
  1166. }
  1167. if (riderPS)
  1168. {
  1169. riderPS->viewangles[m] = pVeh->m_vOrientation[m];
  1170. }
  1171. pVeh->m_vFullAngleVelocity[m] -= dForVel;
  1172. }
  1173. else
  1174. {
  1175. pVeh->m_vFullAngleVelocity[m] = 0.0f;
  1176. }
  1177. }
  1178. m++;
  1179. }
  1180. }
  1181. else
  1182. { //clear decr/incr angles once landed.
  1183. VectorClear(pVeh->m_vFullAngleVelocity);
  1184. }
  1185. curRoll = pVeh->m_vOrientation[ROLL];
  1186. // If we're landed, we shouldn't be able to do anything but take off.
  1187. if ( isLandingOrLanded //going slow enough to start landing
  1188. && !pVeh->m_iRemovedSurfaces
  1189. && parentPS->electrifyTime<curTime)//not spiraling out of control
  1190. {
  1191. if ( parentPS->speed > 0.0f )
  1192. {//Uh... what? Why?
  1193. if ( pVeh->m_LandTrace.fraction < 0.3f )
  1194. {
  1195. pVeh->m_vOrientation[PITCH] = 0.0f;
  1196. }
  1197. else
  1198. {
  1199. pVeh->m_vOrientation[PITCH] = PredictedAngularDecrement(0.83f, angleTimeMod*10.0f, pVeh->m_vOrientation[PITCH]);
  1200. }
  1201. }
  1202. if ( pVeh->m_LandTrace.fraction > 0.1f
  1203. || pVeh->m_LandTrace.plane.normal[2] < MIN_LANDING_SLOPE )
  1204. {//off the ground, at least (or not on a valid landing surf)
  1205. // Dampen the turn rate based on the current height.
  1206. #ifdef _JK2MP
  1207. FighterYawAdjust(pVeh, riderPS, parentPS);
  1208. #else
  1209. pVeh->m_vOrientation[YAW] = riderPS->viewangles[YAW];//*pVeh->m_LandTrace.fraction;
  1210. #endif
  1211. }
  1212. }
  1213. else if ( (pVeh->m_iRemovedSurfaces||parentPS->electrifyTime>=curTime)//spiralling out of control
  1214. && (!(pVeh->m_pParentEntity->s.number%4)||!(pVeh->m_pParentEntity->s.number%5)) )
  1215. {//no yaw control
  1216. }
  1217. else if ( pVeh->m_pPilot && pVeh->m_pPilot->s.number < MAX_CLIENTS && parentPS->speed > 0.0f )//&& !( pVeh->m_ucmd.forwardmove > 0 && pVeh->m_LandTrace.fraction != 1.0f ) )
  1218. {
  1219. if ( BG_UnrestrainedPitchRoll( riderPS, pVeh ) )
  1220. {
  1221. VectorCopy( riderPS->viewangles, pVeh->m_vOrientation );
  1222. VectorCopy( riderPS->viewangles, parentPS->viewangles );
  1223. #ifdef _JK2MP
  1224. //BG_ExternThisSoICanRecompileInDebug( pVeh, riderPS );
  1225. #endif
  1226. curRoll = pVeh->m_vOrientation[ROLL];
  1227. FighterNoseMalfunctionCheck( pVeh, parentPS );
  1228. //VectorCopy( pVeh->m_vOrientation, parentPS->viewangles );
  1229. }
  1230. else
  1231. {
  1232. /*
  1233. float fTurnAmt[3];
  1234. //PITCH
  1235. fTurnAmt[PITCH] = riderPS->viewangles[PITCH] * 0.08f;
  1236. //YAW
  1237. fTurnAmt[YAW] = riderPS->viewangles[YAW] * 0.065f;
  1238. fTurnAmt[YAW] *= fTurnAmt[YAW];
  1239. // Dampen the turn rate based on the current height.
  1240. if ( riderPS->viewangles[YAW] < 0 )
  1241. {//must keep it negative because squaring a negative makes it positive
  1242. fTurnAmt[YAW] = -fTurnAmt[YAW];
  1243. }
  1244. fTurnAmt[YAW] *= pVeh->m_LandTrace.fraction;
  1245. //ROLL
  1246. fTurnAmt[2] = 0.0f;
  1247. */
  1248. //Actal YAW
  1249. #ifdef _JK2MP
  1250. FighterYawAdjust(pVeh, riderPS, parentPS);
  1251. #else
  1252. pVeh->m_vOrientation[YAW] = riderPS->viewangles[YAW];
  1253. #endif
  1254. // If we are not hitting the ground, allow the fighter to pitch up and down.
  1255. if ( !FighterOverValidLandingSurface( pVeh )
  1256. || parentPS->speed > MIN_LANDING_SPEED )
  1257. //if ( ( pVeh->m_LandTrace.fraction >= 1.0f || pVeh->m_ucmd.forwardmove != 0 ) && pVeh->m_LandTrace.fraction >= 0.0f )
  1258. {
  1259. float fYawDelta;
  1260. #ifdef _JK2MP
  1261. FighterPitchAdjust(pVeh, riderPS, parentPS);
  1262. #else
  1263. pVeh->m_vOrientation[PITCH] = riderPS->viewangles[PITCH];
  1264. #endif
  1265. FighterNoseMalfunctionCheck( pVeh, parentPS );
  1266. // Adjust the roll based on the turn amount and dampen it a little.
  1267. fYawDelta = AngleSubtract(pVeh->m_vOrientation[YAW], pVeh->m_vPrevOrientation[YAW]); //pVeh->m_vOrientation[YAW] - pVeh->m_vPrevOrientation[YAW];
  1268. if ( fYawDelta > 8.0f )
  1269. {
  1270. fYawDelta = 8.0f;
  1271. }
  1272. else if ( fYawDelta < -8.0f )
  1273. {
  1274. fYawDelta = -8.0f;
  1275. }
  1276. curRoll -= fYawDelta;
  1277. curRoll = PredictedAngularDecrement(0.93f, angleTimeMod*2.0f, curRoll);
  1278. //cap it reasonably
  1279. //NOTE: was hardcoded to 40.0f, now using extern data
  1280. if ( pVeh->m_pVehicleInfo->rollLimit != -1 )
  1281. {
  1282. if (curRoll > pVeh->m_pVehicleInfo->rollLimit )
  1283. {
  1284. curRoll = pVeh->m_pVehicleInfo->rollLimit;
  1285. }
  1286. else if (curRoll < -pVeh->m_pVehicleInfo->rollLimit)
  1287. {
  1288. curRoll = -pVeh->m_pVehicleInfo->rollLimit;
  1289. }
  1290. }
  1291. }
  1292. }
  1293. }
  1294. // If you are directly impacting the ground, even out your pitch.
  1295. if ( isLandingOrLanded )
  1296. {//only if capable of landing
  1297. if ( !isDead
  1298. && parentPS->electrifyTime<curTime
  1299. && (!pVeh->m_pVehicleInfo->surfDestruction || !pVeh->m_iRemovedSurfaces ) )
  1300. {//not crashing or spiralling out of control...
  1301. if ( pVeh->m_vOrientation[PITCH] > 0 )
  1302. {
  1303. pVeh->m_vOrientation[PITCH] = PredictedAngularDecrement(0.2f, angleTimeMod*10.0f, pVeh->m_vOrientation[PITCH]);
  1304. }
  1305. else
  1306. {
  1307. pVeh->m_vOrientation[PITCH] = PredictedAngularDecrement(0.75f, angleTimeMod*10.0f, pVeh->m_vOrientation[PITCH]);
  1308. }
  1309. }
  1310. }
  1311. /*
  1312. //NOTE: all this is redundant now since we have the FighterDamageRoutine func...
  1313. #ifdef _JK2MP //...yeah. Need to send armor across net for prediction to work.
  1314. if ( isDead )
  1315. #else
  1316. if ( pVeh->m_iArmor <= 0 )
  1317. #endif
  1318. {//going to explode
  1319. //FIXME: maybe make it erratically jerk or spin or start and stop?
  1320. #ifndef _JK2MP
  1321. if ( g_speederControlScheme->value > 0 || !rider || rider->s.number )
  1322. #else
  1323. if (1)
  1324. #endif
  1325. {
  1326. pVeh->m_ucmd.rightmove = Q_irand( -64, 64 );
  1327. }
  1328. else
  1329. {
  1330. pVeh->m_ucmd.rightmove = 0;
  1331. }
  1332. pVeh->m_ucmd.forwardmove = Q_irand( -32, 127 );
  1333. pVeh->m_ucmd.upmove = Q_irand( -127, 127 );
  1334. pVeh->m_vOrientation[YAW] += Q_flrand( -10, 10 );
  1335. pVeh->m_vOrientation[PITCH] += pVeh->m_fTimeModifier;
  1336. if ( pVeh->m_vOrientation[PITCH] > 60.0f )
  1337. {
  1338. pVeh->m_vOrientation[PITCH] = 60.0f;
  1339. }
  1340. if ( pVeh->m_LandTrace.fraction != 0.0f )
  1341. {
  1342. parentPS->velocity[2] -= pVeh->m_pVehicleInfo->acceleration * pVeh->m_fTimeModifier;
  1343. }
  1344. }
  1345. */
  1346. // If no one is in this vehicle and it's up in the sky, pitch it forward as it comes tumbling down.
  1347. #ifdef QAGAME //never gonna happen on client anyway, we can't be getting predicted unless the predicting client is boarded
  1348. if ( !pVeh->m_pVehicleInfo->Inhabited( pVeh )
  1349. && pVeh->m_LandTrace.fraction >= groundFraction
  1350. && !FighterIsInSpace( (gentity_t *)parent )
  1351. && !FighterSuspended( pVeh, parentPS ) )
  1352. {
  1353. pVeh->m_ucmd.upmove = 0;
  1354. //pVeh->m_ucmd.forwardmove = 0;
  1355. pVeh->m_vOrientation[PITCH] += pVeh->m_fTimeModifier;
  1356. if ( !BG_UnrestrainedPitchRoll( riderPS, pVeh ) )
  1357. {
  1358. if ( pVeh->m_vOrientation[PITCH] > 60.0f )
  1359. {
  1360. pVeh->m_vOrientation[PITCH] = 60.0f;
  1361. }
  1362. }
  1363. }
  1364. #endif
  1365. if ( !pVeh->m_fStrafeTime )
  1366. {//use that roll
  1367. pVeh->m_vOrientation[ROLL] = curRoll;
  1368. //NOTE: this seems really backwards...
  1369. if ( pVeh->m_vOrientation[ROLL] )
  1370. { //continually adjust the yaw based on the roll..
  1371. if ( (pVeh->m_iRemovedSurfaces||parentPS->electrifyTime>=curTime)//spiralling out of control
  1372. && (!(pVeh->m_pParentEntity->s.number%4)||!(pVeh->m_pParentEntity->s.number%5)) )
  1373. {//leave YAW alone
  1374. }
  1375. else
  1376. {
  1377. if ( !BG_UnrestrainedPitchRoll( riderPS, pVeh ) )
  1378. {
  1379. pVeh->m_vOrientation[YAW] -= ((pVeh->m_vOrientation[ROLL])*0.05f)*pVeh->m_fTimeModifier;
  1380. }
  1381. }
  1382. }
  1383. }
  1384. else
  1385. {//add in strafing roll
  1386. float strafeRoll = (pVeh->m_fStrafeTime/MAX_STRAFE_TIME)*pVeh->m_pVehicleInfo->rollLimit;//pVeh->m_pVehicleInfo->bankingSpeed*
  1387. float strafeDif = AngleSubtract(strafeRoll, pVeh->m_vOrientation[ROLL]);
  1388. pVeh->m_vOrientation[ROLL] += (strafeDif*0.1f)*pVeh->m_fTimeModifier;
  1389. if ( !BG_UnrestrainedPitchRoll( riderPS, pVeh ) )
  1390. {//cap it reasonably
  1391. if ( pVeh->m_pVehicleInfo->rollLimit != -1
  1392. && !pVeh->m_iRemovedSurfaces
  1393. && parentPS->electrifyTime<curTime)
  1394. {
  1395. if (pVeh->m_vOrientation[ROLL] > pVeh->m_pVehicleInfo->rollLimit )
  1396. {
  1397. pVeh->m_vOrientation[ROLL] = pVeh->m_pVehicleInfo->rollLimit;
  1398. }
  1399. else if (pVeh->m_vOrientation[ROLL] < -pVeh->m_pVehicleInfo->rollLimit)
  1400. {
  1401. pVeh->m_vOrientation[ROLL] = -pVeh->m_pVehicleInfo->rollLimit;
  1402. }
  1403. }
  1404. }
  1405. }
  1406. if (pVeh->m_pVehicleInfo->surfDestruction)
  1407. {
  1408. FighterDamageRoutine(pVeh, parent, parentPS, riderPS, isDead);
  1409. }
  1410. pVeh->m_vOrientation[ROLL] = AngleNormalize180( pVeh->m_vOrientation[ROLL] );
  1411. /********************************************************************************/
  1412. /* END Here is where make sure the vehicle is properly oriented. END */
  1413. /********************************************************************************/
  1414. }
  1415. #ifdef QAGAME //ONLY in SP or on server, not cgame
  1416. extern void PM_SetAnim(pmove_t *pm,int setAnimParts,int anim,int setAnimFlags, int blendTime);
  1417. // This function makes sure that the vehicle is properly animated.
  1418. static void AnimateVehicle( Vehicle_t *pVeh )
  1419. {
  1420. int Anim = -1;
  1421. int iFlags = SETANIM_FLAG_NORMAL, iBlend = 300;
  1422. qboolean isLanding = qfalse, isLanded = qfalse;
  1423. #ifdef _JK2MP
  1424. playerState_t *parentPS = pVeh->m_pParentEntity->playerState;
  1425. #else
  1426. playerState_t *parentPS = &pVeh->m_pParentEntity->client->ps;
  1427. #endif
  1428. #ifndef _JK2MP//SP
  1429. //nothing
  1430. #elif QAGAME//MP GAME
  1431. int curTime = level.time;
  1432. #elif CGAME//MP CGAME
  1433. //FIXME: pass in ucmd? Not sure if this is reliable...
  1434. int curTime = pm->cmd.serverTime;
  1435. #endif
  1436. #ifdef _JK2MP
  1437. if ( parentPS->hyperSpaceTime
  1438. && curTime - parentPS->hyperSpaceTime < HYPERSPACE_TIME )
  1439. {//Going to Hyperspace
  1440. //close the wings (FIXME: makes sense on X-Wing, not Shuttle?)
  1441. if ( pVeh->m_ulFlags & VEH_WINGSOPEN )
  1442. {
  1443. pVeh->m_ulFlags &= ~VEH_WINGSOPEN;
  1444. Anim = BOTH_WINGS_CLOSE;
  1445. }
  1446. }
  1447. else
  1448. #endif
  1449. {
  1450. isLanding = FighterIsLanding( pVeh, parentPS );
  1451. isLanded = FighterIsLanded( pVeh, parentPS );
  1452. // if we're above launch height (way up in the air)...
  1453. if ( !isLanding && !isLanded )
  1454. {
  1455. if ( !( pVeh->m_ulFlags & VEH_WINGSOPEN ) )
  1456. {
  1457. pVeh->m_ulFlags |= VEH_WINGSOPEN;
  1458. pVeh->m_ulFlags &= ~VEH_GEARSOPEN;
  1459. Anim = BOTH_WINGS_OPEN;
  1460. }
  1461. }
  1462. // otherwise we're below launch height and still taking off.
  1463. else
  1464. {
  1465. if ( (pVeh->m_ucmd.forwardmove < 0 || pVeh->m_ucmd.upmove < 0||isLanded)
  1466. && pVeh->m_LandTrace.fraction <= 0.4f
  1467. && pVeh->m_LandTrace.plane.normal[2] >= MIN_LANDING_SLOPE )
  1468. {//already landed or trying to land and close to ground
  1469. // Open gears.
  1470. if ( !( pVeh->m_ulFlags & VEH_GEARSOPEN ) )
  1471. {
  1472. #ifdef _JK2MP
  1473. if ( pVeh->m_pVehicleInfo->soundLand )
  1474. {//just landed?
  1475. #ifdef QAGAME//MP GAME-side
  1476. G_EntitySound( ((gentity_t *)(pVeh->m_pParentEntity)), CHAN_AUTO, pVeh->m_pVehicleInfo->soundLand );
  1477. #elif CGAME//MP CGAME-side
  1478. //trap_S_StartSound( NULL, pVeh->m_pParentEntity->s.number, CHAN_AUTO, pVeh->m_pVehicleInfo->soundLand );
  1479. #endif
  1480. }
  1481. #endif
  1482. pVeh->m_ulFlags |= VEH_GEARSOPEN;
  1483. Anim = BOTH_GEARS_OPEN;
  1484. }
  1485. }
  1486. else
  1487. {//trying to take off and almost halfway off the ground
  1488. // Close gears (if they're open).
  1489. if ( pVeh->m_ulFlags & VEH_GEARSOPEN )
  1490. {
  1491. pVeh->m_ulFlags &= ~VEH_GEARSOPEN;
  1492. Anim = BOTH_GEARS_CLOSE;
  1493. //iFlags = SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD;
  1494. }
  1495. // If gears are closed, and we are below launch height, close the wings.
  1496. else
  1497. {
  1498. if ( pVeh->m_ulFlags & VEH_WINGSOPEN )
  1499. {
  1500. pVeh->m_ulFlags &= ~VEH_WINGSOPEN;
  1501. Anim = BOTH_WINGS_CLOSE;
  1502. }
  1503. }
  1504. }
  1505. }
  1506. }
  1507. if ( Anim != -1 )
  1508. {
  1509. #ifdef _JK2MP
  1510. BG_SetAnim(pVeh->m_pParentEntity->playerState, bgAllAnims[pVeh->m_pParentEntity->localAnimIndex].anims,
  1511. SETANIM_BOTH, Anim, iFlags, iBlend);
  1512. #else
  1513. NPC_SetAnim( pVeh->m_pParentEntity, SETANIM_BOTH, Anim, iFlags, iBlend );
  1514. #endif
  1515. }
  1516. }
  1517. // This function makes sure that the rider's in this vehicle are properly animated.
  1518. static void AnimateRiders( Vehicle_t *pVeh )
  1519. {
  1520. }
  1521. #endif //game-only
  1522. #ifndef QAGAME
  1523. void AttachRidersGeneric( Vehicle_t *pVeh );
  1524. #endif
  1525. void G_SetFighterVehicleFunctions( vehicleInfo_t *pVehInfo )
  1526. {
  1527. #ifdef QAGAME //ONLY in SP or on server, not cgame
  1528. pVehInfo->AnimateVehicle = AnimateVehicle;
  1529. pVehInfo->AnimateRiders = AnimateRiders;
  1530. // pVehInfo->ValidateBoard = ValidateBoard;
  1531. // pVehInfo->SetParent = SetParent;
  1532. // pVehInfo->SetPilot = SetPilot;
  1533. // pVehInfo->AddPassenger = AddPassenger;
  1534. // pVehInfo->Animate = Animate;
  1535. pVehInfo->Board = Board;
  1536. pVehInfo->Eject = Eject;
  1537. // pVehInfo->EjectAll = EjectAll;
  1538. // pVehInfo->StartDeathDelay = StartDeathDelay;
  1539. // pVehInfo->DeathUpdate = DeathUpdate;
  1540. // pVehInfo->RegisterAssets = RegisterAssets;
  1541. // pVehInfo->Initialize = Initialize;
  1542. pVehInfo->Update = Update;
  1543. // pVehInfo->UpdateRider = UpdateRider;
  1544. #endif //game-only
  1545. pVehInfo->ProcessMoveCommands = ProcessMoveCommands;
  1546. pVehInfo->ProcessOrientCommands = ProcessOrientCommands;
  1547. #ifndef QAGAME //cgame prediction attachment func
  1548. pVehInfo->AttachRiders = AttachRidersGeneric;
  1549. #endif
  1550. // pVehInfo->AttachRiders = AttachRiders;
  1551. // pVehInfo->Ghost = Ghost;
  1552. // pVehInfo->UnGhost = UnGhost;
  1553. // pVehInfo->Inhabited = Inhabited;
  1554. }
  1555. // Following is only in game, not in namespace
  1556. #ifdef _JK2MP
  1557. #include "../namespace_end.h"
  1558. #endif
  1559. #ifdef QAGAME
  1560. extern void G_AllocateVehicleObject(Vehicle_t **pVeh);
  1561. #endif
  1562. #ifdef _JK2MP
  1563. #include "../namespace_begin.h"
  1564. #endif
  1565. // Create/Allocate a new Animal Vehicle (initializing it as well).
  1566. void G_CreateFighterNPC( Vehicle_t **pVeh, const char *strType )
  1567. {
  1568. // Allocate the Vehicle.
  1569. #ifdef _JK2MP
  1570. #ifdef QAGAME
  1571. //these will remain on entities on the client once allocated because the pointer is
  1572. //never stomped. on the server, however, when an ent is freed, the entity struct is
  1573. //memset to 0, so this memory would be lost..
  1574. G_AllocateVehicleObject(pVeh);
  1575. #else
  1576. if (!*pVeh)
  1577. { //only allocate a new one if we really have to
  1578. (*pVeh) = (Vehicle_t *) BG_Alloc( sizeof(Vehicle_t) );
  1579. }
  1580. #endif
  1581. memset(*pVeh, 0, sizeof(Vehicle_t));
  1582. #else
  1583. (*pVeh) = (Vehicle_t *) gi.Malloc( sizeof(Vehicle_t), TAG_G_ALLOC, qtrue );
  1584. #endif
  1585. (*pVeh)->m_pVehicleInfo = &g_vehicleInfo[BG_VehicleGetIndex( strType )];
  1586. }
  1587. #ifdef _JK2MP
  1588. #include "../namespace_end.h"
  1589. //get rid of all the crazy defs we added for this file
  1590. #undef currentAngles
  1591. #undef currentOrigin
  1592. #undef mins
  1593. #undef maxs
  1594. #undef legsAnimTimer
  1595. #undef torsoAnimTimer
  1596. #undef bool
  1597. #undef false
  1598. #undef true
  1599. #undef sqrtf
  1600. #undef Q_flrand
  1601. #undef MOD_EXPLOSIVE
  1602. #endif