123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191 |
- // leave this line at the top for all g_xxxx.cpp files...
- #include "g_headers.h"
- //seems to be a compiler bug, it doesn't clean out the #ifdefs between dif-compiles
- //or something, so the headers spew errors on these defs from the previous compile.
- //this fixes that. -rww
- #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 Q_flrand
- #undef MOD_EXPLOSIVE
- #endif
- #ifdef _JK2 //SP does not have this preprocessor for game like MP does
- #ifndef _JK2MP
- #define _JK2MP
- #endif
- #endif
- #ifndef _JK2MP //if single player
- #ifndef QAGAME //I don't think we have a QAGAME define
- #define QAGAME //but define it cause in sp we're always in the game
- #endif
- #endif
- #ifdef QAGAME //including game headers on cgame is FORBIDDEN ^_^
- #include "g_local.h"
- #elif defined _JK2MP
- #include "bg_public.h"
- #endif
- #ifndef _JK2MP
- #include "g_functions.h"
- #include "g_vehicles.h"
- #include "..\game\wp_saber.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 Q_flrand flrand
- #define MOD_EXPLOSIVE MOD_SUICIDE
- #else
- #define bgEntity_t gentity_t
- extern void NPC_SetAnim(gentity_t *ent,int setAnimParts,int anim,int setAnimFlags, int iBlend);
- #endif
- extern float DotToSpot( vec3_t spot, vec3_t from, vec3_t fromAngles );
- #ifdef QAGAME //SP or gameside MP
- extern vmCvar_t cg_thirdPersonAlpha;
- extern vec3_t playerMins;
- extern vec3_t playerMaxs;
- extern cvar_t *g_speederControlScheme;
- extern void ChangeWeapon( gentity_t *ent, int newWeapon );
- extern void PM_SetAnim(pmove_t *pm,int setAnimParts,int anim,int setAnimFlags, int blendTime);
- extern int PM_AnimLength( int index, animNumber_t anim );
- #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 int BG_GetTime(void);
- #endif
- //Alright, actually, most of this file is shared between game and cgame for MP.
- //I would like to keep it this way, so when modifying for SP please keep in
- //mind the bgEntity restrictions imposed. -rww
- #define STRAFERAM_DURATION 8
- #define STRAFERAM_ANGLE 8
- #ifndef _JK2MP
- bool VEH_StartStrafeRam(Vehicle_t *pVeh, bool Right)
- {
- if (!(pVeh->m_ulFlags&VEH_STRAFERAM))
- {
- float speed = VectorLength(pVeh->m_pParentEntity->client->ps.velocity);
- if (speed>400.0f)
- {
- // Compute Pos3
- //--------------
- vec3_t right;
- AngleVectors(pVeh->m_vOrientation, 0, right, 0);
- VectorMA(pVeh->m_pParentEntity->client->ps.velocity, (Right)?( speed):(-speed), right, pVeh->m_pParentEntity->pos3);
- pVeh->m_ulFlags |= VEH_STRAFERAM;
- pVeh->m_fStrafeTime = (Right)?(STRAFERAM_DURATION):(-STRAFERAM_DURATION);
- if (pVeh->m_iSoundDebounceTimer<level.time && Q_irand(0,1)==0)
- {
- 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 = level.time + Q_irand(1000, 4000);
- G_SoundIndexOnEnt( pVeh->m_pParentEntity, CHAN_AUTO, shiftSound);
- }
- }
- return true;
- }
- }
- return false;
- }
- #else
- bool VEH_StartStrafeRam(Vehicle_t *pVeh, bool Right, int Duration)
- {
- return false;
- }
- #endif
- #ifdef QAGAME //game-only.. for now
- // Like a think or move command, this updates various vehicle properties.
- bool Update( Vehicle_t *pVeh, const usercmd_t *pUcmd )
- {
- if ( !g_vehicleInfo[VEHICLE_BASE].Update( pVeh, pUcmd ) )
- {
- return false;
- }
- // See whether this vehicle should be exploding.
- if ( pVeh->m_iDieTime != 0 )
- {
- pVeh->m_pVehicleInfo->DeathUpdate( pVeh );
- }
- // Update move direction.
- #ifndef _JK2MP //this makes prediction unhappy, and rightfully so.
- gentity_t *parent = (gentity_t *)pVeh->m_pParentEntity;
- if ( pVeh->m_ulFlags & VEH_FLYING )
- {
- vec3_t vVehAngles;
- VectorSet(vVehAngles, 0, pVeh->m_vOrientation[YAW], 0 );
- AngleVectors( vVehAngles, parent->client->ps.moveDir, NULL, NULL );
- }
- else
- {
- vec3_t vVehAngles;
- VectorSet(vVehAngles, pVeh->m_vOrientation[PITCH], pVeh->m_vOrientation[YAW], 0 );
- AngleVectors( vVehAngles, parent->client->ps.moveDir, NULL, NULL );
- }
- // Check For A Strafe Ram
- //------------------------
- if (!(pVeh->m_ulFlags&VEH_STRAFERAM) && !(pVeh->m_ulFlags&VEH_FLYING))
- {
- // Started A Strafe
- //------------------
- if (pVeh->m_ucmd.rightmove && !pVeh->m_fStrafeTime)
- {
- pVeh->m_fStrafeTime = (pVeh->m_ucmd.rightmove>0)?(level.time):(-1*level.time);
- }
- // Ended A Strafe
- //----------------
- else if (!pVeh->m_ucmd.rightmove && pVeh->m_fStrafeTime)
- {
- // If It Was A Short Burst, Start The Strafe Ram
- //-----------------------------------------------
- if ((level.time - abs(pVeh->m_fStrafeTime))<300)
- {
- if (!VEH_StartStrafeRam(pVeh, (pVeh->m_fStrafeTime>0)))
- {
- pVeh->m_fStrafeTime = 0;
- }
- }
- // Otherwise, Clear The Timer
- //----------------------------
- else
- {
- pVeh->m_fStrafeTime = 0;
- }
- }
- }
- // If Currently In A StrafeRam, Check To See If It Is Done (Timed Out)
- //---------------------------------------------------------------------
- else if (!pVeh->m_fStrafeTime)
- {
- pVeh->m_ulFlags &=~VEH_STRAFERAM;
- }
- // Exhaust Effects Start And Stop When The Accelerator Is Pressed
- //----------------------------------------------------------------
- if (pVeh->m_pVehicleInfo->iExhaustFX)
- {
- // Start It On Each Exhaust Bolt
- //-------------------------------
- if (pVeh->m_ucmd.forwardmove && !(pVeh->m_ulFlags&VEH_ACCELERATORON))
- {
- pVeh->m_ulFlags |= VEH_ACCELERATORON;
- for (int i=0; (i<MAX_VEHICLE_EXHAUSTS && pVeh->m_iExhaustTag[i]!=-1); i++)
- {
- G_PlayEffect(pVeh->m_pVehicleInfo->iExhaustFX, parent->playerModel, pVeh->m_iExhaustTag[i], parent->s.number, parent->currentOrigin, 1, qtrue);
- }
- }
- // Stop It On Each Exhaust Bolt
- //------------------------------
- else if (!pVeh->m_ucmd.forwardmove && (pVeh->m_ulFlags&VEH_ACCELERATORON))
- {
- pVeh->m_ulFlags &=~VEH_ACCELERATORON;
- 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_ulFlags&VEH_ARMORLOW) && (pVeh->m_iArmor <= pVeh->m_pVehicleInfo->armor/3))
- {
- pVeh->m_ulFlags |= VEH_ARMORLOW;
- }
- // 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
- return true;
- }
- #endif //QAGAME
- //MP RULE - ALL PROCESSMOVECOMMANDS FUNCTIONS MUST BE BG-COMPATIBLE!!!
- //If you really need to violate this rule for SP, then use ifdefs.
- //By BG-compatible, I mean no use of game-specific data - ONLY use
- //stuff available in the MP bgEntity (in SP, the bgEntity is #defined
- //as a gentity, but the MP-compatible access restrictions are based
- //on the bgEntity structure in the MP codebase) -rww
- // ProcessMoveCommands the Vehicle.
- static void ProcessMoveCommands( Vehicle_t *pVeh )
- {
- /************************************************************************************/
- /* BEGIN Here is where we move the vehicle (forward or back or whatever). BEGIN */
- /************************************************************************************/
- //Client sets ucmds and such for speed alterations
- float speedInc, speedIdleDec, speedIdle, speedIdleAccel, speedMin, speedMax;
- playerState_t *parentPS;
- playerState_t *pilotPS = NULL;
- int curTime;
- #ifdef _JK2MP
- parentPS = pVeh->m_pParentEntity->playerState;
- if (pVeh->m_pPilot)
- {
- pilotPS = pVeh->m_pPilot->playerState;
- }
- #else
- parentPS = &pVeh->m_pParentEntity->client->ps;
- if (pVeh->m_pPilot)
- {
- pilotPS = &pVeh->m_pPilot->client->ps;
- }
- #endif
- // If we're flying, make us accelerate at 40% (about half) acceleration rate, and restore the pitch
- // to origin (straight) position (at 5% increments).
- if ( pVeh->m_ulFlags & VEH_FLYING )
- {
- speedInc = pVeh->m_pVehicleInfo->acceleration * pVeh->m_fTimeModifier * 0.4f;
- }
- #ifdef _JK2MP
- else if ( !parentPS->m_iVehicleNum )
- #else
- else if ( !pVeh->m_pVehicleInfo->Inhabited( pVeh ) )
- #endif
- {//drifts to a stop
- speedInc = 0;
- //pVeh->m_ucmd.forwardmove = 127;
- }
- else
- {
- speedInc = pVeh->m_pVehicleInfo->acceleration * pVeh->m_fTimeModifier;
- }
- speedIdleDec = pVeh->m_pVehicleInfo->decelIdle * pVeh->m_fTimeModifier;
- #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
- if ( (pVeh->m_pPilot /*&& (pilotPS->weapon == WP_NONE || pilotPS->weapon == WP_MELEE )*/ &&
- (pVeh->m_ucmd.buttons & BUTTON_ALT_ATTACK) && pVeh->m_pVehicleInfo->turboSpeed)
- #ifdef _JK2MP
- ||
- (parentPS && parentPS->electrifyTime > curTime && pVeh->m_pVehicleInfo->turboSpeed) //make them go!
- #endif
- )
- {
- #ifdef _JK2MP
- if ( (parentPS && parentPS->electrifyTime > curTime) ||
- (pVeh->m_pPilot->playerState &&
- (pVeh->m_pPilot->playerState->weapon == WP_MELEE ||
- (pVeh->m_pPilot->playerState->weapon == WP_SABER && pVeh->m_pPilot->playerState->saberHolstered))) )
- {
- #endif
- if ((curTime - pVeh->m_iTurboTime)>pVeh->m_pVehicleInfo->turboRecharge)
- {
- pVeh->m_iTurboTime = (curTime + pVeh->m_pVehicleInfo->turboDuration);
- if (pVeh->m_pVehicleInfo->iTurboStartFX)
- {
- int i;
- for (i=0; (i<MAX_VEHICLE_EXHAUSTS && pVeh->m_iExhaustTag[i]!=-1); i++)
- {
- #ifndef _JK2MP//SP
- // Start The Turbo Fx Start
- //--------------------------
- G_PlayEffect(pVeh->m_pVehicleInfo->iTurboStartFX, pVeh->m_pParentEntity->playerModel, pVeh->m_iExhaustTag[i], pVeh->m_pParentEntity->s.number, pVeh->m_pParentEntity->currentOrigin );
- // Start The Looping Effect
- //--------------------------
- if (pVeh->m_pVehicleInfo->iTurboFX)
- {
- G_PlayEffect(pVeh->m_pVehicleInfo->iTurboFX, pVeh->m_pParentEntity->playerModel, pVeh->m_iExhaustTag[i], pVeh->m_pParentEntity->s.number, pVeh->m_pParentEntity->currentOrigin, pVeh->m_pVehicleInfo->turboDuration, qtrue);
- }
- #else
- #ifdef QAGAME
- if (pVeh->m_pParentEntity &&
- pVeh->m_pParentEntity->ghoul2 &&
- pVeh->m_pParentEntity->playerState)
- { //fine, I'll use a tempent for this, but only because it's played only once at the start of a turbo.
- vec3_t boltOrg, boltDir;
- mdxaBone_t boltMatrix;
- VectorSet(boltDir, 0.0f, pVeh->m_pParentEntity->playerState->viewangles[YAW], 0.0f);
- trap_G2API_GetBoltMatrix(pVeh->m_pParentEntity->ghoul2, 0, pVeh->m_iExhaustTag[i], &boltMatrix, boltDir, pVeh->m_pParentEntity->playerState->origin, level.time, NULL, pVeh->m_pParentEntity->modelScale);
- BG_GiveMeVectorFromMatrix(&boltMatrix, ORIGIN, boltOrg);
- BG_GiveMeVectorFromMatrix(&boltMatrix, ORIGIN, boltDir);
- G_PlayEffectID(pVeh->m_pVehicleInfo->iTurboStartFX, boltOrg, boltDir);
- }
- #endif
- #endif
- }
- }
- #ifndef _JK2MP //kill me now
- if (pVeh->m_pVehicleInfo->soundTurbo)
- {
- G_SoundIndexOnEnt(pVeh->m_pParentEntity, CHAN_AUTO, pVeh->m_pVehicleInfo->soundTurbo);
- }
- #endif
- parentPS->speed = pVeh->m_pVehicleInfo->turboSpeed; // Instantly Jump To Turbo Speed
- }
- #ifdef _JK2MP
- }
- #endif
- }
- // Slide Breaking
- if (pVeh->m_ulFlags&VEH_SLIDEBREAKING)
- {
- if (pVeh->m_ucmd.forwardmove>=0
- #ifndef _JK2MP
- || ((level.time - pVeh->m_pParentEntity->lastMoveTime)>500)
- #endif
- )
- {
- pVeh->m_ulFlags &= ~VEH_SLIDEBREAKING;
- }
- parentPS->speed = 0;
- }
- else if (
- (curTime > pVeh->m_iTurboTime) &&
- !(pVeh->m_ulFlags&VEH_FLYING) &&
- pVeh->m_ucmd.forwardmove<0 &&
- fabs(pVeh->m_vOrientation[ROLL])>25.0f)
- {
- pVeh->m_ulFlags |= VEH_SLIDEBREAKING;
- }
- if ( curTime < pVeh->m_iTurboTime )
- {
- speedMax = pVeh->m_pVehicleInfo->turboSpeed;
- if (parentPS)
- {
- parentPS->eFlags |= EF_JETPACK_ACTIVE;
- }
- }
- else
- {
- speedMax = pVeh->m_pVehicleInfo->speedMax;
- if (parentPS)
- {
- parentPS->eFlags &= ~EF_JETPACK_ACTIVE;
- }
- }
- speedIdle = pVeh->m_pVehicleInfo->speedIdle;
- speedIdleAccel = pVeh->m_pVehicleInfo->accelIdle * pVeh->m_fTimeModifier;
- speedMin = pVeh->m_pVehicleInfo->speedMin;
- // Xbox - yeah, see we have these input devices -- and they're ANALOG! Wow!
- if( pVeh->m_ucmd.forwardmove > 0 )
- speedMax *= pVeh->m_ucmd.forwardmove / 127.0f;
- if ( parentPS->speed || parentPS->groundEntityNum == ENTITYNUM_NONE ||
- pVeh->m_ucmd.forwardmove || pVeh->m_ucmd.upmove > 0 )
- {
- if ( pVeh->m_ucmd.forwardmove > 0 && speedInc )
- {
- parentPS->speed += speedInc;
- }
- else if ( pVeh->m_ucmd.forwardmove < 0 )
- {
- if ( parentPS->speed > speedIdle )
- {
- parentPS->speed -= speedInc;
- }
- else if ( parentPS->speed > speedMin )
- {
- parentPS->speed -= speedIdleDec;
- }
- }
- // No input, so coast to stop.
- else if ( parentPS->speed > 0.0f )
- {
- parentPS->speed -= speedIdleDec;
- if ( parentPS->speed < 0.0f )
- {
- parentPS->speed = 0.0f;
- }
- }
- else if ( parentPS->speed < 0.0f )
- {
- parentPS->speed += speedIdleDec;
- if ( parentPS->speed > 0.0f )
- {
- parentPS->speed = 0.0f;
- }
- }
- }
- else
- {
- if ( !pVeh->m_pVehicleInfo->strafePerc
- #ifdef _JK2MP
- || (0 && pVeh->m_pParentEntity->s.number < MAX_CLIENTS) )
- #else
- || (!g_speederControlScheme->value && !pVeh->m_pParentEntity->s.number) )
- #endif
- {//if in a strafe-capable vehicle, clear strafing unless using alternate control scheme
- //pVeh->m_ucmd.rightmove = 0;
- }
- }
- if ( parentPS->speed > speedMax )
- {
- parentPS->speed = speedMax;
- }
- else if ( parentPS->speed < speedMin )
- {
- parentPS->speed = speedMin;
- }
- #ifndef _JK2MP
- // In SP, The AI Pilots Can Directly Control The Speed Of Their Bike In Order To
- // Match The Speed Of The Person They Are Trying To Chase
- //-------------------------------------------------------------------------------
- if (pVeh->m_pPilot && (pVeh->m_ucmd.buttons&BUTTON_VEH_SPEED))
- {
- parentPS->speed = pVeh->m_pPilot->client->ps.speed;
- }
- #endif
- /********************************************************************************/
- /* END Here is where we move the vehicle (forward or back or whatever). END */
- /********************************************************************************/
- }
- //MP RULE - ALL PROCESSORIENTCOMMANDS FUNCTIONS MUST BE BG-COMPATIBLE!!!
- //If you really need to violate this rule for SP, then use ifdefs.
- //By BG-compatible, I mean no use of game-specific data - ONLY use
- //stuff available in the MP bgEntity (in SP, the bgEntity is #defined
- //as a gentity, but the MP-compatible access restrictions are based
- //on the bgEntity structure in the MP codebase) -rww
- //Oh, and please, use "< MAX_CLIENTS" to check for "player" and not
- //"!s.number", this is a universal check that will work for both SP
- //and MP. -rww
- // ProcessOrientCommands the Vehicle.
- #ifdef _JK2MP //temp hack til mp speeder controls are sorted -rww
- extern void AnimalProcessOri(Vehicle_t *pVeh);
- #endif
- void ProcessOrientCommands( Vehicle_t *pVeh )
- {
- /********************************************************************************/
- /* BEGIN Here is where make sure the vehicle is properly oriented. BEGIN */
- /********************************************************************************/
- playerState_t *riderPS;
- playerState_t *parentPS;
- #ifdef _JK2MP
- float angDif;
- if (pVeh->m_pPilot)
- {
- riderPS = pVeh->m_pPilot->playerState;
- }
- else
- {
- riderPS = pVeh->m_pParentEntity->playerState;
- }
- parentPS = pVeh->m_pParentEntity->playerState;
- //pVeh->m_vOrientation[YAW] = 0.0f;//riderPS->viewangles[YAW];
- angDif = AngleSubtract(pVeh->m_vOrientation[YAW], riderPS->viewangles[YAW]);
- if (parentPS && parentPS->speed)
- {
- float s = parentPS->speed;
- float maxDif = pVeh->m_pVehicleInfo->turningSpeed*4.0f; //magic number hackery
- if (s < 0.0f)
- {
- s = -s;
- }
- angDif *= s/pVeh->m_pVehicleInfo->speedMax;
- if (angDif > maxDif)
- {
- angDif = maxDif;
- }
- else if (angDif < -maxDif)
- {
- angDif = -maxDif;
- }
- pVeh->m_vOrientation[YAW] = AngleNormalize180(pVeh->m_vOrientation[YAW] - angDif*(pVeh->m_fTimeModifier*0.2f));
- if (parentPS->electrifyTime > pm->cmd.serverTime)
- { //do some crazy stuff
- pVeh->m_vOrientation[YAW] += (sin(pm->cmd.serverTime/1000.0f)*3.0f)*pVeh->m_fTimeModifier;
- }
- }
- #else
- gentity_t *rider = pVeh->m_pParentEntity->owner;
- if ( !rider || !rider->client )
- {
- riderPS = &pVeh->m_pParentEntity->client->ps;
- }
- else
- {
- riderPS = &rider->client->ps;
- }
- parentPS = &pVeh->m_pParentEntity->client->ps;
- if (pVeh->m_ulFlags & VEH_FLYING)
- {
- pVeh->m_vOrientation[YAW] += pVeh->m_vAngularVelocity;
- }
- else if (
- (pVeh->m_ulFlags & VEH_SLIDEBREAKING) || // No Angles Control While Out Of Control
- (pVeh->m_ulFlags & VEH_OUTOFCONTROL) // No Angles Control While Out Of Control
- )
- {
- // Any ability to change orientation?
- }
- else if (
- (pVeh->m_ulFlags & VEH_STRAFERAM) // No Angles Control While Strafe Ramming
- )
- {
- if (pVeh->m_fStrafeTime>0)
- {
- pVeh->m_fStrafeTime--;
- pVeh->m_vOrientation[ROLL] += (pVeh->m_fStrafeTime<( STRAFERAM_DURATION/2))?(-STRAFERAM_ANGLE):( STRAFERAM_ANGLE);
- }
- else if (pVeh->m_fStrafeTime<0)
- {
- pVeh->m_fStrafeTime++;
- pVeh->m_vOrientation[ROLL] += (pVeh->m_fStrafeTime>(-STRAFERAM_DURATION/2))?( STRAFERAM_ANGLE):(-STRAFERAM_ANGLE);
- }
- }
- else
- {
- pVeh->m_vOrientation[YAW] = riderPS->viewangles[YAW];
- }
- #endif
- /********************************************************************************/
- /* END Here is where make sure the vehicle is properly oriented. END */
- /********************************************************************************/
- }
- #ifdef QAGAME
- extern void PM_SetAnim(pmove_t *pm,int setAnimParts,int anim,int setAnimFlags, int blendTime);
- extern int PM_AnimLength( int index, animNumber_t anim );
- // This function makes sure that the vehicle is properly animated.
- void AnimateVehicle( Vehicle_t *pVeh )
- {
- }
- #endif //QAGAME
- //rest of file is shared
- #ifndef _JK2MP
- extern void CG_ChangeWeapon( int num );
- #endif
- #ifndef _JK2MP
- extern void G_StartMatrixEffect( gentity_t *ent, int meFlags = 0, int length = 1000, float timeScale = 0.0f, int spinTime = 0 );
- #endif
- //NOTE NOTE NOTE NOTE NOTE NOTE
- //I want to keep this function BG too, because it's fairly generic already, and it
- //would be nice to have proper prediction of animations. -rww
- // This function makes sure that the rider's in this vehicle are properly animated.
- void AnimateRiders( Vehicle_t *pVeh )
- {
- animNumber_t Anim = BOTH_VS_IDLE;
- float fSpeedPercToMax;
- int iFlags = SETANIM_FLAG_NORMAL, iBlend = 300;
- playerState_t *pilotPS;
- playerState_t *parentPS;
- int curTime;
- // Boarding animation.
- if ( pVeh->m_iBoarding != 0 )
- {
- // We've just started moarding, set the amount of time it will take to finish moarding.
- if ( pVeh->m_iBoarding < 0 )
- {
- int iAnimLen;
- // Boarding from left...
- if ( pVeh->m_iBoarding == -1 )
- {
- Anim = BOTH_VS_MOUNT_L;
- }
- else if ( pVeh->m_iBoarding == -2 )
- {
- Anim = BOTH_VS_MOUNT_R;
- }
- else if ( pVeh->m_iBoarding == -3 )
- {
- Anim = BOTH_VS_MOUNTJUMP_L;
- }
- else if ( pVeh->m_iBoarding == VEH_MOUNT_THROW_LEFT)
- {
- iBlend = 0;
- Anim = BOTH_VS_MOUNTTHROW_R;
- }
- else if ( pVeh->m_iBoarding == VEH_MOUNT_THROW_RIGHT)
- {
- iBlend = 0;
- Anim = BOTH_VS_MOUNTTHROW_L;
- }
- // Set the delay time (which happens to be the time it takes for the animation to complete).
- // NOTE: Here I made it so the delay is actually 40% (0.4f) of the animation time.
- #ifdef _JK2MP
- iAnimLen = BG_AnimLength( pVeh->m_pPilot->localAnimIndex, Anim ) * 0.4f;
- pVeh->m_iBoarding = BG_GetTime() + iAnimLen;
- #else
- iAnimLen = PM_AnimLength( pVeh->m_pPilot->client->clientInfo.animFileIndex, Anim );// * 0.4f;
- if (pVeh->m_iBoarding!=VEH_MOUNT_THROW_LEFT && pVeh->m_iBoarding!=VEH_MOUNT_THROW_RIGHT)
- {
- pVeh->m_iBoarding = level.time + (iAnimLen*0.4f);
- }
- else
- {
- pVeh->m_iBoarding = level.time + iAnimLen;
- }
- #endif
- // Set the animation, which won't be interrupted until it's completed.
- // TODO: But what if he's killed? Should the animation remain persistant???
- iFlags = SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD;
-
- #ifdef _JK2MP
- BG_SetAnim(pVeh->m_pPilot->playerState, bgAllAnims[pVeh->m_pPilot->localAnimIndex].anims,
- SETANIM_BOTH, Anim, iFlags, iBlend);
- #else
- NPC_SetAnim( pVeh->m_pPilot, SETANIM_BOTH, Anim, iFlags, iBlend );
- if (pVeh->m_pOldPilot)
- {
- iAnimLen = PM_AnimLength( pVeh->m_pPilot->client->clientInfo.animFileIndex, BOTH_VS_MOUNTTHROWEE);
- NPC_SetAnim( pVeh->m_pOldPilot, SETANIM_BOTH, BOTH_VS_MOUNTTHROWEE, iFlags, iBlend );
- }
- #endif
- }
- #ifndef _JK2MP
- if (pVeh->m_pOldPilot && pVeh->m_pOldPilot->client->ps.torsoAnimTimer<=0)
- {
- if (Q_irand(0, player->count)==0)
- {
- player->count++;
- player->lastEnemy = pVeh->m_pOldPilot;
- G_StartMatrixEffect(player, MEF_LOOK_AT_ENEMY|MEF_NO_RANGEVAR|MEF_NO_VERTBOB|MEF_NO_SPIN, 1000);
- }
- gentity_t* oldPilot = pVeh->m_pOldPilot;
- pVeh->m_pVehicleInfo->Eject(pVeh, pVeh->m_pOldPilot, qtrue); // will set pointer to zero
- // Kill Him
- //----------
- oldPilot->client->noRagTime = -1; // no ragdoll for you
- G_Damage(oldPilot, pVeh->m_pPilot, pVeh->m_pPilot, pVeh->m_pPilot->currentAngles, pVeh->m_pPilot->currentOrigin, 1000, 0, MOD_CRUSH);
- // Compute THe Throw Direction As Backwards From The Vehicle's Velocity
- //----------------------------------------------------------------------
- vec3_t throwDir;
- VectorScale(pVeh->m_pParentEntity->client->ps.velocity, -1.0f, throwDir);
- VectorNormalize(throwDir);
- throwDir[2] += 0.3f; // up a little
- // Now Throw Him Out
- //-------------------
- G_Throw(oldPilot, throwDir, VectorLength(pVeh->m_pParentEntity->client->ps.velocity)/10.0f);
- NPC_SetAnim(oldPilot, SETANIM_BOTH, BOTH_DEATHBACKWARD1, SETANIM_FLAG_OVERRIDE, iBlend );
- }
- #endif
- return;
- }
- #ifdef _JK2MP //fixme
- if (1) return;
- #endif
- #ifdef _JK2MP
- pilotPS = pVeh->m_pPilot->playerState;
- parentPS = pVeh->m_pPilot->playerState;
- #else
- pilotPS = &pVeh->m_pPilot->client->ps;
- 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
- // Percentage of maximum speed relative to current speed.
- fSpeedPercToMax = parentPS->speed / pVeh->m_pVehicleInfo->speedMax;
- /* // Going in reverse...
- #ifdef _JK2MP
- if ( pVeh->m_ucmd.forwardmove < 0 && !(pVeh->m_ulFlags & VEH_SLIDEBREAKING))
- #else
- if ( fSpeedPercToMax < -0.018f && !(pVeh->m_ulFlags & VEH_SLIDEBREAKING))
- #endif
- {
- Anim = BOTH_VS_REV;
- iBlend = 500;
- bool HasWeapon = ((pilotPS->weapon != WP_NONE) && (pilotPS->weapon != WP_MELEE));
- if (HasWeapon)
- {
- if (pVeh->m_pPilot->s.number<MAX_CLIENTS)
- {
- CG_ChangeWeapon(WP_NONE);
- }
- pVeh->m_pPilot->client->ps.weapon = WP_NONE;
- G_RemoveWeaponModels(pVeh->m_pPilot);
- }
- }
- else
- */
- {
- bool HasWeapon = ((pilotPS->weapon != WP_NONE) && (pilotPS->weapon != WP_MELEE));
- bool Attacking = (HasWeapon && !!(pVeh->m_ucmd.buttons&BUTTON_ATTACK));
- #ifdef _JK2MP //fixme: flying tends to spaz out a lot
- bool Flying = false;
- bool Crashing = false;
- #else
- bool Flying = !!(pVeh->m_ulFlags & VEH_FLYING);
- bool Crashing = !!(pVeh->m_ulFlags & VEH_CRASHING);
- #endif
- bool Right = (pVeh->m_ucmd.rightmove>0);
- bool Left = (pVeh->m_ucmd.rightmove<0);
- bool Turbo = (curTime<pVeh->m_iTurboTime);
- EWeaponPose WeaponPose = WPOSE_NONE;
- // Remove Crashing Flag
- //----------------------
- pVeh->m_ulFlags &= ~VEH_CRASHING;
- // Put Away Saber When It Is Not Active
- //--------------------------------------
- #ifndef _JK2MP
- if (HasWeapon &&
- (pVeh->m_pPilot->s.number>=MAX_CLIENTS || (cg.weaponSelectTime+500)<cg.time) &&
- (Turbo || (pilotPS->weapon==WP_SABER && !pilotPS->SaberActive())))
- {
- if (pVeh->m_pPilot->s.number<MAX_CLIENTS)
- {
- pVeh->m_pPilot->client->ps.stats[ STAT_WEAPONS ] |= 1; // Riding means you get WP_NONE
- CG_ChangeWeapon(WP_NONE);
- }
- pVeh->m_pPilot->client->ps.weapon = WP_NONE;
- G_RemoveWeaponModels(pVeh->m_pPilot);
- }
- #endif
- // Don't Interrupt Attack Anims
- //------------------------------
- #ifdef _JK2MP
- if (pilotPS->weaponTime>0)
- {
- return;
- }
- #else
- if (pilotPS->torsoAnim>=BOTH_VS_ATL_S && pilotPS->torsoAnim<=BOTH_VS_ATF_G)
- {
- float bodyCurrent = 0.0f;
- int bodyEnd = 0;
- if (!!gi.G2API_GetBoneAnimIndex(&pVeh->m_pPilot->ghoul2[pVeh->m_pPilot->playerModel], pVeh->m_pPilot->rootBone, level.time, &bodyCurrent, NULL, &bodyEnd, NULL, NULL, NULL))
- {
- if (bodyCurrent<=((float)(bodyEnd)-1.5f))
- {
- return;
- }
- }
- }
- #endif
- // Compute The Weapon Pose
- //--------------------------
- if (pilotPS->weapon==WP_BLASTER)
- {
- WeaponPose = WPOSE_BLASTER;
- }
- else if (pilotPS->weapon==WP_SABER)
- {
- if ( (pVeh->m_ulFlags&VEH_SABERINLEFTHAND) && pilotPS->torsoAnim==BOTH_VS_ATL_TO_R_S)
- {
- pVeh->m_ulFlags &= ~VEH_SABERINLEFTHAND;
- }
- if (!(pVeh->m_ulFlags&VEH_SABERINLEFTHAND) && pilotPS->torsoAnim==BOTH_VS_ATR_TO_L_S)
- {
- pVeh->m_ulFlags |= VEH_SABERINLEFTHAND;
- }
- WeaponPose = (pVeh->m_ulFlags&VEH_SABERINLEFTHAND)?(WPOSE_SABERLEFT):(WPOSE_SABERRIGHT);
- }
-
- if (Attacking && WeaponPose)
- {// Attack!
- iBlend = 100;
- iFlags = SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD|SETANIM_FLAG_RESTART;
-
- // Auto Aiming
- //===============================================
- if (!Left && !Right) // Allow player strafe keys to override
- {
- #ifndef _JK2MP
- if (pVeh->m_pPilot->enemy)
- {
- vec3_t toEnemy;
- float toEnemyDistance;
- vec3_t actorRight;
- float actorRightDot;
- VectorSubtract(pVeh->m_pPilot->currentOrigin, pVeh->m_pPilot->enemy->currentOrigin, toEnemy);
- toEnemyDistance = VectorNormalize(toEnemy);
- AngleVectors(pVeh->m_pParentEntity->currentAngles, 0, actorRight, 0);
- actorRightDot = DotProduct(toEnemy, actorRight);
- if (fabsf(actorRightDot)>0.5f || pilotPS->weapon==WP_SABER)
- {
- Left = (actorRightDot>0.0f);
- Right = !Left;
- }
- else
- {
- Right = Left = false;
- }
- }
- else
- #endif
- if (pilotPS->weapon==WP_SABER && !Left && !Right)
- {
- Left = (WeaponPose==WPOSE_SABERLEFT);
- Right = !Left;
- }
- }
- if (Left)
- {// Attack Left
- switch(WeaponPose)
- {
- case WPOSE_BLASTER: Anim = BOTH_VS_ATL_G; break;
- case WPOSE_SABERLEFT: Anim = BOTH_VS_ATL_S; break;
- case WPOSE_SABERRIGHT: Anim = BOTH_VS_ATR_TO_L_S; break;
- default: assert(0);
- }
- }
- else if (Right)
- {// Attack Right
- switch(WeaponPose)
- {
- case WPOSE_BLASTER: Anim = BOTH_VS_ATR_G; break;
- case WPOSE_SABERLEFT: Anim = BOTH_VS_ATL_TO_R_S; break;
- case WPOSE_SABERRIGHT: Anim = BOTH_VS_ATR_S; break;
- default: assert(0);
- }
- }
- else
- {// Attack Ahead
- switch(WeaponPose)
- {
- case WPOSE_BLASTER: Anim = BOTH_VS_ATF_G; break;
- default: assert(0);
- }
- }
- }
- else if (Left && pVeh->m_ucmd.buttons&BUTTON_USE)
- {// Look To The Left Behind
- iBlend = 400;
- iFlags = SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD;
- switch(WeaponPose)
- {
- case WPOSE_SABERLEFT: Anim = BOTH_VS_IDLE_SL; break;
- case WPOSE_SABERRIGHT: Anim = BOTH_VS_IDLE_SR; break;
- default: Anim = BOTH_VS_LOOKLEFT;
- }
- }
- else if (Right && pVeh->m_ucmd.buttons&BUTTON_USE)
- {// Look To The Right Behind
- iBlend = 400;
- iFlags = SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD;
- switch(WeaponPose)
- {
- case WPOSE_SABERLEFT: Anim = BOTH_VS_IDLE_SL; break;
- case WPOSE_SABERRIGHT: Anim = BOTH_VS_IDLE_SR; break;
- default: Anim = BOTH_VS_LOOKRIGHT;
- }
- }
- else if (Turbo)
- {// Kicked In Turbo
- iBlend = 50;
- iFlags = SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLDLESS;
- Anim = BOTH_VS_TURBO;
- }
- else if (Flying)
- {// Off the ground in a jump
- iBlend = 800;
- iFlags = SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD;
- switch(WeaponPose)
- {
- case WPOSE_NONE: Anim = BOTH_VS_AIR; break;
- case WPOSE_BLASTER: Anim = BOTH_VS_AIR_G; break;
- case WPOSE_SABERLEFT: Anim = BOTH_VS_AIR_SL; break;
- case WPOSE_SABERRIGHT: Anim = BOTH_VS_AIR_SR; break;
- default: assert(0);
- }
- }
- else if (Crashing)
- {// Hit the ground!
- iBlend = 100;
- iFlags = SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLDLESS;
- switch(WeaponPose)
- {
- case WPOSE_NONE: Anim = BOTH_VS_LAND; break;
- case WPOSE_BLASTER: Anim = BOTH_VS_LAND_G; break;
- case WPOSE_SABERLEFT: Anim = BOTH_VS_LAND_SL; break;
- case WPOSE_SABERRIGHT: Anim = BOTH_VS_LAND_SR; break;
- default: assert(0);
- }
- }
- else
- {// No Special Moves
- iBlend = 300;
- iFlags = SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLDLESS;
- if (pVeh->m_vOrientation[ROLL] <= -20)
- {// Lean Left
- switch(WeaponPose)
- {
- case WPOSE_NONE: Anim = BOTH_VS_LEANL; break;
- case WPOSE_BLASTER: Anim = BOTH_VS_LEANL_G; break;
- case WPOSE_SABERLEFT: Anim = BOTH_VS_LEANL_SL; break;
- case WPOSE_SABERRIGHT: Anim = BOTH_VS_LEANL_SR; break;
- default: assert(0);
- }
- }
- else if (pVeh->m_vOrientation[ROLL] >= 20)
- {// Lean Right
- switch(WeaponPose)
- {
- case WPOSE_NONE: Anim = BOTH_VS_LEANR; break;
- case WPOSE_BLASTER: Anim = BOTH_VS_LEANR_G; break;
- case WPOSE_SABERLEFT: Anim = BOTH_VS_LEANR_SL; break;
- case WPOSE_SABERRIGHT: Anim = BOTH_VS_LEANR_SR; break;
- default: assert(0);
- }
- }
- else
- {// No Lean
- switch(WeaponPose)
- {
- case WPOSE_NONE: Anim = BOTH_VS_IDLE; break;
- case WPOSE_BLASTER: Anim = BOTH_VS_IDLE_G; break;
- case WPOSE_SABERLEFT: Anim = BOTH_VS_IDLE_SL; break;
- case WPOSE_SABERRIGHT: Anim = BOTH_VS_IDLE_SR; break;
- default: assert(0);
- }
- }
- }// No Special Moves
- }// Going backwards?
- #ifdef _JK2MP
- iFlags &= ~SETANIM_FLAG_OVERRIDE;
- if (pVeh->m_pPilot->playerState->torsoAnim == Anim)
- {
- pVeh->m_pPilot->playerState->torsoTimer = BG_AnimLength(pVeh->m_pPilot->localAnimIndex, Anim);
- }
- if (pVeh->m_pPilot->playerState->legsAnim == Anim)
- {
- pVeh->m_pPilot->playerState->legsTimer = BG_AnimLength(pVeh->m_pPilot->localAnimIndex, Anim);
- }
- BG_SetAnim(pVeh->m_pPilot->playerState, bgAllAnims[pVeh->m_pPilot->localAnimIndex].anims,
- SETANIM_BOTH, Anim, iFlags|SETANIM_FLAG_HOLD, iBlend);
- #else
- NPC_SetAnim( pVeh->m_pPilot, SETANIM_BOTH, Anim, iFlags, iBlend );
- #endif
- }
- #ifndef QAGAME
- void AttachRidersGeneric( Vehicle_t *pVeh );
- #endif
- void G_SetSpeederVehicleFunctions( vehicleInfo_t *pVehInfo )
- {
- #ifdef QAGAME
- 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;
- #endif
- //shared
- pVehInfo->ProcessMoveCommands = ProcessMoveCommands;
- pVehInfo->ProcessOrientCommands = ProcessOrientCommands;
- #ifndef QAGAME //cgame prediction attachment func
- pVehInfo->AttachRiders = AttachRidersGeneric;
- #endif
- // pVehInfo->AttachRiders = AttachRiders;
- // pVehInfo->Ghost = Ghost;
- // pVehInfo->UnGhost = UnGhost;
- // pVehInfo->Inhabited = Inhabited;
- }
- // Following is only in game, not in namespace
- #ifdef _JK2MP
- #include "../namespace_end.h"
- #endif
- #ifdef QAGAME
- extern void G_AllocateVehicleObject(Vehicle_t **pVeh);
- #endif
- #ifdef _JK2MP
- #include "../namespace_begin.h"
- #endif
- extern char current_speeders;
- // Create/Allocate a new Animal Vehicle (initializing it as well).
- void G_CreateSpeederNPC( Vehicle_t **pVeh, const char *strType )
- {
-
- current_speeders++;
-
- #ifdef _JK2MP
- #ifdef QAGAME
- //these will remain on entities on the client once allocated because the pointer is
- //never stomped. on the server, however, when an ent is freed, the entity struct is
- //memset to 0, so this memory would be lost..
- G_AllocateVehicleObject(pVeh);
- #else
- if (!*pVeh)
- { //only allocate a new one if we really have to
- (*pVeh) = (Vehicle_t *) BG_Alloc( sizeof(Vehicle_t) );
- }
- #endif
- memset(*pVeh, 0, sizeof(Vehicle_t));
- (*pVeh)->m_pVehicleInfo = &g_vehicleInfo[BG_VehicleGetIndex( strType )];
- #else
- // Allocate the Vehicle.
- (*pVeh) = (Vehicle_t *) gi.Malloc( sizeof(Vehicle_t), TAG_G_ALLOC, qtrue );
- (*pVeh)->m_pVehicleInfo = &g_vehicleInfo[BG_VehicleGetIndex( strType )];
- #endif
- (*pVeh)->alreadyCleaned = false;
- }
- #ifdef _JK2MP
- #include "../namespace_end.h"
- //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 Q_flrand
- #undef MOD_EXPLOSIVE
- #endif
|