1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202 |
- // leave this line at the top for all g_xxxx.cpp files...
- #include "g_headers.h"
- #include "q_shared.h"
- #include "g_local.h"
- #ifdef _JK2 //SP does not have this preprocessor for game like MP does
- #ifndef _JK2MP
- #define _JK2MP
- #endif
- #endif
- #ifndef _JK2MP
- #include "g_functions.h"
- #include "g_vehicles.h"
- #include "../CGame/cg_Local.h"
- #else
- #include "bg_vehicles.h"
- #endif
- #ifdef _JK2MP
- //this is really horrible, but it works! just be sure not to use any locals or anything
- //with these names (exluding bool, false, true). -rww
- #define currentAngles r.currentAngles
- #define currentOrigin r.currentOrigin
- #define mins r.mins
- #define maxs r.maxs
- #define legsAnimTimer legsTimer
- #define torsoAnimTimer torsoTimer
- #define bool qboolean
- #define false qfalse
- #define true qtrue
- #define sqrtf sqrt
- #define MOD_EXPLOSIVE MOD_SUICIDE
- #endif
- #ifndef _JK2MP
- #define GAME_INLINE inline
- #define bgEntity_t gentity_t
- #endif
- #ifdef _JK2MP
- extern gentity_t *NPC_Spawn_Do( gentity_t *ent );
- extern void NPC_SetAnim(gentity_t *ent,int setAnimParts,int anim,int setAnimFlags);
- #else
- extern gentity_t *NPC_Spawn_Do( gentity_t *pEnt, qboolean fullSpawnNow );
- extern qboolean G_ClearLineOfSight(const vec3_t point1, const vec3_t point2, int ignore, int clipmask);
- extern qboolean G_SetG2PlayerModelInfo( gentity_t *pEnt, const char *modelName, const char *customSkin, const char *surfOff, const char *surfOn );
- extern void G_RemovePlayerModel( gentity_t *pEnt );
- extern void G_ChangePlayerModel( gentity_t *pEnt, const char *newModel );
- extern void G_RemoveWeaponModels( gentity_t *pEnt );
- extern void CG_ChangeWeapon( int num );
- extern float DotToSpot( vec3_t spot, vec3_t from, vec3_t fromAngles );
- extern qboolean Q3_TaskIDPending( gentity_t *ent, taskID_t taskType );
- extern void SetClientViewAngle( gentity_t *ent, vec3_t angle );
- extern vmCvar_t cg_thirdPersonAlpha;
- extern vec3_t playerMins;
- extern vec3_t playerMaxs;
- extern cvar_t *g_speederControlScheme;
- extern cvar_t *in_joystick;
- extern void PM_SetAnim(pmove_t *pm,int setAnimParts,int anim,int setAnimFlags, int blendTime);
- extern int PM_AnimLength( int index, animNumber_t anim );
- extern void NPC_SetAnim(gentity_t *ent,int setAnimParts,int anim,int setAnimFlags, int iBlend);
- extern void G_Knockdown( gentity_t *self, gentity_t *attacker, const vec3_t pushDir, float strength, qboolean breakSaberLock );
- #endif
- #ifdef _JK2MP
- #include "../namespace_begin.h"
- extern void BG_SetAnim(playerState_t *ps, animation_t *animations, int setAnimParts,int anim,int setAnimFlags, int blendTime);
- extern void BG_SetLegsAnimTimer(playerState_t *ps, int time );
- extern void BG_SetTorsoAnimTimer(playerState_t *ps, int time );
- #include "../namespace_end.h"
- void G_VehUpdateShields( gentity_t *targ );
- #ifdef QAGAME
- extern void VEH_TurretThink( Vehicle_t *pVeh, gentity_t *parent, int turretNum );
- #endif
- #else
- extern void PM_SetTorsoAnimTimer( gentity_t *ent, int *torsoAnimTimer, int time );
- extern void PM_SetLegsAnimTimer( gentity_t *ent, int *legsAnimTimer, int time );
- #endif
- extern qboolean BG_UnrestrainedPitchRoll( playerState_t *ps, Vehicle_t *pVeh );
- void Vehicle_SetAnim(gentity_t *ent,int setAnimParts,int anim,int setAnimFlags, int iBlend)
- {
- #ifdef _JK2MP
- assert(ent->client);
- BG_SetAnim(&ent->client->ps, bgAllAnims[ent->localAnimIndex].anims, setAnimParts, anim, setAnimFlags, iBlend);
- ent->s.legsAnim = ent->client->ps.legsAnim;
- #else
- NPC_SetAnim(ent, setAnimParts, anim, setAnimFlags, iBlend);
- #endif
- }
- 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 )
- {
- #ifdef _JK2MP
- trap_Trace(results, start, tMins, tMaxs, end, passEntityNum, contentmask);
- #else
- gi.trace( results, start, tMins, tMaxs, end, passEntityNum, contentmask );
- #endif
- }
- Vehicle_t *G_IsRidingVehicle( gentity_t *pEnt )
- {
- gentity_t *ent = (gentity_t *)pEnt;
- 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 )
- {
- return g_entities[ent->s.m_iVehicleNum].m_pVehicle;
- }
- return NULL;
- }
- bool G_IsRidingTurboVehicle( gentity_t *pEnt )
- {
- gentity_t *ent = (gentity_t *)pEnt;
- 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 )
- {
- return (level.time<g_entities[ent->s.m_iVehicleNum].m_pVehicle->m_iTurboTime);
- }
- return false;
- }
- float G_CanJumpToEnemyVeh(Vehicle_t *pVeh, const usercmd_t *pUcmd )
- {
- #ifndef _JK2MP
- gentity_t* rider = pVeh->m_pPilot;
- // If There Is An Enemy And We Are At The Same Z Height
- //------------------------------------------------------
- if (rider &&
- rider->enemy &&
- pUcmd->rightmove &&
- fabsf(rider->enemy->currentOrigin[2] - rider->currentOrigin[2])<50.0f)
- {
- if (level.time<pVeh->m_safeJumpMountTime)
- {
- return pVeh->m_safeJumpMountRightDot;
- }
- // If The Enemy Is Riding Another Vehicle
- //----------------------------------------
- Vehicle_t* enemyVeh = G_IsRidingVehicle(rider->enemy);
- if (enemyVeh)
- {
- vec3_t enemyFwd;
- vec3_t toEnemy;
- float toEnemyDistance;
- vec3_t riderFwd;
- vec3_t riderRight;
- float riderRightDot;
- // If He Is Close Enough And Going The Same Speed
- //------------------------------------------------
- VectorSubtract(rider->enemy->currentOrigin, rider->currentOrigin, toEnemy);
- toEnemyDistance = VectorNormalize(toEnemy);
- if (toEnemyDistance<70.0f &&
- pVeh->m_pParentEntity->resultspeed>100.0f &&
- fabsf(pVeh->m_pParentEntity->resultspeed - enemyVeh->m_pParentEntity->resultspeed)<100.0f)
- {
- // If He Is Either To The Left Or Right Of Me
- //--------------------------------------------
- AngleVectors(rider->currentAngles, riderFwd, riderRight, 0);
- riderRightDot = DotProduct(riderRight, toEnemy);
- if ((pUcmd->rightmove>0 && riderRightDot>0.2) || (pUcmd->rightmove<0 &&riderRightDot<-0.2))
- {
- // If We Are Both Going About The Same Direction
- //-----------------------------------------------
- AngleVectors(rider->enemy->currentAngles, enemyFwd, 0, 0);
- if (DotProduct(enemyFwd, riderFwd)>0.2f)
- {
- pVeh->m_safeJumpMountTime = level.time + Q_irand(3000, 4000); // Ok, now you get a 3 sec window
- pVeh->m_safeJumpMountRightDot = riderRightDot;
- return riderRightDot;
- }// Same Direction?
- }// To Left Or Right?
- }// Close Enough & Same Speed?
- }// Enemy Riding A Vehicle?
- }// Has Enemy And On Same Z-Height
- #endif
- return 0.0f;
- }
- // Spawn this vehicle into the world.
- void G_VehicleSpawn( gentity_t *self )
- {
- float yaw;
- gentity_t *vehEnt;
- VectorCopy( self->currentOrigin, self->s.origin );
- #ifdef _JK2MP
- trap_LinkEntity( self );
- #else
- gi.linkentity( self );
- #endif
- if ( !self->count )
- {
- self->count = 1;
- }
- //save this because self gets removed in next func
- yaw = self->s.angles[YAW];
-
- #ifdef _JK2MP
- vehEnt = NPC_Spawn_Do( self );
- #else
- vehEnt = NPC_Spawn_Do( self, qtrue );
- #endif
-
- if ( !vehEnt )
- {
- return;//return NULL;
- }
-
- vehEnt->s.angles[YAW] = yaw;
- if ( vehEnt->m_pVehicle->m_pVehicleInfo->type != VH_ANIMAL )
- {
- vehEnt->NPC->behaviorState = BS_CINEMATIC;
- }
- #ifdef _JK2MP //special check in case someone disconnects/dies while boarding
- if (vehEnt->spawnflags & 1)
- { //die without pilot
- if (!vehEnt->damage)
- { //default 10 sec
- vehEnt->damage = 10000;
- }
- if (!vehEnt->speed)
- { //default 512 units
- vehEnt->speed = 512.0f;
- }
- vehEnt->m_pVehicle->m_iPilotTime = level.time + vehEnt->damage;
- }
- #else
- if (vehEnt->spawnflags & 1)
- { //die without pilot
- vehEnt->m_pVehicle->m_iPilotTime = level.time + vehEnt->endFrame;
- }
- #endif
- //return vehEnt;
- }
- // Attachs an entity to the vehicle it's riding (it's owner).
- void G_AttachToVehicle( gentity_t *pEnt, usercmd_t **ucmd )
- {
- gentity_t *vehEnt;
- mdxaBone_t boltMatrix;
- gentity_t *ent;
- #ifdef _JK2MP
- int crotchBolt;
- #endif
- if ( !pEnt || !ucmd )
- return;
- ent = (gentity_t *)pEnt;
- #ifdef _JK2MP
- vehEnt = &g_entities[ent->r.ownerNum];
- #else
- vehEnt = ent->owner;
- #endif
- ent->waypoint = vehEnt->waypoint; // take the veh's waypoint as your own
- if ( !vehEnt->m_pVehicle )
- return;
- #ifdef _JK2MP
- crotchBolt = trap_G2API_AddBolt(vehEnt->ghoul2, 0, "*driver");
- // Get the driver tag.
- trap_G2API_GetBoltMatrix( vehEnt->ghoul2, 0, crotchBolt, &boltMatrix,
- vehEnt->m_pVehicle->m_vOrientation, vehEnt->currentOrigin,
- level.time, NULL, vehEnt->modelScale );
- BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, ent->client->ps.origin );
- G_SetOrigin(ent, ent->client->ps.origin);
- trap_LinkEntity( ent );
- #else
- // Get the driver tag.
- gi.G2API_GetBoltMatrix( vehEnt->ghoul2, vehEnt->playerModel, vehEnt->crotchBolt, &boltMatrix,
- vehEnt->m_pVehicle->m_vOrientation, vehEnt->currentOrigin,
- (cg.time?cg.time:level.time), NULL, vehEnt->s.modelScale );
- gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, ent->client->ps.origin );
- gi.linkentity( ent );
- #endif
- }
- #ifndef _JK2MP
- void G_KnockOffVehicle( gentity_t *pRider, gentity_t *self, qboolean bPull )
- {
- Vehicle_t *pVeh = NULL;
- vec3_t riderAngles, fDir, rDir, dir2Me;
- float fDot, rDot;
- if ( !pRider || !pRider->client )
- {
- return;
- }
-
- pVeh = G_IsRidingVehicle( pRider );
- if ( !pVeh || !pVeh->m_pVehicleInfo )
- {
- return;
- }
- VectorCopy( pRider->currentAngles, riderAngles );
- riderAngles[0] = 0;
- AngleVectors( riderAngles, fDir, rDir, NULL );
- VectorSubtract( self->currentOrigin, pRider->currentOrigin, dir2Me );
- dir2Me[2] = 0;
- VectorNormalize( dir2Me );
- fDot = DotProduct( fDir, dir2Me );
- if ( fDot >= 0.5f )
- {//I'm in front of them
- if ( bPull )
- {//pull them foward
- pVeh->m_EjectDir = VEH_EJECT_FRONT;
- }
- else
- {//push them back
- pVeh->m_EjectDir = VEH_EJECT_REAR;
- }
- }
- else if ( fDot <= -0.5f )
- {//I'm behind them
- if ( bPull )
- {//pull them back
- pVeh->m_EjectDir = VEH_EJECT_REAR;
- }
- else
- {//push them forward
- pVeh->m_EjectDir = VEH_EJECT_FRONT;
- }
- }
- else
- {//to the side of them
- rDot = DotProduct( fDir, dir2Me );
- if ( rDot >= 0.0f )
- {//to the right
- if ( bPull )
- {//pull them right
- pVeh->m_EjectDir = VEH_EJECT_RIGHT;
- }
- else
- {//push them left
- pVeh->m_EjectDir = VEH_EJECT_LEFT;
- }
- }
- else
- {//to the left
- if ( bPull )
- {//pull them left
- pVeh->m_EjectDir = VEH_EJECT_LEFT;
- }
- else
- {//push them right
- pVeh->m_EjectDir = VEH_EJECT_RIGHT;
- }
- }
- }
- //now forcibly eject them
- pVeh->m_pVehicleInfo->Eject( pVeh, pRider, qtrue );
- }
- #endif
- #ifndef _JK2MP //don't want this in mp at least for now
- void G_DrivableATSTDie( gentity_t *self )
- {
- }
- void G_DriveATST( gentity_t *pEnt, gentity_t *atst )
- {
- if ( pEnt->NPC_type && pEnt->client && (pEnt->client->NPC_class == CLASS_ATST) )
- {//already an atst, switch back
- //open hatch
- G_RemovePlayerModel( pEnt );
- pEnt->NPC_type = "player";
- pEnt->client->NPC_class = CLASS_PLAYER;
- pEnt->flags &= ~FL_SHIELDED;
- pEnt->client->ps.eFlags &= ~EF_IN_ATST;
- //size
- VectorCopy( playerMins, pEnt->mins );
- VectorCopy( playerMaxs, pEnt->maxs );
- pEnt->client->crouchheight = CROUCH_MAXS_2;
- pEnt->client->standheight = DEFAULT_MAXS_2;
- pEnt->s.radius = 0;//clear it so the G2-model-setting stuff will recalc it
- G_ChangePlayerModel( pEnt, pEnt->NPC_type );
- //G_SetG2PlayerModel( pEnt, pEnt->NPC_type, NULL, NULL, NULL );
- //FIXME: reset/4 their weapon
- pEnt->client->ps.stats[STAT_WEAPONS] &= ~(( 1 << WP_ATST_MAIN )|( 1 << WP_ATST_SIDE ));
- pEnt->client->ps.ammo[weaponData[WP_ATST_MAIN].ammoIndex] = 0;
- pEnt->client->ps.ammo[weaponData[WP_ATST_SIDE].ammoIndex] = 0;
- if ( pEnt->client->ps.stats[STAT_WEAPONS] & (1<<WP_BLASTER) )
- {
- CG_ChangeWeapon( WP_BLASTER );
- //camera
- if ( cg_gunAutoFirst.integer )
- {//go back to first person
- gi.cvar_set( "cg_thirdperson", "0" );
- }
- }
- else
- {
- CG_ChangeWeapon( WP_NONE );
- }
- cg.overrides.active &= ~(CG_OVERRIDE_3RD_PERSON_RNG|CG_OVERRIDE_3RD_PERSON_VOF|CG_OVERRIDE_3RD_PERSON_POF|CG_OVERRIDE_3RD_PERSON_APH);
- cg.overrides.thirdPersonRange = cg.overrides.thirdPersonVertOffset = cg.overrides.thirdPersonPitchOffset = 0;
- cg.overrides.thirdPersonAlpha = cg_thirdPersonAlpha.value;
- pEnt->client->ps.viewheight = pEnt->maxs[2] + STANDARD_VIEWHEIGHT_OFFSET;
- //pEnt->mass = 10;
- }
- else
- {//become an atst
- pEnt->NPC_type = "atst";
- pEnt->client->NPC_class = CLASS_ATST;
- pEnt->client->ps.eFlags |= EF_IN_ATST;
- pEnt->flags |= FL_SHIELDED;
- //size
- VectorSet( pEnt->mins, ATST_MINS0, ATST_MINS1, ATST_MINS2 );
- VectorSet( pEnt->maxs, ATST_MAXS0, ATST_MAXS1, ATST_MAXS2 );
- pEnt->client->crouchheight = ATST_MAXS2;
- pEnt->client->standheight = ATST_MAXS2;
- if ( !atst )
- {//no pEnt to copy from
- G_ChangePlayerModel( pEnt, "atst" );
- //G_SetG2PlayerModel( pEnt, "atst", NULL, NULL, NULL );
- NPC_SetAnim( pEnt, SETANIM_BOTH, BOTH_STAND1, SETANIM_FLAG_OVERRIDE, 200 );
- }
- else
- {
- G_RemovePlayerModel( pEnt );
- G_RemoveWeaponModels( pEnt );
- gi.G2API_CopyGhoul2Instance( atst->ghoul2, pEnt->ghoul2 );
- pEnt->playerModel = 0;
- G_SetG2PlayerModelInfo( pEnt, "atst", NULL, NULL, NULL );
- //turn off hatch underside
- gi.G2API_SetSurfaceOnOff( &pEnt->ghoul2[pEnt->playerModel], "head_hatchcover", 0x00000002/*G2SURFACEFLAG_OFF*/ );
- G_Sound( pEnt, G_SoundIndex( "sound/chars/atst/atst_hatch_close" ));
- }
- pEnt->s.radius = 320;
- //weapon
- gitem_t *item = FindItemForWeapon( WP_ATST_MAIN ); //precache the weapon
- CG_RegisterItemSounds( (item-bg_itemlist) );
- CG_RegisterItemVisuals( (item-bg_itemlist) );
- item = FindItemForWeapon( WP_ATST_SIDE ); //precache the weapon
- CG_RegisterItemSounds( (item-bg_itemlist) );
- CG_RegisterItemVisuals( (item-bg_itemlist) );
- pEnt->client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_ATST_MAIN )|( 1 << WP_ATST_SIDE );
- pEnt->client->ps.ammo[weaponData[WP_ATST_MAIN].ammoIndex] = ammoData[weaponData[WP_ATST_MAIN].ammoIndex].max;
- pEnt->client->ps.ammo[weaponData[WP_ATST_SIDE].ammoIndex] = ammoData[weaponData[WP_ATST_SIDE].ammoIndex].max;
- CG_ChangeWeapon( WP_ATST_MAIN );
- //HACKHACKHACKTEMP
- item = FindItemForWeapon( WP_EMPLACED_GUN );
- CG_RegisterItemSounds( (item-bg_itemlist) );
- CG_RegisterItemVisuals( (item-bg_itemlist) );
- item = FindItemForWeapon( WP_ROCKET_LAUNCHER );
- CG_RegisterItemSounds( (item-bg_itemlist) );
- CG_RegisterItemVisuals( (item-bg_itemlist) );
- item = FindItemForWeapon( WP_BOWCASTER );
- CG_RegisterItemSounds( (item-bg_itemlist) );
- CG_RegisterItemVisuals( (item-bg_itemlist) );
- //HACKHACKHACKTEMP
- //FIXME: these get lost in load/save! Must use variables that are set every frame or saved/loaded
- //camera
- gi.cvar_set( "cg_thirdperson", "1" );
- cg.overrides.active |= CG_OVERRIDE_3RD_PERSON_RNG;
- cg.overrides.thirdPersonRange = 240;
- //cg.overrides.thirdPersonVertOffset = 100;
- //cg.overrides.thirdPersonPitchOffset = -30;
- //FIXME: this gets stomped in pmove?
- pEnt->client->ps.viewheight = 120;
- //FIXME: setting these broke things very badly...?
- //pEnt->client->standheight = 200;
- //pEnt->client->crouchheight = 200;
- //pEnt->mass = 300;
- //movement
- //pEnt->client->ps.speed = 0;//FIXME: override speed?
- //FIXME: slow turn turning/can't turn if not moving?
- }
- }
- #endif //_JK2MP
- // Animate the vehicle and it's riders.
- void Animate( Vehicle_t *pVeh )
- {
- // Validate a pilot rider.
- if ( pVeh->m_pPilot )
- {
- if (pVeh->m_pVehicleInfo->AnimateRiders)
- {
- pVeh->m_pVehicleInfo->AnimateRiders( pVeh );
- }
- }
- pVeh->m_pVehicleInfo->AnimateVehicle( pVeh );
- }
- // Determine whether this entity is able to board this vehicle or not.
- bool ValidateBoard( Vehicle_t *pVeh, bgEntity_t *pEnt )
- {
- // Determine where the entity is entering the vehicle from (left, right, or back).
- vec3_t vVehToEnt;
- vec3_t vVehDir;
- const gentity_t *parent = (gentity_t *)pVeh->m_pParentEntity;
- const gentity_t *ent = (gentity_t *)pEnt;
- vec3_t vVehAngles;
- float fDot;
- if ( pVeh->m_iDieTime>0)
- {
- return false;
- }
- if ( ent->health <= 0 )
- {//dead men can't ride vehicles
- return false;
- }
- if ( pVeh->m_pPilot != NULL )
- {//already have a driver!
- if ( pVeh->m_pVehicleInfo->type == VH_FIGHTER )
- {//I know, I know, this should by in the fighters's validateboard()
- //can never steal a fighter from it's pilot
- return false;
- }
- else if ( pVeh->m_pVehicleInfo->type == VH_WALKER )
- {//I know, I know, this should by in the walker's validateboard()
- if ( !ent->client || ent->client->ps.groundEntityNum != parent->s.number )
- {//can only steal an occupied AT-ST if you're on top (by the hatch)
- return false;
- }
- }
- else if (pVeh->m_pVehicleInfo->type == VH_SPEEDER)
- {//you can only steal the bike from the driver if you landed on the driver or bike
- return (pVeh->m_iBoarding==VEH_MOUNT_THROW_LEFT || pVeh->m_iBoarding==VEH_MOUNT_THROW_RIGHT);
- }
- }
- // Yes, you shouldn't have put this here (you 'should' have made an 'overriden' ValidateBoard func), but in this
- // instance it's more than adequate (which is why I do it too :-). Making a whole other function for this is silly.
- else if ( pVeh->m_pVehicleInfo->type == VH_FIGHTER )
- {
- // If you're a fighter, you allow everyone to enter you from all directions.
- return true;
- }
- // Clear out all orientation axis except for the yaw.
- VectorSet(vVehAngles, 0, parent->currentAngles[YAW], 0);
- // Vector from Entity to Vehicle.
- VectorSubtract( ent->currentOrigin, parent->currentOrigin, vVehToEnt );
- vVehToEnt[2] = 0;
- VectorNormalize( vVehToEnt );
- // Get the right vector.
- AngleVectors( vVehAngles, NULL, vVehDir, NULL );
- VectorNormalize( vVehDir );
- // Find the angle between the vehicle right vector and the vehicle to entity vector.
- fDot = DotProduct( vVehToEnt, vVehDir );
- // If the entity is within a certain angle to the left of the vehicle...
- if ( fDot >= 0.5f )
- {
- // Right board.
- pVeh->m_iBoarding = -2;
- }
- else if ( fDot <= -0.5f )
- {
- // Left board.
- pVeh->m_iBoarding = -1;
- }
- // Maybe they're trying to board from the back...
- else
- {
- // The forward vector of the vehicle.
- // AngleVectors( vVehAngles, vVehDir, NULL, NULL );
- // VectorNormalize( vVehDir );
- // Find the angle between the vehicle forward and the vehicle to entity vector.
- // fDot = DotProduct( vVehToEnt, vVehDir );
- // If the entity is within a certain angle behind the vehicle...
- //if ( fDot <= -0.85f )
- {
- // Jump board.
- pVeh->m_iBoarding = -3;
- }
- }
- // If for some reason we couldn't board, leave...
- if ( pVeh->m_iBoarding > -1 )
- return false;
- return true;
- }
- // Board this Vehicle (get on). The first entity to board an empty vehicle becomes the Pilot.
- bool Board( Vehicle_t *pVeh, bgEntity_t *pEnt )
- {
- vec3_t vPlayerDir;
- gentity_t *ent = (gentity_t *)pEnt;
- gentity_t *parent = (gentity_t *)pVeh->m_pParentEntity;
- // If it's not a valid entity, OR if the vehicle is blowing up (it's dead), OR it's not
- // empty, OR we're already being boarded, OR the person trying to get on us is already
- // in a vehicle (that was a fun bug :-), leave!
- if ( !ent || parent->health <= 0 /*|| !( parent->client->ps.eFlags & EF_EMPTY_VEHICLE )*/ || (pVeh->m_iBoarding > 0) ||
- #ifdef _JK2MP
- ( ent->client->ps.m_iVehicleNum ) )
- #else
- ( ent->s.m_iVehicleNum != 0 ) )
- #endif
- return false;
- // Bucking so we can't do anything (NOTE: Should probably be a better name since fighters don't buck...).
- if ( pVeh->m_ulFlags & VEH_BUCKING )
- return false;
- // Validate the entity's ability to board this vehicle.
- if ( !pVeh->m_pVehicleInfo->ValidateBoard( pVeh, pEnt ) )
- return false;
- // FIXME FIXME!!! Ask Mike monday where ent->client->ps.eFlags might be getting changed!!! It is always 0 (when it should
- // be 1024) so a person riding a vehicle is able to ride another vehicle!!!!!!!!
- // Tell everybody their status.
- // ALWAYS let the player be the pilot.
- if ( ent->s.number < MAX_CLIENTS )
- {
- pVeh->m_pOldPilot = pVeh->m_pPilot;
- #ifdef _JK2MP
- if ( !pVeh->m_pPilot )
- { //become the pilot, if there isn't one now
- pVeh->m_pVehicleInfo->SetPilot( pVeh, (bgEntity_t *)ent );
- }
- // If we're not yet full...
- else if ( pVeh->m_iNumPassengers < pVeh->m_pVehicleInfo->maxPassengers )
- {
- int i;
- // Find an empty slot and put that passenger here.
- for ( i = 0; i < pVeh->m_pVehicleInfo->maxPassengers; i++ )
- {
- if ( pVeh->m_ppPassengers[i] == NULL )
- {
- pVeh->m_ppPassengers[i] = (bgEntity_t *)ent;
- #ifdef QAGAME
- //Server just needs to tell client which passengernum he is
- if ( ent->client )
- {
- ent->client->ps.generic1 = i+1;
- }
- #endif
- break;
- }
- }
- pVeh->m_iNumPassengers++;
- }
- // We're full, sorry...
- else
- {
- return false;
- }
- ent->s.m_iVehicleNum = parent->s.number;
- if (ent->client)
- {
- ent->client->ps.m_iVehicleNum = ent->s.m_iVehicleNum;
- }
- if ( pVeh->m_pPilot == (bgEntity_t *)ent )
- {
- parent->r.ownerNum = ent->s.number;
- parent->s.owner = parent->r.ownerNum; //for prediction
- }
- #else
- pVeh->m_pVehicleInfo->SetPilot( pVeh, ent );
- ent->s.m_iVehicleNum = parent->s.number;
- parent->owner = ent;
- #endif
- #ifdef QAGAME
- {
- gentity_t *gParent = (gentity_t *)parent;
- if ( (gParent->spawnflags&2) )
- {//was being suspended
- gParent->spawnflags &= ~2;//SUSPENDED - clear this spawnflag, no longer docked, okay to free-fall if not in space
- //gParent->client->ps.eFlags &= ~EF_RADAROBJECT;
- G_Sound( gParent, CHAN_AUTO, G_SoundIndex( "sound/vehicles/common/release.wav" ) );
- if ( gParent->fly_sound_debounce_time )
- {//we should drop like a rock for a few seconds
- pVeh->m_iDropTime = level.time + gParent->fly_sound_debounce_time;
- }
- }
- }
- #endif
- #ifndef _JK2MP
- gi.cvar_set( "cg_thirdperson", "1" ); //go to third person
- CG_CenterPrint( "@SP_INGAME_EXIT_VIEW", SCREEN_HEIGHT * 0.87 ); //tell them how to get out!
- #endif
- //FIXME: rider needs to look in vehicle's direction when he gets in
- // Clear these since they're used to turn the vehicle now.
- /*SetClientViewAngle( ent, pVeh->m_vOrientation );
- memset( &parent->client->usercmd, 0, sizeof( usercmd_t ) );
- memset( &pVeh->m_ucmd, 0, sizeof( usercmd_t ) );
- VectorClear( parent->client->ps.viewangles );
- VectorClear( parent->client->ps.delta_angles );*/
- // Set the looping sound only when there is a pilot (when the vehicle is "on").
- if ( pVeh->m_pVehicleInfo->soundLoop )
- {
- #ifdef _JK2MP
- parent->client->ps.loopSound = parent->s.loopSound = pVeh->m_pVehicleInfo->soundLoop;
- #else
- parent->s.loopSound = pVeh->m_pVehicleInfo->soundLoop;
- #endif
- }
- }
- else
- {
- // If there's no pilot, try to drive this vehicle.
- if ( pVeh->m_pPilot == NULL )
- {
- #ifdef _JK2MP
- pVeh->m_pVehicleInfo->SetPilot( pVeh, (bgEntity_t *)ent );
- // TODO: Set pilot should do all this stuff....
- parent->r.ownerNum = ent->s.number;
- parent->s.owner = parent->r.ownerNum; //for prediction
- #else
- pVeh->m_pVehicleInfo->SetPilot( pVeh, ent );
- // TODO: Set pilot should do all this stuff....
- parent->owner = ent;
- #endif
- // Set the looping sound only when there is a pilot (when the vehicle is "on").
- if ( pVeh->m_pVehicleInfo->soundLoop )
- {
- #ifdef _JK2MP
- parent->client->ps.loopSound = parent->s.loopSound = pVeh->m_pVehicleInfo->soundLoop;
- #else
- parent->s.loopSound = pVeh->m_pVehicleInfo->soundLoop;
- #endif
- }
- parent->client->ps.speed = 0;
- memset( &pVeh->m_ucmd, 0, sizeof( usercmd_t ) );
- }
- // We're full, sorry...
- else
- {
- return false;
- }
- }
-
- // Make sure the entity knows it's in a vehicle.
- #ifdef _JK2MP
- ent->client->ps.m_iVehicleNum = parent->s.number;
- ent->r.ownerNum = parent->s.number;
- ent->s.owner = ent->r.ownerNum; //for prediction
- if (pVeh->m_pPilot == (bgEntity_t *)ent)
- {
- parent->client->ps.m_iVehicleNum = ent->s.number+1; //always gonna be under MAX_CLIENTS so no worries about 1 byte overflow
- }
- #else
- ent->s.m_iVehicleNum = parent->s.number;
- ent->owner = parent;
- parent->s.m_iVehicleNum = ent->s.number+1;
- #endif
- //memset( &ent->client->usercmd, 0, sizeof( usercmd_t ) );
- //FIXME: no saber or weapons if numHands = 2, should switch to speeder weapon, no attack anim on player
- if ( pVeh->m_pVehicleInfo->numHands == 2 )
- {//switch to vehicle weapon
- #ifndef _JK2MP //rwwFIXMEFIXMEFIXME
- if (ent->s.number<MAX_CLIENTS)
- {// Riding means you get WP_NONE
- ent->client->ps.stats[ STAT_WEAPONS ] |= (1<<WP_NONE);
- }
- if ( ent->client->ps.weapon != WP_SABER
- && ent->client->ps.weapon != WP_BLASTER )
- {//switch to weapon none?
- if (ent->s.number<MAX_CLIENTS)
- {
- CG_ChangeWeapon(WP_NONE);
- }
- ent->client->ps.weapon = WP_NONE;
- G_RemoveWeaponModels( ent );
- }
- #endif
- }
- if ( pVeh->m_pVehicleInfo->hideRider )
- {//hide the rider
- pVeh->m_pVehicleInfo->Ghost( pVeh, (bgEntity_t *)ent );
- }
- // Play the start sounds
- if ( pVeh->m_pVehicleInfo->soundOn )
- {
- #ifdef _JK2MP
- G_Sound( parent, CHAN_AUTO, pVeh->m_pVehicleInfo->soundOn );
- #else
- // NOTE: Use this type so it's spatialized and updates play origin as bike moves - MCG
- G_SoundIndexOnEnt( parent, CHAN_AUTO, pVeh->m_pVehicleInfo->soundOn );
- #endif
- }
- VectorCopy( pVeh->m_vOrientation, vPlayerDir );
- vPlayerDir[ROLL] = 0;
- SetClientViewAngle( ent, vPlayerDir );
- return true;
- }
- bool VEH_TryEject( Vehicle_t *pVeh,
- gentity_t *parent,
- gentity_t *ent,
- int ejectDir,
- vec3_t vExitPos )
- {
- float fBias;
- float fVehDiag;
- float fEntDiag;
- vec3_t vEntMins, vEntMaxs, vVehLeaveDir, vVehAngles;
- trace_t m_ExitTrace;
- // Make sure that the entity is not 'stuck' inside the vehicle (since their bboxes will now intersect).
- // This makes the entity leave the vehicle from the right side.
- VectorSet(vVehAngles, 0, parent->currentAngles[YAW], 0);
- switch ( ejectDir )
- {
- // Left.
- case VEH_EJECT_LEFT:
- AngleVectors( vVehAngles, NULL, vVehLeaveDir, NULL );
- vVehLeaveDir[0] = -vVehLeaveDir[0];
- vVehLeaveDir[1] = -vVehLeaveDir[1];
- vVehLeaveDir[2] = -vVehLeaveDir[2];
- break;
- // Right.
- case VEH_EJECT_RIGHT:
- AngleVectors( vVehAngles, NULL, vVehLeaveDir, NULL );
- break;
- // Front.
- case VEH_EJECT_FRONT:
- AngleVectors( vVehAngles, vVehLeaveDir, NULL, NULL );
- break;
- // Rear.
- case VEH_EJECT_REAR:
- AngleVectors( vVehAngles, vVehLeaveDir, NULL, NULL );
- vVehLeaveDir[0] = -vVehLeaveDir[0];
- vVehLeaveDir[1] = -vVehLeaveDir[1];
- vVehLeaveDir[2] = -vVehLeaveDir[2];
- break;
- // Top.
- case VEH_EJECT_TOP:
- AngleVectors( vVehAngles, NULL, NULL, vVehLeaveDir );
- break;
- // Bottom?.
- case VEH_EJECT_BOTTOM:
- break;
- }
- VectorNormalize( vVehLeaveDir );
- //NOTE: not sure why following line was needed - MCG
- //pVeh->m_EjectDir = VEH_EJECT_LEFT;
- // Since (as of this time) the collidable geometry of the entity is just an axis
- // aligned box, we need to get the diagonal length of it in case we come out on that side.
- // Diagonal Length == squareroot( squared( Sidex / 2 ) + squared( Sidey / 2 ) );
- // TODO: DO diagonal for entity.
- fBias = 1.0f;
- if (pVeh->m_pVehicleInfo->type == VH_WALKER)
- { //hacktastic!
- fBias += 0.2f;
- }
- VectorCopy( ent->currentOrigin, vExitPos );
- fVehDiag = sqrtf( ( parent->maxs[0] * parent->maxs[0] ) + ( parent->maxs[1] * parent->maxs[1] ) );
- VectorCopy( ent->maxs, vEntMaxs );
- #ifdef _JK2MP
- if ( ent->s.number < MAX_CLIENTS )
- {//for some reason, in MP, player client mins and maxs are never stored permanently, just set to these hardcoded numbers in PMove
- vEntMaxs[0] = 15;
- vEntMaxs[1] = 15;
- }
- #endif
- fEntDiag = sqrtf( ( vEntMaxs[0] * vEntMaxs[0] ) + ( vEntMaxs[1] * vEntMaxs[1] ) );
- vVehLeaveDir[0] *= ( fVehDiag + fEntDiag ) * fBias; // x
- vVehLeaveDir[1] *= ( fVehDiag + fEntDiag ) * fBias; // y
- vVehLeaveDir[2] *= ( fVehDiag + fEntDiag ) * fBias;
- VectorAdd( vExitPos, vVehLeaveDir, vExitPos );
- //we actually could end up *not* getting off if the trace fails...
- // Check to see if this new position is a valid place for our entity to go.
- #ifdef _JK2MP
- VectorSet(vEntMins, -15.0f, -15.0f, DEFAULT_MINS_2);
- VectorSet(vEntMaxs, 15.0f, 15.0f, DEFAULT_MAXS_2);
- #else
- VectorCopy(ent->mins, vEntMins);
- VectorCopy(ent->maxs, vEntMaxs);
- #endif
- G_VehicleTrace( &m_ExitTrace, ent->currentOrigin, vEntMins, vEntMaxs, vExitPos, ent->s.number, ent->clipmask );
- if ( m_ExitTrace.allsolid//in solid
- || m_ExitTrace.startsolid)
- {
- return false;
- }
- // If the trace hit something, we can't go there!
- if ( m_ExitTrace.fraction < 1.0f )
- {//not totally clear
- #ifdef _JK2MP
- if ( (parent->clipmask&ent->r.contents) )//vehicle could actually get stuck on body
- #else
- if ( (parent->clipmask&ent->contents) )//vehicle could actually get stuck on body
- #endif
- {//the trace hit the vehicle, don't let them get out, just in case
- return false;
- }
- //otherwise, use the trace.endpos
- VectorCopy( m_ExitTrace.endpos, vExitPos );
- }
- return true;
- }
- void G_EjectDroidUnit( Vehicle_t *pVeh, qboolean kill )
- {
- pVeh->m_pDroidUnit->s.m_iVehicleNum = ENTITYNUM_NONE;
- #ifdef _JK2MP
- pVeh->m_pDroidUnit->s.owner = ENTITYNUM_NONE;
- #else
- pVeh->m_pDroidUnit->owner = NULL;
- #endif
- // pVeh->m_pDroidUnit->s.otherEntityNum2 = ENTITYNUM_NONE;
- #ifdef QAGAME
- {
- gentity_t *droidEnt = (gentity_t *)pVeh->m_pDroidUnit;
- droidEnt->flags &= ~FL_UNDYING;
- droidEnt->r.ownerNum = ENTITYNUM_NONE;
- if ( droidEnt->client )
- {
- droidEnt->client->ps.m_iVehicleNum = ENTITYNUM_NONE;
- }
- if ( kill )
- {//Kill them, too
- //FIXME: proper origin, MOD and attacker (for credit/death message)? Get from vehicle?
- G_MuteSound(droidEnt->s.number, CHAN_VOICE);
- G_Damage( droidEnt, NULL, NULL, NULL, droidEnt->s.origin, 10000, 0, MOD_SUICIDE );//FIXME: proper MOD? Get from vehicle?
- }
- }
- #endif
- pVeh->m_pDroidUnit = NULL;
- }
- // Eject the pilot from the vehicle.
- bool Eject( Vehicle_t *pVeh, bgEntity_t *pEnt, qboolean forceEject )
- {
- gentity_t *parent;
- vec3_t vExitPos;
- #ifndef _JK2MP
- vec3_t vPlayerDir;
- #endif
- gentity_t *ent = (gentity_t *)pEnt;
- int firstEjectDir;
- #ifdef _JK2MP
- qboolean taintedRider = qfalse;
- qboolean deadRider = qfalse;
- if ( pEnt == pVeh->m_pDroidUnit )
- {
- G_EjectDroidUnit( pVeh, qfalse );
- return true;
- }
- if (ent)
- {
- if (!ent->inuse || !ent->client || ent->client->pers.connected != CON_CONNECTED)
- {
- taintedRider = qtrue;
- parent = (gentity_t *)pVeh->m_pParentEntity;
- goto getItOutOfMe;
- }
- else if (ent->health < 1)
- {
- deadRider = qtrue;
- }
- }
- #endif
- // Validate.
- if ( !ent )
- {
- return false;
- }
- if ( !forceEject )
- {
- if ( !( pVeh->m_iBoarding == 0 || pVeh->m_iBoarding == -999 || ( pVeh->m_iBoarding < -3 && pVeh->m_iBoarding >= -9 ) ) )
- {
- #ifdef _JK2MP //I don't care, if he's dead get him off even if he died while boarding
- deadRider = qtrue;
- pVeh->m_iBoarding = 0;
- pVeh->m_bWasBoarding = false;
- #else
- return false;
- #endif
- }
- }
- /*#ifndef _JK2MP //rwwFIXMEFIXMEFIXME
- if (ent->s.number<MAX_CLIENTS)
- {
- CG_ChangeWeapon(WP_NONE);
- }
- ent->client->ps.weapon = WP_NONE;
- G_RemoveWeaponModels( ent );
- #endif*/
- parent = (gentity_t *)pVeh->m_pParentEntity;
- //Try ejecting in every direction
- if ( pVeh->m_EjectDir < VEH_EJECT_LEFT )
- {
- pVeh->m_EjectDir = VEH_EJECT_LEFT;
- }
- else if ( pVeh->m_EjectDir > VEH_EJECT_BOTTOM )
- {
- pVeh->m_EjectDir = VEH_EJECT_BOTTOM;
- }
- firstEjectDir = pVeh->m_EjectDir;
- while ( !VEH_TryEject( pVeh, parent, ent, pVeh->m_EjectDir, vExitPos ) )
- {
- pVeh->m_EjectDir++;
- if ( pVeh->m_EjectDir > VEH_EJECT_BOTTOM )
- {
- pVeh->m_EjectDir = VEH_EJECT_LEFT;
- }
- if ( pVeh->m_EjectDir == firstEjectDir )
- {//they all failed
- #ifdef _JK2MP
- if (!deadRider)
- { //if he's dead.. just shove him in solid, who cares.
- return false;
- }
- #endif
- if ( forceEject )
- {//we want to always get out, just eject him here
- VectorCopy( ent->currentOrigin, vExitPos );
- break;
- }
- else
- {//can't eject
- return false;
- }
- }
- }
- // Move them to the exit position.
- G_SetOrigin( ent, vExitPos );
- #ifdef _JK2MP
- VectorCopy(ent->currentOrigin, ent->client->ps.origin);
- trap_LinkEntity( ent );
- #else
- gi.linkentity( ent );
- #endif
- // If it's the player, stop overrides.
- if ( ent->s.number < MAX_CLIENTS )
- {
- #ifndef _JK2MP
- cg.overrides.active = 0;
- #else
- #endif
- }
- #ifdef _JK2MP //in MP if someone disconnects on us, we still have to clear our owner
- getItOutOfMe:
- #endif
- // If he's the pilot...
- if ( (gentity_t *)pVeh->m_pPilot == ent )
- {
- #ifdef _JK2MP
- int j = 0;
- #endif
- pVeh->m_pPilot = NULL;
- #ifdef _JK2MP
- parent->r.ownerNum = ENTITYNUM_NONE;
- parent->s.owner = parent->r.ownerNum; //for prediction
- //keep these current angles
- //SetClientViewAngle( parent, pVeh->m_vOrientation );
- memset( &parent->client->pers.cmd, 0, sizeof( usercmd_t ) );
- #else
- parent->owner = NULL;
- //keep these current angles
- //SetClientViewAngle( parent, pVeh->m_vOrientation );
- memset( &parent->client->usercmd, 0, sizeof( usercmd_t ) );
- #endif
- memset( &pVeh->m_ucmd, 0, sizeof( usercmd_t ) );
- #ifdef _JK2MP //if there are some passengers, promote the first passenger to pilot
- while (j < pVeh->m_iNumPassengers)
- {
- if (pVeh->m_ppPassengers[j])
- {
- int k = 1;
- pVeh->m_pVehicleInfo->SetPilot( pVeh, pVeh->m_ppPassengers[j] );
- parent->r.ownerNum = pVeh->m_ppPassengers[j]->s.number;
- parent->s.owner = parent->r.ownerNum; //for prediction
- parent->client->ps.m_iVehicleNum = pVeh->m_ppPassengers[j]->s.number+1;
- //rearrange the passenger slots now..
- #ifdef QAGAME
- //Server just needs to tell client he's not a passenger anymore
- if ( ((gentity_t *)pVeh->m_ppPassengers[j])->client )
- {
- ((gentity_t *)pVeh->m_ppPassengers[j])->client->ps.generic1 = 0;
- }
- #endif
- pVeh->m_ppPassengers[j] = NULL;
- while (k < pVeh->m_iNumPassengers)
- {
- if (!pVeh->m_ppPassengers[k-1])
- { //move down
- pVeh->m_ppPassengers[k-1] = pVeh->m_ppPassengers[k];
- pVeh->m_ppPassengers[k] = NULL;
- #ifdef QAGAME
- //Server just needs to tell client which passenger he is
- if ( ((gentity_t *)pVeh->m_ppPassengers[k-1])->client )
- {
- ((gentity_t *)pVeh->m_ppPassengers[k-1])->client->ps.generic1 = k;
- }
- #endif
- }
- k++;
- }
- pVeh->m_iNumPassengers--;
- break;
- }
- j++;
- }
- #endif
- }
- else if (ent==(gentity_t *)pVeh->m_pOldPilot)
- {
- pVeh->m_pOldPilot = 0;
- }
- #ifdef _JK2MP //I hate adding these!
- if (!taintedRider)
- {
- #endif
- if ( pVeh->m_pVehicleInfo->hideRider )
- {
- pVeh->m_pVehicleInfo->UnGhost( pVeh, (bgEntity_t *)ent );
- }
- #ifdef _JK2MP
- }
- #endif
- // If the vehicle now has no pilot...
- if ( pVeh->m_pPilot == NULL )
- {
- #ifdef _JK2MP
- parent->client->ps.loopSound = parent->s.loopSound = 0;
- #else
- parent->s.loopSound = 0;
- #endif
- // Completely empty vehicle...?
- #ifdef _JK2MP
- parent->client->ps.m_iVehicleNum = 0;
- #else
- parent->s.m_iVehicleNum = 0;
- #endif
- }
- #ifdef _JK2MP
- if (taintedRider)
- { //you can go now
- pVeh->m_iBoarding = level.time + 1000;
- return true;
- }
- #endif
- // Client not in a vehicle.
- #ifdef _JK2MP
- ent->client->ps.m_iVehicleNum = 0;
- ent->r.ownerNum = ENTITYNUM_NONE;
- ent->s.owner = ent->r.ownerNum; //for prediction
- ent->client->ps.viewangles[PITCH] = 0.0f;
- ent->client->ps.viewangles[ROLL] = 0.0f;
- ent->client->ps.viewangles[YAW] = pVeh->m_vOrientation[YAW];
- SetClientViewAngle(ent, ent->client->ps.viewangles);
- if (ent->client->solidHack)
- {
- ent->client->solidHack = 0;
- ent->r.contents = CONTENTS_BODY;
- }
- #else
- ent->owner = NULL;
- #endif
- ent->s.m_iVehicleNum = 0;
- // Jump out.
- /* if ( ent->client->ps.velocity[2] < JUMP_VELOCITY )
- {
- ent->client->ps.velocity[2] = JUMP_VELOCITY;
- }
- else
- {
- ent->client->ps.velocity[2] += JUMP_VELOCITY;
- }*/
- // Make sure entity is facing the direction it got off at.
- #ifndef _JK2MP
- VectorCopy( pVeh->m_vOrientation, vPlayerDir );
- vPlayerDir[ROLL] = 0;
- SetClientViewAngle( ent, vPlayerDir );
- #endif
- //if was using vehicle weapon, remove it and switch to normal weapon when hop out...
- if ( ent->client->ps.weapon == WP_NONE )
- {//FIXME: check against this vehicle's gun from the g_vehicleInfo table
- //remove the vehicle's weapon from me
- //ent->client->ps.stats[STAT_WEAPONS] &= ~( 1 << WP_EMPLACED_GUN );
- //ent->client->ps.ammo[weaponData[WP_EMPLACED_GUN].ammoIndex] = 0;//maybe store this ammo on the vehicle before clearing it?
- //switch back to a normal weapon we're carrying
-
- //FIXME: store the weapon we were using when we got on and restore that when hop off
- /* if ( (ent->client->ps.stats[STAT_WEAPONS]&(1<<WP_SABER)) )
- {
- CG_ChangeWeapon( WP_SABER );
- }
- else
- {//go through all weapons and switch to highest held
- for ( int checkWp = WP_NUM_WEAPONS-1; checkWp > WP_NONE; checkWp-- )
- {
- if ( (ent->client->ps.stats[STAT_WEAPONS]&(1<<checkWp)) )
- {
- CG_ChangeWeapon( checkWp );
- }
- }
- if ( checkWp == WP_NONE )
- {
- CG_ChangeWeapon( WP_NONE );
- }
- }*/
- }
- else
- {//FIXME: if they have their saber out:
- //if dualSabers, add the second saber into the left hand
- //saber[0] has more than one blade, turn them all on
- //NOTE: this is because you're only allowed to use your first saber's first blade on a vehicle
- }
- /* if ( !ent->s.number && ent->client->ps.weapon != WP_SABER
- && cg_gunAutoFirst.value )
- {
- gi.cvar_set( "cg_thirdperson", "0" );
- }*/
- #ifdef _JK2MP
- BG_SetLegsAnimTimer( &ent->client->ps, 0 );
- BG_SetTorsoAnimTimer( &ent->client->ps, 0 );
- #else
- PM_SetLegsAnimTimer( ent, &ent->client->ps.legsAnimTimer, 0 );
- PM_SetTorsoAnimTimer( ent, &ent->client->ps.torsoAnimTimer, 0 );
- #endif
- // Set how long until this vehicle can be boarded again.
- pVeh->m_iBoarding = level.time + 1000;
- return true;
- }
- // Eject all the inhabitants of this vehicle.
- bool EjectAll( Vehicle_t *pVeh )
- {
- // TODO: Setup a default escape for ever vehicle type.
- pVeh->m_EjectDir = VEH_EJECT_TOP;
- // Make sure no other boarding calls exist. We MUST exit.
- pVeh->m_iBoarding = 0;
- pVeh->m_bWasBoarding = false;
- // Throw them off.
- if ( pVeh->m_pPilot )
- {
- #ifdef QAGAME
- gentity_t *pilot = (gentity_t*)pVeh->m_pPilot;
- #endif
- pVeh->m_pVehicleInfo->Eject( pVeh, pVeh->m_pPilot, qtrue );
- #ifdef QAGAME
- if ( pVeh->m_pVehicleInfo->killRiderOnDeath && pilot )
- {//Kill them, too
- //FIXME: proper origin, MOD and attacker (for credit/death message)? Get from vehicle?
- G_MuteSound(pilot->s.number, CHAN_VOICE);
- G_Damage( pilot, player, player, NULL, pilot->s.origin, 10000, 0, MOD_SUICIDE );
- }
- #endif
- }
- if ( pVeh->m_pOldPilot )
- {
- #ifdef QAGAME
- gentity_t *pilot = (gentity_t*)pVeh->m_pOldPilot;
- #endif
- pVeh->m_pVehicleInfo->Eject( pVeh, pVeh->m_pOldPilot, qtrue );
- #ifdef QAGAME
- if ( pVeh->m_pVehicleInfo->killRiderOnDeath && pilot )
- {//Kill them, too
- //FIXME: proper origin, MOD and attacker (for credit/death message)? Get from vehicle?
- G_MuteSound(pilot->s.number, CHAN_VOICE);
- G_Damage( pilot, player, player, NULL, pilot->s.origin, 10000, 0, MOD_SUICIDE );
- }
- #endif
- }
-
- if ( pVeh->m_pDroidUnit )
- {
- G_EjectDroidUnit( pVeh, pVeh->m_pVehicleInfo->killRiderOnDeath );
- }
- return true;
- }
- // Start a delay until the vehicle explodes.
- static void StartDeathDelay( Vehicle_t *pVeh, int iDelayTimeOverride )
- {
- gentity_t *parent = (gentity_t *)pVeh->m_pParentEntity;
- if ( iDelayTimeOverride )
- {
- pVeh->m_iDieTime = level.time + iDelayTimeOverride;
- }
- else
- {
- pVeh->m_iDieTime = level.time + pVeh->m_pVehicleInfo->explosionDelay;
- }
- #ifdef _JK2MP
- if ( pVeh->m_pVehicleInfo->flammable )
- {
- parent->client->ps.loopSound = parent->s.loopSound = G_SoundIndex( "sound/vehicles/common/fire_lp.wav" );
- }
- #else
- // Armor Gone Effects (Fire)
- //---------------------------
- if (pVeh->m_pVehicleInfo->iArmorGoneFX)
- {
- if (!(pVeh->m_ulFlags&VEH_ARMORGONE) && (pVeh->m_iArmor <= 0))
- {
- pVeh->m_ulFlags |= VEH_ARMORGONE;
- G_PlayEffect(pVeh->m_pVehicleInfo->iArmorGoneFX, parent->playerModel, parent->crotchBolt, parent->s.number, parent->currentOrigin, 1, qtrue);
- parent->s.loopSound = G_SoundIndex( "sound/vehicles/common/fire_lp.wav" );
- }
- }
- #endif
- }
- extern char current_speeders;
- // Decide whether to explode the vehicle or not.
- static void DeathUpdate( Vehicle_t *pVeh )
- {
- gentity_t *parent = (gentity_t *)pVeh->m_pParentEntity;
- if ( level.time >= pVeh->m_iDieTime )
- {
- // If the vehicle is not empty.
- if ( pVeh->m_pVehicleInfo->Inhabited( pVeh ) )
- {
- #ifndef _JK2MP
- if (pVeh->m_pPilot)
- {
- pVeh->m_pPilot->client->noRagTime = -1; // no ragdoll for you
- }
- #endif
- pVeh->m_pVehicleInfo->EjectAll( pVeh );
- #ifdef _JK2MP
- if ( pVeh->m_pVehicleInfo->Inhabited( pVeh ) )
- { //if we've still got people in us, just kill the bastards
- if ( pVeh->m_pPilot )
- {
- //FIXME: does this give proper credit to the enemy who shot you down?
- G_Damage((gentity_t *)pVeh->m_pPilot, (gentity_t *)pVeh->m_pParentEntity, (gentity_t *)pVeh->m_pParentEntity,
- NULL, pVeh->m_pParentEntity->playerState->origin, 999, DAMAGE_NO_PROTECTION, MOD_EXPLOSIVE);
- }
- if ( pVeh->m_iNumPassengers )
- {
- int i;
- for ( i = 0; i < pVeh->m_pVehicleInfo->maxPassengers; i++ )
- {
- if ( pVeh->m_ppPassengers[i] )
- {
- //FIXME: does this give proper credit to the enemy who shot you down?
- G_Damage((gentity_t *)pVeh->m_ppPassengers[i], (gentity_t *)pVeh->m_pParentEntity, (gentity_t *)pVeh->m_pParentEntity,
- NULL, pVeh->m_pParentEntity->playerState->origin, 999, DAMAGE_NO_PROTECTION, MOD_EXPLOSIVE);
- }
- }
- }
- }
- #endif
- }
- if ( !pVeh->m_pVehicleInfo->Inhabited( pVeh ) )
- { //explode now as long as we managed to kick everyone out
- vec3_t lMins, lMaxs, bottom;
- trace_t trace;
- #ifndef _JK2MP
- // Kill All Client Side Looping Effects
- //--------------------------------------
- if (pVeh->m_pVehicleInfo->iExhaustFX)
- {
- for (int i=0; (i<MAX_VEHICLE_EXHAUSTS && pVeh->m_iExhaustTag[i]!=-1); i++)
- {
- G_StopEffect(pVeh->m_pVehicleInfo->iExhaustFX, parent->playerModel, pVeh->m_iExhaustTag[i], parent->s.number);
- }
- }
- if (pVeh->m_pVehicleInfo->iArmorLowFX)
- {
- G_StopEffect(pVeh->m_pVehicleInfo->iArmorLowFX, parent->playerModel, parent->crotchBolt, parent->s.number);
- }
- if (pVeh->m_pVehicleInfo->iArmorGoneFX)
- {
- G_StopEffect(pVeh->m_pVehicleInfo->iArmorGoneFX, parent->playerModel, parent->crotchBolt, parent->s.number);
- }
- //--------------------------------------
- #endif
- if ( pVeh->m_pVehicleInfo->iExplodeFX )
- {
- #ifdef _JK2MP
- vec3_t fxAng;
- VectorSet(fxAng, -90.0f, 0.0f, 0.0f);
- G_PlayEffectID( pVeh->m_pVehicleInfo->iExplodeFX, parent->currentOrigin, fxAng );
- #else
- G_PlayEffect( pVeh->m_pVehicleInfo->iExplodeFX, parent->currentOrigin, vec3_origin );
- #endif
- //trace down and place mark
- VectorCopy( parent->currentOrigin, bottom );
- bottom[2] -= 80;
- G_VehicleTrace( &trace, parent->currentOrigin, vec3_origin, vec3_origin, bottom, parent->s.number, CONTENTS_SOLID );
- if ( trace.fraction < 1.0f )
- {
- VectorCopy( trace.endpos, bottom );
- bottom[2] += 2;
- #ifdef _JK2MP
- VectorSet(fxAng, -90.0f, 0.0f, 0.0f);
- G_PlayEffectID( G_EffectIndex("ships/ship_explosion_mark"), trace.endpos, fxAng );
- #else
- G_PlayEffect( "ships/ship_explosion_mark", trace.endpos );
- #endif
- }
- }
- parent->takedamage = qfalse;//so we don't recursively damage ourselves
- if ( pVeh->m_pVehicleInfo->explosionRadius > 0 && pVeh->m_pVehicleInfo->explosionDamage > 0 )
- {
- VectorCopy( parent->mins, lMins );
- lMins[2] = -4;//to keep it off the ground a *little*
- VectorCopy( parent->maxs, lMaxs );
- VectorCopy( parent->currentOrigin, bottom );
- bottom[2] += parent->mins[2] - 32;
- G_VehicleTrace( &trace, parent->currentOrigin, lMins, lMaxs, bottom, parent->s.number, CONTENTS_SOLID );
- #ifdef _JK2MP
- 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
- #else
- 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
- #endif
- }
- #ifdef _JK2MP
- parent->think = G_FreeEntity;
- #else
- parent->e_ThinkFunc = thinkF_G_FreeEntity;
- #endif
- parent->nextthink = level.time + FRAMETIME;
- }
- }
- #ifndef _JK2MP
- else
- {//let everyone around me know I'm gonna blow!
- if ( !Q_irand( 0, 10 ) )
- {//not so often...
- AddSoundEvent( parent, parent->currentOrigin, 512, AEL_DANGER );
- AddSightEvent( parent, parent->currentOrigin, 512, AEL_DANGER, 100 );
- }
- }
- #endif
- }
- // Register all the assets used by this vehicle.
- void RegisterAssets( Vehicle_t *pVeh )
- {
- }
- extern void ChangeWeapon( gentity_t *ent, int newWeapon );
- // Initialize the vehicle.
- bool Initialize( Vehicle_t *pVeh )
- {
- gentity_t *parent = (gentity_t *)pVeh->m_pParentEntity;
- int i = 0;
- if ( !parent || !parent->client )
- return false;
- #ifdef _JK2MP
- parent->client->ps.m_iVehicleNum = 0;
- #endif
- parent->s.m_iVehicleNum = 0;
- {
- pVeh->m_iArmor = pVeh->m_pVehicleInfo->armor;
- 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;
- pVeh->m_iShields = pVeh->m_pVehicleInfo->shields;
- #ifdef _JK2MP
- G_VehUpdateShields( parent );
- #endif
- parent->client->ps.stats[STAT_ARMOR] = pVeh->m_iShields;
- }
- parent->mass = pVeh->m_pVehicleInfo->mass;
- //initialize the ammo to max
- for ( i = 0; i < MAX_VEHICLE_WEAPONS; i++ )
- {
- parent->client->ps.ammo[i] = pVeh->weaponStatus[i].ammo = pVeh->m_pVehicleInfo->weapon[i].ammoMax;
- }
- for ( i = 0; i < MAX_VEHICLE_TURRETS; i++ )
- {
- pVeh->turretStatus[i].nextMuzzle = (pVeh->m_pVehicleInfo->turret[i].iMuzzle[i]-1);
- parent->client->ps.ammo[MAX_VEHICLE_WEAPONS+i] = pVeh->turretStatus[i].ammo = pVeh->m_pVehicleInfo->turret[i].iAmmoMax;
- if ( pVeh->m_pVehicleInfo->turret[i].bAI )
- {//they're going to be finding enemies, init this to NONE
- pVeh->turretStatus[i].enemyEntNum = ENTITYNUM_NONE;
- }
- }
- //begin stopped...?
- parent->client->ps.speed = 0;
-
- VectorClear( pVeh->m_vOrientation );
- pVeh->m_vOrientation[YAW] = parent->s.angles[YAW];
- #ifdef _JK2MP
- if ( pVeh->m_pVehicleInfo->gravity &&
- pVeh->m_pVehicleInfo->gravity != g_gravity.value )
- {//not normal gravity
- if ( parent->NPC )
- {
- parent->NPC->aiFlags |= NPCAI_CUSTOM_GRAVITY;
- }
- parent->client->ps.gravity = pVeh->m_pVehicleInfo->gravity;
- }
- #else
- if ( pVeh->m_pVehicleInfo->gravity &&
- pVeh->m_pVehicleInfo->gravity != g_gravity->value )
- {//not normal gravity
- parent->svFlags |= SVF_CUSTOM_GRAVITY;
- parent->client->ps.gravity = pVeh->m_pVehicleInfo->gravity;
- }
- #endif
- /*
- if ( pVeh->m_iVehicleTypeID == VH_FIGHTER )
- {
- pVeh->m_ulFlags = VEH_GEARSOPEN;
- }
- else
- */
- //why?! -rww
- {
- pVeh->m_ulFlags = 0;
- }
- pVeh->m_fTimeModifier = 1.0f;
- pVeh->m_iBoarding = 0;
- pVeh->m_bWasBoarding = false;
- pVeh->m_pOldPilot = NULL;
- VectorClear(pVeh->m_vBoardingVelocity);
- pVeh->m_pPilot = NULL;
- memset( &pVeh->m_ucmd, 0, sizeof( usercmd_t ) );
- pVeh->m_iDieTime = 0;
- pVeh->m_EjectDir = VEH_EJECT_LEFT;
- //pVeh->m_iDriverTag = -1;
- //pVeh->m_iLeftExhaustTag = -1;
- //pVeh->m_iRightExhaustTag = -1;
- //pVeh->m_iGun1Tag = -1;
- //pVeh->m_iGun1Bone = -1;
- //pVeh->m_iLeftWingBone = -1;
- //pVeh->m_iRightWingBone = -1;
- memset( pVeh->m_iExhaustTag, -1, sizeof( int ) * MAX_VEHICLE_EXHAUSTS );
- memset( pVeh->m_iMuzzleTag, -1, sizeof( int ) * MAX_VEHICLE_MUZZLES );
- // FIXME! Use external values read from the vehicle data file!
- #ifndef _JK2MP //blargh, fixme
- memset( pVeh->m_Muzzles, 0, sizeof( Muzzle ) * MAX_VEHICLE_MUZZLES );
- #endif
- pVeh->m_iDroidUnitTag = -1;
- //initialize to blaster, just since it's a basic weapon and there's no lightsaber crap...?
- parent->client->ps.weapon = WP_BLASTER;
- parent->client->ps.weaponstate = WEAPON_READY;
- parent->client->ps.stats[STAT_WEAPONS] |= (1<<WP_BLASTER);
- //Initialize to landed (wings closed, gears down) animation
- {
- int iFlags = SETANIM_FLAG_NORMAL, iBlend = 300;
- #ifdef _JK2MP
- pVeh->m_ulFlags |= VEH_GEARSOPEN;
- BG_SetAnim(pVeh->m_pParentEntity->playerState,
- bgAllAnims[pVeh->m_pParentEntity->localAnimIndex].anims,
- SETANIM_BOTH, BOTH_VS_IDLE, iFlags, iBlend);
- #else
- NPC_SetAnim( pVeh->m_pParentEntity, SETANIM_BOTH, BOTH_VS_IDLE, iFlags, iBlend );
- #endif
- }
- return true;
- }
- // Like a think or move command, this updates various vehicle properties.
- #ifdef _JK2MP
- void G_VehicleDamageBoxSizing(Vehicle_t *pVeh); //declared below
- #endif
- static bool Update( Vehicle_t *pVeh, const usercmd_t *pUmcd )
- {
- gentity_t *parent = (gentity_t *)pVeh->m_pParentEntity;
- gentity_t *pilotEnt;
- //static float fMod = 1000.0f / 60.0f;
- vec3_t vVehAngles;
- int i;
- int prevSpeed;
- int nextSpeed;
- int curTime;
- int halfMaxSpeed;
- playerState_t *parentPS;
- qboolean linkHeld = qfalse;
- #ifdef _JK2MP
- parentPS = pVeh->m_pParentEntity->playerState;
- #else
- parentPS = &pVeh->m_pParentEntity->client->ps;
- #endif
- #ifndef _JK2MP//SP
- curTime = level.time;
- #elif QAGAME//MP GAME
- curTime = level.time;
- #elif CGAME//MP CGAME
- //FIXME: pass in ucmd? Not sure if this is reliable...
- curTime = pm->cmd.serverTime;
- #endif
- //increment the ammo for all rechargeable weapons
- for ( i = 0; i < MAX_VEHICLE_WEAPONS; i++ )
- {
- if ( pVeh->m_pVehicleInfo->weapon[i].ID > VEH_WEAPON_BASE//have a weapon in this slot
- && pVeh->m_pVehicleInfo->weapon[i].ammoRechargeMS//its ammo is rechargable
- && pVeh->weaponStatus[i].ammo < pVeh->m_pVehicleInfo->weapon[i].ammoMax//its ammo is below max
- && pUmcd->serverTime-pVeh->weaponStatus[i].lastAmmoInc >= pVeh->m_pVehicleInfo->weapon[i].ammoRechargeMS )//enough time has passed
- {//add 1 to the ammo
- pVeh->weaponStatus[i].lastAmmoInc = pUmcd->serverTime;
- pVeh->weaponStatus[i].ammo++;
- //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
- if ( parent && parent->client )
- {
- parent->client->ps.ammo[i] = pVeh->weaponStatus[i].ammo;
- }
- }
- }
- for ( i = 0; i < MAX_VEHICLE_TURRETS; i++ )
- {
- if ( pVeh->m_pVehicleInfo->turret[i].iWeapon > VEH_WEAPON_BASE//have a weapon in this slot
- && pVeh->m_pVehicleInfo->turret[i].iAmmoRechargeMS//its ammo is rechargable
- && pVeh->turretStatus[i].ammo < pVeh->m_pVehicleInfo->turret[i].iAmmoMax//its ammo is below max
- && pUmcd->serverTime-pVeh->turretStatus[i].lastAmmoInc >= pVeh->m_pVehicleInfo->turret[i].iAmmoRechargeMS )//enough time has passed
- {//add 1 to the ammo
- pVeh->turretStatus[i].lastAmmoInc = pUmcd->serverTime;
- pVeh->turretStatus[i].ammo++;
- //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
- if ( parent && parent->client )
- {
- parent->client->ps.ammo[MAX_VEHICLE_WEAPONS+i] = pVeh->turretStatus[i].ammo;
- }
- }
- }
- //increment shields for rechargable shields
- if ( pVeh->m_pVehicleInfo->shieldRechargeMS
- && parentPS->stats[STAT_ARMOR] > 0 //still have some shields left
- && parentPS->stats[STAT_ARMOR] < pVeh->m_pVehicleInfo->shields//its below max
- && pUmcd->serverTime-pVeh->lastShieldInc >= pVeh->m_pVehicleInfo->shieldRechargeMS )//enough time has passed
- {
- parentPS->stats[STAT_ARMOR]++;
- if ( parentPS->stats[STAT_ARMOR] > pVeh->m_pVehicleInfo->shields )
- {
- parentPS->stats[STAT_ARMOR] = pVeh->m_pVehicleInfo->shields;
- }
- pVeh->m_iShields = parentPS->stats[STAT_ARMOR];
- #ifdef _JK2MP
- G_VehUpdateShields( parent );
- #endif
- }
- #ifdef _JK2MP //sometimes this gets out of whack, probably init'ing
- if (parent && parent->r.ownerNum != parent->s.owner)
- {
- parent->s.owner = parent->r.ownerNum;
- }
- //keep the PS value in sync. set it up here in case we return below at some point.
- if (pVeh->m_iBoarding)
- {
- parent->client->ps.vehBoarding = qtrue;
- }
- else
- {
- parent->client->ps.vehBoarding = qfalse;
- }
- #endif
- // See whether this vehicle should be dieing or dead.
- if ( pVeh->m_iDieTime != 0
- #ifndef _JK2MP //sometimes this gets out of whack, probably init'ing
- || (parent->health <= 0)
- #endif
- )
- {//NOTE!!!: This HAS to be consistent with cgame!!!
- // Keep track of the old orientation.
- VectorCopy( pVeh->m_vOrientation, pVeh->m_vPrevOrientation );
- // Process the orient commands.
- pVeh->m_pVehicleInfo->ProcessOrientCommands( pVeh );
- // Need to copy orientation to our entity's viewangles so that it renders at the proper angle and currentAngles is correct.
- SetClientViewAngle( parent, pVeh->m_vOrientation );
- if ( pVeh->m_pPilot )
- {
- SetClientViewAngle( (gentity_t *)pVeh->m_pPilot, pVeh->m_vOrientation );
- }
- /*
- for ( i = 0; i < pVeh->m_pVehicleInfo->maxPassengers; i++ )
- {
- if ( pVeh->m_ppPassengers[i] )
- {
- SetClientViewAngle( (gentity_t *)pVeh->m_ppPassengers[i], pVeh->m_vOrientation );
- }
- }
- */
- // Process the move commands.
- pVeh->m_pVehicleInfo->ProcessMoveCommands( pVeh );
- // Setup the move direction.
- if ( pVeh->m_pVehicleInfo->type == VH_FIGHTER )
- {
- AngleVectors( pVeh->m_vOrientation, parent->client->ps.moveDir, NULL, NULL );
- }
- else
- {
- VectorSet(vVehAngles, 0, pVeh->m_vOrientation[YAW], 0);
- AngleVectors( vVehAngles, parent->client->ps.moveDir, NULL, NULL );
- }
- pVeh->m_pVehicleInfo->DeathUpdate( pVeh );
- return false;
- }
- // Vehicle dead!
- #ifdef _JK2MP
- else if ( parent->health <= 0 )
- {
- // Instant kill.
- if (pVeh->m_pVehicleInfo->type == VH_FIGHTER &&
- pVeh->m_iLastImpactDmg > 500)
- { //explode instantly in inferno-y death
- pVeh->m_pVehicleInfo->StartDeathDelay( pVeh, -1/* -1 causes instant death */);
- }
- else
- {
- pVeh->m_pVehicleInfo->StartDeathDelay( pVeh, 0 );
- }
- pVeh->m_pVehicleInfo->DeathUpdate( pVeh );
- return false;
- }
- #endif
-
- #ifdef _JK2MP //special check in case someone disconnects/dies while boarding
- #ifdef QAGAME
- if (parent->spawnflags & 1)
- {
- if (pVeh->m_pPilot || !pVeh->m_bHasHadPilot)
- {
- if (pVeh->m_pPilot && !pVeh->m_bHasHadPilot)
- {
- pVeh->m_bHasHadPilot = qtrue;
- pVeh->m_iPilotLastIndex = pVeh->m_pPilot->s.number;
- }
- pVeh->m_iPilotTime = level.time + parent->damage;
- }
- else if (pVeh->m_iPilotTime)
- { //die
- gentity_t *oldPilot = &g_entities[pVeh->m_iPilotLastIndex];
- if (!oldPilot->inuse || !oldPilot->client ||
- oldPilot->client->pers.connected != CON_CONNECTED)
- { //no longer in the game?
- G_Damage(parent, parent, parent, NULL, parent->client->ps.origin, 99999, DAMAGE_NO_PROTECTION, MOD_SUICIDE);
- }
- else
- {
- vec3_t v;
- VectorSubtract(parent->client->ps.origin, oldPilot->client->ps.origin, v);
- if (VectorLength(v) < parent->speed)
- { //they are still within the minimum distance to their vehicle
- pVeh->m_iPilotTime = level.time + parent->damage;
- }
- else if (pVeh->m_iPilotTime < level.time)
- { //dying time
- G_Damage(parent, parent, parent, NULL, parent->client->ps.origin, 99999, DAMAGE_NO_PROTECTION, MOD_SUICIDE);
- }
- }
- }
- }
- #endif
- #else
- if (parent->spawnflags & 1)
- {//NOTE: in SP, this actually just checks LOS to the Player
- if (pVeh->m_iPilotTime < level.time)
- {//do another check?
- if ( !player || G_ClearLineOfSight(pVeh->m_pParentEntity->currentOrigin, player->currentOrigin, pVeh->m_pParentEntity->s.number, MASK_OPAQUE ) )
- {
- pVeh->m_iPilotTime = level.time + pVeh->m_pParentEntity->endFrame;
- }
- }
- if (pVeh->m_iPilotTime && pVeh->m_iPilotTime < level.time)
- { //die
- //FIXME: does this give proper credit to the enemy who shot you down?
- G_Damage(parent, player, player, NULL, parent->client->ps.origin, 99999, DAMAGE_NO_PROTECTION, MOD_SUICIDE);
- }
- }
- #endif
- #ifndef _JK2MP
- // if (level.time<pVeh->m_iTurboTime || pVeh->m_pVehicleInfo->type==VH_ANIMAL)
- // always knock guys around now...
- {
- vec3_t dir;
- vec3_t projectedPosition;
- VectorCopy(parent->client->ps.velocity, dir);
- VectorMA(parent->currentOrigin, 0.1f, dir, projectedPosition);
- float force = VectorNormalize(dir);
- force /= 10.0f;
- if (force>30.0f)
- {
- trace_t tr;
- G_VehicleTrace(&tr, parent->currentOrigin, parent->mins, parent->maxs, projectedPosition, parent->s.number, CONTENTS_BODY);
- if (tr.fraction<1.0f &&
- !tr.allsolid &&
- !tr.startsolid &&
- tr.entityNum!=ENTITYNUM_NONE &&
- tr.entityNum!=ENTITYNUM_WORLD &&
- (level.time<pVeh->m_iTurboTime || Q_irand(0,3)==0))
- {
- gentity_t* other = &g_entities[tr.entityNum];
- if (other && other->client && !other->s.m_iVehicleNum)
- {
- G_Throw( other, dir, force/10.0f );
- G_Knockdown( other, parent, dir, force, qtrue );
- G_Damage( other, player, player, parent->client->ps.velocity, parent->currentOrigin, force, DAMAGE_NO_ARMOR|DAMAGE_EXTRA_KNOCKBACK, MOD_IMPACT);
- }
- }
- }
- }
- #endif
- #ifdef _JK2MP //special check in case someone disconnects/dies while boarding
- if (pVeh->m_iBoarding != 0)
- {
- pilotEnt = (gentity_t *)pVeh->m_pPilot;
- if (pilotEnt)
- {
- if (!pilotEnt->inuse || !pilotEnt->client || pilotEnt->health <= 0 ||
- pilotEnt->client->pers.connected != CON_CONNECTED)
- {
- pVeh->m_pVehicleInfo->Eject( pVeh, pVeh->m_pPilot, qtrue );
- return false;
- }
- }
- }
- #endif
- // If we're not done mounting, can't do anything.
- if ( pVeh->m_iBoarding != 0 )
- {
- if (!pVeh->m_bWasBoarding)
- {
- VectorCopy(parentPS->velocity, pVeh->m_vBoardingVelocity);
- pVeh->m_bWasBoarding = true;
- }
- // See if we're done boarding.
- if ( pVeh->m_iBoarding > -1 && pVeh->m_iBoarding <= level.time )
- {
- pVeh->m_bWasBoarding = false;
- pVeh->m_iBoarding = 0;
- }
- else
- {
- #ifdef _JK2MP
- goto maintainSelfDuringBoarding;
- #else
- return false;
- #endif
- }
- }
- parent = (gentity_t *)pVeh->m_pParentEntity;
- // Validate vehicle.
- if ( !parent || !parent->client || parent->health <= 0 )
- return false;
- // See if any of the riders are dead and if so kick em off.
- if ( pVeh->m_pPilot )
- {
- pilotEnt = (gentity_t *)pVeh->m_pPilot;
-
- #ifdef _JK2MP
- if (!pilotEnt->inuse || !pilotEnt->client || pilotEnt->health <= 0 ||
- pilotEnt->client->pers.connected != CON_CONNECTED)
- #else
- if (pilotEnt->health <= 0)
- #endif
- {
- pVeh->m_pVehicleInfo->Eject( pVeh, pVeh->m_pPilot, qtrue );
- }
- }
- #ifdef _JK2MP
- // Copy over the commands for local storage.
- memcpy( &parent->client->pers.cmd, &pVeh->m_ucmd, sizeof( usercmd_t ) );
- pVeh->m_ucmd.buttons &= ~(BUTTON_TALK);//|BUTTON_GESTURE); //don't want some of these buttons
- #else
- // Copy over the commands for local storage.
- memcpy( &pVeh->m_ucmd, pUmcd, sizeof( usercmd_t ) );
- memcpy( &parent->client->pers.lastCommand, pUmcd, sizeof( usercmd_t ) );
- #endif
- /*
- // Update time modifier.
- pVeh->m_fTimeModifier = pVeh->m_ucmd.serverTime - parent->client->ps.commandTime;
- //sanity check
- if ( pVeh->m_fTimeModifier < 1 )
- {
- pVeh->m_fTimeModifier = 1;
- }
- else if ( pVeh->m_fTimeModifier > 200 )
- {
- pVeh->m_fTimeModifier = 200;
- }
- //normalize to 1.0f at 20fps
- pVeh->m_fTimeModifier = pVeh->m_fTimeModifier / fMod;
- */
-
- //check for weapon linking/unlinking command
- for ( i = 0; i < MAX_VEHICLE_WEAPONS; i++ )
- {//HMM... can't get a seperate command for each weapon, so do them all...?
- if ( pVeh->m_pVehicleInfo->weapon[i].linkable == 2 )
- {//always linked
- //FIXME: just set this once, on Initialize...?
- if ( !pVeh->weaponStatus[i].linked )
- {
- pVeh->weaponStatus[i].linked = qtrue;
- }
- }
- #ifdef _JK2MP
- else if ( (pVeh->m_ucmd.buttons&BUTTON_USE_HOLDABLE) )
- #else
- //FIXME: implement... just a console command bound to a key?
- else if ( 0 )
- #endif
- {//pilot pressed the "weapon link" toggle button
- playerState_t *pilotPS;
- #ifdef _JK2MP
- bgEntity_t *rider = NULL;
- if (parent->s.owner != ENTITYNUM_NONE)
- {
- rider = PM_BGEntForNum(parent->s.owner); //&g_entities[parent->r.ownerNum];
- }
- pilotPS = rider->playerState;
- #else
- gentity_t *rider = parent->owner;
- pilotPS = &rider->client->ps;
- #endif
- if ( !pVeh->linkWeaponToggleHeld )//so we don't hold it down and toggle it back and forth
- {//okay to toggle
- if ( pVeh->m_pVehicleInfo->weapon[i].linkable == 1 )
- {//link-toggleable
- pVeh->weaponStatus[i].linked = !pVeh->weaponStatus[i].linked;
- }
- }
- linkHeld = qtrue;
- }
- }
- if ( linkHeld )
- {
- //so we don't hold it down and toggle it back and forth
- pVeh->linkWeaponToggleHeld = qtrue;
- }
- else
- {
- //so we don't hold it down and toggle it back and forth
- pVeh->linkWeaponToggleHeld = qfalse;
- }
- #ifdef _JK2MP
- //now pass it over the network so cgame knows about it
- //NOTE: SP can just cheat and check directly
- parentPS->vehWeaponsLinked = qfalse;
- for ( i = 0; i < MAX_VEHICLE_WEAPONS; i++ )
- {//HMM... can't get a seperate command for each weapon, so do them all...?
- if ( pVeh->weaponStatus[i].linked )
- {
- parentPS->vehWeaponsLinked = qtrue;
- }
- }
- #endif
- #ifdef QAGAME
- for ( i = 0; i < MAX_VEHICLE_TURRETS; i++ )
- {//HMM... can't get a seperate command for each weapon, so do them all...?
- VEH_TurretThink( pVeh, parent, i );
- }
- #endif
- #ifdef _JK2MP
- maintainSelfDuringBoarding:
- if (pVeh->m_pPilot && pVeh->m_pPilot->playerState && pVeh->m_iBoarding != 0)
- {
- VectorCopy(pVeh->m_vOrientation, pVeh->m_pPilot->playerState->viewangles);
- pVeh->m_ucmd.buttons = 0;
- pVeh->m_ucmd.forwardmove = 0;
- pVeh->m_ucmd.rightmove = 0;
- pVeh->m_ucmd.upmove = 0;
- }
- #endif
- // Keep track of the old orientation.
- VectorCopy( pVeh->m_vOrientation, pVeh->m_vPrevOrientation );
- // Process the orient commands.
- pVeh->m_pVehicleInfo->ProcessOrientCommands( pVeh );
- // Need to copy orientation to our entity's viewangles so that it renders at the proper angle and currentAngles is correct.
- SetClientViewAngle( parent, pVeh->m_vOrientation );
- if ( pVeh->m_pPilot )
- {
- #ifdef _JK2MP
- if ( !BG_UnrestrainedPitchRoll( pVeh->m_pPilot->playerState, pVeh ) )
- {
- vec3_t newVAngle;
- newVAngle[PITCH] = pVeh->m_pPilot->playerState->viewangles[PITCH];
- newVAngle[YAW] = pVeh->m_pPilot->playerState->viewangles[YAW];
- newVAngle[ROLL] = pVeh->m_vOrientation[ROLL];
- SetClientViewAngle( (gentity_t *)pVeh->m_pPilot, newVAngle );
- }
- #else
- if ( !BG_UnrestrainedPitchRoll( &pVeh->m_pPilot->client->ps, pVeh ) )
- {
- SetClientViewAngle( (gentity_t *)pVeh->m_pPilot, pVeh->m_vOrientation );
- }
- #endif
- }
- /*
- for ( i = 0; i < pVeh->m_pVehicleInfo->maxPassengers; i++ )
- {
- if ( pVeh->m_ppPassengers[i] )
- {
- SetClientViewAngle( (gentity_t *)pVeh->m_ppPassengers[i], pVeh->m_vOrientation );
- }
- }
- */
- // Process the move commands.
- prevSpeed = parentPS->speed;
- pVeh->m_pVehicleInfo->ProcessMoveCommands( pVeh );
- nextSpeed = parentPS->speed;
- halfMaxSpeed = pVeh->m_pVehicleInfo->speedMax*0.5f;
-
- // Shifting Sounds
- //=====================================================================
- if (pVeh->m_iTurboTime<curTime &&
- pVeh->m_iSoundDebounceTimer<curTime &&
- ((nextSpeed>prevSpeed && nextSpeed>halfMaxSpeed && prevSpeed<halfMaxSpeed) || (nextSpeed>halfMaxSpeed && !Q_irand(0,1000)))
- )
- {
- int shiftSound = Q_irand(1,4);
- switch (shiftSound)
- {
- case 1: shiftSound=pVeh->m_pVehicleInfo->soundShift1; break;
- case 2: shiftSound=pVeh->m_pVehicleInfo->soundShift2; break;
- case 3: shiftSound=pVeh->m_pVehicleInfo->soundShift3; break;
- case 4: shiftSound=pVeh->m_pVehicleInfo->soundShift4; break;
- }
- if (shiftSound)
- {
- pVeh->m_iSoundDebounceTimer = curTime + Q_irand(1000, 4000);
- #ifdef _JK2MP
- // TODO: MP Shift Sound Playback
- #else
- // NOTE: Use this type so it's spatialized and updates play origin as bike moves - MCG
- G_SoundIndexOnEnt( pVeh->m_pParentEntity, CHAN_AUTO, shiftSound);
- #endif
- }
- }
- //=====================================================================
- // Setup the move direction.
- if ( pVeh->m_pVehicleInfo->type == VH_FIGHTER )
- {
- AngleVectors( pVeh->m_vOrientation, parent->client->ps.moveDir, NULL, NULL );
- }
- else
- {
- VectorSet(vVehAngles, 0, pVeh->m_vOrientation[YAW], 0);
- AngleVectors( vVehAngles, parent->client->ps.moveDir, NULL, NULL );
- }
- #ifdef _JK2MP
- if (pVeh->m_pVehicleInfo->surfDestruction)
- {
- if (pVeh->m_iRemovedSurfaces)
- {
- gentity_t *killer = parent;
- G_VehicleDamageBoxSizing(pVeh);
- //damage him constantly if any chunks are currently taken off
- if (parent->client->ps.otherKiller < ENTITYNUM_WORLD &&
- parent->client->ps.otherKillerTime > level.time)
- {
- gentity_t *potentialKiller = &g_entities[parent->client->ps.otherKiller];
- if (potentialKiller->inuse && potentialKiller->client)
- { //he's valid I guess
- killer = potentialKiller;
- }
- }
- //FIXME: aside from bypassing shields, maybe set m_iShields to 0, too... ?
- G_Damage(parent, killer, killer, NULL, parent->client->ps.origin, Q_irand(2, 5), DAMAGE_NO_PROTECTION|DAMAGE_NO_ARMOR, MOD_SUICIDE);
- }
-
- //make sure playerstate value stays in sync
- parent->client->ps.vehSurfaces = pVeh->m_iRemovedSurfaces;
- }
- #endif
- #ifdef _JK2MP
- //keep the PS value in sync
- if (pVeh->m_iBoarding)
- {
- parent->client->ps.vehBoarding = qtrue;
- }
- else
- {
- parent->client->ps.vehBoarding = qfalse;
- }
- #endif
- #ifndef _JK2MP
- // Make sure the vehicle takes on the enemy of it's rider (for homing missles for instance).
- if ( pVeh->m_pPilot )
- {
- parent->enemy = pVeh->m_pPilot->enemy;
- }
- #endif
-
- return true;
- }
- // Update the properties of a Rider (that may reflect what happens to the vehicle).
- static bool UpdateRider( Vehicle_t *pVeh, bgEntity_t *pRider, usercmd_t *pUmcd )
- {
- gentity_t *parent;
- gentity_t *rider;
- if ( pVeh->m_iBoarding != 0 && pVeh->m_iDieTime==0)
- return true;
- parent = (gentity_t *)pVeh->m_pParentEntity;
- rider = (gentity_t *)pRider;
- #ifdef _JK2MP
- //MG FIXME !! Single player needs update!
- if ( rider && rider->client
- && parent && parent->client )
- {//so they know who we're locking onto with our rockets, if anyone
- rider->client->ps.rocketLockIndex = parent->client->ps.rocketLockIndex;
- rider->client->ps.rocketLockTime = parent->client->ps.rocketLockTime;
- rider->client->ps.rocketTargetTime = parent->client->ps.rocketTargetTime;
- }
- #endif
- // Regular exit.
- if ( pUmcd->buttons & BUTTON_USE && pVeh->m_pVehicleInfo->type!=VH_SPEEDER)
- {
- if ( pVeh->m_pVehicleInfo->type == VH_WALKER )
- {//just get the fuck out
- pVeh->m_EjectDir = VEH_EJECT_REAR;
- if ( pVeh->m_pVehicleInfo->Eject( pVeh, pRider, qfalse ) )
- return false;
- }
- else if ( !(pVeh->m_ulFlags & VEH_FLYING))
- {
- // If going too fast, roll off.
- if ((parent->client->ps.speed<=600) && pUmcd->rightmove!=0)
- {
- if ( pVeh->m_pVehicleInfo->Eject( pVeh, pRider, qfalse ) )
- {
- animNumber_t Anim;
- int iFlags = SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD | SETANIM_FLAG_HOLDLESS, iBlend = 300;
- if ( pUmcd->rightmove > 0 )
- {
- Anim = BOTH_ROLL_R;
- pVeh->m_EjectDir = VEH_EJECT_RIGHT;
- }
- else
- {
- Anim = BOTH_ROLL_L;
- pVeh->m_EjectDir = VEH_EJECT_LEFT;
- }
- VectorScale( parent->client->ps.velocity, 0.25f, rider->client->ps.velocity );
- #if 1
- Vehicle_SetAnim( rider, SETANIM_BOTH, Anim, iFlags, iBlend );
- #else
- #endif
- //PM_SetAnim(pm,SETANIM_BOTH,anim,SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD|SETANIM_FLAG_HOLDLESS);
- rider->client->ps.weaponTime = rider->client->ps.torsoAnimTimer - 200;//just to make sure it's cleared when roll is done
- G_AddEvent( rider, EV_ROLL, 0 );
- return false;
- }
- }
- else
- {
- // FIXME: Check trace to see if we should start playing the animation.
- animNumber_t Anim;
- int iFlags = SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD, iBlend = 500;
- if ( pUmcd->rightmove > 0 )
- {
- Anim = BOTH_VS_DISMOUNT_R;
- pVeh->m_EjectDir = VEH_EJECT_RIGHT;
- }
- else
- {
- Anim = BOTH_VS_DISMOUNT_L;
- pVeh->m_EjectDir = VEH_EJECT_LEFT;
- }
-
- if ( pVeh->m_iBoarding <= 1 )
- {
- int iAnimLen;
- // NOTE: I know I shouldn't reuse pVeh->m_iBoarding so many times for so many different
- // purposes, but it's not used anywhere else right here so why waste memory???
- #ifdef _JK2MP
- iAnimLen = BG_AnimLength( rider->localAnimIndex, Anim );
- #else
- iAnimLen = PM_AnimLength( pRider->client->clientInfo.animFileIndex, Anim );
- #endif
- pVeh->m_iBoarding = level.time + iAnimLen;
- // Weird huh? Well I wanted to reuse flags and this should never be set in an
- // entity, so what the heck.
- #ifdef _JK2MP
- rider->flags |= FL_VEH_BOARDING;
- #else
- rider->client->ps.eFlags |= EF_VEH_BOARDING;
- #endif
- // Make sure they can't fire when leaving.
- rider->client->ps.weaponTime = iAnimLen;
- }
- VectorScale( parent->client->ps.velocity, 0.25f, rider->client->ps.velocity );
- Vehicle_SetAnim( rider, SETANIM_BOTH, Anim, iFlags, iBlend );
- }
- }
- // Flying, so just fall off.
- else
- {
- pVeh->m_EjectDir = VEH_EJECT_LEFT;
- if ( pVeh->m_pVehicleInfo->Eject( pVeh, pRider, qfalse ) )
- return false;
- }
- }
- // Getting off animation complete (if we had one going)?
- #ifdef _JK2MP
- if ( pVeh->m_iBoarding < level.time && (rider->flags & FL_VEH_BOARDING) )
- {
- rider->flags &= ~FL_VEH_BOARDING;
- #else
- if ( pVeh->m_iBoarding < level.time && (rider->client->ps.eFlags & EF_VEH_BOARDING) )
- {
- rider->client->ps.eFlags &= ~EF_VEH_BOARDING;
- #endif
- // Eject this guy now.
- if ( pVeh->m_pVehicleInfo->Eject( pVeh, pRider, qfalse ) )
- {
- return false;
- }
- }
- if ( pVeh->m_pVehicleInfo->type != VH_FIGHTER
- && pVeh->m_pVehicleInfo->type != VH_WALKER )
- {
- // Jump off.
- if ( pUmcd->upmove > 0 )
- {
- // NOT IN MULTI PLAYER!
- //===================================================================
- #ifndef _JK2MP
- float riderRightDot = G_CanJumpToEnemyVeh(pVeh, pUmcd);
- if (riderRightDot!=0.0f)
- {
- // Eject Player From Current Vehicle
- //-----------------------------------
- pVeh->m_EjectDir = VEH_EJECT_TOP;
- pVeh->m_pVehicleInfo->Eject( pVeh, pRider, qtrue );
- // Send Current Vehicle Spinning Out Of Control
- //----------------------------------------------
- pVeh->m_pVehicleInfo->StartDeathDelay(pVeh, 10000);
- pVeh->m_ulFlags |= (VEH_OUTOFCONTROL);
- VectorScale(pVeh->m_pParentEntity->client->ps.velocity, 1.0f, pVeh->m_pParentEntity->pos3);
- // Todo: Throw Old Vehicle Away From The New Vehicle Some
- //-------------------------------------------------------
- vec3_t toEnemy;
- VectorSubtract(pVeh->m_pParentEntity->currentOrigin, rider->enemy->currentOrigin, toEnemy);
- VectorNormalize(toEnemy);
- G_Throw(pVeh->m_pParentEntity, toEnemy, 50);
- // Start Boarding On Enemy's Vehicle
- //-----------------------------------
- Vehicle_t* enemyVeh = G_IsRidingVehicle(rider->enemy);
- enemyVeh->m_iBoarding = (riderRightDot>0)?(VEH_MOUNT_THROW_RIGHT):(VEH_MOUNT_THROW_LEFT);
- enemyVeh->m_pVehicleInfo->Board(enemyVeh, rider);
- }
- // Don't Jump Off If Holding Strafe Key and Moving Fast
- else if (pUmcd->rightmove && (parent->client->ps.speed>=10))
- {
- return true;
- }
- #endif
- //===================================================================
- if ( pVeh->m_pVehicleInfo->Eject( pVeh, pRider, qfalse ) )
- {
- // Allow them to force jump off.
- VectorScale( parent->client->ps.velocity, 0.5f, rider->client->ps.velocity );
- rider->client->ps.velocity[2] += JUMP_VELOCITY;
- #ifdef _JK2MP
- rider->client->ps.fd.forceJumpZStart = rider->client->ps.origin[2];
- if (!trap_ICARUS_TaskIDPending(rider, TID_CHAN_VOICE))
- #else
- rider->client->ps.pm_flags |= ( PMF_JUMPING | PMF_JUMP_HELD );
- rider->client->ps.forceJumpZStart = rider->client->ps.origin[2];
- if ( !Q3_TaskIDPending( rider, TID_CHAN_VOICE ) )
- #endif
- {
- G_AddEvent( rider, EV_JUMP, 0 );
- }
- #if 1
- Vehicle_SetAnim( rider, SETANIM_BOTH, BOTH_JUMP1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD, 300 );
- // Force first person mode when exiting the vehicle
- // If you're carrying a saber, it will get reset later
- extern void Cvar_SetValue(const char *var_name, float value);
- Cvar_SetValue("cg_thirdPerson", 0);
- #else
- #endif
- return false;
- }
- }
- // Roll off.
- #ifdef _JK2MP
- if ( pUmcd->upmove < 0 )
- {
- animNumber_t Anim = BOTH_ROLL_B;
- pVeh->m_EjectDir = VEH_EJECT_REAR;
- if ( pUmcd->rightmove > 0 )
- {
- Anim = BOTH_ROLL_R;
- pVeh->m_EjectDir = VEH_EJECT_RIGHT;
- }
- else if ( pUmcd->rightmove < 0 )
- {
- Anim = BOTH_ROLL_L;
- pVeh->m_EjectDir = VEH_EJECT_LEFT;
- }
- else if ( pUmcd->forwardmove < 0 )
- {
- Anim = BOTH_ROLL_B;
- pVeh->m_EjectDir = VEH_EJECT_REAR;
- }
- else if ( pUmcd->forwardmove > 0 )
- {
- Anim = BOTH_ROLL_F;
- pVeh->m_EjectDir = VEH_EJECT_FRONT;
- }
- if ( pVeh->m_pVehicleInfo->Eject( pVeh, pRider, qfalse ) )
- {
- if ( !(pVeh->m_ulFlags & VEH_FLYING) )
- {
- VectorScale( parent->client->ps.velocity, 0.25f, rider->client->ps.velocity );
- #if 1
- Vehicle_SetAnim( rider, SETANIM_BOTH, Anim, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD | SETANIM_FLAG_HOLDLESS, 300 );
- #else
- #endif
- //PM_SetAnim(pm,SETANIM_BOTH,anim,SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD|SETANIM_FLAG_HOLDLESS);
- rider->client->ps.weaponTime = rider->client->ps.torsoAnimTimer - 200;//just to make sure it's cleared when roll is done
- G_AddEvent( rider, EV_ROLL, 0 );
- }
- return false;
- }
- }
- #endif
- }
- return true;
- }
- #ifdef _JK2MP //we want access to this one clientside, but it's the only
- //generic vehicle function we care about over there
- #include "../namespace_begin.h"
- extern void AttachRidersGeneric( Vehicle_t *pVeh );
- #include "../namespace_end.h"
- #endif
- // Attachs all the riders of this vehicle to their appropriate tag (*driver, *pass1, *pass2, whatever...).
- static void AttachRiders( Vehicle_t *pVeh )
- {
- #ifdef _JK2MP
- int i = 0;
- AttachRidersGeneric(pVeh);
- if (pVeh->m_pPilot)
- {
- gentity_t *parent = (gentity_t *)pVeh->m_pParentEntity;
- gentity_t *pilot = (gentity_t *)pVeh->m_pPilot;
- pilot->waypoint = parent->waypoint; // take the veh's waypoint as your own
- //assuming we updated him relative to the bolt in AttachRidersGeneric
- G_SetOrigin( pilot, pilot->client->ps.origin );
- trap_LinkEntity( pilot );
- }
- if (pVeh->m_pOldPilot)
- {
- gentity_t *parent = (gentity_t *)pVeh->m_pParentEntity;
- gentity_t *oldpilot = (gentity_t *)pVeh->m_pOldPilot;
- oldpilot->waypoint = parent->waypoint; // take the veh's waypoint as your own
- //assuming we updated him relative to the bolt in AttachRidersGeneric
- G_SetOrigin( oldpilot, oldpilot->client->ps.origin );
- trap_LinkEntity( oldpilot );
- }
- //attach passengers
- while (i < pVeh->m_iNumPassengers)
- {
- if (pVeh->m_ppPassengers[i])
- {
- mdxaBone_t boltMatrix;
- vec3_t yawOnlyAngles;
- gentity_t *parent = (gentity_t *)pVeh->m_pParentEntity;
- gentity_t *pilot = (gentity_t *)pVeh->m_ppPassengers[i];
- int crotchBolt;
- assert(parent->ghoul2);
- crotchBolt = trap_G2API_AddBolt(parent->ghoul2, 0, "*driver");
- assert(parent->client);
- assert(pilot->client);
- VectorSet(yawOnlyAngles, 0, parent->client->ps.viewangles[YAW], 0);
- // Get the driver tag.
- trap_G2API_GetBoltMatrix( parent->ghoul2, 0, crotchBolt, &boltMatrix,
- yawOnlyAngles, parent->client->ps.origin,
- level.time, NULL, parent->modelScale );
- BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, pilot->client->ps.origin );
- G_SetOrigin( pilot, pilot->client->ps.origin );
- trap_LinkEntity( pilot );
- }
- i++;
- }
- //attach droid
- if (pVeh->m_pDroidUnit
- && pVeh->m_iDroidUnitTag != -1)
- {
- mdxaBone_t boltMatrix;
- vec3_t yawOnlyAngles, fwd;
- gentity_t *parent = (gentity_t *)pVeh->m_pParentEntity;
- gentity_t *droid = (gentity_t *)pVeh->m_pDroidUnit;
- assert(parent->ghoul2);
- assert(parent->client);
- //assert(droid->client);
- if ( droid->client )
- {
- VectorSet(yawOnlyAngles, 0, parent->client->ps.viewangles[YAW], 0);
- // Get the droid tag.
- trap_G2API_GetBoltMatrix( parent->ghoul2, 0, pVeh->m_iDroidUnitTag, &boltMatrix,
- yawOnlyAngles, parent->currentOrigin,
- level.time, NULL, parent->modelScale );
- BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, droid->client->ps.origin );
- BG_GiveMeVectorFromMatrix( &boltMatrix, NEGATIVE_Y, fwd );
- vectoangles( fwd, droid->client->ps.viewangles );
- G_SetOrigin( droid, droid->client->ps.origin );
- G_SetAngles( droid, droid->client->ps.viewangles);
- SetClientViewAngle( droid, droid->client->ps.viewangles );
- trap_LinkEntity( droid );
- if ( droid->NPC )
- {
- NPC_SetAnim( droid, SETANIM_BOTH, BOTH_STAND2, (SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD) );
- droid->client->ps.legsTimer = 500;
- droid->client->ps.torsoTimer = 500;
- }
- }
- }
- #else
- // If we have a pilot, attach him to the driver tag.
- if ( pVeh->m_pPilot )
- {
- gentity_t * const parent = pVeh->m_pParentEntity;
- gentity_t * const pilot = pVeh->m_pPilot;
- mdxaBone_t boltMatrix;
- pilot->waypoint = parent->waypoint; // take the veh's waypoint as your own
- // Get the driver tag.
- gi.G2API_GetBoltMatrix( parent->ghoul2, parent->playerModel, parent->crotchBolt, &boltMatrix,
- pVeh->m_vOrientation, parent->currentOrigin,
- (cg.time?cg.time:level.time), NULL, parent->s.modelScale );
- gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, pilot->client->ps.origin );
- G_SetOrigin( pilot, pilot->client->ps.origin );
- gi.linkentity( pilot );
- }
- // If we have a pilot, attach him to the driver tag.
- if ( pVeh->m_pOldPilot )
- {
- gentity_t * const parent = pVeh->m_pParentEntity;
- gentity_t * const pilot = pVeh->m_pOldPilot;
- mdxaBone_t boltMatrix;
- pilot->waypoint = parent->waypoint; // take the veh's waypoint as your own
- // Get the driver tag.
- gi.G2API_GetBoltMatrix( parent->ghoul2, parent->playerModel, parent->crotchBolt, &boltMatrix,
- pVeh->m_vOrientation, parent->currentOrigin,
- (cg.time?cg.time:level.time), NULL, parent->s.modelScale );
- gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, pilot->client->ps.origin );
- G_SetOrigin( pilot, pilot->client->ps.origin );
- gi.linkentity( pilot );
- }
- #endif
- }
- // Make someone invisible and un-collidable.
- static void Ghost( Vehicle_t *pVeh, bgEntity_t *pEnt )
- {
- gentity_t *ent;
- if ( !pEnt )
- return;
- ent = (gentity_t *)pEnt;
- ent->s.eFlags |= EF_NODRAW;
- if ( ent->client )
- {
- ent->client->ps.eFlags |= EF_NODRAW;
- }
- #ifdef _JK2MP
- ent->r.contents = 0;
- #else
- ent->contents = 0;
- #endif
- }
- // Make someone visible and collidable.
- static void UnGhost( Vehicle_t *pVeh, bgEntity_t *pEnt )
- {
- gentity_t *ent;
- if ( !pEnt )
- return;
- ent = (gentity_t *)pEnt;
- ent->s.eFlags &= ~EF_NODRAW;
- if ( ent->client )
- {
- ent->client->ps.eFlags &= ~EF_NODRAW;
- }
- #ifdef _JK2MP
- ent->r.contents = CONTENTS_BODY;
- #else
- ent->contents = CONTENTS_BODY;
- #endif
- }
- #ifdef _JK2MP
- //try to resize the bounding box around a torn apart ship
- void G_VehicleDamageBoxSizing(Vehicle_t *pVeh)
- {
- vec3_t fwd, right, up;
- vec3_t nose; //maxs
- vec3_t back; //mins
- trace_t trace;
- const float fDist = 256.0f; //estimated distance to nose from origin
- const float bDist = 256.0f; //estimated distance to back from origin
- const float wDist = 32.0f; //width on each side from origin
- const float hDist = 32.0f; //height on each side from origin
- gentity_t *parent = (gentity_t *)pVeh->m_pParentEntity;
- if (!parent->ghoul2 || !parent->m_pVehicle || !parent->client)
- { //shouldn't have gotten in here then
- return;
- }
- //for now, let's only do anything if all wings are stripped off.
- //this is because I want to be able to tear my wings off and fling
- //myself down narrow hallways to my death. Because it's fun! -rww
- if (!(pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_C) ||
- !(pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_D) ||
- !(pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_E) ||
- !(pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_F) )
- {
- return;
- }
- //get directions based on orientation
- AngleVectors(pVeh->m_vOrientation, fwd, right, up);
- //get the nose and back positions (relative to 0, they're gonna be mins/maxs)
- VectorMA(vec3_origin, fDist, fwd, nose);
- VectorMA(vec3_origin, -bDist, fwd, back);
- //move the nose and back to opposite right/left, they will end up as our relative mins and maxs
- VectorMA(nose, wDist, right, nose);
- VectorMA(nose, -wDist, right, back);
- //use the same concept for up/down now
- VectorMA(nose, hDist, up, nose);
- VectorMA(nose, -hDist, up, back);
- //and now, let's trace and see if our new mins/maxs are safe..
- trap_Trace(&trace, parent->client->ps.origin, back, nose, parent->client->ps.origin, parent->s.number, parent->clipmask);
- if (!trace.allsolid && !trace.startsolid && trace.fraction == 1.0f)
- { //all clear!
- VectorCopy(nose, parent->maxs);
- VectorCopy(back, parent->mins);
- }
- else
- { //oh well, DIE!
- //FIXME: does this give proper credit to the enemy who shot you down?
- G_Damage(parent, parent, parent, NULL, parent->client->ps.origin, 9999, DAMAGE_NO_PROTECTION, MOD_SUICIDE);
- }
- }
- //get one of 4 possible impact locations based on the trace direction
- int G_FlyVehicleImpactDir(gentity_t *veh, trace_t *trace)
- {
- float impactAngle;
- float relativeAngle;
- trace_t localTrace;
- vec3_t testMins, testMaxs;
- vec3_t rWing, lWing;
- vec3_t fwd, right;
- vec3_t fPos;
- Vehicle_t *pVeh = veh->m_pVehicle;
- qboolean noseClear = qfalse;
- if (!trace || !pVeh || !veh->client)
- {
- return -1;
- }
- AngleVectors(veh->client->ps.viewangles, fwd, right, 0);
- VectorSet(testMins, -24.0f, -24.0f, -24.0f);
- VectorSet(testMaxs, 24.0f, 24.0f, 24.0f);
- //do a trace to determine if the nose is clear
- VectorMA(veh->client->ps.origin, 256.0f, fwd, fPos);
- trap_Trace(&localTrace, veh->client->ps.origin, testMins, testMaxs, fPos, veh->s.number, veh->clipmask);
- if (!localTrace.startsolid && !localTrace.allsolid && localTrace.fraction == 1.0f)
- { //otherwise I guess it's not clear..
- noseClear = qtrue;
- }
- if (noseClear)
- { //if nose is clear check for tearing the wings off
- //sadly, the trace endpos given always matches the vehicle origin, so we
- //can't get a real impact direction. First we'll trace forward and see if the wings are colliding
- //with anything, and if not, we'll fall back to checking the trace plane normal.
- VectorMA(veh->client->ps.origin, 128.0f, right, rWing);
- VectorMA(veh->client->ps.origin, -128.0f, right, lWing);
- //test the right wing - unless it's already removed
- if (!(pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_E) ||
- !(pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_F))
- {
- VectorMA(rWing, 256.0f, fwd, fPos);
- trap_Trace(&localTrace, rWing, testMins, testMaxs, fPos, veh->s.number, veh->clipmask);
- if (localTrace.startsolid || localTrace.allsolid || localTrace.fraction != 1.0f)
- { //impact
- return SHIPSURF_RIGHT;
- }
- }
- //test the left wing - unless it's already removed
- if (!(pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_C) ||
- !(pVeh->m_iRemovedSurfaces & SHIPSURF_BROKEN_D))
- {
- VectorMA(lWing, 256.0f, fwd, fPos);
- trap_Trace(&localTrace, lWing, testMins, testMaxs, fPos, veh->s.number, veh->clipmask);
- if (localTrace.startsolid || localTrace.allsolid || localTrace.fraction != 1.0f)
- { //impact
- return SHIPSURF_LEFT;
- }
- }
- }
- //try to use the trace plane normal
- impactAngle = vectoyaw(trace->plane.normal);
- relativeAngle = AngleSubtract(impactAngle, veh->client->ps.viewangles[YAW]);
- if (relativeAngle > 130 ||
- relativeAngle < -130)
- { //consider this front
- return SHIPSURF_FRONT;
- }
- else if (relativeAngle > 0)
- {
- return SHIPSURF_RIGHT;
- }
- else if (relativeAngle < 0)
- {
- return SHIPSURF_LEFT;
- }
- return SHIPSURF_BACK;
- }
- //try to break surfaces off the ship on impact
- #define TURN_ON 0x00000000
- #define TURN_OFF 0x00000100
- extern void NPC_SetSurfaceOnOff(gentity_t *ent, const char *surfaceName, int surfaceFlags); //NPC_utils.c
- int G_ShipSurfaceForSurfName( const char *surfaceName )
- {
- if ( !surfaceName )
- {
- return -1;
- }
- if ( !Q_strncmp( "nose", surfaceName, 4 )
- || !Q_strncmp( "f_gear", surfaceName, 6 )
- || !Q_strncmp( "glass", surfaceName, 5 ) )
- {
- return SHIPSURF_FRONT;
- }
- if ( !Q_strncmp( "body", surfaceName, 4 ) )
- {
- return SHIPSURF_BACK;
- }
- if ( !Q_strncmp( "r_wing1", surfaceName, 7 )
- || !Q_strncmp( "r_wing2", surfaceName, 7 )
- || !Q_strncmp( "r_gear", surfaceName, 6 ) )
- {
- return SHIPSURF_RIGHT;
- }
- if ( !Q_strncmp( "l_wing1", surfaceName, 7 )
- || !Q_strncmp( "l_wing2", surfaceName, 7 )
- || !Q_strncmp( "l_gear", surfaceName, 6 ) )
- {
- return SHIPSURF_LEFT;
- }
- return -1;
- }
- void G_SetVehDamageFlags( gentity_t *veh, int shipSurf, int damageLevel )
- {
- int dmgFlag;
- switch ( damageLevel )
- {
- case 3://destroyed
- //add both flags so cgame side knows this surf is GONE
- //add heavy
- dmgFlag = SHIPSURF_DAMAGE_FRONT_HEAVY+(shipSurf-SHIPSURF_FRONT);
- veh->client->ps.brokenLimbs |= (1<<dmgFlag);
- //add light
- dmgFlag = SHIPSURF_DAMAGE_FRONT_LIGHT+(shipSurf-SHIPSURF_FRONT);
- veh->client->ps.brokenLimbs |= (1<<dmgFlag);
- //copy down
- veh->s.brokenLimbs = veh->client->ps.brokenLimbs;
- //check droid
- if ( shipSurf == SHIPSURF_BACK )
- {//destroy the droid if we have one
- if ( veh->m_pVehicle
- && veh->m_pVehicle->m_pDroidUnit )
- {//we have one
- gentity_t *droidEnt = (gentity_t *)veh->m_pVehicle->m_pDroidUnit;
- if ( droidEnt
- && ((droidEnt->flags&FL_UNDYING) || droidEnt->health > 0) )
- {//boom
- //make it vulnerable
- droidEnt->flags &= ~FL_UNDYING;
- //blow it up
- G_Damage( droidEnt, veh->enemy, veh->enemy, NULL, NULL, 99999, 0, MOD_UNKNOWN );
- }
- }
- }
- break;
- case 2://heavy only
- dmgFlag = SHIPSURF_DAMAGE_FRONT_HEAVY+(shipSurf-SHIPSURF_FRONT);
- veh->client->ps.brokenLimbs |= (1<<dmgFlag);
- //remove light
- dmgFlag = SHIPSURF_DAMAGE_FRONT_LIGHT+(shipSurf-SHIPSURF_FRONT);
- veh->client->ps.brokenLimbs &= ~(1<<dmgFlag);
- //copy down
- veh->s.brokenLimbs = veh->client->ps.brokenLimbs;
- //check droid
- if ( shipSurf == SHIPSURF_BACK )
- {//make the droid vulnerable if we have one
- if ( veh->m_pVehicle
- && veh->m_pVehicle->m_pDroidUnit )
- {//we have one
- gentity_t *droidEnt = (gentity_t *)veh->m_pVehicle->m_pDroidUnit;
- if ( droidEnt
- && (droidEnt->flags&FL_UNDYING) )
- {//make it vulnerab;e
- droidEnt->flags &= ~FL_UNDYING;
- }
- }
- }
- break;
- case 1://light only
- //add light
- dmgFlag = SHIPSURF_DAMAGE_FRONT_LIGHT+(shipSurf-SHIPSURF_FRONT);
- veh->client->ps.brokenLimbs |= (1<<dmgFlag);
- //remove heavy (shouldn't have to do this, but...
- dmgFlag = SHIPSURF_DAMAGE_FRONT_HEAVY+(shipSurf-SHIPSURF_FRONT);
- veh->client->ps.brokenLimbs &= ~(1<<dmgFlag);
- //copy down
- veh->s.brokenLimbs = veh->client->ps.brokenLimbs;
- break;
- case 0://no damage
- default:
- //remove heavy
- dmgFlag = SHIPSURF_DAMAGE_FRONT_HEAVY+(shipSurf-SHIPSURF_FRONT);
- veh->client->ps.brokenLimbs &= ~(1<<dmgFlag);
- //remove light
- dmgFlag = SHIPSURF_DAMAGE_FRONT_LIGHT+(shipSurf-SHIPSURF_FRONT);
- veh->client->ps.brokenLimbs &= ~(1<<dmgFlag);
- //copy down
- veh->s.brokenLimbs = veh->client->ps.brokenLimbs;
- break;
- }
- }
- void G_VehicleSetDamageLocFlags( gentity_t *veh, int impactDir, int deathPoint )
- {
- if ( !veh->client )
- {
- return;
- }
- else
- {
- int deathPoint, heavyDamagePoint, lightDamagePoint;
- switch(impactDir)
- {
- case SHIPSURF_FRONT:
- deathPoint = veh->m_pVehicle->m_pVehicleInfo->health_front;
- break;
- case SHIPSURF_BACK:
- deathPoint = veh->m_pVehicle->m_pVehicleInfo->health_back;
- break;
- case SHIPSURF_RIGHT:
- deathPoint = veh->m_pVehicle->m_pVehicleInfo->health_right;
- break;
- case SHIPSURF_LEFT:
- deathPoint = veh->m_pVehicle->m_pVehicleInfo->health_left;
- break;
- default:
- return;
- break;
- }
- if ( veh->m_pVehicle
- && veh->m_pVehicle->m_pVehicleInfo
- && veh->m_pVehicle->m_pVehicleInfo->malfunctionArmorLevel
- && veh->m_pVehicle->m_pVehicleInfo->armor )
- {
- float perc = ((float)veh->m_pVehicle->m_pVehicleInfo->malfunctionArmorLevel/(float)veh->m_pVehicle->m_pVehicleInfo->armor);
- if ( perc > 0.99f )
- {
- perc = 0.99f;
- }
- heavyDamagePoint = ceil( deathPoint*perc*0.25f );
- lightDamagePoint = ceil( deathPoint*perc );
- }
- else
- {
- heavyDamagePoint = ceil( deathPoint*0.66f );
- lightDamagePoint = ceil( deathPoint*0.14f );
- }
- if ( veh->locationDamage[impactDir] >= deathPoint)
- {//destroyed
- G_SetVehDamageFlags( veh, impactDir, 3 );
- }
- else if ( veh->locationDamage[impactDir] <= heavyDamagePoint )
- {//heavy only
- G_SetVehDamageFlags( veh, impactDir, 2 );
- }
- else if ( veh->locationDamage[impactDir] <= lightDamagePoint )
- {//light only
- G_SetVehDamageFlags( veh, impactDir, 1 );
- }
- }
- }
- qboolean G_FlyVehicleDestroySurface( gentity_t *veh, int surface )
- {
- char *surfName[4]; //up to 4 surfs at once
- int numSurfs = 0;
- int smashedBits = 0;
- if (surface == -1)
- { //not valid?
- return qfalse;
- }
- switch(surface)
- {
- case SHIPSURF_FRONT: //break the nose off
- surfName[0] = "nose";
- smashedBits = (SHIPSURF_BROKEN_G);
- numSurfs = 1;
- break;
- case SHIPSURF_BACK: //break both the bottom wings off for a backward impact I guess
- surfName[0] = "r_wing2";
- surfName[1] = "l_wing2";
- //get rid of the landing gear
- surfName[2] = "r_gear";
- surfName[3] = "l_gear";
- smashedBits = (SHIPSURF_BROKEN_A|SHIPSURF_BROKEN_B|SHIPSURF_BROKEN_D|SHIPSURF_BROKEN_F);
- numSurfs = 4;
- break;
- case SHIPSURF_RIGHT: //break both right wings off
- surfName[0] = "r_wing1";
- surfName[1] = "r_wing2";
- //get rid of the landing gear
- surfName[2] = "r_gear";
- smashedBits = (SHIPSURF_BROKEN_B|SHIPSURF_BROKEN_E|SHIPSURF_BROKEN_F);
- numSurfs = 3;
- break;
- case SHIPSURF_LEFT: //break both left wings off
- surfName[0] = "l_wing1";
- surfName[1] = "l_wing2";
- //get rid of the landing gear
- surfName[2] = "l_gear";
- smashedBits = (SHIPSURF_BROKEN_A|SHIPSURF_BROKEN_C|SHIPSURF_BROKEN_D);
- numSurfs = 3;
- break;
- default:
- break;
- }
- if (numSurfs < 1)
- { //didn't get any valid surfs..
- return qfalse;
- }
- while (numSurfs > 0)
- { //use my silly system of automatically managing surf status on both client and server
- numSurfs--;
- NPC_SetSurfaceOnOff(veh, surfName[numSurfs], TURN_OFF);
- }
- if ( !veh->m_pVehicle->m_iRemovedSurfaces )
- {//first time something got blown off
- if ( veh->m_pVehicle->m_pPilot )
- {//make the pilot scream to his death
- G_EntitySound((gentity_t*)veh->m_pVehicle->m_pPilot, CHAN_VOICE, G_SoundIndex("*falling1.wav"));
- }
- }
- //so we can check what's broken
- veh->m_pVehicle->m_iRemovedSurfaces |= smashedBits;
- //do some explosive damage, but don't damage this ship with it
- G_RadiusDamage(veh->client->ps.origin, veh, 100, 500, veh, NULL, MOD_SUICIDE);
- //when spiraling to your death, do the electical shader
- veh->client->ps.electrifyTime = level.time + 10000;
- return qtrue;
- }
- void G_FlyVehicleSurfaceDestruction(gentity_t *veh, trace_t *trace, int magnitude, qboolean force)
- {
- int impactDir;
- int secondImpact;
- int deathPoint = -1;
- qboolean alreadyRebroken = qfalse;
- if (!veh->ghoul2 || !veh->m_pVehicle)
- { //no g2 instance.. or no vehicle instance
- return;
- }
- impactDir = G_FlyVehicleImpactDir(veh, trace);
- anotherImpact:
- if (impactDir == -1)
- { //not valid?
- return;
- }
- veh->locationDamage[impactDir] += magnitude*7;
- switch(impactDir)
- {
- case SHIPSURF_FRONT:
- deathPoint = veh->m_pVehicle->m_pVehicleInfo->health_front;
- break;
- case SHIPSURF_BACK:
- deathPoint = veh->m_pVehicle->m_pVehicleInfo->health_back;
- break;
- case SHIPSURF_RIGHT:
- deathPoint = veh->m_pVehicle->m_pVehicleInfo->health_right;
- break;
- case SHIPSURF_LEFT:
- deathPoint = veh->m_pVehicle->m_pVehicleInfo->health_left;
- break;
- default:
- break;
- }
- if ( deathPoint != -1 )
- {//got a valid health value
- if ( force && veh->locationDamage[impactDir] < deathPoint )
- {//force that surf to be destroyed
- veh->locationDamage[impactDir] = deathPoint;
- }
- if ( veh->locationDamage[impactDir] >= deathPoint)
- { //do it
- if ( G_FlyVehicleDestroySurface( veh, impactDir ) )
- {//actually took off a surface
- G_VehicleSetDamageLocFlags( veh, impactDir, deathPoint );
- }
- }
- else
- {
- G_VehicleSetDamageLocFlags( veh, impactDir, deathPoint );
- }
- }
- if (!alreadyRebroken)
- {
- secondImpact = G_FlyVehicleImpactDir(veh, trace);
- if (impactDir != secondImpact)
- { //can break off another piece in this same impact.. but only break off up to 2 at once
- alreadyRebroken = qtrue;
- impactDir = secondImpact;
- goto anotherImpact;
- }
- }
- }
- void G_VehUpdateShields( gentity_t *targ )
- {
- if ( !targ || !targ->client
- || !targ->m_pVehicle || !targ->m_pVehicle->m_pVehicleInfo )
- {
- return;
- }
- if ( targ->m_pVehicle->m_pVehicleInfo->shields <= 0 )
- {//doesn't have shields, so don't have to send it
- return;
- }
- targ->client->ps.activeForcePass = floor(((float)targ->m_pVehicle->m_iShields/(float)targ->m_pVehicle->m_pVehicleInfo->shields)*10.0f);
- }
- #endif
- // Set the parent entity of this Vehicle NPC.
- GAME_INLINE void SetParent( Vehicle_t *pVeh, bgEntity_t *pParentEntity ) { pVeh->m_pParentEntity = pParentEntity; }
- // Add a pilot to the vehicle.
- GAME_INLINE void SetPilot( Vehicle_t *pVeh, bgEntity_t *pPilot ) { pVeh->m_pPilot = pPilot; }
- // Add a passenger to the vehicle (false if we're full).
- GAME_INLINE bool AddPassenger( Vehicle_t *pVeh ) { return false; }
- // Whether this vehicle is currently inhabited (by anyone) or not.
- GAME_INLINE bool Inhabited( Vehicle_t *pVeh ) { return ( pVeh->m_pPilot ) ? true : false; }
- // Setup the shared functions (one's that all vehicles would generally use).
- void G_SetSharedVehicleFunctions( vehicleInfo_t *pVehInfo )
- {
- // pVehInfo->AnimateVehicle = AnimateVehicle;
- // pVehInfo->AnimateRiders = AnimateRiders;
- pVehInfo->ValidateBoard = ValidateBoard;
- pVehInfo->SetParent = SetParent;
- pVehInfo->SetPilot = SetPilot;
- pVehInfo->AddPassenger = AddPassenger;
- pVehInfo->Animate = Animate;
- pVehInfo->Board = Board;
- pVehInfo->Eject = Eject;
- pVehInfo->EjectAll = EjectAll;
- pVehInfo->StartDeathDelay = StartDeathDelay;
- pVehInfo->DeathUpdate = DeathUpdate;
- pVehInfo->RegisterAssets = RegisterAssets;
- pVehInfo->Initialize = Initialize;
- pVehInfo->Update = Update;
- pVehInfo->UpdateRider = UpdateRider;
- // pVehInfo->ProcessMoveCommands = ProcessMoveCommands;
- // pVehInfo->ProcessOrientCommands = ProcessOrientCommands;
- pVehInfo->AttachRiders = AttachRiders;
- pVehInfo->Ghost = Ghost;
- pVehInfo->UnGhost = UnGhost;
- pVehInfo->Inhabited = Inhabited;
- }
- #ifdef _JK2MP
- //get rid of all the crazy defs we added for this file
- #undef currentAngles
- #undef currentOrigin
- #undef mins
- #undef maxs
- #undef legsAnimTimer
- #undef torsoAnimTimer
- #undef bool
- #undef false
- #undef true
- #undef sqrtf
- #undef MOD_EXPLOSIVE
- #endif
|