g_vehicles.c 96 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202
  1. // leave this line at the top for all g_xxxx.cpp files...
  2. #include "g_headers.h"
  3. #include "q_shared.h"
  4. #include "g_local.h"
  5. #ifdef _JK2 //SP does not have this preprocessor for game like MP does
  6. #ifndef _JK2MP
  7. #define _JK2MP
  8. #endif
  9. #endif
  10. #ifndef _JK2MP
  11. #include "g_functions.h"
  12. #include "g_vehicles.h"
  13. #include "../CGame/cg_Local.h"
  14. #else
  15. #include "bg_vehicles.h"
  16. #endif
  17. #ifdef _JK2MP
  18. //this is really horrible, but it works! just be sure not to use any locals or anything
  19. //with these names (exluding bool, false, true). -rww
  20. #define currentAngles r.currentAngles
  21. #define currentOrigin r.currentOrigin
  22. #define mins r.mins
  23. #define maxs r.maxs
  24. #define legsAnimTimer legsTimer
  25. #define torsoAnimTimer torsoTimer
  26. #define bool qboolean
  27. #define false qfalse
  28. #define true qtrue
  29. #define sqrtf sqrt
  30. #define MOD_EXPLOSIVE MOD_SUICIDE
  31. #endif
  32. #ifndef _JK2MP
  33. #define GAME_INLINE inline
  34. #define bgEntity_t gentity_t
  35. #endif
  36. #ifdef _JK2MP
  37. extern gentity_t *NPC_Spawn_Do( gentity_t *ent );
  38. extern void NPC_SetAnim(gentity_t *ent,int setAnimParts,int anim,int setAnimFlags);
  39. #else
  40. extern gentity_t *NPC_Spawn_Do( gentity_t *pEnt, qboolean fullSpawnNow );
  41. extern qboolean G_ClearLineOfSight(const vec3_t point1, const vec3_t point2, int ignore, int clipmask);
  42. extern qboolean G_SetG2PlayerModelInfo( gentity_t *pEnt, const char *modelName, const char *customSkin, const char *surfOff, const char *surfOn );
  43. extern void G_RemovePlayerModel( gentity_t *pEnt );
  44. extern void G_ChangePlayerModel( gentity_t *pEnt, const char *newModel );
  45. extern void G_RemoveWeaponModels( gentity_t *pEnt );
  46. extern void CG_ChangeWeapon( int num );
  47. extern float DotToSpot( vec3_t spot, vec3_t from, vec3_t fromAngles );
  48. extern qboolean Q3_TaskIDPending( gentity_t *ent, taskID_t taskType );
  49. extern void SetClientViewAngle( gentity_t *ent, vec3_t angle );
  50. extern vmCvar_t cg_thirdPersonAlpha;
  51. extern vec3_t playerMins;
  52. extern vec3_t playerMaxs;
  53. extern cvar_t *g_speederControlScheme;
  54. extern cvar_t *in_joystick;
  55. extern void PM_SetAnim(pmove_t *pm,int setAnimParts,int anim,int setAnimFlags, int blendTime);
  56. extern int PM_AnimLength( int index, animNumber_t anim );
  57. extern void NPC_SetAnim(gentity_t *ent,int setAnimParts,int anim,int setAnimFlags, int iBlend);
  58. extern void G_Knockdown( gentity_t *self, gentity_t *attacker, const vec3_t pushDir, float strength, qboolean breakSaberLock );
  59. #endif
  60. #ifdef _JK2MP
  61. #include "../namespace_begin.h"
  62. extern void BG_SetAnim(playerState_t *ps, animation_t *animations, int setAnimParts,int anim,int setAnimFlags, int blendTime);
  63. extern void BG_SetLegsAnimTimer(playerState_t *ps, int time );
  64. extern void BG_SetTorsoAnimTimer(playerState_t *ps, int time );
  65. #include "../namespace_end.h"
  66. void G_VehUpdateShields( gentity_t *targ );
  67. #ifdef QAGAME
  68. extern void VEH_TurretThink( Vehicle_t *pVeh, gentity_t *parent, int turretNum );
  69. #endif
  70. #else
  71. extern void PM_SetTorsoAnimTimer( gentity_t *ent, int *torsoAnimTimer, int time );
  72. extern void PM_SetLegsAnimTimer( gentity_t *ent, int *legsAnimTimer, int time );
  73. #endif
  74. extern qboolean BG_UnrestrainedPitchRoll( playerState_t *ps, Vehicle_t *pVeh );
  75. void Vehicle_SetAnim(gentity_t *ent,int setAnimParts,int anim,int setAnimFlags, int iBlend)
  76. {
  77. #ifdef _JK2MP
  78. assert(ent->client);
  79. BG_SetAnim(&ent->client->ps, bgAllAnims[ent->localAnimIndex].anims, setAnimParts, anim, setAnimFlags, iBlend);
  80. ent->s.legsAnim = ent->client->ps.legsAnim;
  81. #else
  82. NPC_SetAnim(ent, setAnimParts, anim, setAnimFlags, iBlend);
  83. #endif
  84. }
  85. 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 )
  86. {
  87. #ifdef _JK2MP
  88. trap_Trace(results, start, tMins, tMaxs, end, passEntityNum, contentmask);
  89. #else
  90. gi.trace( results, start, tMins, tMaxs, end, passEntityNum, contentmask );
  91. #endif
  92. }
  93. Vehicle_t *G_IsRidingVehicle( gentity_t *pEnt )
  94. {
  95. gentity_t *ent = (gentity_t *)pEnt;
  96. if ( ent && ent->client && ent->client->NPC_class != CLASS_VEHICLE && ent->s.m_iVehicleNum != 0 ) //ent->client && ( ent->client->ps.eFlags & EF_IN_VEHICLE ) && ent->owner )
  97. {
  98. return g_entities[ent->s.m_iVehicleNum].m_pVehicle;
  99. }
  100. return NULL;
  101. }
  102. bool G_IsRidingTurboVehicle( gentity_t *pEnt )
  103. {
  104. gentity_t *ent = (gentity_t *)pEnt;
  105. if ( ent && ent->client && ent->client->NPC_class != CLASS_VEHICLE && ent->s.m_iVehicleNum != 0 ) //ent->client && ( ent->client->ps.eFlags & EF_IN_VEHICLE ) && ent->owner )
  106. {
  107. return (level.time<g_entities[ent->s.m_iVehicleNum].m_pVehicle->m_iTurboTime);
  108. }
  109. return false;
  110. }
  111. float G_CanJumpToEnemyVeh(Vehicle_t *pVeh, const usercmd_t *pUcmd )
  112. {
  113. #ifndef _JK2MP
  114. gentity_t* rider = pVeh->m_pPilot;
  115. // If There Is An Enemy And We Are At The Same Z Height
  116. //------------------------------------------------------
  117. if (rider &&
  118. rider->enemy &&
  119. pUcmd->rightmove &&
  120. fabsf(rider->enemy->currentOrigin[2] - rider->currentOrigin[2])<50.0f)
  121. {
  122. if (level.time<pVeh->m_safeJumpMountTime)
  123. {
  124. return pVeh->m_safeJumpMountRightDot;
  125. }
  126. // If The Enemy Is Riding Another Vehicle
  127. //----------------------------------------
  128. Vehicle_t* enemyVeh = G_IsRidingVehicle(rider->enemy);
  129. if (enemyVeh)
  130. {
  131. vec3_t enemyFwd;
  132. vec3_t toEnemy;
  133. float toEnemyDistance;
  134. vec3_t riderFwd;
  135. vec3_t riderRight;
  136. float riderRightDot;
  137. // If He Is Close Enough And Going The Same Speed
  138. //------------------------------------------------
  139. VectorSubtract(rider->enemy->currentOrigin, rider->currentOrigin, toEnemy);
  140. toEnemyDistance = VectorNormalize(toEnemy);
  141. if (toEnemyDistance<70.0f &&
  142. pVeh->m_pParentEntity->resultspeed>100.0f &&
  143. fabsf(pVeh->m_pParentEntity->resultspeed - enemyVeh->m_pParentEntity->resultspeed)<100.0f)
  144. {
  145. // If He Is Either To The Left Or Right Of Me
  146. //--------------------------------------------
  147. AngleVectors(rider->currentAngles, riderFwd, riderRight, 0);
  148. riderRightDot = DotProduct(riderRight, toEnemy);
  149. if ((pUcmd->rightmove>0 && riderRightDot>0.2) || (pUcmd->rightmove<0 &&riderRightDot<-0.2))
  150. {
  151. // If We Are Both Going About The Same Direction
  152. //-----------------------------------------------
  153. AngleVectors(rider->enemy->currentAngles, enemyFwd, 0, 0);
  154. if (DotProduct(enemyFwd, riderFwd)>0.2f)
  155. {
  156. pVeh->m_safeJumpMountTime = level.time + Q_irand(3000, 4000); // Ok, now you get a 3 sec window
  157. pVeh->m_safeJumpMountRightDot = riderRightDot;
  158. return riderRightDot;
  159. }// Same Direction?
  160. }// To Left Or Right?
  161. }// Close Enough & Same Speed?
  162. }// Enemy Riding A Vehicle?
  163. }// Has Enemy And On Same Z-Height
  164. #endif
  165. return 0.0f;
  166. }
  167. // Spawn this vehicle into the world.
  168. void G_VehicleSpawn( gentity_t *self )
  169. {
  170. float yaw;
  171. gentity_t *vehEnt;
  172. VectorCopy( self->currentOrigin, self->s.origin );
  173. #ifdef _JK2MP
  174. trap_LinkEntity( self );
  175. #else
  176. gi.linkentity( self );
  177. #endif
  178. if ( !self->count )
  179. {
  180. self->count = 1;
  181. }
  182. //save this because self gets removed in next func
  183. yaw = self->s.angles[YAW];
  184. #ifdef _JK2MP
  185. vehEnt = NPC_Spawn_Do( self );
  186. #else
  187. vehEnt = NPC_Spawn_Do( self, qtrue );
  188. #endif
  189. if ( !vehEnt )
  190. {
  191. return;//return NULL;
  192. }
  193. vehEnt->s.angles[YAW] = yaw;
  194. if ( vehEnt->m_pVehicle->m_pVehicleInfo->type != VH_ANIMAL )
  195. {
  196. vehEnt->NPC->behaviorState = BS_CINEMATIC;
  197. }
  198. #ifdef _JK2MP //special check in case someone disconnects/dies while boarding
  199. if (vehEnt->spawnflags & 1)
  200. { //die without pilot
  201. if (!vehEnt->damage)
  202. { //default 10 sec
  203. vehEnt->damage = 10000;
  204. }
  205. if (!vehEnt->speed)
  206. { //default 512 units
  207. vehEnt->speed = 512.0f;
  208. }
  209. vehEnt->m_pVehicle->m_iPilotTime = level.time + vehEnt->damage;
  210. }
  211. #else
  212. if (vehEnt->spawnflags & 1)
  213. { //die without pilot
  214. vehEnt->m_pVehicle->m_iPilotTime = level.time + vehEnt->endFrame;
  215. }
  216. #endif
  217. //return vehEnt;
  218. }
  219. // Attachs an entity to the vehicle it's riding (it's owner).
  220. void G_AttachToVehicle( gentity_t *pEnt, usercmd_t **ucmd )
  221. {
  222. gentity_t *vehEnt;
  223. mdxaBone_t boltMatrix;
  224. gentity_t *ent;
  225. #ifdef _JK2MP
  226. int crotchBolt;
  227. #endif
  228. if ( !pEnt || !ucmd )
  229. return;
  230. ent = (gentity_t *)pEnt;
  231. #ifdef _JK2MP
  232. vehEnt = &g_entities[ent->r.ownerNum];
  233. #else
  234. vehEnt = ent->owner;
  235. #endif
  236. ent->waypoint = vehEnt->waypoint; // take the veh's waypoint as your own
  237. if ( !vehEnt->m_pVehicle )
  238. return;
  239. #ifdef _JK2MP
  240. crotchBolt = trap_G2API_AddBolt(vehEnt->ghoul2, 0, "*driver");
  241. // Get the driver tag.
  242. trap_G2API_GetBoltMatrix( vehEnt->ghoul2, 0, crotchBolt, &boltMatrix,
  243. vehEnt->m_pVehicle->m_vOrientation, vehEnt->currentOrigin,
  244. level.time, NULL, vehEnt->modelScale );
  245. BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, ent->client->ps.origin );
  246. G_SetOrigin(ent, ent->client->ps.origin);
  247. trap_LinkEntity( ent );
  248. #else
  249. // Get the driver tag.
  250. gi.G2API_GetBoltMatrix( vehEnt->ghoul2, vehEnt->playerModel, vehEnt->crotchBolt, &boltMatrix,
  251. vehEnt->m_pVehicle->m_vOrientation, vehEnt->currentOrigin,
  252. (cg.time?cg.time:level.time), NULL, vehEnt->s.modelScale );
  253. gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, ent->client->ps.origin );
  254. gi.linkentity( ent );
  255. #endif
  256. }
  257. #ifndef _JK2MP
  258. void G_KnockOffVehicle( gentity_t *pRider, gentity_t *self, qboolean bPull )
  259. {
  260. Vehicle_t *pVeh = NULL;
  261. vec3_t riderAngles, fDir, rDir, dir2Me;
  262. float fDot, rDot;
  263. if ( !pRider || !pRider->client )
  264. {
  265. return;
  266. }
  267. pVeh = G_IsRidingVehicle( pRider );
  268. if ( !pVeh || !pVeh->m_pVehicleInfo )
  269. {
  270. return;
  271. }
  272. VectorCopy( pRider->currentAngles, riderAngles );
  273. riderAngles[0] = 0;
  274. AngleVectors( riderAngles, fDir, rDir, NULL );
  275. VectorSubtract( self->currentOrigin, pRider->currentOrigin, dir2Me );
  276. dir2Me[2] = 0;
  277. VectorNormalize( dir2Me );
  278. fDot = DotProduct( fDir, dir2Me );
  279. if ( fDot >= 0.5f )
  280. {//I'm in front of them
  281. if ( bPull )
  282. {//pull them foward
  283. pVeh->m_EjectDir = VEH_EJECT_FRONT;
  284. }
  285. else
  286. {//push them back
  287. pVeh->m_EjectDir = VEH_EJECT_REAR;
  288. }
  289. }
  290. else if ( fDot <= -0.5f )
  291. {//I'm behind them
  292. if ( bPull )
  293. {//pull them back
  294. pVeh->m_EjectDir = VEH_EJECT_REAR;
  295. }
  296. else
  297. {//push them forward
  298. pVeh->m_EjectDir = VEH_EJECT_FRONT;
  299. }
  300. }
  301. else
  302. {//to the side of them
  303. rDot = DotProduct( fDir, dir2Me );
  304. if ( rDot >= 0.0f )
  305. {//to the right
  306. if ( bPull )
  307. {//pull them right
  308. pVeh->m_EjectDir = VEH_EJECT_RIGHT;
  309. }
  310. else
  311. {//push them left
  312. pVeh->m_EjectDir = VEH_EJECT_LEFT;
  313. }
  314. }
  315. else
  316. {//to the left
  317. if ( bPull )
  318. {//pull them left
  319. pVeh->m_EjectDir = VEH_EJECT_LEFT;
  320. }
  321. else
  322. {//push them right
  323. pVeh->m_EjectDir = VEH_EJECT_RIGHT;
  324. }
  325. }
  326. }
  327. //now forcibly eject them
  328. pVeh->m_pVehicleInfo->Eject( pVeh, pRider, qtrue );
  329. }
  330. #endif
  331. #ifndef _JK2MP //don't want this in mp at least for now
  332. void G_DrivableATSTDie( gentity_t *self )
  333. {
  334. }
  335. void G_DriveATST( gentity_t *pEnt, gentity_t *atst )
  336. {
  337. if ( pEnt->NPC_type && pEnt->client && (pEnt->client->NPC_class == CLASS_ATST) )
  338. {//already an atst, switch back
  339. //open hatch
  340. G_RemovePlayerModel( pEnt );
  341. pEnt->NPC_type = "player";
  342. pEnt->client->NPC_class = CLASS_PLAYER;
  343. pEnt->flags &= ~FL_SHIELDED;
  344. pEnt->client->ps.eFlags &= ~EF_IN_ATST;
  345. //size
  346. VectorCopy( playerMins, pEnt->mins );
  347. VectorCopy( playerMaxs, pEnt->maxs );
  348. pEnt->client->crouchheight = CROUCH_MAXS_2;
  349. pEnt->client->standheight = DEFAULT_MAXS_2;
  350. pEnt->s.radius = 0;//clear it so the G2-model-setting stuff will recalc it
  351. G_ChangePlayerModel( pEnt, pEnt->NPC_type );
  352. //G_SetG2PlayerModel( pEnt, pEnt->NPC_type, NULL, NULL, NULL );
  353. //FIXME: reset/4 their weapon
  354. pEnt->client->ps.stats[STAT_WEAPONS] &= ~(( 1 << WP_ATST_MAIN )|( 1 << WP_ATST_SIDE ));
  355. pEnt->client->ps.ammo[weaponData[WP_ATST_MAIN].ammoIndex] = 0;
  356. pEnt->client->ps.ammo[weaponData[WP_ATST_SIDE].ammoIndex] = 0;
  357. if ( pEnt->client->ps.stats[STAT_WEAPONS] & (1<<WP_BLASTER) )
  358. {
  359. CG_ChangeWeapon( WP_BLASTER );
  360. //camera
  361. if ( cg_gunAutoFirst.integer )
  362. {//go back to first person
  363. gi.cvar_set( "cg_thirdperson", "0" );
  364. }
  365. }
  366. else
  367. {
  368. CG_ChangeWeapon( WP_NONE );
  369. }
  370. cg.overrides.active &= ~(CG_OVERRIDE_3RD_PERSON_RNG|CG_OVERRIDE_3RD_PERSON_VOF|CG_OVERRIDE_3RD_PERSON_POF|CG_OVERRIDE_3RD_PERSON_APH);
  371. cg.overrides.thirdPersonRange = cg.overrides.thirdPersonVertOffset = cg.overrides.thirdPersonPitchOffset = 0;
  372. cg.overrides.thirdPersonAlpha = cg_thirdPersonAlpha.value;
  373. pEnt->client->ps.viewheight = pEnt->maxs[2] + STANDARD_VIEWHEIGHT_OFFSET;
  374. //pEnt->mass = 10;
  375. }
  376. else
  377. {//become an atst
  378. pEnt->NPC_type = "atst";
  379. pEnt->client->NPC_class = CLASS_ATST;
  380. pEnt->client->ps.eFlags |= EF_IN_ATST;
  381. pEnt->flags |= FL_SHIELDED;
  382. //size
  383. VectorSet( pEnt->mins, ATST_MINS0, ATST_MINS1, ATST_MINS2 );
  384. VectorSet( pEnt->maxs, ATST_MAXS0, ATST_MAXS1, ATST_MAXS2 );
  385. pEnt->client->crouchheight = ATST_MAXS2;
  386. pEnt->client->standheight = ATST_MAXS2;
  387. if ( !atst )
  388. {//no pEnt to copy from
  389. G_ChangePlayerModel( pEnt, "atst" );
  390. //G_SetG2PlayerModel( pEnt, "atst", NULL, NULL, NULL );
  391. NPC_SetAnim( pEnt, SETANIM_BOTH, BOTH_STAND1, SETANIM_FLAG_OVERRIDE, 200 );
  392. }
  393. else
  394. {
  395. G_RemovePlayerModel( pEnt );
  396. G_RemoveWeaponModels( pEnt );
  397. gi.G2API_CopyGhoul2Instance( atst->ghoul2, pEnt->ghoul2 );
  398. pEnt->playerModel = 0;
  399. G_SetG2PlayerModelInfo( pEnt, "atst", NULL, NULL, NULL );
  400. //turn off hatch underside
  401. gi.G2API_SetSurfaceOnOff( &pEnt->ghoul2[pEnt->playerModel], "head_hatchcover", 0x00000002/*G2SURFACEFLAG_OFF*/ );
  402. G_Sound( pEnt, G_SoundIndex( "sound/chars/atst/atst_hatch_close" ));
  403. }
  404. pEnt->s.radius = 320;
  405. //weapon
  406. gitem_t *item = FindItemForWeapon( WP_ATST_MAIN ); //precache the weapon
  407. CG_RegisterItemSounds( (item-bg_itemlist) );
  408. CG_RegisterItemVisuals( (item-bg_itemlist) );
  409. item = FindItemForWeapon( WP_ATST_SIDE ); //precache the weapon
  410. CG_RegisterItemSounds( (item-bg_itemlist) );
  411. CG_RegisterItemVisuals( (item-bg_itemlist) );
  412. pEnt->client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_ATST_MAIN )|( 1 << WP_ATST_SIDE );
  413. pEnt->client->ps.ammo[weaponData[WP_ATST_MAIN].ammoIndex] = ammoData[weaponData[WP_ATST_MAIN].ammoIndex].max;
  414. pEnt->client->ps.ammo[weaponData[WP_ATST_SIDE].ammoIndex] = ammoData[weaponData[WP_ATST_SIDE].ammoIndex].max;
  415. CG_ChangeWeapon( WP_ATST_MAIN );
  416. //HACKHACKHACKTEMP
  417. item = FindItemForWeapon( WP_EMPLACED_GUN );
  418. CG_RegisterItemSounds( (item-bg_itemlist) );
  419. CG_RegisterItemVisuals( (item-bg_itemlist) );
  420. item = FindItemForWeapon( WP_ROCKET_LAUNCHER );
  421. CG_RegisterItemSounds( (item-bg_itemlist) );
  422. CG_RegisterItemVisuals( (item-bg_itemlist) );
  423. item = FindItemForWeapon( WP_BOWCASTER );
  424. CG_RegisterItemSounds( (item-bg_itemlist) );
  425. CG_RegisterItemVisuals( (item-bg_itemlist) );
  426. //HACKHACKHACKTEMP
  427. //FIXME: these get lost in load/save! Must use variables that are set every frame or saved/loaded
  428. //camera
  429. gi.cvar_set( "cg_thirdperson", "1" );
  430. cg.overrides.active |= CG_OVERRIDE_3RD_PERSON_RNG;
  431. cg.overrides.thirdPersonRange = 240;
  432. //cg.overrides.thirdPersonVertOffset = 100;
  433. //cg.overrides.thirdPersonPitchOffset = -30;
  434. //FIXME: this gets stomped in pmove?
  435. pEnt->client->ps.viewheight = 120;
  436. //FIXME: setting these broke things very badly...?
  437. //pEnt->client->standheight = 200;
  438. //pEnt->client->crouchheight = 200;
  439. //pEnt->mass = 300;
  440. //movement
  441. //pEnt->client->ps.speed = 0;//FIXME: override speed?
  442. //FIXME: slow turn turning/can't turn if not moving?
  443. }
  444. }
  445. #endif //_JK2MP
  446. // Animate the vehicle and it's riders.
  447. void Animate( Vehicle_t *pVeh )
  448. {
  449. // Validate a pilot rider.
  450. if ( pVeh->m_pPilot )
  451. {
  452. if (pVeh->m_pVehicleInfo->AnimateRiders)
  453. {
  454. pVeh->m_pVehicleInfo->AnimateRiders( pVeh );
  455. }
  456. }
  457. pVeh->m_pVehicleInfo->AnimateVehicle( pVeh );
  458. }
  459. // Determine whether this entity is able to board this vehicle or not.
  460. bool ValidateBoard( Vehicle_t *pVeh, bgEntity_t *pEnt )
  461. {
  462. // Determine where the entity is entering the vehicle from (left, right, or back).
  463. vec3_t vVehToEnt;
  464. vec3_t vVehDir;
  465. const gentity_t *parent = (gentity_t *)pVeh->m_pParentEntity;
  466. const gentity_t *ent = (gentity_t *)pEnt;
  467. vec3_t vVehAngles;
  468. float fDot;
  469. if ( pVeh->m_iDieTime>0)
  470. {
  471. return false;
  472. }
  473. if ( ent->health <= 0 )
  474. {//dead men can't ride vehicles
  475. return false;
  476. }
  477. if ( pVeh->m_pPilot != NULL )
  478. {//already have a driver!
  479. if ( pVeh->m_pVehicleInfo->type == VH_FIGHTER )
  480. {//I know, I know, this should by in the fighters's validateboard()
  481. //can never steal a fighter from it's pilot
  482. return false;
  483. }
  484. else if ( pVeh->m_pVehicleInfo->type == VH_WALKER )
  485. {//I know, I know, this should by in the walker's validateboard()
  486. if ( !ent->client || ent->client->ps.groundEntityNum != parent->s.number )
  487. {//can only steal an occupied AT-ST if you're on top (by the hatch)
  488. return false;
  489. }
  490. }
  491. else if (pVeh->m_pVehicleInfo->type == VH_SPEEDER)
  492. {//you can only steal the bike from the driver if you landed on the driver or bike
  493. return (pVeh->m_iBoarding==VEH_MOUNT_THROW_LEFT || pVeh->m_iBoarding==VEH_MOUNT_THROW_RIGHT);
  494. }
  495. }
  496. // Yes, you shouldn't have put this here (you 'should' have made an 'overriden' ValidateBoard func), but in this
  497. // instance it's more than adequate (which is why I do it too :-). Making a whole other function for this is silly.
  498. else if ( pVeh->m_pVehicleInfo->type == VH_FIGHTER )
  499. {
  500. // If you're a fighter, you allow everyone to enter you from all directions.
  501. return true;
  502. }
  503. // Clear out all orientation axis except for the yaw.
  504. VectorSet(vVehAngles, 0, parent->currentAngles[YAW], 0);
  505. // Vector from Entity to Vehicle.
  506. VectorSubtract( ent->currentOrigin, parent->currentOrigin, vVehToEnt );
  507. vVehToEnt[2] = 0;
  508. VectorNormalize( vVehToEnt );
  509. // Get the right vector.
  510. AngleVectors( vVehAngles, NULL, vVehDir, NULL );
  511. VectorNormalize( vVehDir );
  512. // Find the angle between the vehicle right vector and the vehicle to entity vector.
  513. fDot = DotProduct( vVehToEnt, vVehDir );
  514. // If the entity is within a certain angle to the left of the vehicle...
  515. if ( fDot >= 0.5f )
  516. {
  517. // Right board.
  518. pVeh->m_iBoarding = -2;
  519. }
  520. else if ( fDot <= -0.5f )
  521. {
  522. // Left board.
  523. pVeh->m_iBoarding = -1;
  524. }
  525. // Maybe they're trying to board from the back...
  526. else
  527. {
  528. // The forward vector of the vehicle.
  529. // AngleVectors( vVehAngles, vVehDir, NULL, NULL );
  530. // VectorNormalize( vVehDir );
  531. // Find the angle between the vehicle forward and the vehicle to entity vector.
  532. // fDot = DotProduct( vVehToEnt, vVehDir );
  533. // If the entity is within a certain angle behind the vehicle...
  534. //if ( fDot <= -0.85f )
  535. {
  536. // Jump board.
  537. pVeh->m_iBoarding = -3;
  538. }
  539. }
  540. // If for some reason we couldn't board, leave...
  541. if ( pVeh->m_iBoarding > -1 )
  542. return false;
  543. return true;
  544. }
  545. // Board this Vehicle (get on). The first entity to board an empty vehicle becomes the Pilot.
  546. bool Board( Vehicle_t *pVeh, bgEntity_t *pEnt )
  547. {
  548. vec3_t vPlayerDir;
  549. gentity_t *ent = (gentity_t *)pEnt;
  550. gentity_t *parent = (gentity_t *)pVeh->m_pParentEntity;
  551. // If it's not a valid entity, OR if the vehicle is blowing up (it's dead), OR it's not
  552. // empty, OR we're already being boarded, OR the person trying to get on us is already
  553. // in a vehicle (that was a fun bug :-), leave!
  554. if ( !ent || parent->health <= 0 /*|| !( parent->client->ps.eFlags & EF_EMPTY_VEHICLE )*/ || (pVeh->m_iBoarding > 0) ||
  555. #ifdef _JK2MP
  556. ( ent->client->ps.m_iVehicleNum ) )
  557. #else
  558. ( ent->s.m_iVehicleNum != 0 ) )
  559. #endif
  560. return false;
  561. // Bucking so we can't do anything (NOTE: Should probably be a better name since fighters don't buck...).
  562. if ( pVeh->m_ulFlags & VEH_BUCKING )
  563. return false;
  564. // Validate the entity's ability to board this vehicle.
  565. if ( !pVeh->m_pVehicleInfo->ValidateBoard( pVeh, pEnt ) )
  566. return false;
  567. // FIXME FIXME!!! Ask Mike monday where ent->client->ps.eFlags might be getting changed!!! It is always 0 (when it should
  568. // be 1024) so a person riding a vehicle is able to ride another vehicle!!!!!!!!
  569. // Tell everybody their status.
  570. // ALWAYS let the player be the pilot.
  571. if ( ent->s.number < MAX_CLIENTS )
  572. {
  573. pVeh->m_pOldPilot = pVeh->m_pPilot;
  574. #ifdef _JK2MP
  575. if ( !pVeh->m_pPilot )
  576. { //become the pilot, if there isn't one now
  577. pVeh->m_pVehicleInfo->SetPilot( pVeh, (bgEntity_t *)ent );
  578. }
  579. // If we're not yet full...
  580. else if ( pVeh->m_iNumPassengers < pVeh->m_pVehicleInfo->maxPassengers )
  581. {
  582. int i;
  583. // Find an empty slot and put that passenger here.
  584. for ( i = 0; i < pVeh->m_pVehicleInfo->maxPassengers; i++ )
  585. {
  586. if ( pVeh->m_ppPassengers[i] == NULL )
  587. {
  588. pVeh->m_ppPassengers[i] = (bgEntity_t *)ent;
  589. #ifdef QAGAME
  590. //Server just needs to tell client which passengernum he is
  591. if ( ent->client )
  592. {
  593. ent->client->ps.generic1 = i+1;
  594. }
  595. #endif
  596. break;
  597. }
  598. }
  599. pVeh->m_iNumPassengers++;
  600. }
  601. // We're full, sorry...
  602. else
  603. {
  604. return false;
  605. }
  606. ent->s.m_iVehicleNum = parent->s.number;
  607. if (ent->client)
  608. {
  609. ent->client->ps.m_iVehicleNum = ent->s.m_iVehicleNum;
  610. }
  611. if ( pVeh->m_pPilot == (bgEntity_t *)ent )
  612. {
  613. parent->r.ownerNum = ent->s.number;
  614. parent->s.owner = parent->r.ownerNum; //for prediction
  615. }
  616. #else
  617. pVeh->m_pVehicleInfo->SetPilot( pVeh, ent );
  618. ent->s.m_iVehicleNum = parent->s.number;
  619. parent->owner = ent;
  620. #endif
  621. #ifdef QAGAME
  622. {
  623. gentity_t *gParent = (gentity_t *)parent;
  624. if ( (gParent->spawnflags&2) )
  625. {//was being suspended
  626. gParent->spawnflags &= ~2;//SUSPENDED - clear this spawnflag, no longer docked, okay to free-fall if not in space
  627. //gParent->client->ps.eFlags &= ~EF_RADAROBJECT;
  628. G_Sound( gParent, CHAN_AUTO, G_SoundIndex( "sound/vehicles/common/release.wav" ) );
  629. if ( gParent->fly_sound_debounce_time )
  630. {//we should drop like a rock for a few seconds
  631. pVeh->m_iDropTime = level.time + gParent->fly_sound_debounce_time;
  632. }
  633. }
  634. }
  635. #endif
  636. #ifndef _JK2MP
  637. gi.cvar_set( "cg_thirdperson", "1" ); //go to third person
  638. CG_CenterPrint( "@SP_INGAME_EXIT_VIEW", SCREEN_HEIGHT * 0.87 ); //tell them how to get out!
  639. #endif
  640. //FIXME: rider needs to look in vehicle's direction when he gets in
  641. // Clear these since they're used to turn the vehicle now.
  642. /*SetClientViewAngle( ent, pVeh->m_vOrientation );
  643. memset( &parent->client->usercmd, 0, sizeof( usercmd_t ) );
  644. memset( &pVeh->m_ucmd, 0, sizeof( usercmd_t ) );
  645. VectorClear( parent->client->ps.viewangles );
  646. VectorClear( parent->client->ps.delta_angles );*/
  647. // Set the looping sound only when there is a pilot (when the vehicle is "on").
  648. if ( pVeh->m_pVehicleInfo->soundLoop )
  649. {
  650. #ifdef _JK2MP
  651. parent->client->ps.loopSound = parent->s.loopSound = pVeh->m_pVehicleInfo->soundLoop;
  652. #else
  653. parent->s.loopSound = pVeh->m_pVehicleInfo->soundLoop;
  654. #endif
  655. }
  656. }
  657. else
  658. {
  659. // If there's no pilot, try to drive this vehicle.
  660. if ( pVeh->m_pPilot == NULL )
  661. {
  662. #ifdef _JK2MP
  663. pVeh->m_pVehicleInfo->SetPilot( pVeh, (bgEntity_t *)ent );
  664. // TODO: Set pilot should do all this stuff....
  665. parent->r.ownerNum = ent->s.number;
  666. parent->s.owner = parent->r.ownerNum; //for prediction
  667. #else
  668. pVeh->m_pVehicleInfo->SetPilot( pVeh, ent );
  669. // TODO: Set pilot should do all this stuff....
  670. parent->owner = ent;
  671. #endif
  672. // Set the looping sound only when there is a pilot (when the vehicle is "on").
  673. if ( pVeh->m_pVehicleInfo->soundLoop )
  674. {
  675. #ifdef _JK2MP
  676. parent->client->ps.loopSound = parent->s.loopSound = pVeh->m_pVehicleInfo->soundLoop;
  677. #else
  678. parent->s.loopSound = pVeh->m_pVehicleInfo->soundLoop;
  679. #endif
  680. }
  681. parent->client->ps.speed = 0;
  682. memset( &pVeh->m_ucmd, 0, sizeof( usercmd_t ) );
  683. }
  684. // We're full, sorry...
  685. else
  686. {
  687. return false;
  688. }
  689. }
  690. // Make sure the entity knows it's in a vehicle.
  691. #ifdef _JK2MP
  692. ent->client->ps.m_iVehicleNum = parent->s.number;
  693. ent->r.ownerNum = parent->s.number;
  694. ent->s.owner = ent->r.ownerNum; //for prediction
  695. if (pVeh->m_pPilot == (bgEntity_t *)ent)
  696. {
  697. parent->client->ps.m_iVehicleNum = ent->s.number+1; //always gonna be under MAX_CLIENTS so no worries about 1 byte overflow
  698. }
  699. #else
  700. ent->s.m_iVehicleNum = parent->s.number;
  701. ent->owner = parent;
  702. parent->s.m_iVehicleNum = ent->s.number+1;
  703. #endif
  704. //memset( &ent->client->usercmd, 0, sizeof( usercmd_t ) );
  705. //FIXME: no saber or weapons if numHands = 2, should switch to speeder weapon, no attack anim on player
  706. if ( pVeh->m_pVehicleInfo->numHands == 2 )
  707. {//switch to vehicle weapon
  708. #ifndef _JK2MP //rwwFIXMEFIXMEFIXME
  709. if (ent->s.number<MAX_CLIENTS)
  710. {// Riding means you get WP_NONE
  711. ent->client->ps.stats[ STAT_WEAPONS ] |= (1<<WP_NONE);
  712. }
  713. if ( ent->client->ps.weapon != WP_SABER
  714. && ent->client->ps.weapon != WP_BLASTER )
  715. {//switch to weapon none?
  716. if (ent->s.number<MAX_CLIENTS)
  717. {
  718. CG_ChangeWeapon(WP_NONE);
  719. }
  720. ent->client->ps.weapon = WP_NONE;
  721. G_RemoveWeaponModels( ent );
  722. }
  723. #endif
  724. }
  725. if ( pVeh->m_pVehicleInfo->hideRider )
  726. {//hide the rider
  727. pVeh->m_pVehicleInfo->Ghost( pVeh, (bgEntity_t *)ent );
  728. }
  729. // Play the start sounds
  730. if ( pVeh->m_pVehicleInfo->soundOn )
  731. {
  732. #ifdef _JK2MP
  733. G_Sound( parent, CHAN_AUTO, pVeh->m_pVehicleInfo->soundOn );
  734. #else
  735. // NOTE: Use this type so it's spatialized and updates play origin as bike moves - MCG
  736. G_SoundIndexOnEnt( parent, CHAN_AUTO, pVeh->m_pVehicleInfo->soundOn );
  737. #endif
  738. }
  739. VectorCopy( pVeh->m_vOrientation, vPlayerDir );
  740. vPlayerDir[ROLL] = 0;
  741. SetClientViewAngle( ent, vPlayerDir );
  742. return true;
  743. }
  744. bool VEH_TryEject( Vehicle_t *pVeh,
  745. gentity_t *parent,
  746. gentity_t *ent,
  747. int ejectDir,
  748. vec3_t vExitPos )
  749. {
  750. float fBias;
  751. float fVehDiag;
  752. float fEntDiag;
  753. vec3_t vEntMins, vEntMaxs, vVehLeaveDir, vVehAngles;
  754. trace_t m_ExitTrace;
  755. // Make sure that the entity is not 'stuck' inside the vehicle (since their bboxes will now intersect).
  756. // This makes the entity leave the vehicle from the right side.
  757. VectorSet(vVehAngles, 0, parent->currentAngles[YAW], 0);
  758. switch ( ejectDir )
  759. {
  760. // Left.
  761. case VEH_EJECT_LEFT:
  762. AngleVectors( vVehAngles, NULL, vVehLeaveDir, NULL );
  763. vVehLeaveDir[0] = -vVehLeaveDir[0];
  764. vVehLeaveDir[1] = -vVehLeaveDir[1];
  765. vVehLeaveDir[2] = -vVehLeaveDir[2];
  766. break;
  767. // Right.
  768. case VEH_EJECT_RIGHT:
  769. AngleVectors( vVehAngles, NULL, vVehLeaveDir, NULL );
  770. break;
  771. // Front.
  772. case VEH_EJECT_FRONT:
  773. AngleVectors( vVehAngles, vVehLeaveDir, NULL, NULL );
  774. break;
  775. // Rear.
  776. case VEH_EJECT_REAR:
  777. AngleVectors( vVehAngles, vVehLeaveDir, NULL, NULL );
  778. vVehLeaveDir[0] = -vVehLeaveDir[0];
  779. vVehLeaveDir[1] = -vVehLeaveDir[1];
  780. vVehLeaveDir[2] = -vVehLeaveDir[2];
  781. break;
  782. // Top.
  783. case VEH_EJECT_TOP:
  784. AngleVectors( vVehAngles, NULL, NULL, vVehLeaveDir );
  785. break;
  786. // Bottom?.
  787. case VEH_EJECT_BOTTOM:
  788. break;
  789. }
  790. VectorNormalize( vVehLeaveDir );
  791. //NOTE: not sure why following line was needed - MCG
  792. //pVeh->m_EjectDir = VEH_EJECT_LEFT;
  793. // Since (as of this time) the collidable geometry of the entity is just an axis
  794. // aligned box, we need to get the diagonal length of it in case we come out on that side.
  795. // Diagonal Length == squareroot( squared( Sidex / 2 ) + squared( Sidey / 2 ) );
  796. // TODO: DO diagonal for entity.
  797. fBias = 1.0f;
  798. if (pVeh->m_pVehicleInfo->type == VH_WALKER)
  799. { //hacktastic!
  800. fBias += 0.2f;
  801. }
  802. VectorCopy( ent->currentOrigin, vExitPos );
  803. fVehDiag = sqrtf( ( parent->maxs[0] * parent->maxs[0] ) + ( parent->maxs[1] * parent->maxs[1] ) );
  804. VectorCopy( ent->maxs, vEntMaxs );
  805. #ifdef _JK2MP
  806. if ( ent->s.number < MAX_CLIENTS )
  807. {//for some reason, in MP, player client mins and maxs are never stored permanently, just set to these hardcoded numbers in PMove
  808. vEntMaxs[0] = 15;
  809. vEntMaxs[1] = 15;
  810. }
  811. #endif
  812. fEntDiag = sqrtf( ( vEntMaxs[0] * vEntMaxs[0] ) + ( vEntMaxs[1] * vEntMaxs[1] ) );
  813. vVehLeaveDir[0] *= ( fVehDiag + fEntDiag ) * fBias; // x
  814. vVehLeaveDir[1] *= ( fVehDiag + fEntDiag ) * fBias; // y
  815. vVehLeaveDir[2] *= ( fVehDiag + fEntDiag ) * fBias;
  816. VectorAdd( vExitPos, vVehLeaveDir, vExitPos );
  817. //we actually could end up *not* getting off if the trace fails...
  818. // Check to see if this new position is a valid place for our entity to go.
  819. #ifdef _JK2MP
  820. VectorSet(vEntMins, -15.0f, -15.0f, DEFAULT_MINS_2);
  821. VectorSet(vEntMaxs, 15.0f, 15.0f, DEFAULT_MAXS_2);
  822. #else
  823. VectorCopy(ent->mins, vEntMins);
  824. VectorCopy(ent->maxs, vEntMaxs);
  825. #endif
  826. G_VehicleTrace( &m_ExitTrace, ent->currentOrigin, vEntMins, vEntMaxs, vExitPos, ent->s.number, ent->clipmask );
  827. if ( m_ExitTrace.allsolid//in solid
  828. || m_ExitTrace.startsolid)
  829. {
  830. return false;
  831. }
  832. // If the trace hit something, we can't go there!
  833. if ( m_ExitTrace.fraction < 1.0f )
  834. {//not totally clear
  835. #ifdef _JK2MP
  836. if ( (parent->clipmask&ent->r.contents) )//vehicle could actually get stuck on body
  837. #else
  838. if ( (parent->clipmask&ent->contents) )//vehicle could actually get stuck on body
  839. #endif
  840. {//the trace hit the vehicle, don't let them get out, just in case
  841. return false;
  842. }
  843. //otherwise, use the trace.endpos
  844. VectorCopy( m_ExitTrace.endpos, vExitPos );
  845. }
  846. return true;
  847. }
  848. void G_EjectDroidUnit( Vehicle_t *pVeh, qboolean kill )
  849. {
  850. pVeh->m_pDroidUnit->s.m_iVehicleNum = ENTITYNUM_NONE;
  851. #ifdef _JK2MP
  852. pVeh->m_pDroidUnit->s.owner = ENTITYNUM_NONE;
  853. #else
  854. pVeh->m_pDroidUnit->owner = NULL;
  855. #endif
  856. // pVeh->m_pDroidUnit->s.otherEntityNum2 = ENTITYNUM_NONE;
  857. #ifdef QAGAME
  858. {
  859. gentity_t *droidEnt = (gentity_t *)pVeh->m_pDroidUnit;
  860. droidEnt->flags &= ~FL_UNDYING;
  861. droidEnt->r.ownerNum = ENTITYNUM_NONE;
  862. if ( droidEnt->client )
  863. {
  864. droidEnt->client->ps.m_iVehicleNum = ENTITYNUM_NONE;
  865. }
  866. if ( kill )
  867. {//Kill them, too
  868. //FIXME: proper origin, MOD and attacker (for credit/death message)? Get from vehicle?
  869. G_MuteSound(droidEnt->s.number, CHAN_VOICE);
  870. G_Damage( droidEnt, NULL, NULL, NULL, droidEnt->s.origin, 10000, 0, MOD_SUICIDE );//FIXME: proper MOD? Get from vehicle?
  871. }
  872. }
  873. #endif
  874. pVeh->m_pDroidUnit = NULL;
  875. }
  876. // Eject the pilot from the vehicle.
  877. bool Eject( Vehicle_t *pVeh, bgEntity_t *pEnt, qboolean forceEject )
  878. {
  879. gentity_t *parent;
  880. vec3_t vExitPos;
  881. #ifndef _JK2MP
  882. vec3_t vPlayerDir;
  883. #endif
  884. gentity_t *ent = (gentity_t *)pEnt;
  885. int firstEjectDir;
  886. #ifdef _JK2MP
  887. qboolean taintedRider = qfalse;
  888. qboolean deadRider = qfalse;
  889. if ( pEnt == pVeh->m_pDroidUnit )
  890. {
  891. G_EjectDroidUnit( pVeh, qfalse );
  892. return true;
  893. }
  894. if (ent)
  895. {
  896. if (!ent->inuse || !ent->client || ent->client->pers.connected != CON_CONNECTED)
  897. {
  898. taintedRider = qtrue;
  899. parent = (gentity_t *)pVeh->m_pParentEntity;
  900. goto getItOutOfMe;
  901. }
  902. else if (ent->health < 1)
  903. {
  904. deadRider = qtrue;
  905. }
  906. }
  907. #endif
  908. // Validate.
  909. if ( !ent )
  910. {
  911. return false;
  912. }
  913. if ( !forceEject )
  914. {
  915. if ( !( pVeh->m_iBoarding == 0 || pVeh->m_iBoarding == -999 || ( pVeh->m_iBoarding < -3 && pVeh->m_iBoarding >= -9 ) ) )
  916. {
  917. #ifdef _JK2MP //I don't care, if he's dead get him off even if he died while boarding
  918. deadRider = qtrue;
  919. pVeh->m_iBoarding = 0;
  920. pVeh->m_bWasBoarding = false;
  921. #else
  922. return false;
  923. #endif
  924. }
  925. }
  926. /*#ifndef _JK2MP //rwwFIXMEFIXMEFIXME
  927. if (ent->s.number<MAX_CLIENTS)
  928. {
  929. CG_ChangeWeapon(WP_NONE);
  930. }
  931. ent->client->ps.weapon = WP_NONE;
  932. G_RemoveWeaponModels( ent );
  933. #endif*/
  934. parent = (gentity_t *)pVeh->m_pParentEntity;
  935. //Try ejecting in every direction
  936. if ( pVeh->m_EjectDir < VEH_EJECT_LEFT )
  937. {
  938. pVeh->m_EjectDir = VEH_EJECT_LEFT;
  939. }
  940. else if ( pVeh->m_EjectDir > VEH_EJECT_BOTTOM )
  941. {
  942. pVeh->m_EjectDir = VEH_EJECT_BOTTOM;
  943. }
  944. firstEjectDir = pVeh->m_EjectDir;
  945. while ( !VEH_TryEject( pVeh, parent, ent, pVeh->m_EjectDir, vExitPos ) )
  946. {
  947. pVeh->m_EjectDir++;
  948. if ( pVeh->m_EjectDir > VEH_EJECT_BOTTOM )
  949. {
  950. pVeh->m_EjectDir = VEH_EJECT_LEFT;
  951. }
  952. if ( pVeh->m_EjectDir == firstEjectDir )
  953. {//they all failed
  954. #ifdef _JK2MP
  955. if (!deadRider)
  956. { //if he's dead.. just shove him in solid, who cares.
  957. return false;
  958. }
  959. #endif
  960. if ( forceEject )
  961. {//we want to always get out, just eject him here
  962. VectorCopy( ent->currentOrigin, vExitPos );
  963. break;
  964. }
  965. else
  966. {//can't eject
  967. return false;
  968. }
  969. }
  970. }
  971. // Move them to the exit position.
  972. G_SetOrigin( ent, vExitPos );
  973. #ifdef _JK2MP
  974. VectorCopy(ent->currentOrigin, ent->client->ps.origin);
  975. trap_LinkEntity( ent );
  976. #else
  977. gi.linkentity( ent );
  978. #endif
  979. // If it's the player, stop overrides.
  980. if ( ent->s.number < MAX_CLIENTS )
  981. {
  982. #ifndef _JK2MP
  983. cg.overrides.active = 0;
  984. #else
  985. #endif
  986. }
  987. #ifdef _JK2MP //in MP if someone disconnects on us, we still have to clear our owner
  988. getItOutOfMe:
  989. #endif
  990. // If he's the pilot...
  991. if ( (gentity_t *)pVeh->m_pPilot == ent )
  992. {
  993. #ifdef _JK2MP
  994. int j = 0;
  995. #endif
  996. pVeh->m_pPilot = NULL;
  997. #ifdef _JK2MP
  998. parent->r.ownerNum = ENTITYNUM_NONE;
  999. parent->s.owner = parent->r.ownerNum; //for prediction
  1000. //keep these current angles
  1001. //SetClientViewAngle( parent, pVeh->m_vOrientation );
  1002. memset( &parent->client->pers.cmd, 0, sizeof( usercmd_t ) );
  1003. #else
  1004. parent->owner = NULL;
  1005. //keep these current angles
  1006. //SetClientViewAngle( parent, pVeh->m_vOrientation );
  1007. memset( &parent->client->usercmd, 0, sizeof( usercmd_t ) );
  1008. #endif
  1009. memset( &pVeh->m_ucmd, 0, sizeof( usercmd_t ) );
  1010. #ifdef _JK2MP //if there are some passengers, promote the first passenger to pilot
  1011. while (j < pVeh->m_iNumPassengers)
  1012. {
  1013. if (pVeh->m_ppPassengers[j])
  1014. {
  1015. int k = 1;
  1016. pVeh->m_pVehicleInfo->SetPilot( pVeh, pVeh->m_ppPassengers[j] );
  1017. parent->r.ownerNum = pVeh->m_ppPassengers[j]->s.number;
  1018. parent->s.owner = parent->r.ownerNum; //for prediction
  1019. parent->client->ps.m_iVehicleNum = pVeh->m_ppPassengers[j]->s.number+1;
  1020. //rearrange the passenger slots now..
  1021. #ifdef QAGAME
  1022. //Server just needs to tell client he's not a passenger anymore
  1023. if ( ((gentity_t *)pVeh->m_ppPassengers[j])->client )
  1024. {
  1025. ((gentity_t *)pVeh->m_ppPassengers[j])->client->ps.generic1 = 0;
  1026. }
  1027. #endif
  1028. pVeh->m_ppPassengers[j] = NULL;
  1029. while (k < pVeh->m_iNumPassengers)
  1030. {
  1031. if (!pVeh->m_ppPassengers[k-1])
  1032. { //move down
  1033. pVeh->m_ppPassengers[k-1] = pVeh->m_ppPassengers[k];
  1034. pVeh->m_ppPassengers[k] = NULL;
  1035. #ifdef QAGAME
  1036. //Server just needs to tell client which passenger he is
  1037. if ( ((gentity_t *)pVeh->m_ppPassengers[k-1])->client )
  1038. {
  1039. ((gentity_t *)pVeh->m_ppPassengers[k-1])->client->ps.generic1 = k;
  1040. }
  1041. #endif
  1042. }
  1043. k++;
  1044. }
  1045. pVeh->m_iNumPassengers--;
  1046. break;
  1047. }
  1048. j++;
  1049. }
  1050. #endif
  1051. }
  1052. else if (ent==(gentity_t *)pVeh->m_pOldPilot)
  1053. {
  1054. pVeh->m_pOldPilot = 0;
  1055. }
  1056. #ifdef _JK2MP //I hate adding these!
  1057. if (!taintedRider)
  1058. {
  1059. #endif
  1060. if ( pVeh->m_pVehicleInfo->hideRider )
  1061. {
  1062. pVeh->m_pVehicleInfo->UnGhost( pVeh, (bgEntity_t *)ent );
  1063. }
  1064. #ifdef _JK2MP
  1065. }
  1066. #endif
  1067. // If the vehicle now has no pilot...
  1068. if ( pVeh->m_pPilot == NULL )
  1069. {
  1070. #ifdef _JK2MP
  1071. parent->client->ps.loopSound = parent->s.loopSound = 0;
  1072. #else
  1073. parent->s.loopSound = 0;
  1074. #endif
  1075. // Completely empty vehicle...?
  1076. #ifdef _JK2MP
  1077. parent->client->ps.m_iVehicleNum = 0;
  1078. #else
  1079. parent->s.m_iVehicleNum = 0;
  1080. #endif
  1081. }
  1082. #ifdef _JK2MP
  1083. if (taintedRider)
  1084. { //you can go now
  1085. pVeh->m_iBoarding = level.time + 1000;
  1086. return true;
  1087. }
  1088. #endif
  1089. // Client not in a vehicle.
  1090. #ifdef _JK2MP
  1091. ent->client->ps.m_iVehicleNum = 0;
  1092. ent->r.ownerNum = ENTITYNUM_NONE;
  1093. ent->s.owner = ent->r.ownerNum; //for prediction
  1094. ent->client->ps.viewangles[PITCH] = 0.0f;
  1095. ent->client->ps.viewangles[ROLL] = 0.0f;
  1096. ent->client->ps.viewangles[YAW] = pVeh->m_vOrientation[YAW];
  1097. SetClientViewAngle(ent, ent->client->ps.viewangles);
  1098. if (ent->client->solidHack)
  1099. {
  1100. ent->client->solidHack = 0;
  1101. ent->r.contents = CONTENTS_BODY;
  1102. }
  1103. #else
  1104. ent->owner = NULL;
  1105. #endif
  1106. ent->s.m_iVehicleNum = 0;
  1107. // Jump out.
  1108. /* if ( ent->client->ps.velocity[2] < JUMP_VELOCITY )
  1109. {
  1110. ent->client->ps.velocity[2] = JUMP_VELOCITY;
  1111. }
  1112. else
  1113. {
  1114. ent->client->ps.velocity[2] += JUMP_VELOCITY;
  1115. }*/
  1116. // Make sure entity is facing the direction it got off at.
  1117. #ifndef _JK2MP
  1118. VectorCopy( pVeh->m_vOrientation, vPlayerDir );
  1119. vPlayerDir[ROLL] = 0;
  1120. SetClientViewAngle( ent, vPlayerDir );
  1121. #endif
  1122. //if was using vehicle weapon, remove it and switch to normal weapon when hop out...
  1123. if ( ent->client->ps.weapon == WP_NONE )
  1124. {//FIXME: check against this vehicle's gun from the g_vehicleInfo table
  1125. //remove the vehicle's weapon from me
  1126. //ent->client->ps.stats[STAT_WEAPONS] &= ~( 1 << WP_EMPLACED_GUN );
  1127. //ent->client->ps.ammo[weaponData[WP_EMPLACED_GUN].ammoIndex] = 0;//maybe store this ammo on the vehicle before clearing it?
  1128. //switch back to a normal weapon we're carrying
  1129. //FIXME: store the weapon we were using when we got on and restore that when hop off
  1130. /* if ( (ent->client->ps.stats[STAT_WEAPONS]&(1<<WP_SABER)) )
  1131. {
  1132. CG_ChangeWeapon( WP_SABER );
  1133. }
  1134. else
  1135. {//go through all weapons and switch to highest held
  1136. for ( int checkWp = WP_NUM_WEAPONS-1; checkWp > WP_NONE; checkWp-- )
  1137. {
  1138. if ( (ent->client->ps.stats[STAT_WEAPONS]&(1<<checkWp)) )
  1139. {
  1140. CG_ChangeWeapon( checkWp );
  1141. }
  1142. }
  1143. if ( checkWp == WP_NONE )
  1144. {
  1145. CG_ChangeWeapon( WP_NONE );
  1146. }
  1147. }*/
  1148. }
  1149. else
  1150. {//FIXME: if they have their saber out:
  1151. //if dualSabers, add the second saber into the left hand
  1152. //saber[0] has more than one blade, turn them all on
  1153. //NOTE: this is because you're only allowed to use your first saber's first blade on a vehicle
  1154. }
  1155. /* if ( !ent->s.number && ent->client->ps.weapon != WP_SABER
  1156. && cg_gunAutoFirst.value )
  1157. {
  1158. gi.cvar_set( "cg_thirdperson", "0" );
  1159. }*/
  1160. #ifdef _JK2MP
  1161. BG_SetLegsAnimTimer( &ent->client->ps, 0 );
  1162. BG_SetTorsoAnimTimer( &ent->client->ps, 0 );
  1163. #else
  1164. PM_SetLegsAnimTimer( ent, &ent->client->ps.legsAnimTimer, 0 );
  1165. PM_SetTorsoAnimTimer( ent, &ent->client->ps.torsoAnimTimer, 0 );
  1166. #endif
  1167. // Set how long until this vehicle can be boarded again.
  1168. pVeh->m_iBoarding = level.time + 1000;
  1169. return true;
  1170. }
  1171. // Eject all the inhabitants of this vehicle.
  1172. bool EjectAll( Vehicle_t *pVeh )
  1173. {
  1174. // TODO: Setup a default escape for ever vehicle type.
  1175. pVeh->m_EjectDir = VEH_EJECT_TOP;
  1176. // Make sure no other boarding calls exist. We MUST exit.
  1177. pVeh->m_iBoarding = 0;
  1178. pVeh->m_bWasBoarding = false;
  1179. // Throw them off.
  1180. if ( pVeh->m_pPilot )
  1181. {
  1182. #ifdef QAGAME
  1183. gentity_t *pilot = (gentity_t*)pVeh->m_pPilot;
  1184. #endif
  1185. pVeh->m_pVehicleInfo->Eject( pVeh, pVeh->m_pPilot, qtrue );
  1186. #ifdef QAGAME
  1187. if ( pVeh->m_pVehicleInfo->killRiderOnDeath && pilot )
  1188. {//Kill them, too
  1189. //FIXME: proper origin, MOD and attacker (for credit/death message)? Get from vehicle?
  1190. G_MuteSound(pilot->s.number, CHAN_VOICE);
  1191. G_Damage( pilot, player, player, NULL, pilot->s.origin, 10000, 0, MOD_SUICIDE );
  1192. }
  1193. #endif
  1194. }
  1195. if ( pVeh->m_pOldPilot )
  1196. {
  1197. #ifdef QAGAME
  1198. gentity_t *pilot = (gentity_t*)pVeh->m_pOldPilot;
  1199. #endif
  1200. pVeh->m_pVehicleInfo->Eject( pVeh, pVeh->m_pOldPilot, qtrue );
  1201. #ifdef QAGAME
  1202. if ( pVeh->m_pVehicleInfo->killRiderOnDeath && pilot )
  1203. {//Kill them, too
  1204. //FIXME: proper origin, MOD and attacker (for credit/death message)? Get from vehicle?
  1205. G_MuteSound(pilot->s.number, CHAN_VOICE);
  1206. G_Damage( pilot, player, player, NULL, pilot->s.origin, 10000, 0, MOD_SUICIDE );
  1207. }
  1208. #endif
  1209. }
  1210. if ( pVeh->m_pDroidUnit )
  1211. {
  1212. G_EjectDroidUnit( pVeh, pVeh->m_pVehicleInfo->killRiderOnDeath );
  1213. }
  1214. return true;
  1215. }
  1216. // Start a delay until the vehicle explodes.
  1217. static void StartDeathDelay( Vehicle_t *pVeh, int iDelayTimeOverride )
  1218. {
  1219. gentity_t *parent = (gentity_t *)pVeh->m_pParentEntity;
  1220. if ( iDelayTimeOverride )
  1221. {
  1222. pVeh->m_iDieTime = level.time + iDelayTimeOverride;
  1223. }
  1224. else
  1225. {
  1226. pVeh->m_iDieTime = level.time + pVeh->m_pVehicleInfo->explosionDelay;
  1227. }
  1228. #ifdef _JK2MP
  1229. if ( pVeh->m_pVehicleInfo->flammable )
  1230. {
  1231. parent->client->ps.loopSound = parent->s.loopSound = G_SoundIndex( "sound/vehicles/common/fire_lp.wav" );
  1232. }
  1233. #else
  1234. // Armor Gone Effects (Fire)
  1235. //---------------------------
  1236. if (pVeh->m_pVehicleInfo->iArmorGoneFX)
  1237. {
  1238. if (!(pVeh->m_ulFlags&VEH_ARMORGONE) && (pVeh->m_iArmor <= 0))
  1239. {
  1240. pVeh->m_ulFlags |= VEH_ARMORGONE;
  1241. G_PlayEffect(pVeh->m_pVehicleInfo->iArmorGoneFX, parent->playerModel, parent->crotchBolt, parent->s.number, parent->currentOrigin, 1, qtrue);
  1242. parent->s.loopSound = G_SoundIndex( "sound/vehicles/common/fire_lp.wav" );
  1243. }
  1244. }
  1245. #endif
  1246. }
  1247. extern char current_speeders;
  1248. // Decide whether to explode the vehicle or not.
  1249. static void DeathUpdate( Vehicle_t *pVeh )
  1250. {
  1251. gentity_t *parent = (gentity_t *)pVeh->m_pParentEntity;
  1252. if ( level.time >= pVeh->m_iDieTime )
  1253. {
  1254. // If the vehicle is not empty.
  1255. if ( pVeh->m_pVehicleInfo->Inhabited( pVeh ) )
  1256. {
  1257. #ifndef _JK2MP
  1258. if (pVeh->m_pPilot)
  1259. {
  1260. pVeh->m_pPilot->client->noRagTime = -1; // no ragdoll for you
  1261. }
  1262. #endif
  1263. pVeh->m_pVehicleInfo->EjectAll( pVeh );
  1264. #ifdef _JK2MP
  1265. if ( pVeh->m_pVehicleInfo->Inhabited( pVeh ) )
  1266. { //if we've still got people in us, just kill the bastards
  1267. if ( pVeh->m_pPilot )
  1268. {
  1269. //FIXME: does this give proper credit to the enemy who shot you down?
  1270. G_Damage((gentity_t *)pVeh->m_pPilot, (gentity_t *)pVeh->m_pParentEntity, (gentity_t *)pVeh->m_pParentEntity,
  1271. NULL, pVeh->m_pParentEntity->playerState->origin, 999, DAMAGE_NO_PROTECTION, MOD_EXPLOSIVE);
  1272. }
  1273. if ( pVeh->m_iNumPassengers )
  1274. {
  1275. int i;
  1276. for ( i = 0; i < pVeh->m_pVehicleInfo->maxPassengers; i++ )
  1277. {
  1278. if ( pVeh->m_ppPassengers[i] )
  1279. {
  1280. //FIXME: does this give proper credit to the enemy who shot you down?
  1281. G_Damage((gentity_t *)pVeh->m_ppPassengers[i], (gentity_t *)pVeh->m_pParentEntity, (gentity_t *)pVeh->m_pParentEntity,
  1282. NULL, pVeh->m_pParentEntity->playerState->origin, 999, DAMAGE_NO_PROTECTION, MOD_EXPLOSIVE);
  1283. }
  1284. }
  1285. }
  1286. }
  1287. #endif
  1288. }
  1289. if ( !pVeh->m_pVehicleInfo->Inhabited( pVeh ) )
  1290. { //explode now as long as we managed to kick everyone out
  1291. vec3_t lMins, lMaxs, bottom;
  1292. trace_t trace;
  1293. #ifndef _JK2MP
  1294. // Kill All Client Side Looping Effects
  1295. //--------------------------------------
  1296. if (pVeh->m_pVehicleInfo->iExhaustFX)
  1297. {
  1298. for (int i=0; (i<MAX_VEHICLE_EXHAUSTS && pVeh->m_iExhaustTag[i]!=-1); i++)
  1299. {
  1300. G_StopEffect(pVeh->m_pVehicleInfo->iExhaustFX, parent->playerModel, pVeh->m_iExhaustTag[i], parent->s.number);
  1301. }
  1302. }
  1303. if (pVeh->m_pVehicleInfo->iArmorLowFX)
  1304. {
  1305. G_StopEffect(pVeh->m_pVehicleInfo->iArmorLowFX, parent->playerModel, parent->crotchBolt, parent->s.number);
  1306. }
  1307. if (pVeh->m_pVehicleInfo->iArmorGoneFX)
  1308. {
  1309. G_StopEffect(pVeh->m_pVehicleInfo->iArmorGoneFX, parent->playerModel, parent->crotchBolt, parent->s.number);
  1310. }
  1311. //--------------------------------------
  1312. #endif
  1313. if ( pVeh->m_pVehicleInfo->iExplodeFX )
  1314. {
  1315. #ifdef _JK2MP
  1316. vec3_t fxAng;
  1317. VectorSet(fxAng, -90.0f, 0.0f, 0.0f);
  1318. G_PlayEffectID( pVeh->m_pVehicleInfo->iExplodeFX, parent->currentOrigin, fxAng );
  1319. #else
  1320. G_PlayEffect( pVeh->m_pVehicleInfo->iExplodeFX, parent->currentOrigin, vec3_origin );
  1321. #endif
  1322. //trace down and place mark
  1323. VectorCopy( parent->currentOrigin, bottom );
  1324. bottom[2] -= 80;
  1325. G_VehicleTrace( &trace, parent->currentOrigin, vec3_origin, vec3_origin, bottom, parent->s.number, CONTENTS_SOLID );
  1326. if ( trace.fraction < 1.0f )
  1327. {
  1328. VectorCopy( trace.endpos, bottom );
  1329. bottom[2] += 2;
  1330. #ifdef _JK2MP
  1331. VectorSet(fxAng, -90.0f, 0.0f, 0.0f);
  1332. G_PlayEffectID( G_EffectIndex("ships/ship_explosion_mark"), trace.endpos, fxAng );
  1333. #else
  1334. G_PlayEffect( "ships/ship_explosion_mark", trace.endpos );
  1335. #endif
  1336. }
  1337. }
  1338. parent->takedamage = qfalse;//so we don't recursively damage ourselves
  1339. if ( pVeh->m_pVehicleInfo->explosionRadius > 0 && pVeh->m_pVehicleInfo->explosionDamage > 0 )
  1340. {
  1341. VectorCopy( parent->mins, lMins );
  1342. lMins[2] = -4;//to keep it off the ground a *little*
  1343. VectorCopy( parent->maxs, lMaxs );
  1344. VectorCopy( parent->currentOrigin, bottom );
  1345. bottom[2] += parent->mins[2] - 32;
  1346. G_VehicleTrace( &trace, parent->currentOrigin, lMins, lMaxs, bottom, parent->s.number, CONTENTS_SOLID );
  1347. #ifdef _JK2MP
  1348. G_RadiusDamage( trace.endpos, NULL, pVeh->m_pVehicleInfo->explosionDamage, pVeh->m_pVehicleInfo->explosionRadius, NULL, NULL, MOD_EXPLOSIVE );//FIXME: extern damage and radius or base on fuel
  1349. #else
  1350. G_RadiusDamage( trace.endpos, player, pVeh->m_pVehicleInfo->explosionDamage, pVeh->m_pVehicleInfo->explosionRadius, NULL, MOD_EXPLOSIVE );//FIXME: extern damage and radius or base on fuel
  1351. #endif
  1352. }
  1353. #ifdef _JK2MP
  1354. parent->think = G_FreeEntity;
  1355. #else
  1356. parent->e_ThinkFunc = thinkF_G_FreeEntity;
  1357. #endif
  1358. parent->nextthink = level.time + FRAMETIME;
  1359. }
  1360. }
  1361. #ifndef _JK2MP
  1362. else
  1363. {//let everyone around me know I'm gonna blow!
  1364. if ( !Q_irand( 0, 10 ) )
  1365. {//not so often...
  1366. AddSoundEvent( parent, parent->currentOrigin, 512, AEL_DANGER );
  1367. AddSightEvent( parent, parent->currentOrigin, 512, AEL_DANGER, 100 );
  1368. }
  1369. }
  1370. #endif
  1371. }
  1372. // Register all the assets used by this vehicle.
  1373. void RegisterAssets( Vehicle_t *pVeh )
  1374. {
  1375. }
  1376. extern void ChangeWeapon( gentity_t *ent, int newWeapon );
  1377. // Initialize the vehicle.
  1378. bool Initialize( Vehicle_t *pVeh )
  1379. {
  1380. gentity_t *parent = (gentity_t *)pVeh->m_pParentEntity;
  1381. int i = 0;
  1382. if ( !parent || !parent->client )
  1383. return false;
  1384. #ifdef _JK2MP
  1385. parent->client->ps.m_iVehicleNum = 0;
  1386. #endif
  1387. parent->s.m_iVehicleNum = 0;
  1388. {
  1389. pVeh->m_iArmor = pVeh->m_pVehicleInfo->armor;
  1390. parent->client->pers.maxHealth = parent->client->ps.stats[STAT_MAX_HEALTH] = parent->NPC->stats.health = parent->health = parent->client->ps.stats[STAT_HEALTH] = pVeh->m_iArmor;
  1391. pVeh->m_iShields = pVeh->m_pVehicleInfo->shields;
  1392. #ifdef _JK2MP
  1393. G_VehUpdateShields( parent );
  1394. #endif
  1395. parent->client->ps.stats[STAT_ARMOR] = pVeh->m_iShields;
  1396. }
  1397. parent->mass = pVeh->m_pVehicleInfo->mass;
  1398. //initialize the ammo to max
  1399. for ( i = 0; i < MAX_VEHICLE_WEAPONS; i++ )
  1400. {
  1401. parent->client->ps.ammo[i] = pVeh->weaponStatus[i].ammo = pVeh->m_pVehicleInfo->weapon[i].ammoMax;
  1402. }
  1403. for ( i = 0; i < MAX_VEHICLE_TURRETS; i++ )
  1404. {
  1405. pVeh->turretStatus[i].nextMuzzle = (pVeh->m_pVehicleInfo->turret[i].iMuzzle[i]-1);
  1406. parent->client->ps.ammo[MAX_VEHICLE_WEAPONS+i] = pVeh->turretStatus[i].ammo = pVeh->m_pVehicleInfo->turret[i].iAmmoMax;
  1407. if ( pVeh->m_pVehicleInfo->turret[i].bAI )
  1408. {//they're going to be finding enemies, init this to NONE
  1409. pVeh->turretStatus[i].enemyEntNum = ENTITYNUM_NONE;
  1410. }
  1411. }
  1412. //begin stopped...?
  1413. parent->client->ps.speed = 0;
  1414. VectorClear( pVeh->m_vOrientation );
  1415. pVeh->m_vOrientation[YAW] = parent->s.angles[YAW];
  1416. #ifdef _JK2MP
  1417. if ( pVeh->m_pVehicleInfo->gravity &&
  1418. pVeh->m_pVehicleInfo->gravity != g_gravity.value )
  1419. {//not normal gravity
  1420. if ( parent->NPC )
  1421. {
  1422. parent->NPC->aiFlags |= NPCAI_CUSTOM_GRAVITY;
  1423. }
  1424. parent->client->ps.gravity = pVeh->m_pVehicleInfo->gravity;
  1425. }
  1426. #else
  1427. if ( pVeh->m_pVehicleInfo->gravity &&
  1428. pVeh->m_pVehicleInfo->gravity != g_gravity->value )
  1429. {//not normal gravity
  1430. parent->svFlags |= SVF_CUSTOM_GRAVITY;
  1431. parent->client->ps.gravity = pVeh->m_pVehicleInfo->gravity;
  1432. }
  1433. #endif
  1434. /*
  1435. if ( pVeh->m_iVehicleTypeID == VH_FIGHTER )
  1436. {
  1437. pVeh->m_ulFlags = VEH_GEARSOPEN;
  1438. }
  1439. else
  1440. */
  1441. //why?! -rww
  1442. {
  1443. pVeh->m_ulFlags = 0;
  1444. }
  1445. pVeh->m_fTimeModifier = 1.0f;
  1446. pVeh->m_iBoarding = 0;
  1447. pVeh->m_bWasBoarding = false;
  1448. pVeh->m_pOldPilot = NULL;
  1449. VectorClear(pVeh->m_vBoardingVelocity);
  1450. pVeh->m_pPilot = NULL;
  1451. memset( &pVeh->m_ucmd, 0, sizeof( usercmd_t ) );
  1452. pVeh->m_iDieTime = 0;
  1453. pVeh->m_EjectDir = VEH_EJECT_LEFT;
  1454. //pVeh->m_iDriverTag = -1;
  1455. //pVeh->m_iLeftExhaustTag = -1;
  1456. //pVeh->m_iRightExhaustTag = -1;
  1457. //pVeh->m_iGun1Tag = -1;
  1458. //pVeh->m_iGun1Bone = -1;
  1459. //pVeh->m_iLeftWingBone = -1;
  1460. //pVeh->m_iRightWingBone = -1;
  1461. memset( pVeh->m_iExhaustTag, -1, sizeof( int ) * MAX_VEHICLE_EXHAUSTS );
  1462. memset( pVeh->m_iMuzzleTag, -1, sizeof( int ) * MAX_VEHICLE_MUZZLES );
  1463. // FIXME! Use external values read from the vehicle data file!
  1464. #ifndef _JK2MP //blargh, fixme
  1465. memset( pVeh->m_Muzzles, 0, sizeof( Muzzle ) * MAX_VEHICLE_MUZZLES );
  1466. #endif
  1467. pVeh->m_iDroidUnitTag = -1;
  1468. //initialize to blaster, just since it's a basic weapon and there's no lightsaber crap...?
  1469. parent->client->ps.weapon = WP_BLASTER;
  1470. parent->client->ps.weaponstate = WEAPON_READY;
  1471. parent->client->ps.stats[STAT_WEAPONS] |= (1<<WP_BLASTER);
  1472. //Initialize to landed (wings closed, gears down) animation
  1473. {
  1474. int iFlags = SETANIM_FLAG_NORMAL, iBlend = 300;
  1475. #ifdef _JK2MP
  1476. pVeh->m_ulFlags |= VEH_GEARSOPEN;
  1477. BG_SetAnim(pVeh->m_pParentEntity->playerState,
  1478. bgAllAnims[pVeh->m_pParentEntity->localAnimIndex].anims,
  1479. SETANIM_BOTH, BOTH_VS_IDLE, iFlags, iBlend);
  1480. #else
  1481. NPC_SetAnim( pVeh->m_pParentEntity, SETANIM_BOTH, BOTH_VS_IDLE, iFlags, iBlend );
  1482. #endif
  1483. }
  1484. return true;
  1485. }
  1486. // Like a think or move command, this updates various vehicle properties.
  1487. #ifdef _JK2MP
  1488. void G_VehicleDamageBoxSizing(Vehicle_t *pVeh); //declared below
  1489. #endif
  1490. static bool Update( Vehicle_t *pVeh, const usercmd_t *pUmcd )
  1491. {
  1492. gentity_t *parent = (gentity_t *)pVeh->m_pParentEntity;
  1493. gentity_t *pilotEnt;
  1494. //static float fMod = 1000.0f / 60.0f;
  1495. vec3_t vVehAngles;
  1496. int i;
  1497. int prevSpeed;
  1498. int nextSpeed;
  1499. int curTime;
  1500. int halfMaxSpeed;
  1501. playerState_t *parentPS;
  1502. qboolean linkHeld = qfalse;
  1503. #ifdef _JK2MP
  1504. parentPS = pVeh->m_pParentEntity->playerState;
  1505. #else
  1506. parentPS = &pVeh->m_pParentEntity->client->ps;
  1507. #endif
  1508. #ifndef _JK2MP//SP
  1509. curTime = level.time;
  1510. #elif QAGAME//MP GAME
  1511. curTime = level.time;
  1512. #elif CGAME//MP CGAME
  1513. //FIXME: pass in ucmd? Not sure if this is reliable...
  1514. curTime = pm->cmd.serverTime;
  1515. #endif
  1516. //increment the ammo for all rechargeable weapons
  1517. for ( i = 0; i < MAX_VEHICLE_WEAPONS; i++ )
  1518. {
  1519. if ( pVeh->m_pVehicleInfo->weapon[i].ID > VEH_WEAPON_BASE//have a weapon in this slot
  1520. && pVeh->m_pVehicleInfo->weapon[i].ammoRechargeMS//its ammo is rechargable
  1521. && pVeh->weaponStatus[i].ammo < pVeh->m_pVehicleInfo->weapon[i].ammoMax//its ammo is below max
  1522. && pUmcd->serverTime-pVeh->weaponStatus[i].lastAmmoInc >= pVeh->m_pVehicleInfo->weapon[i].ammoRechargeMS )//enough time has passed
  1523. {//add 1 to the ammo
  1524. pVeh->weaponStatus[i].lastAmmoInc = pUmcd->serverTime;
  1525. pVeh->weaponStatus[i].ammo++;
  1526. //NOTE: in order to send the vehicle's ammo info to the client, we copy the ammo into the first 2 ammo slots on the vehicle NPC's client->ps.ammo array
  1527. if ( parent && parent->client )
  1528. {
  1529. parent->client->ps.ammo[i] = pVeh->weaponStatus[i].ammo;
  1530. }
  1531. }
  1532. }
  1533. for ( i = 0; i < MAX_VEHICLE_TURRETS; i++ )
  1534. {
  1535. if ( pVeh->m_pVehicleInfo->turret[i].iWeapon > VEH_WEAPON_BASE//have a weapon in this slot
  1536. && pVeh->m_pVehicleInfo->turret[i].iAmmoRechargeMS//its ammo is rechargable
  1537. && pVeh->turretStatus[i].ammo < pVeh->m_pVehicleInfo->turret[i].iAmmoMax//its ammo is below max
  1538. && pUmcd->serverTime-pVeh->turretStatus[i].lastAmmoInc >= pVeh->m_pVehicleInfo->turret[i].iAmmoRechargeMS )//enough time has passed
  1539. {//add 1 to the ammo
  1540. pVeh->turretStatus[i].lastAmmoInc = pUmcd->serverTime;
  1541. pVeh->turretStatus[i].ammo++;
  1542. //NOTE: in order to send the vehicle's ammo info to the client, we copy the ammo into the first 2 ammo slots on the vehicle NPC's client->ps.ammo array
  1543. if ( parent && parent->client )
  1544. {
  1545. parent->client->ps.ammo[MAX_VEHICLE_WEAPONS+i] = pVeh->turretStatus[i].ammo;
  1546. }
  1547. }
  1548. }
  1549. //increment shields for rechargable shields
  1550. if ( pVeh->m_pVehicleInfo->shieldRechargeMS
  1551. && parentPS->stats[STAT_ARMOR] > 0 //still have some shields left
  1552. && parentPS->stats[STAT_ARMOR] < pVeh->m_pVehicleInfo->shields//its below max
  1553. && pUmcd->serverTime-pVeh->lastShieldInc >= pVeh->m_pVehicleInfo->shieldRechargeMS )//enough time has passed
  1554. {
  1555. parentPS->stats[STAT_ARMOR]++;
  1556. if ( parentPS->stats[STAT_ARMOR] > pVeh->m_pVehicleInfo->shields )
  1557. {
  1558. parentPS->stats[STAT_ARMOR] = pVeh->m_pVehicleInfo->shields;
  1559. }
  1560. pVeh->m_iShields = parentPS->stats[STAT_ARMOR];
  1561. #ifdef _JK2MP
  1562. G_VehUpdateShields( parent );
  1563. #endif
  1564. }
  1565. #ifdef _JK2MP //sometimes this gets out of whack, probably init'ing
  1566. if (parent && parent->r.ownerNum != parent->s.owner)
  1567. {
  1568. parent->s.owner = parent->r.ownerNum;
  1569. }
  1570. //keep the PS value in sync. set it up here in case we return below at some point.
  1571. if (pVeh->m_iBoarding)
  1572. {
  1573. parent->client->ps.vehBoarding = qtrue;
  1574. }
  1575. else
  1576. {
  1577. parent->client->ps.vehBoarding = qfalse;
  1578. }
  1579. #endif
  1580. // See whether this vehicle should be dieing or dead.
  1581. if ( pVeh->m_iDieTime != 0
  1582. #ifndef _JK2MP //sometimes this gets out of whack, probably init'ing
  1583. || (parent->health <= 0)
  1584. #endif
  1585. )
  1586. {//NOTE!!!: This HAS to be consistent with cgame!!!
  1587. // Keep track of the old orientation.
  1588. VectorCopy( pVeh->m_vOrientation, pVeh->m_vPrevOrientation );
  1589. // Process the orient commands.
  1590. pVeh->m_pVehicleInfo->ProcessOrientCommands( pVeh );
  1591. // Need to copy orientation to our entity's viewangles so that it renders at the proper angle and currentAngles is correct.
  1592. SetClientViewAngle( parent, pVeh->m_vOrientation );
  1593. if ( pVeh->m_pPilot )
  1594. {
  1595. SetClientViewAngle( (gentity_t *)pVeh->m_pPilot, pVeh->m_vOrientation );
  1596. }
  1597. /*
  1598. for ( i = 0; i < pVeh->m_pVehicleInfo->maxPassengers; i++ )
  1599. {
  1600. if ( pVeh->m_ppPassengers[i] )
  1601. {
  1602. SetClientViewAngle( (gentity_t *)pVeh->m_ppPassengers[i], pVeh->m_vOrientation );
  1603. }
  1604. }
  1605. */
  1606. // Process the move commands.
  1607. pVeh->m_pVehicleInfo->ProcessMoveCommands( pVeh );
  1608. // Setup the move direction.
  1609. if ( pVeh->m_pVehicleInfo->type == VH_FIGHTER )
  1610. {
  1611. AngleVectors( pVeh->m_vOrientation, parent->client->ps.moveDir, NULL, NULL );
  1612. }
  1613. else
  1614. {
  1615. VectorSet(vVehAngles, 0, pVeh->m_vOrientation[YAW], 0);
  1616. AngleVectors( vVehAngles, parent->client->ps.moveDir, NULL, NULL );
  1617. }
  1618. pVeh->m_pVehicleInfo->DeathUpdate( pVeh );
  1619. return false;
  1620. }
  1621. // Vehicle dead!
  1622. #ifdef _JK2MP
  1623. else if ( parent->health <= 0 )
  1624. {
  1625. // Instant kill.
  1626. if (pVeh->m_pVehicleInfo->type == VH_FIGHTER &&
  1627. pVeh->m_iLastImpactDmg > 500)
  1628. { //explode instantly in inferno-y death
  1629. pVeh->m_pVehicleInfo->StartDeathDelay( pVeh, -1/* -1 causes instant death */);
  1630. }
  1631. else
  1632. {
  1633. pVeh->m_pVehicleInfo->StartDeathDelay( pVeh, 0 );
  1634. }
  1635. pVeh->m_pVehicleInfo->DeathUpdate( pVeh );
  1636. return false;
  1637. }
  1638. #endif
  1639. #ifdef _JK2MP //special check in case someone disconnects/dies while boarding
  1640. #ifdef QAGAME
  1641. if (parent->spawnflags & 1)
  1642. {
  1643. if (pVeh->m_pPilot || !pVeh->m_bHasHadPilot)
  1644. {
  1645. if (pVeh->m_pPilot && !pVeh->m_bHasHadPilot)
  1646. {
  1647. pVeh->m_bHasHadPilot = qtrue;
  1648. pVeh->m_iPilotLastIndex = pVeh->m_pPilot->s.number;
  1649. }
  1650. pVeh->m_iPilotTime = level.time + parent->damage;
  1651. }
  1652. else if (pVeh->m_iPilotTime)
  1653. { //die
  1654. gentity_t *oldPilot = &g_entities[pVeh->m_iPilotLastIndex];
  1655. if (!oldPilot->inuse || !oldPilot->client ||
  1656. oldPilot->client->pers.connected != CON_CONNECTED)
  1657. { //no longer in the game?
  1658. G_Damage(parent, parent, parent, NULL, parent->client->ps.origin, 99999, DAMAGE_NO_PROTECTION, MOD_SUICIDE);
  1659. }
  1660. else
  1661. {
  1662. vec3_t v;
  1663. VectorSubtract(parent->client->ps.origin, oldPilot->client->ps.origin, v);
  1664. if (VectorLength(v) < parent->speed)
  1665. { //they are still within the minimum distance to their vehicle
  1666. pVeh->m_iPilotTime = level.time + parent->damage;
  1667. }
  1668. else if (pVeh->m_iPilotTime < level.time)
  1669. { //dying time
  1670. G_Damage(parent, parent, parent, NULL, parent->client->ps.origin, 99999, DAMAGE_NO_PROTECTION, MOD_SUICIDE);
  1671. }
  1672. }
  1673. }
  1674. }
  1675. #endif
  1676. #else
  1677. if (parent->spawnflags & 1)
  1678. {//NOTE: in SP, this actually just checks LOS to the Player
  1679. if (pVeh->m_iPilotTime < level.time)
  1680. {//do another check?
  1681. if ( !player || G_ClearLineOfSight(pVeh->m_pParentEntity->currentOrigin, player->currentOrigin, pVeh->m_pParentEntity->s.number, MASK_OPAQUE ) )
  1682. {
  1683. pVeh->m_iPilotTime = level.time + pVeh->m_pParentEntity->endFrame;
  1684. }
  1685. }
  1686. if (pVeh->m_iPilotTime && pVeh->m_iPilotTime < level.time)
  1687. { //die
  1688. //FIXME: does this give proper credit to the enemy who shot you down?
  1689. G_Damage(parent, player, player, NULL, parent->client->ps.origin, 99999, DAMAGE_NO_PROTECTION, MOD_SUICIDE);
  1690. }
  1691. }
  1692. #endif
  1693. #ifndef _JK2MP
  1694. // if (level.time<pVeh->m_iTurboTime || pVeh->m_pVehicleInfo->type==VH_ANIMAL)
  1695. // always knock guys around now...
  1696. {
  1697. vec3_t dir;
  1698. vec3_t projectedPosition;
  1699. VectorCopy(parent->client->ps.velocity, dir);
  1700. VectorMA(parent->currentOrigin, 0.1f, dir, projectedPosition);
  1701. float force = VectorNormalize(dir);
  1702. force /= 10.0f;
  1703. if (force>30.0f)
  1704. {
  1705. trace_t tr;
  1706. G_VehicleTrace(&tr, parent->currentOrigin, parent->mins, parent->maxs, projectedPosition, parent->s.number, CONTENTS_BODY);
  1707. if (tr.fraction<1.0f &&
  1708. !tr.allsolid &&
  1709. !tr.startsolid &&
  1710. tr.entityNum!=ENTITYNUM_NONE &&
  1711. tr.entityNum!=ENTITYNUM_WORLD &&
  1712. (level.time<pVeh->m_iTurboTime || Q_irand(0,3)==0))
  1713. {
  1714. gentity_t* other = &g_entities[tr.entityNum];
  1715. if (other && other->client && !other->s.m_iVehicleNum)
  1716. {
  1717. G_Throw( other, dir, force/10.0f );
  1718. G_Knockdown( other, parent, dir, force, qtrue );
  1719. G_Damage( other, player, player, parent->client->ps.velocity, parent->currentOrigin, force, DAMAGE_NO_ARMOR|DAMAGE_EXTRA_KNOCKBACK, MOD_IMPACT);
  1720. }
  1721. }
  1722. }
  1723. }
  1724. #endif
  1725. #ifdef _JK2MP //special check in case someone disconnects/dies while boarding
  1726. if (pVeh->m_iBoarding != 0)
  1727. {
  1728. pilotEnt = (gentity_t *)pVeh->m_pPilot;
  1729. if (pilotEnt)
  1730. {
  1731. if (!pilotEnt->inuse || !pilotEnt->client || pilotEnt->health <= 0 ||
  1732. pilotEnt->client->pers.connected != CON_CONNECTED)
  1733. {
  1734. pVeh->m_pVehicleInfo->Eject( pVeh, pVeh->m_pPilot, qtrue );
  1735. return false;
  1736. }
  1737. }
  1738. }
  1739. #endif
  1740. // If we're not done mounting, can't do anything.
  1741. if ( pVeh->m_iBoarding != 0 )
  1742. {
  1743. if (!pVeh->m_bWasBoarding)
  1744. {
  1745. VectorCopy(parentPS->velocity, pVeh->m_vBoardingVelocity);
  1746. pVeh->m_bWasBoarding = true;
  1747. }
  1748. // See if we're done boarding.
  1749. if ( pVeh->m_iBoarding > -1 && pVeh->m_iBoarding <= level.time )
  1750. {
  1751. pVeh->m_bWasBoarding = false;
  1752. pVeh->m_iBoarding = 0;
  1753. }
  1754. else
  1755. {
  1756. #ifdef _JK2MP
  1757. goto maintainSelfDuringBoarding;
  1758. #else
  1759. return false;
  1760. #endif
  1761. }
  1762. }
  1763. parent = (gentity_t *)pVeh->m_pParentEntity;
  1764. // Validate vehicle.
  1765. if ( !parent || !parent->client || parent->health <= 0 )
  1766. return false;
  1767. // See if any of the riders are dead and if so kick em off.
  1768. if ( pVeh->m_pPilot )
  1769. {
  1770. pilotEnt = (gentity_t *)pVeh->m_pPilot;
  1771. #ifdef _JK2MP
  1772. if (!pilotEnt->inuse || !pilotEnt->client || pilotEnt->health <= 0 ||
  1773. pilotEnt->client->pers.connected != CON_CONNECTED)
  1774. #else
  1775. if (pilotEnt->health <= 0)
  1776. #endif
  1777. {
  1778. pVeh->m_pVehicleInfo->Eject( pVeh, pVeh->m_pPilot, qtrue );
  1779. }
  1780. }
  1781. #ifdef _JK2MP
  1782. // Copy over the commands for local storage.
  1783. memcpy( &parent->client->pers.cmd, &pVeh->m_ucmd, sizeof( usercmd_t ) );
  1784. pVeh->m_ucmd.buttons &= ~(BUTTON_TALK);//|BUTTON_GESTURE); //don't want some of these buttons
  1785. #else
  1786. // Copy over the commands for local storage.
  1787. memcpy( &pVeh->m_ucmd, pUmcd, sizeof( usercmd_t ) );
  1788. memcpy( &parent->client->pers.lastCommand, pUmcd, sizeof( usercmd_t ) );
  1789. #endif
  1790. /*
  1791. // Update time modifier.
  1792. pVeh->m_fTimeModifier = pVeh->m_ucmd.serverTime - parent->client->ps.commandTime;
  1793. //sanity check
  1794. if ( pVeh->m_fTimeModifier < 1 )
  1795. {
  1796. pVeh->m_fTimeModifier = 1;
  1797. }
  1798. else if ( pVeh->m_fTimeModifier > 200 )
  1799. {
  1800. pVeh->m_fTimeModifier = 200;
  1801. }
  1802. //normalize to 1.0f at 20fps
  1803. pVeh->m_fTimeModifier = pVeh->m_fTimeModifier / fMod;
  1804. */
  1805. //check for weapon linking/unlinking command
  1806. for ( i = 0; i < MAX_VEHICLE_WEAPONS; i++ )
  1807. {//HMM... can't get a seperate command for each weapon, so do them all...?
  1808. if ( pVeh->m_pVehicleInfo->weapon[i].linkable == 2 )
  1809. {//always linked
  1810. //FIXME: just set this once, on Initialize...?
  1811. if ( !pVeh->weaponStatus[i].linked )
  1812. {
  1813. pVeh->weaponStatus[i].linked = qtrue;
  1814. }
  1815. }
  1816. #ifdef _JK2MP
  1817. else if ( (pVeh->m_ucmd.buttons&BUTTON_USE_HOLDABLE) )
  1818. #else
  1819. //FIXME: implement... just a console command bound to a key?
  1820. else if ( 0 )
  1821. #endif
  1822. {//pilot pressed the "weapon link" toggle button
  1823. playerState_t *pilotPS;
  1824. #ifdef _JK2MP
  1825. bgEntity_t *rider = NULL;
  1826. if (parent->s.owner != ENTITYNUM_NONE)
  1827. {
  1828. rider = PM_BGEntForNum(parent->s.owner); //&g_entities[parent->r.ownerNum];
  1829. }
  1830. pilotPS = rider->playerState;
  1831. #else
  1832. gentity_t *rider = parent->owner;
  1833. pilotPS = &rider->client->ps;
  1834. #endif
  1835. if ( !pVeh->linkWeaponToggleHeld )//so we don't hold it down and toggle it back and forth
  1836. {//okay to toggle
  1837. if ( pVeh->m_pVehicleInfo->weapon[i].linkable == 1 )
  1838. {//link-toggleable
  1839. pVeh->weaponStatus[i].linked = !pVeh->weaponStatus[i].linked;
  1840. }
  1841. }
  1842. linkHeld = qtrue;
  1843. }
  1844. }
  1845. if ( linkHeld )
  1846. {
  1847. //so we don't hold it down and toggle it back and forth
  1848. pVeh->linkWeaponToggleHeld = qtrue;
  1849. }
  1850. else
  1851. {
  1852. //so we don't hold it down and toggle it back and forth
  1853. pVeh->linkWeaponToggleHeld = qfalse;
  1854. }
  1855. #ifdef _JK2MP
  1856. //now pass it over the network so cgame knows about it
  1857. //NOTE: SP can just cheat and check directly
  1858. parentPS->vehWeaponsLinked = qfalse;
  1859. for ( i = 0; i < MAX_VEHICLE_WEAPONS; i++ )
  1860. {//HMM... can't get a seperate command for each weapon, so do them all...?
  1861. if ( pVeh->weaponStatus[i].linked )
  1862. {
  1863. parentPS->vehWeaponsLinked = qtrue;
  1864. }
  1865. }
  1866. #endif
  1867. #ifdef QAGAME
  1868. for ( i = 0; i < MAX_VEHICLE_TURRETS; i++ )
  1869. {//HMM... can't get a seperate command for each weapon, so do them all...?
  1870. VEH_TurretThink( pVeh, parent, i );
  1871. }
  1872. #endif
  1873. #ifdef _JK2MP
  1874. maintainSelfDuringBoarding:
  1875. if (pVeh->m_pPilot && pVeh->m_pPilot->playerState && pVeh->m_iBoarding != 0)
  1876. {
  1877. VectorCopy(pVeh->m_vOrientation, pVeh->m_pPilot->playerState->viewangles);
  1878. pVeh->m_ucmd.buttons = 0;
  1879. pVeh->m_ucmd.forwardmove = 0;
  1880. pVeh->m_ucmd.rightmove = 0;
  1881. pVeh->m_ucmd.upmove = 0;
  1882. }
  1883. #endif
  1884. // Keep track of the old orientation.
  1885. VectorCopy( pVeh->m_vOrientation, pVeh->m_vPrevOrientation );
  1886. // Process the orient commands.
  1887. pVeh->m_pVehicleInfo->ProcessOrientCommands( pVeh );
  1888. // Need to copy orientation to our entity's viewangles so that it renders at the proper angle and currentAngles is correct.
  1889. SetClientViewAngle( parent, pVeh->m_vOrientation );
  1890. if ( pVeh->m_pPilot )
  1891. {
  1892. #ifdef _JK2MP
  1893. if ( !BG_UnrestrainedPitchRoll( pVeh->m_pPilot->playerState, pVeh ) )
  1894. {
  1895. vec3_t newVAngle;
  1896. newVAngle[PITCH] = pVeh->m_pPilot->playerState->viewangles[PITCH];
  1897. newVAngle[YAW] = pVeh->m_pPilot->playerState->viewangles[YAW];
  1898. newVAngle[ROLL] = pVeh->m_vOrientation[ROLL];
  1899. SetClientViewAngle( (gentity_t *)pVeh->m_pPilot, newVAngle );
  1900. }
  1901. #else
  1902. if ( !BG_UnrestrainedPitchRoll( &pVeh->m_pPilot->client->ps, pVeh ) )
  1903. {
  1904. SetClientViewAngle( (gentity_t *)pVeh->m_pPilot, pVeh->m_vOrientation );
  1905. }
  1906. #endif
  1907. }
  1908. /*
  1909. for ( i = 0; i < pVeh->m_pVehicleInfo->maxPassengers; i++ )
  1910. {
  1911. if ( pVeh->m_ppPassengers[i] )
  1912. {
  1913. SetClientViewAngle( (gentity_t *)pVeh->m_ppPassengers[i], pVeh->m_vOrientation );
  1914. }
  1915. }
  1916. */
  1917. // Process the move commands.
  1918. prevSpeed = parentPS->speed;
  1919. pVeh->m_pVehicleInfo->ProcessMoveCommands( pVeh );
  1920. nextSpeed = parentPS->speed;
  1921. halfMaxSpeed = pVeh->m_pVehicleInfo->speedMax*0.5f;
  1922. // Shifting Sounds
  1923. //=====================================================================
  1924. if (pVeh->m_iTurboTime<curTime &&
  1925. pVeh->m_iSoundDebounceTimer<curTime &&
  1926. ((nextSpeed>prevSpeed && nextSpeed>halfMaxSpeed && prevSpeed<halfMaxSpeed) || (nextSpeed>halfMaxSpeed && !Q_irand(0,1000)))
  1927. )
  1928. {
  1929. int shiftSound = Q_irand(1,4);
  1930. switch (shiftSound)
  1931. {
  1932. case 1: shiftSound=pVeh->m_pVehicleInfo->soundShift1; break;
  1933. case 2: shiftSound=pVeh->m_pVehicleInfo->soundShift2; break;
  1934. case 3: shiftSound=pVeh->m_pVehicleInfo->soundShift3; break;
  1935. case 4: shiftSound=pVeh->m_pVehicleInfo->soundShift4; break;
  1936. }
  1937. if (shiftSound)
  1938. {
  1939. pVeh->m_iSoundDebounceTimer = curTime + Q_irand(1000, 4000);
  1940. #ifdef _JK2MP
  1941. // TODO: MP Shift Sound Playback
  1942. #else
  1943. // NOTE: Use this type so it's spatialized and updates play origin as bike moves - MCG
  1944. G_SoundIndexOnEnt( pVeh->m_pParentEntity, CHAN_AUTO, shiftSound);
  1945. #endif
  1946. }
  1947. }
  1948. //=====================================================================
  1949. // Setup the move direction.
  1950. if ( pVeh->m_pVehicleInfo->type == VH_FIGHTER )
  1951. {
  1952. AngleVectors( pVeh->m_vOrientation, parent->client->ps.moveDir, NULL, NULL );
  1953. }
  1954. else
  1955. {
  1956. VectorSet(vVehAngles, 0, pVeh->m_vOrientation[YAW], 0);
  1957. AngleVectors( vVehAngles, parent->client->ps.moveDir, NULL, NULL );
  1958. }
  1959. #ifdef _JK2MP
  1960. if (pVeh->m_pVehicleInfo->surfDestruction)
  1961. {
  1962. if (pVeh->m_iRemovedSurfaces)
  1963. {
  1964. gentity_t *killer = parent;
  1965. G_VehicleDamageBoxSizing(pVeh);
  1966. //damage him constantly if any chunks are currently taken off
  1967. if (parent->client->ps.otherKiller < ENTITYNUM_WORLD &&
  1968. parent->client->ps.otherKillerTime > level.time)
  1969. {
  1970. gentity_t *potentialKiller = &g_entities[parent->client->ps.otherKiller];
  1971. if (potentialKiller->inuse && potentialKiller->client)
  1972. { //he's valid I guess
  1973. killer = potentialKiller;
  1974. }
  1975. }
  1976. //FIXME: aside from bypassing shields, maybe set m_iShields to 0, too... ?
  1977. G_Damage(parent, killer, killer, NULL, parent->client->ps.origin, Q_irand(2, 5), DAMAGE_NO_PROTECTION|DAMAGE_NO_ARMOR, MOD_SUICIDE);
  1978. }
  1979. //make sure playerstate value stays in sync
  1980. parent->client->ps.vehSurfaces = pVeh->m_iRemovedSurfaces;
  1981. }
  1982. #endif
  1983. #ifdef _JK2MP
  1984. //keep the PS value in sync
  1985. if (pVeh->m_iBoarding)
  1986. {
  1987. parent->client->ps.vehBoarding = qtrue;
  1988. }
  1989. else
  1990. {
  1991. parent->client->ps.vehBoarding = qfalse;
  1992. }
  1993. #endif
  1994. #ifndef _JK2MP
  1995. // Make sure the vehicle takes on the enemy of it's rider (for homing missles for instance).
  1996. if ( pVeh->m_pPilot )
  1997. {
  1998. parent->enemy = pVeh->m_pPilot->enemy;
  1999. }
  2000. #endif
  2001. return true;
  2002. }
  2003. // Update the properties of a Rider (that may reflect what happens to the vehicle).
  2004. static bool UpdateRider( Vehicle_t *pVeh, bgEntity_t *pRider, usercmd_t *pUmcd )
  2005. {
  2006. gentity_t *parent;
  2007. gentity_t *rider;
  2008. if ( pVeh->m_iBoarding != 0 && pVeh->m_iDieTime==0)
  2009. return true;
  2010. parent = (gentity_t *)pVeh->m_pParentEntity;
  2011. rider = (gentity_t *)pRider;
  2012. #ifdef _JK2MP
  2013. //MG FIXME !! Single player needs update!
  2014. if ( rider && rider->client
  2015. && parent && parent->client )
  2016. {//so they know who we're locking onto with our rockets, if anyone
  2017. rider->client->ps.rocketLockIndex = parent->client->ps.rocketLockIndex;
  2018. rider->client->ps.rocketLockTime = parent->client->ps.rocketLockTime;
  2019. rider->client->ps.rocketTargetTime = parent->client->ps.rocketTargetTime;
  2020. }
  2021. #endif
  2022. // Regular exit.
  2023. if ( pUmcd->buttons & BUTTON_USE && pVeh->m_pVehicleInfo->type!=VH_SPEEDER)
  2024. {
  2025. if ( pVeh->m_pVehicleInfo->type == VH_WALKER )
  2026. {//just get the fuck out
  2027. pVeh->m_EjectDir = VEH_EJECT_REAR;
  2028. if ( pVeh->m_pVehicleInfo->Eject( pVeh, pRider, qfalse ) )
  2029. return false;
  2030. }
  2031. else if ( !(pVeh->m_ulFlags & VEH_FLYING))
  2032. {
  2033. // If going too fast, roll off.
  2034. if ((parent->client->ps.speed<=600) && pUmcd->rightmove!=0)
  2035. {
  2036. if ( pVeh->m_pVehicleInfo->Eject( pVeh, pRider, qfalse ) )
  2037. {
  2038. animNumber_t Anim;
  2039. int iFlags = SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD | SETANIM_FLAG_HOLDLESS, iBlend = 300;
  2040. if ( pUmcd->rightmove > 0 )
  2041. {
  2042. Anim = BOTH_ROLL_R;
  2043. pVeh->m_EjectDir = VEH_EJECT_RIGHT;
  2044. }
  2045. else
  2046. {
  2047. Anim = BOTH_ROLL_L;
  2048. pVeh->m_EjectDir = VEH_EJECT_LEFT;
  2049. }
  2050. VectorScale( parent->client->ps.velocity, 0.25f, rider->client->ps.velocity );
  2051. #if 1
  2052. Vehicle_SetAnim( rider, SETANIM_BOTH, Anim, iFlags, iBlend );
  2053. #else
  2054. #endif
  2055. //PM_SetAnim(pm,SETANIM_BOTH,anim,SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD|SETANIM_FLAG_HOLDLESS);
  2056. rider->client->ps.weaponTime = rider->client->ps.torsoAnimTimer - 200;//just to make sure it's cleared when roll is done
  2057. G_AddEvent( rider, EV_ROLL, 0 );
  2058. return false;
  2059. }
  2060. }
  2061. else
  2062. {
  2063. // FIXME: Check trace to see if we should start playing the animation.
  2064. animNumber_t Anim;
  2065. int iFlags = SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD, iBlend = 500;
  2066. if ( pUmcd->rightmove > 0 )
  2067. {
  2068. Anim = BOTH_VS_DISMOUNT_R;
  2069. pVeh->m_EjectDir = VEH_EJECT_RIGHT;
  2070. }
  2071. else
  2072. {
  2073. Anim = BOTH_VS_DISMOUNT_L;
  2074. pVeh->m_EjectDir = VEH_EJECT_LEFT;
  2075. }
  2076. if ( pVeh->m_iBoarding <= 1 )
  2077. {
  2078. int iAnimLen;
  2079. // NOTE: I know I shouldn't reuse pVeh->m_iBoarding so many times for so many different
  2080. // purposes, but it's not used anywhere else right here so why waste memory???
  2081. #ifdef _JK2MP
  2082. iAnimLen = BG_AnimLength( rider->localAnimIndex, Anim );
  2083. #else
  2084. iAnimLen = PM_AnimLength( pRider->client->clientInfo.animFileIndex, Anim );
  2085. #endif
  2086. pVeh->m_iBoarding = level.time + iAnimLen;
  2087. // Weird huh? Well I wanted to reuse flags and this should never be set in an
  2088. // entity, so what the heck.
  2089. #ifdef _JK2MP
  2090. rider->flags |= FL_VEH_BOARDING;
  2091. #else
  2092. rider->client->ps.eFlags |= EF_VEH_BOARDING;
  2093. #endif
  2094. // Make sure they can't fire when leaving.
  2095. rider->client->ps.weaponTime = iAnimLen;
  2096. }
  2097. VectorScale( parent->client->ps.velocity, 0.25f, rider->client->ps.velocity );
  2098. Vehicle_SetAnim( rider, SETANIM_BOTH, Anim, iFlags, iBlend );
  2099. }
  2100. }
  2101. // Flying, so just fall off.
  2102. else
  2103. {
  2104. pVeh->m_EjectDir = VEH_EJECT_LEFT;
  2105. if ( pVeh->m_pVehicleInfo->Eject( pVeh, pRider, qfalse ) )
  2106. return false;
  2107. }
  2108. }
  2109. // Getting off animation complete (if we had one going)?
  2110. #ifdef _JK2MP
  2111. if ( pVeh->m_iBoarding < level.time && (rider->flags & FL_VEH_BOARDING) )
  2112. {
  2113. rider->flags &= ~FL_VEH_BOARDING;
  2114. #else
  2115. if ( pVeh->m_iBoarding < level.time && (rider->client->ps.eFlags & EF_VEH_BOARDING) )
  2116. {
  2117. rider->client->ps.eFlags &= ~EF_VEH_BOARDING;
  2118. #endif
  2119. // Eject this guy now.
  2120. if ( pVeh->m_pVehicleInfo->Eject( pVeh, pRider, qfalse ) )
  2121. {
  2122. return false;
  2123. }
  2124. }
  2125. if ( pVeh->m_pVehicleInfo->type != VH_FIGHTER
  2126. && pVeh->m_pVehicleInfo->type != VH_WALKER )
  2127. {
  2128. // Jump off.
  2129. if ( pUmcd->upmove > 0 )
  2130. {
  2131. // NOT IN MULTI PLAYER!
  2132. //===================================================================
  2133. #ifndef _JK2MP
  2134. float riderRightDot = G_CanJumpToEnemyVeh(pVeh, pUmcd);
  2135. if (riderRightDot!=0.0f)
  2136. {
  2137. // Eject Player From Current Vehicle
  2138. //-----------------------------------
  2139. pVeh->m_EjectDir = VEH_EJECT_TOP;
  2140. pVeh->m_pVehicleInfo->Eject( pVeh, pRider, qtrue );
  2141. // Send Current Vehicle Spinning Out Of Control
  2142. //----------------------------------------------
  2143. pVeh->m_pVehicleInfo->StartDeathDelay(pVeh, 10000);
  2144. pVeh->m_ulFlags |= (VEH_OUTOFCONTROL);
  2145. VectorScale(pVeh->m_pParentEntity->client->ps.velocity, 1.0f, pVeh->m_pParentEntity->pos3);
  2146. // Todo: Throw Old Vehicle Away From The New Vehicle Some
  2147. //-------------------------------------------------------
  2148. vec3_t toEnemy;
  2149. VectorSubtract(pVeh->m_pParentEntity->currentOrigin, rider->enemy->currentOrigin, toEnemy);
  2150. VectorNormalize(toEnemy);
  2151. G_Throw(pVeh->m_pParentEntity, toEnemy, 50);
  2152. // Start Boarding On Enemy's Vehicle
  2153. //-----------------------------------
  2154. Vehicle_t* enemyVeh = G_IsRidingVehicle(rider->enemy);
  2155. enemyVeh->m_iBoarding = (riderRightDot>0)?(VEH_MOUNT_THROW_RIGHT):(VEH_MOUNT_THROW_LEFT);
  2156. enemyVeh->m_pVehicleInfo->Board(enemyVeh, rider);
  2157. }
  2158. // Don't Jump Off If Holding Strafe Key and Moving Fast
  2159. else if (pUmcd->rightmove && (parent->client->ps.speed>=10))
  2160. {
  2161. return true;
  2162. }
  2163. #endif
  2164. //===================================================================
  2165. if ( pVeh->m_pVehicleInfo->Eject( pVeh, pRider, qfalse ) )
  2166. {
  2167. // Allow them to force jump off.
  2168. VectorScale( parent->client->ps.velocity, 0.5f, rider->client->ps.velocity );
  2169. rider->client->ps.velocity[2] += JUMP_VELOCITY;
  2170. #ifdef _JK2MP
  2171. rider->client->ps.fd.forceJumpZStart = rider->client->ps.origin[2];
  2172. if (!trap_ICARUS_TaskIDPending(rider, TID_CHAN_VOICE))
  2173. #else
  2174. rider->client->ps.pm_flags |= ( PMF_JUMPING | PMF_JUMP_HELD );
  2175. rider->client->ps.forceJumpZStart = rider->client->ps.origin[2];
  2176. if ( !Q3_TaskIDPending( rider, TID_CHAN_VOICE ) )
  2177. #endif
  2178. {
  2179. G_AddEvent( rider, EV_JUMP, 0 );
  2180. }
  2181. #if 1
  2182. Vehicle_SetAnim( rider, SETANIM_BOTH, BOTH_JUMP1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD, 300 );
  2183. // Force first person mode when exiting the vehicle
  2184. // If you're carrying a saber, it will get reset later
  2185. extern void Cvar_SetValue(const char *var_name, float value);
  2186. Cvar_SetValue("cg_thirdPerson", 0);
  2187. #else
  2188. #endif
  2189. return false;
  2190. }
  2191. }
  2192. // Roll off.
  2193. #ifdef _JK2MP
  2194. if ( pUmcd->upmove < 0 )
  2195. {
  2196. animNumber_t Anim = BOTH_ROLL_B;
  2197. pVeh->m_EjectDir = VEH_EJECT_REAR;
  2198. if ( pUmcd->rightmove > 0 )
  2199. {
  2200. Anim = BOTH_ROLL_R;
  2201. pVeh->m_EjectDir = VEH_EJECT_RIGHT;
  2202. }
  2203. else if ( pUmcd->rightmove < 0 )
  2204. {
  2205. Anim = BOTH_ROLL_L;
  2206. pVeh->m_EjectDir = VEH_EJECT_LEFT;
  2207. }
  2208. else if ( pUmcd->forwardmove < 0 )
  2209. {
  2210. Anim = BOTH_ROLL_B;
  2211. pVeh->m_EjectDir = VEH_EJECT_REAR;
  2212. }
  2213. else if ( pUmcd->forwardmove > 0 )
  2214. {
  2215. Anim = BOTH_ROLL_F;
  2216. pVeh->m_EjectDir = VEH_EJECT_FRONT;
  2217. }
  2218. if ( pVeh->m_pVehicleInfo->Eject( pVeh, pRider, qfalse ) )
  2219. {
  2220. if ( !(pVeh->m_ulFlags & VEH_FLYING) )
  2221. {
  2222. VectorScale( parent->client->ps.velocity, 0.25f, rider->client->ps.velocity );
  2223. #if 1
  2224. Vehicle_SetAnim( rider, SETANIM_BOTH, Anim, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD | SETANIM_FLAG_HOLDLESS, 300 );
  2225. #else
  2226. #endif
  2227. //PM_SetAnim(pm,SETANIM_BOTH,anim,SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD|SETANIM_FLAG_HOLDLESS);
  2228. rider->client->ps.weaponTime = rider->client->ps.torsoAnimTimer - 200;//just to make sure it's cleared when roll is done
  2229. G_AddEvent( rider, EV_ROLL, 0 );
  2230. }
  2231. return false;
  2232. }
  2233. }
  2234. #endif
  2235. }
  2236. return true;
  2237. }
  2238. #ifdef _JK2MP //we want access to this one clientside, but it's the only
  2239. //generic vehicle function we care about over there
  2240. #include "../namespace_begin.h"
  2241. extern void AttachRidersGeneric( Vehicle_t *pVeh );
  2242. #include "../namespace_end.h"
  2243. #endif
  2244. // Attachs all the riders of this vehicle to their appropriate tag (*driver, *pass1, *pass2, whatever...).
  2245. static void AttachRiders( Vehicle_t *pVeh )
  2246. {
  2247. #ifdef _JK2MP
  2248. int i = 0;
  2249. AttachRidersGeneric(pVeh);
  2250. if (pVeh->m_pPilot)
  2251. {
  2252. gentity_t *parent = (gentity_t *)pVeh->m_pParentEntity;
  2253. gentity_t *pilot = (gentity_t *)pVeh->m_pPilot;
  2254. pilot->waypoint = parent->waypoint; // take the veh's waypoint as your own
  2255. //assuming we updated him relative to the bolt in AttachRidersGeneric
  2256. G_SetOrigin( pilot, pilot->client->ps.origin );
  2257. trap_LinkEntity( pilot );
  2258. }
  2259. if (pVeh->m_pOldPilot)
  2260. {
  2261. gentity_t *parent = (gentity_t *)pVeh->m_pParentEntity;
  2262. gentity_t *oldpilot = (gentity_t *)pVeh->m_pOldPilot;
  2263. oldpilot->waypoint = parent->waypoint; // take the veh's waypoint as your own
  2264. //assuming we updated him relative to the bolt in AttachRidersGeneric
  2265. G_SetOrigin( oldpilot, oldpilot->client->ps.origin );
  2266. trap_LinkEntity( oldpilot );
  2267. }
  2268. //attach passengers
  2269. while (i < pVeh->m_iNumPassengers)
  2270. {
  2271. if (pVeh->m_ppPassengers[i])
  2272. {
  2273. mdxaBone_t boltMatrix;
  2274. vec3_t yawOnlyAngles;
  2275. gentity_t *parent = (gentity_t *)pVeh->m_pParentEntity;
  2276. gentity_t *pilot = (gentity_t *)pVeh->m_ppPassengers[i];
  2277. int crotchBolt;
  2278. assert(parent->ghoul2);
  2279. crotchBolt = trap_G2API_AddBolt(parent->ghoul2, 0, "*driver");
  2280. assert(parent->client);
  2281. assert(pilot->client);
  2282. VectorSet(yawOnlyAngles, 0, parent->client->ps.viewangles[YAW], 0);
  2283. // Get the driver tag.
  2284. trap_G2API_GetBoltMatrix( parent->ghoul2, 0, crotchBolt, &boltMatrix,
  2285. yawOnlyAngles, parent->client->ps.origin,
  2286. level.time, NULL, parent->modelScale );
  2287. BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, pilot->client->ps.origin );
  2288. G_SetOrigin( pilot, pilot->client->ps.origin );
  2289. trap_LinkEntity( pilot );
  2290. }
  2291. i++;
  2292. }
  2293. //attach droid
  2294. if (pVeh->m_pDroidUnit
  2295. && pVeh->m_iDroidUnitTag != -1)
  2296. {
  2297. mdxaBone_t boltMatrix;
  2298. vec3_t yawOnlyAngles, fwd;
  2299. gentity_t *parent = (gentity_t *)pVeh->m_pParentEntity;
  2300. gentity_t *droid = (gentity_t *)pVeh->m_pDroidUnit;
  2301. assert(parent->ghoul2);
  2302. assert(parent->client);
  2303. //assert(droid->client);
  2304. if ( droid->client )
  2305. {
  2306. VectorSet(yawOnlyAngles, 0, parent->client->ps.viewangles[YAW], 0);
  2307. // Get the droid tag.
  2308. trap_G2API_GetBoltMatrix( parent->ghoul2, 0, pVeh->m_iDroidUnitTag, &boltMatrix,
  2309. yawOnlyAngles, parent->currentOrigin,
  2310. level.time, NULL, parent->modelScale );
  2311. BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, droid->client->ps.origin );
  2312. BG_GiveMeVectorFromMatrix( &boltMatrix, NEGATIVE_Y, fwd );
  2313. vectoangles( fwd, droid->client->ps.viewangles );
  2314. G_SetOrigin( droid, droid->client->ps.origin );
  2315. G_SetAngles( droid, droid->client->ps.viewangles);
  2316. SetClientViewAngle( droid, droid->client->ps.viewangles );
  2317. trap_LinkEntity( droid );
  2318. if ( droid->NPC )
  2319. {
  2320. NPC_SetAnim( droid, SETANIM_BOTH, BOTH_STAND2, (SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD) );
  2321. droid->client->ps.legsTimer = 500;
  2322. droid->client->ps.torsoTimer = 500;
  2323. }
  2324. }
  2325. }
  2326. #else
  2327. // If we have a pilot, attach him to the driver tag.
  2328. if ( pVeh->m_pPilot )
  2329. {
  2330. gentity_t * const parent = pVeh->m_pParentEntity;
  2331. gentity_t * const pilot = pVeh->m_pPilot;
  2332. mdxaBone_t boltMatrix;
  2333. pilot->waypoint = parent->waypoint; // take the veh's waypoint as your own
  2334. // Get the driver tag.
  2335. gi.G2API_GetBoltMatrix( parent->ghoul2, parent->playerModel, parent->crotchBolt, &boltMatrix,
  2336. pVeh->m_vOrientation, parent->currentOrigin,
  2337. (cg.time?cg.time:level.time), NULL, parent->s.modelScale );
  2338. gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, pilot->client->ps.origin );
  2339. G_SetOrigin( pilot, pilot->client->ps.origin );
  2340. gi.linkentity( pilot );
  2341. }
  2342. // If we have a pilot, attach him to the driver tag.
  2343. if ( pVeh->m_pOldPilot )
  2344. {
  2345. gentity_t * const parent = pVeh->m_pParentEntity;
  2346. gentity_t * const pilot = pVeh->m_pOldPilot;
  2347. mdxaBone_t boltMatrix;
  2348. pilot->waypoint = parent->waypoint; // take the veh's waypoint as your own
  2349. // Get the driver tag.
  2350. gi.G2API_GetBoltMatrix( parent->ghoul2, parent->playerModel, parent->crotchBolt, &boltMatrix,
  2351. pVeh->m_vOrientation, parent->currentOrigin,
  2352. (cg.time?cg.time:level.time), NULL, parent->s.modelScale );
  2353. gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, pilot->client->ps.origin );
  2354. G_SetOrigin( pilot, pilot->client->ps.origin );
  2355. gi.linkentity( pilot );
  2356. }
  2357. #endif
  2358. }
  2359. // Make someone invisible and un-collidable.
  2360. static void Ghost( Vehicle_t *pVeh, bgEntity_t *pEnt )
  2361. {
  2362. gentity_t *ent;
  2363. if ( !pEnt )
  2364. return;
  2365. ent = (gentity_t *)pEnt;
  2366. ent->s.eFlags |= EF_NODRAW;
  2367. if ( ent->client )
  2368. {
  2369. ent->client->ps.eFlags |= EF_NODRAW;
  2370. }
  2371. #ifdef _JK2MP
  2372. ent->r.contents = 0;
  2373. #else
  2374. ent->contents = 0;
  2375. #endif
  2376. }
  2377. // Make someone visible and collidable.
  2378. static void UnGhost( Vehicle_t *pVeh, bgEntity_t *pEnt )
  2379. {
  2380. gentity_t *ent;
  2381. if ( !pEnt )
  2382. return;
  2383. ent = (gentity_t *)pEnt;
  2384. ent->s.eFlags &= ~EF_NODRAW;
  2385. if ( ent->client )
  2386. {
  2387. ent->client->ps.eFlags &= ~EF_NODRAW;
  2388. }
  2389. #ifdef _JK2MP
  2390. ent->r.contents = CONTENTS_BODY;
  2391. #else
  2392. ent->contents = CONTENTS_BODY;
  2393. #endif
  2394. }
  2395. #ifdef _JK2MP
  2396. //try to resize the bounding box around a torn apart ship
  2397. void G_VehicleDamageBoxSizing(Vehicle_t *pVeh)
  2398. {
  2399. vec3_t fwd, right, up;
  2400. vec3_t nose; //maxs
  2401. vec3_t back; //mins
  2402. trace_t trace;
  2403. const float fDist = 256.0f; //estimated distance to nose from origin
  2404. const float bDist = 256.0f; //estimated distance to back from origin
  2405. const float wDist = 32.0f; //width on each side from origin
  2406. const float hDist = 32.0f; //height on each side from origin
  2407. gentity_t *parent = (gentity_t *)pVeh->m_pParentEntity;
  2408. if (!parent->ghoul2 || !parent->m_pVehicle || !parent->client)
  2409. { //shouldn't have gotten in here then
  2410. return;
  2411. }
  2412. //for now, let's only do anything if all wings are stripped off.
  2413. //this is because I want to be able to tear my wings off and fling
  2414. //myself down narrow hallways to my death. Because it's fun! -rww
  2415. if (!(pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_C) ||
  2416. !(pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_D) ||
  2417. !(pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_E) ||
  2418. !(pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_F) )
  2419. {
  2420. return;
  2421. }
  2422. //get directions based on orientation
  2423. AngleVectors(pVeh->m_vOrientation, fwd, right, up);
  2424. //get the nose and back positions (relative to 0, they're gonna be mins/maxs)
  2425. VectorMA(vec3_origin, fDist, fwd, nose);
  2426. VectorMA(vec3_origin, -bDist, fwd, back);
  2427. //move the nose and back to opposite right/left, they will end up as our relative mins and maxs
  2428. VectorMA(nose, wDist, right, nose);
  2429. VectorMA(nose, -wDist, right, back);
  2430. //use the same concept for up/down now
  2431. VectorMA(nose, hDist, up, nose);
  2432. VectorMA(nose, -hDist, up, back);
  2433. //and now, let's trace and see if our new mins/maxs are safe..
  2434. trap_Trace(&trace, parent->client->ps.origin, back, nose, parent->client->ps.origin, parent->s.number, parent->clipmask);
  2435. if (!trace.allsolid && !trace.startsolid && trace.fraction == 1.0f)
  2436. { //all clear!
  2437. VectorCopy(nose, parent->maxs);
  2438. VectorCopy(back, parent->mins);
  2439. }
  2440. else
  2441. { //oh well, DIE!
  2442. //FIXME: does this give proper credit to the enemy who shot you down?
  2443. G_Damage(parent, parent, parent, NULL, parent->client->ps.origin, 9999, DAMAGE_NO_PROTECTION, MOD_SUICIDE);
  2444. }
  2445. }
  2446. //get one of 4 possible impact locations based on the trace direction
  2447. int G_FlyVehicleImpactDir(gentity_t *veh, trace_t *trace)
  2448. {
  2449. float impactAngle;
  2450. float relativeAngle;
  2451. trace_t localTrace;
  2452. vec3_t testMins, testMaxs;
  2453. vec3_t rWing, lWing;
  2454. vec3_t fwd, right;
  2455. vec3_t fPos;
  2456. Vehicle_t *pVeh = veh->m_pVehicle;
  2457. qboolean noseClear = qfalse;
  2458. if (!trace || !pVeh || !veh->client)
  2459. {
  2460. return -1;
  2461. }
  2462. AngleVectors(veh->client->ps.viewangles, fwd, right, 0);
  2463. VectorSet(testMins, -24.0f, -24.0f, -24.0f);
  2464. VectorSet(testMaxs, 24.0f, 24.0f, 24.0f);
  2465. //do a trace to determine if the nose is clear
  2466. VectorMA(veh->client->ps.origin, 256.0f, fwd, fPos);
  2467. trap_Trace(&localTrace, veh->client->ps.origin, testMins, testMaxs, fPos, veh->s.number, veh->clipmask);
  2468. if (!localTrace.startsolid && !localTrace.allsolid && localTrace.fraction == 1.0f)
  2469. { //otherwise I guess it's not clear..
  2470. noseClear = qtrue;
  2471. }
  2472. if (noseClear)
  2473. { //if nose is clear check for tearing the wings off
  2474. //sadly, the trace endpos given always matches the vehicle origin, so we
  2475. //can't get a real impact direction. First we'll trace forward and see if the wings are colliding
  2476. //with anything, and if not, we'll fall back to checking the trace plane normal.
  2477. VectorMA(veh->client->ps.origin, 128.0f, right, rWing);
  2478. VectorMA(veh->client->ps.origin, -128.0f, right, lWing);
  2479. //test the right wing - unless it's already removed
  2480. if (!(pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_E) ||
  2481. !(pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_F))
  2482. {
  2483. VectorMA(rWing, 256.0f, fwd, fPos);
  2484. trap_Trace(&localTrace, rWing, testMins, testMaxs, fPos, veh->s.number, veh->clipmask);
  2485. if (localTrace.startsolid || localTrace.allsolid || localTrace.fraction != 1.0f)
  2486. { //impact
  2487. return SHIPSURF_RIGHT;
  2488. }
  2489. }
  2490. //test the left wing - unless it's already removed
  2491. if (!(pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_C) ||
  2492. !(pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_D))
  2493. {
  2494. VectorMA(lWing, 256.0f, fwd, fPos);
  2495. trap_Trace(&localTrace, lWing, testMins, testMaxs, fPos, veh->s.number, veh->clipmask);
  2496. if (localTrace.startsolid || localTrace.allsolid || localTrace.fraction != 1.0f)
  2497. { //impact
  2498. return SHIPSURF_LEFT;
  2499. }
  2500. }
  2501. }
  2502. //try to use the trace plane normal
  2503. impactAngle = vectoyaw(trace->plane.normal);
  2504. relativeAngle = AngleSubtract(impactAngle, veh->client->ps.viewangles[YAW]);
  2505. if (relativeAngle > 130 ||
  2506. relativeAngle < -130)
  2507. { //consider this front
  2508. return SHIPSURF_FRONT;
  2509. }
  2510. else if (relativeAngle > 0)
  2511. {
  2512. return SHIPSURF_RIGHT;
  2513. }
  2514. else if (relativeAngle < 0)
  2515. {
  2516. return SHIPSURF_LEFT;
  2517. }
  2518. return SHIPSURF_BACK;
  2519. }
  2520. //try to break surfaces off the ship on impact
  2521. #define TURN_ON 0x00000000
  2522. #define TURN_OFF 0x00000100
  2523. extern void NPC_SetSurfaceOnOff(gentity_t *ent, const char *surfaceName, int surfaceFlags); //NPC_utils.c
  2524. int G_ShipSurfaceForSurfName( const char *surfaceName )
  2525. {
  2526. if ( !surfaceName )
  2527. {
  2528. return -1;
  2529. }
  2530. if ( !Q_strncmp( "nose", surfaceName, 4 )
  2531. || !Q_strncmp( "f_gear", surfaceName, 6 )
  2532. || !Q_strncmp( "glass", surfaceName, 5 ) )
  2533. {
  2534. return SHIPSURF_FRONT;
  2535. }
  2536. if ( !Q_strncmp( "body", surfaceName, 4 ) )
  2537. {
  2538. return SHIPSURF_BACK;
  2539. }
  2540. if ( !Q_strncmp( "r_wing1", surfaceName, 7 )
  2541. || !Q_strncmp( "r_wing2", surfaceName, 7 )
  2542. || !Q_strncmp( "r_gear", surfaceName, 6 ) )
  2543. {
  2544. return SHIPSURF_RIGHT;
  2545. }
  2546. if ( !Q_strncmp( "l_wing1", surfaceName, 7 )
  2547. || !Q_strncmp( "l_wing2", surfaceName, 7 )
  2548. || !Q_strncmp( "l_gear", surfaceName, 6 ) )
  2549. {
  2550. return SHIPSURF_LEFT;
  2551. }
  2552. return -1;
  2553. }
  2554. void G_SetVehDamageFlags( gentity_t *veh, int shipSurf, int damageLevel )
  2555. {
  2556. int dmgFlag;
  2557. switch ( damageLevel )
  2558. {
  2559. case 3://destroyed
  2560. //add both flags so cgame side knows this surf is GONE
  2561. //add heavy
  2562. dmgFlag = SHIPSURF_DAMAGE_FRONT_HEAVY+(shipSurf-SHIPSURF_FRONT);
  2563. veh->client->ps.brokenLimbs |= (1<<dmgFlag);
  2564. //add light
  2565. dmgFlag = SHIPSURF_DAMAGE_FRONT_LIGHT+(shipSurf-SHIPSURF_FRONT);
  2566. veh->client->ps.brokenLimbs |= (1<<dmgFlag);
  2567. //copy down
  2568. veh->s.brokenLimbs = veh->client->ps.brokenLimbs;
  2569. //check droid
  2570. if ( shipSurf == SHIPSURF_BACK )
  2571. {//destroy the droid if we have one
  2572. if ( veh->m_pVehicle
  2573. && veh->m_pVehicle->m_pDroidUnit )
  2574. {//we have one
  2575. gentity_t *droidEnt = (gentity_t *)veh->m_pVehicle->m_pDroidUnit;
  2576. if ( droidEnt
  2577. && ((droidEnt->flags&FL_UNDYING) || droidEnt->health > 0) )
  2578. {//boom
  2579. //make it vulnerable
  2580. droidEnt->flags &= ~FL_UNDYING;
  2581. //blow it up
  2582. G_Damage( droidEnt, veh->enemy, veh->enemy, NULL, NULL, 99999, 0, MOD_UNKNOWN );
  2583. }
  2584. }
  2585. }
  2586. break;
  2587. case 2://heavy only
  2588. dmgFlag = SHIPSURF_DAMAGE_FRONT_HEAVY+(shipSurf-SHIPSURF_FRONT);
  2589. veh->client->ps.brokenLimbs |= (1<<dmgFlag);
  2590. //remove light
  2591. dmgFlag = SHIPSURF_DAMAGE_FRONT_LIGHT+(shipSurf-SHIPSURF_FRONT);
  2592. veh->client->ps.brokenLimbs &= ~(1<<dmgFlag);
  2593. //copy down
  2594. veh->s.brokenLimbs = veh->client->ps.brokenLimbs;
  2595. //check droid
  2596. if ( shipSurf == SHIPSURF_BACK )
  2597. {//make the droid vulnerable if we have one
  2598. if ( veh->m_pVehicle
  2599. && veh->m_pVehicle->m_pDroidUnit )
  2600. {//we have one
  2601. gentity_t *droidEnt = (gentity_t *)veh->m_pVehicle->m_pDroidUnit;
  2602. if ( droidEnt
  2603. && (droidEnt->flags&FL_UNDYING) )
  2604. {//make it vulnerab;e
  2605. droidEnt->flags &= ~FL_UNDYING;
  2606. }
  2607. }
  2608. }
  2609. break;
  2610. case 1://light only
  2611. //add light
  2612. dmgFlag = SHIPSURF_DAMAGE_FRONT_LIGHT+(shipSurf-SHIPSURF_FRONT);
  2613. veh->client->ps.brokenLimbs |= (1<<dmgFlag);
  2614. //remove heavy (shouldn't have to do this, but...
  2615. dmgFlag = SHIPSURF_DAMAGE_FRONT_HEAVY+(shipSurf-SHIPSURF_FRONT);
  2616. veh->client->ps.brokenLimbs &= ~(1<<dmgFlag);
  2617. //copy down
  2618. veh->s.brokenLimbs = veh->client->ps.brokenLimbs;
  2619. break;
  2620. case 0://no damage
  2621. default:
  2622. //remove heavy
  2623. dmgFlag = SHIPSURF_DAMAGE_FRONT_HEAVY+(shipSurf-SHIPSURF_FRONT);
  2624. veh->client->ps.brokenLimbs &= ~(1<<dmgFlag);
  2625. //remove light
  2626. dmgFlag = SHIPSURF_DAMAGE_FRONT_LIGHT+(shipSurf-SHIPSURF_FRONT);
  2627. veh->client->ps.brokenLimbs &= ~(1<<dmgFlag);
  2628. //copy down
  2629. veh->s.brokenLimbs = veh->client->ps.brokenLimbs;
  2630. break;
  2631. }
  2632. }
  2633. void G_VehicleSetDamageLocFlags( gentity_t *veh, int impactDir, int deathPoint )
  2634. {
  2635. if ( !veh->client )
  2636. {
  2637. return;
  2638. }
  2639. else
  2640. {
  2641. int deathPoint, heavyDamagePoint, lightDamagePoint;
  2642. switch(impactDir)
  2643. {
  2644. case SHIPSURF_FRONT:
  2645. deathPoint = veh->m_pVehicle->m_pVehicleInfo->health_front;
  2646. break;
  2647. case SHIPSURF_BACK:
  2648. deathPoint = veh->m_pVehicle->m_pVehicleInfo->health_back;
  2649. break;
  2650. case SHIPSURF_RIGHT:
  2651. deathPoint = veh->m_pVehicle->m_pVehicleInfo->health_right;
  2652. break;
  2653. case SHIPSURF_LEFT:
  2654. deathPoint = veh->m_pVehicle->m_pVehicleInfo->health_left;
  2655. break;
  2656. default:
  2657. return;
  2658. break;
  2659. }
  2660. if ( veh->m_pVehicle
  2661. && veh->m_pVehicle->m_pVehicleInfo
  2662. && veh->m_pVehicle->m_pVehicleInfo->malfunctionArmorLevel
  2663. && veh->m_pVehicle->m_pVehicleInfo->armor )
  2664. {
  2665. float perc = ((float)veh->m_pVehicle->m_pVehicleInfo->malfunctionArmorLevel/(float)veh->m_pVehicle->m_pVehicleInfo->armor);
  2666. if ( perc > 0.99f )
  2667. {
  2668. perc = 0.99f;
  2669. }
  2670. heavyDamagePoint = ceil( deathPoint*perc*0.25f );
  2671. lightDamagePoint = ceil( deathPoint*perc );
  2672. }
  2673. else
  2674. {
  2675. heavyDamagePoint = ceil( deathPoint*0.66f );
  2676. lightDamagePoint = ceil( deathPoint*0.14f );
  2677. }
  2678. if ( veh->locationDamage[impactDir] >= deathPoint)
  2679. {//destroyed
  2680. G_SetVehDamageFlags( veh, impactDir, 3 );
  2681. }
  2682. else if ( veh->locationDamage[impactDir] <= heavyDamagePoint )
  2683. {//heavy only
  2684. G_SetVehDamageFlags( veh, impactDir, 2 );
  2685. }
  2686. else if ( veh->locationDamage[impactDir] <= lightDamagePoint )
  2687. {//light only
  2688. G_SetVehDamageFlags( veh, impactDir, 1 );
  2689. }
  2690. }
  2691. }
  2692. qboolean G_FlyVehicleDestroySurface( gentity_t *veh, int surface )
  2693. {
  2694. char *surfName[4]; //up to 4 surfs at once
  2695. int numSurfs = 0;
  2696. int smashedBits = 0;
  2697. if (surface == -1)
  2698. { //not valid?
  2699. return qfalse;
  2700. }
  2701. switch(surface)
  2702. {
  2703. case SHIPSURF_FRONT: //break the nose off
  2704. surfName[0] = "nose";
  2705. smashedBits = (SHIPSURF_BROKEN_G);
  2706. numSurfs = 1;
  2707. break;
  2708. case SHIPSURF_BACK: //break both the bottom wings off for a backward impact I guess
  2709. surfName[0] = "r_wing2";
  2710. surfName[1] = "l_wing2";
  2711. //get rid of the landing gear
  2712. surfName[2] = "r_gear";
  2713. surfName[3] = "l_gear";
  2714. smashedBits = (SHIPSURF_BROKEN_A|SHIPSURF_BROKEN_B|SHIPSURF_BROKEN_D|SHIPSURF_BROKEN_F);
  2715. numSurfs = 4;
  2716. break;
  2717. case SHIPSURF_RIGHT: //break both right wings off
  2718. surfName[0] = "r_wing1";
  2719. surfName[1] = "r_wing2";
  2720. //get rid of the landing gear
  2721. surfName[2] = "r_gear";
  2722. smashedBits = (SHIPSURF_BROKEN_B|SHIPSURF_BROKEN_E|SHIPSURF_BROKEN_F);
  2723. numSurfs = 3;
  2724. break;
  2725. case SHIPSURF_LEFT: //break both left wings off
  2726. surfName[0] = "l_wing1";
  2727. surfName[1] = "l_wing2";
  2728. //get rid of the landing gear
  2729. surfName[2] = "l_gear";
  2730. smashedBits = (SHIPSURF_BROKEN_A|SHIPSURF_BROKEN_C|SHIPSURF_BROKEN_D);
  2731. numSurfs = 3;
  2732. break;
  2733. default:
  2734. break;
  2735. }
  2736. if (numSurfs < 1)
  2737. { //didn't get any valid surfs..
  2738. return qfalse;
  2739. }
  2740. while (numSurfs > 0)
  2741. { //use my silly system of automatically managing surf status on both client and server
  2742. numSurfs--;
  2743. NPC_SetSurfaceOnOff(veh, surfName[numSurfs], TURN_OFF);
  2744. }
  2745. if ( !veh->m_pVehicle->m_iRemovedSurfaces )
  2746. {//first time something got blown off
  2747. if ( veh->m_pVehicle->m_pPilot )
  2748. {//make the pilot scream to his death
  2749. G_EntitySound((gentity_t*)veh->m_pVehicle->m_pPilot, CHAN_VOICE, G_SoundIndex("*falling1.wav"));
  2750. }
  2751. }
  2752. //so we can check what's broken
  2753. veh->m_pVehicle->m_iRemovedSurfaces |= smashedBits;
  2754. //do some explosive damage, but don't damage this ship with it
  2755. G_RadiusDamage(veh->client->ps.origin, veh, 100, 500, veh, NULL, MOD_SUICIDE);
  2756. //when spiraling to your death, do the electical shader
  2757. veh->client->ps.electrifyTime = level.time + 10000;
  2758. return qtrue;
  2759. }
  2760. void G_FlyVehicleSurfaceDestruction(gentity_t *veh, trace_t *trace, int magnitude, qboolean force)
  2761. {
  2762. int impactDir;
  2763. int secondImpact;
  2764. int deathPoint = -1;
  2765. qboolean alreadyRebroken = qfalse;
  2766. if (!veh->ghoul2 || !veh->m_pVehicle)
  2767. { //no g2 instance.. or no vehicle instance
  2768. return;
  2769. }
  2770. impactDir = G_FlyVehicleImpactDir(veh, trace);
  2771. anotherImpact:
  2772. if (impactDir == -1)
  2773. { //not valid?
  2774. return;
  2775. }
  2776. veh->locationDamage[impactDir] += magnitude*7;
  2777. switch(impactDir)
  2778. {
  2779. case SHIPSURF_FRONT:
  2780. deathPoint = veh->m_pVehicle->m_pVehicleInfo->health_front;
  2781. break;
  2782. case SHIPSURF_BACK:
  2783. deathPoint = veh->m_pVehicle->m_pVehicleInfo->health_back;
  2784. break;
  2785. case SHIPSURF_RIGHT:
  2786. deathPoint = veh->m_pVehicle->m_pVehicleInfo->health_right;
  2787. break;
  2788. case SHIPSURF_LEFT:
  2789. deathPoint = veh->m_pVehicle->m_pVehicleInfo->health_left;
  2790. break;
  2791. default:
  2792. break;
  2793. }
  2794. if ( deathPoint != -1 )
  2795. {//got a valid health value
  2796. if ( force && veh->locationDamage[impactDir] < deathPoint )
  2797. {//force that surf to be destroyed
  2798. veh->locationDamage[impactDir] = deathPoint;
  2799. }
  2800. if ( veh->locationDamage[impactDir] >= deathPoint)
  2801. { //do it
  2802. if ( G_FlyVehicleDestroySurface( veh, impactDir ) )
  2803. {//actually took off a surface
  2804. G_VehicleSetDamageLocFlags( veh, impactDir, deathPoint );
  2805. }
  2806. }
  2807. else
  2808. {
  2809. G_VehicleSetDamageLocFlags( veh, impactDir, deathPoint );
  2810. }
  2811. }
  2812. if (!alreadyRebroken)
  2813. {
  2814. secondImpact = G_FlyVehicleImpactDir(veh, trace);
  2815. if (impactDir != secondImpact)
  2816. { //can break off another piece in this same impact.. but only break off up to 2 at once
  2817. alreadyRebroken = qtrue;
  2818. impactDir = secondImpact;
  2819. goto anotherImpact;
  2820. }
  2821. }
  2822. }
  2823. void G_VehUpdateShields( gentity_t *targ )
  2824. {
  2825. if ( !targ || !targ->client
  2826. || !targ->m_pVehicle || !targ->m_pVehicle->m_pVehicleInfo )
  2827. {
  2828. return;
  2829. }
  2830. if ( targ->m_pVehicle->m_pVehicleInfo->shields <= 0 )
  2831. {//doesn't have shields, so don't have to send it
  2832. return;
  2833. }
  2834. targ->client->ps.activeForcePass = floor(((float)targ->m_pVehicle->m_iShields/(float)targ->m_pVehicle->m_pVehicleInfo->shields)*10.0f);
  2835. }
  2836. #endif
  2837. // Set the parent entity of this Vehicle NPC.
  2838. GAME_INLINE void SetParent( Vehicle_t *pVeh, bgEntity_t *pParentEntity ) { pVeh->m_pParentEntity = pParentEntity; }
  2839. // Add a pilot to the vehicle.
  2840. GAME_INLINE void SetPilot( Vehicle_t *pVeh, bgEntity_t *pPilot ) { pVeh->m_pPilot = pPilot; }
  2841. // Add a passenger to the vehicle (false if we're full).
  2842. GAME_INLINE bool AddPassenger( Vehicle_t *pVeh ) { return false; }
  2843. // Whether this vehicle is currently inhabited (by anyone) or not.
  2844. GAME_INLINE bool Inhabited( Vehicle_t *pVeh ) { return ( pVeh->m_pPilot ) ? true : false; }
  2845. // Setup the shared functions (one's that all vehicles would generally use).
  2846. void G_SetSharedVehicleFunctions( vehicleInfo_t *pVehInfo )
  2847. {
  2848. // pVehInfo->AnimateVehicle = AnimateVehicle;
  2849. // pVehInfo->AnimateRiders = AnimateRiders;
  2850. pVehInfo->ValidateBoard = ValidateBoard;
  2851. pVehInfo->SetParent = SetParent;
  2852. pVehInfo->SetPilot = SetPilot;
  2853. pVehInfo->AddPassenger = AddPassenger;
  2854. pVehInfo->Animate = Animate;
  2855. pVehInfo->Board = Board;
  2856. pVehInfo->Eject = Eject;
  2857. pVehInfo->EjectAll = EjectAll;
  2858. pVehInfo->StartDeathDelay = StartDeathDelay;
  2859. pVehInfo->DeathUpdate = DeathUpdate;
  2860. pVehInfo->RegisterAssets = RegisterAssets;
  2861. pVehInfo->Initialize = Initialize;
  2862. pVehInfo->Update = Update;
  2863. pVehInfo->UpdateRider = UpdateRider;
  2864. // pVehInfo->ProcessMoveCommands = ProcessMoveCommands;
  2865. // pVehInfo->ProcessOrientCommands = ProcessOrientCommands;
  2866. pVehInfo->AttachRiders = AttachRiders;
  2867. pVehInfo->Ghost = Ghost;
  2868. pVehInfo->UnGhost = UnGhost;
  2869. pVehInfo->Inhabited = Inhabited;
  2870. }
  2871. #ifdef _JK2MP
  2872. //get rid of all the crazy defs we added for this file
  2873. #undef currentAngles
  2874. #undef currentOrigin
  2875. #undef mins
  2876. #undef maxs
  2877. #undef legsAnimTimer
  2878. #undef torsoAnimTimer
  2879. #undef bool
  2880. #undef false
  2881. #undef true
  2882. #undef sqrtf
  2883. #undef MOD_EXPLOSIVE
  2884. #endif