From bbff053fc51e79a405775eedc42a1ad17d20912c Mon Sep 17 00:00:00 2001 From: Wanne Date: Sun, 18 May 2014 15:26:15 +0000 Subject: [PATCH] Driveable vehicle Update: Externalized vehicle seats (by anv) - externalised vehicle seats (TableData\Vehicles.xml) influence position of passenger, field of view, ability to shoot and being hidden, - seat can chosen by using ctrl+RMB on vehicle (ctrl + LMB just takes the first visible seat) - seats can be changed or swapped while inside vehicle, - remade JSD files for cars, - vehicles aren't transparent anymore, - vehicles are louder than people, depending how fast they move. see: http://www.bears-pit.com/board/ubbthreads.php/topics/332790/5.html git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@7212 3b4a5df2-a311-0410-b5c6-a8a6f20db521 --- Strategic/Assignments.cpp | 7 +- Tactical/Animation Data.cpp | 30 +- Tactical/Handle UI.cpp | 51 ++- Tactical/Handle UI.h | 1 + Tactical/Interface Panels.cpp | 72 +++-- Tactical/Interface.cpp | 44 ++- Tactical/LOS.cpp | 37 +++ Tactical/Overhead.cpp | 13 +- Tactical/Real Time Input.cpp | 24 +- Tactical/Soldier Control.cpp | 10 +- Tactical/Soldier Control.h | 2 +- Tactical/Tactical_VS2005.vcproj | 8 + Tactical/Tactical_VS2008.vcproj | 8 + Tactical/Tactical_VS2010.vcxproj | 1 + Tactical/Tactical_VS2010.vcxproj.filters | 3 + Tactical/Tactical_VS2013.vcxproj | 2 + Tactical/Tactical_VS2013.vcxproj.filters | 6 + Tactical/Turn Based Input.cpp | 97 +++++- Tactical/VehicleMenu.cpp | 222 +++++++++++++ Tactical/VehicleMenu.h | 85 +++++ Tactical/Vehicles.cpp | 395 ++++++++++++++++++++--- Tactical/Vehicles.h | 47 +-- Tactical/XML_Vehicles.cpp | 106 +++++- Tactical/opplist.cpp | 34 ++ Utils/ExportStrings.cpp | 1 + Utils/Text.h | 1 + Utils/_ChineseText.cpp | 5 + Utils/_DutchText.cpp | 5 + Utils/_EnglishText.cpp | 5 + Utils/_FrenchText.cpp | 5 + Utils/_GermanText.cpp | 6 + Utils/_ItalianText.cpp | 5 + Utils/_PolishText.cpp | 5 + Utils/_RussianText.cpp | 5 + Utils/_TaiwaneseText.cpp | 5 + 35 files changed, 1209 insertions(+), 144 deletions(-) create mode 100644 Tactical/VehicleMenu.cpp create mode 100644 Tactical/VehicleMenu.h diff --git a/Strategic/Assignments.cpp b/Strategic/Assignments.cpp index 0f30eb19..48cc43f1 100644 --- a/Strategic/Assignments.cpp +++ b/Strategic/Assignments.cpp @@ -16750,7 +16750,12 @@ SOLDIERTYPE *GetSelectedAssignSoldier( BOOLEAN fNullOK ) { // better be an active person, not a vehicle Assert( pSoldier->bActive ); - Assert( !( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) ); + // anv: don't assert, handle... + //Assert( !( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) ); + if( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) + { + pSoldier = GetDriver( pSoldier->iVehicleId ); + } } return( pSoldier ); diff --git a/Tactical/Animation Data.cpp b/Tactical/Animation Data.cpp index cd628244..cf94ae25 100644 --- a/Tactical/Animation Data.cpp +++ b/Tactical/Animation Data.cpp @@ -777,27 +777,27 @@ AnimationStructureType gAnimStructureDatabase[ TOTALBODYTYPES ][ NUM_STRUCT_IDS "ANIMS\\STRUCTDATA\\M_CROUCH.JSD", NULL, // default //ELDORADO - "ANIMS\\STRUCTDATA\\HMMV.JSD", NULL, - "ANIMS\\STRUCTDATA\\HMMV.JSD", NULL, - "ANIMS\\STRUCTDATA\\HMMV.JSD", NULL, - "ANIMS\\STRUCTDATA\\HMMV.JSD", NULL, - "ANIMS\\STRUCTDATA\\HMMV.JSD", NULL, + "ANIMS\\STRUCTDATA\\ELDRDO.JSD", NULL, + "ANIMS\\STRUCTDATA\\ELDRDO.JSD", NULL, + "ANIMS\\STRUCTDATA\\ELDRDO.JSD", NULL, + "ANIMS\\STRUCTDATA\\ELDRDO.JSD", NULL, + "ANIMS\\STRUCTDATA\\ELDRDO.JSD", NULL, "ANIMS\\STRUCTDATA\\M_CROUCH.JSD",NULL, // default //ICECREAMTRUCK - "ANIMS\\STRUCTDATA\\HMMV.JSD", NULL, - "ANIMS\\STRUCTDATA\\HMMV.JSD", NULL, - "ANIMS\\STRUCTDATA\\HMMV.JSD", NULL, - "ANIMS\\STRUCTDATA\\HMMV.JSD", NULL, - "ANIMS\\STRUCTDATA\\HMMV.JSD", NULL, + "ANIMS\\STRUCTDATA\\ICECREAM.JSD", NULL, + "ANIMS\\STRUCTDATA\\ICECREAM.JSD", NULL, + "ANIMS\\STRUCTDATA\\ICECREAM.JSD", NULL, + "ANIMS\\STRUCTDATA\\ICECREAM.JSD", NULL, + "ANIMS\\STRUCTDATA\\ICECREAM.JSD", NULL, "ANIMS\\STRUCTDATA\\M_CROUCH.JSD",NULL, // default //JEEP - "ANIMS\\STRUCTDATA\\HMMV.JSD", NULL, - "ANIMS\\STRUCTDATA\\HMMV.JSD", NULL, - "ANIMS\\STRUCTDATA\\HMMV.JSD", NULL, - "ANIMS\\STRUCTDATA\\HMMV.JSD", NULL, - "ANIMS\\STRUCTDATA\\HMMV.JSD", NULL, + "ANIMS\\STRUCTDATA\\JEEP.JSD", NULL, + "ANIMS\\STRUCTDATA\\JEEP.JSD", NULL, + "ANIMS\\STRUCTDATA\\JEEP.JSD", NULL, + "ANIMS\\STRUCTDATA\\JEEP.JSD", NULL, + "ANIMS\\STRUCTDATA\\JEEP.JSD", NULL, "ANIMS\\STRUCTDATA\\M_CROUCH.JSD",NULL, // default }; diff --git a/Tactical/Handle UI.cpp b/Tactical/Handle UI.cpp index 7fa53aa8..c1b7e66d 100644 --- a/Tactical/Handle UI.cpp +++ b/Tactical/Handle UI.cpp @@ -1491,14 +1491,14 @@ UINT32 UIHandleMOnTerrain( UI_EVENT *pUIEvent ) } } - // If we are a passenger or driver just show an X + // If we are a passenger or driver just show ? if ( GetSoldier( &pSoldier, gusSelectedSoldier ) ) { if ( ( pSoldier->flags.uiStatusFlags & ( SOLDIER_PASSENGER )) ) { if ( !UIHandleOnMerc( TRUE ) ) { - guiNewUICursor = FLOATING_X_UICURSOR; + guiNewUICursor = INVALID_ACTION_UICURSOR; return( GAME_SCREEN ); } } @@ -3219,16 +3219,6 @@ UINT32 UIHandleHCOnTerrain( UI_EVENT *pUIEvent ) return( GAME_SCREEN ); } - // If we are a passenger or driver just show an ? - if ( GetSoldier( &pSoldier, gusSelectedSoldier ) ) - { - if ( ( pSoldier->flags.uiStatusFlags & ( SOLDIER_VEHICLE | SOLDIER_DRIVER | SOLDIER_PASSENGER )) ) - { - guiNewUICursor = INVALID_ACTION_UICURSOR; - return( GAME_SCREEN ); - } - } - // If we are out of breath, no cursor... if ( pSoldier->bBreath < OKBREATH && pSoldier->bCollapsed ) { @@ -3445,6 +3435,20 @@ BOOLEAN UIHandleOnMerc( BOOLEAN fMovementMode ) // Check if this guy is on the enemy team.... if ( !pSoldier->aiData.bNeutral && (pSoldier->bSide != gbPlayerNum ) ) { + // anv: don't switch if passengers are blocked from attacking + if( gusSelectedSoldier != NOBODY ) + { + SOLDIERTYPE *pSelectedSoldier = MercPtrs[gusSelectedSoldier]; + if( pSelectedSoldier->flags.uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER ) ) + { + SOLDIERTYPE *pVehicle = GetSoldierStructureForVehicle( pSelectedSoldier->iVehicleId ); + INT8 bSeatIndex = GetSeatIndexFromSoldier( pSelectedSoldier ); + if( gNewVehicle[ pVehicleList[ pSelectedSoldier->iVehicleId ].ubVehicleType ].VehicleSeats[bSeatIndex].fBlockedShots == TRUE ) + { + return( FALSE ); + } + } + } gUIActionModeChangeDueToMouseOver = TRUE; guiPendingOverrideEvent = M_CHANGE_TO_ACTION; @@ -3531,7 +3535,7 @@ void UIHandleSoldierStanceChange( UINT8 ubSoldierID, INT8 bNewStance ) { SOLDIERTYPE *pSoldier = MercPtrs[ ubSoldierID ]; - if( pSoldier->flags.uiStatusFlags & SOLDIER_DRIVER ) + if( pSoldier->flags.uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER ) ) { pSoldier = GetSoldierStructureForVehicle( pSoldier->iVehicleId ); } @@ -6371,11 +6375,30 @@ INT8 UIHandleInteractiveTilesAndItemsOnTerrain( SOLDIERTYPE *pSoldier, INT32 usM gfBeginVehicleCursor = FALSE; + // If we are a passenger or driver just show an ? + if ( ( pSoldier->flags.uiStatusFlags & ( SOLDIER_VEHICLE | SOLDIER_DRIVER | SOLDIER_PASSENGER )) ) + { + // unless we are over our own vehicle, then we can call vehicle menu + if( gfUIFullTargetFound ) + { + pTSoldier = MercPtrs[ gusUIFullTargetID ]; + if( pSoldier->iVehicleId == pTSoldier->bVehicleID ) + { + guiNewUICursor = ENTER_VEHICLE_UICURSOR; + return( 1 ); + } + } + guiNewUICursor = INVALID_ACTION_UICURSOR; + return( 0 ); + } + if ( gfUIFullTargetFound ) { pTSoldier = MercPtrs[ gusUIFullTargetID ]; - if ( OK_ENTERABLE_VEHICLE( pTSoldier ) && pTSoldier->bVisible != -1 ) + // anv: added condition - make sure we won't put vehicle in another vehicle + if ( OK_ENTERABLE_VEHICLE( pTSoldier ) && pTSoldier->bVisible != -1 && !( pSoldier->flags.uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER | SOLDIER_VEHICLE ) ) ) + //if ( OK_ENTERABLE_VEHICLE( pTSoldier ) && pTSoldier->bVisible != -1 ) { // grab number of occupants in vehicles if ( fItemsOnlyIfOnIntTiles ) diff --git a/Tactical/Handle UI.h b/Tactical/Handle UI.h index db0ec0b6..af02cca1 100644 --- a/Tactical/Handle UI.h +++ b/Tactical/Handle UI.h @@ -343,6 +343,7 @@ UINT32 UIHandleLUIEndLock( UI_EVENT *pUIEvent ); void BeginDisplayTimedCursor( UINT32 uiCursorID, UINT32 uiDelay ); void HandleHandCursorClick( INT32 usMapPos, UINT32 *puiNewEvent ); +void HandleHandCursorRightClick( INT32 usMapPos, UINT32 *puiNewEvent ); INT8 HandleMoveModeInteractiveClick( INT32 usMapPos, UINT32 *puiNewEvent ); BOOLEAN HandleUIReloading( SOLDIERTYPE *pSoldier ); diff --git a/Tactical/Interface Panels.cpp b/Tactical/Interface Panels.cpp index 0d87ae66..7c3518da 100644 --- a/Tactical/Interface Panels.cpp +++ b/Tactical/Interface Panels.cpp @@ -5693,6 +5693,13 @@ void RenderTEAMPanel( BOOLEAN fDirty ) // clear pStr value swprintf( pStr, L""); + INT8 bSeatIndex = GetSeatIndexFromSoldier( pSoldier ); + if( bSeatIndex != (-1) ) + { + swprintf( sTemp, L"%s\n", gNewVehicle[ pVehicleList[ pSoldier->iVehicleId ].ubVehicleType ].VehicleSeats[ bSeatIndex ].zSeatName ); + wcscat( pStr, sTemp ); + } + if (gGameOptions.fNewTraitSystem) // SANDRO - old/new traits check { UINT8 ubTempSkillArray[30]; @@ -5716,7 +5723,8 @@ void RenderTEAMPanel( BOOLEAN fDirty ) if ( bNumSkillTraits == 0 ) { - swprintf( pStr, L"%s", pPersonnelScreenStrings[ PRSNL_TXT_NOSKILLS ] ); + swprintf( sTemp, L"%s", pPersonnelScreenStrings[ PRSNL_TXT_NOSKILLS ] ); + wcscat( pStr, sTemp ); } else { @@ -6974,8 +6982,8 @@ void AddPlayerToInterfaceTeamSlot( UINT8 ubID ) return; } - //if ( !( MercPtrs[ ubID ]->flags.uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER ) ) ) - //{ + if ( !( MercPtrs[ ubID ]->flags.uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER ) ) ) + { if ( !PlayerExistsInSlot( ubID ) ) { // Find a free slot @@ -6999,38 +7007,38 @@ void AddPlayerToInterfaceTeamSlot( UINT8 ubID ) } } } - //} - //else - //{ - // // anv: for passengers, position on team panel will be linked with seat in vehicle - // if ( MercPtrs[ ubID ]->flags.uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER ) ) - // { - // SOLDIERTYPE *pVehicle = GetSoldierStructureForVehicle( MercPtrs[ ubID ]->iVehicleId ); - // if( pVehicle != NULL ) - // { - // for( UINT8 iCounter = 0; iCounter < gNewVehicle[ pVehicleList[ MercPtrs[ ubID ]->iVehicleId ].ubVehicleType ].iNewSeatingCapacities; iCounter++ ) - // { - // SOLDIERTYPE *pPassenger = pVehicleList[ MercPtrs[ ubID ]->iVehicleId ].pPassengers[ iCounter ]; - // if( pPassenger != NULL && pPassenger->ubID == ubID ) - // { - // gTeamPanel[ iCounter ].fOccupied = TRUE; - // gTeamPanel[ iCounter ].ubID = ubID; + } + else + { + // anv: for passengers, position on team panel will be linked with seat in vehicle + if ( MercPtrs[ ubID ]->flags.uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER ) ) + { + SOLDIERTYPE *pVehicle = GetSoldierStructureForVehicle( MercPtrs[ ubID ]->iVehicleId ); + if( pVehicle != NULL ) + { + for( UINT8 iCounter = 0; iCounter < gNewVehicle[ pVehicleList[ MercPtrs[ ubID ]->iVehicleId ].ubVehicleType ].iNewSeatingCapacities; iCounter++ ) + { + SOLDIERTYPE *pPassenger = pVehicleList[ MercPtrs[ ubID ]->iVehicleId ].pPassengers[ iCounter ]; + if( pPassenger != NULL && pPassenger->ubID == ubID ) + { + gTeamPanel[ iCounter ].fOccupied = TRUE; + gTeamPanel[ iCounter ].ubID = ubID; - // MSYS_SetRegionUserData( &gTEAM_FirstHandInv[ iCounter ], 0, iCounter ); - // MSYS_SetRegionUserData( &gTEAM_FaceRegions[ iCounter ], 0, iCounter ); + MSYS_SetRegionUserData( &gTEAM_FirstHandInv[ iCounter ], 0, iCounter ); + MSYS_SetRegionUserData( &gTEAM_FaceRegions[ iCounter ], 0, iCounter ); - // // DIRTY INTERFACE - // fInterfacePanelDirty = DIRTYLEVEL2; + // DIRTY INTERFACE + fInterfacePanelDirty = DIRTYLEVEL2; - // // Set ID to do open anim - // MercPtrs[ ubID ]->flags.fUInewMerc = TRUE; - // - // return; - // } - // } - // } - // } - //} + // Set ID to do open anim + MercPtrs[ ubID ]->flags.fUInewMerc = TRUE; + + return; + } + } + } + } + } } BOOLEAN InitTEAMSlots( ) diff --git a/Tactical/Interface.cpp b/Tactical/Interface.cpp index 072c4ad6..b4d17797 100644 --- a/Tactical/Interface.cpp +++ b/Tactical/Interface.cpp @@ -1083,6 +1083,17 @@ void PopupMovementMenu( UI_EVENT *pUIEvent ) fDisableAction = TRUE; } + // anv: don't switch if passengers are blocked from attacking + if( pSoldier->flags.uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER ) ) + { + SOLDIERTYPE *pVehicle = GetSoldierStructureForVehicle( pSoldier->iVehicleId ); + INT8 bSeatIndex = GetSeatIndexFromSoldier( pSoldier ); + if( gNewVehicle[ pVehicleList[ pSoldier->iVehicleId ].ubVehicleType ].VehicleSeats[bSeatIndex].fBlockedShots == TRUE ) + { + fDisableAction = TRUE; + } + } + iActionIcons[ ACTIONC_ICON ] = QuickCreateButton( iIconImages[ uiActionImages ], (INT16)(iMenuAnchorX ), (INT16)(iMenuAnchorY + 20 ), BUTTON_NO_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, DEFAULT_MOVE_CALLBACK, (GUI_CALLBACK)BtnMovementCallback ); @@ -1776,7 +1787,16 @@ void DrawSelectedUIAboveGuy( UINT16 usSoldierID ) //if ( pSoldier->flags.fShowLocator ) { // Render the beastie - GetSoldierAboveGuyPositions( pSoldier, &sXPos, &sYPos, TRUE ); + // anv: if soldier is in vehicle, draw above middle of the vehicle + if( !(pSoldier->flags.uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER ) ) ) + { + GetSoldierAboveGuyPositions( pSoldier, &sXPos, &sYPos, TRUE ); + } + else + { + SOLDIERTYPE *pVehicle = GetSoldierStructureForVehicle( pSoldier->iVehicleId ); + GetSoldierAboveGuyPositions( pVehicle, &sXPos, &sYPos, TRUE ); + } // Adjust for bars! sXPos += 25; @@ -1833,7 +1853,16 @@ void DrawSelectedUIAboveGuy( UINT16 usSoldierID ) if ( gGameExternalOptions.ubShowHealthBarsOnHead ) { // Render the beastie - GetSoldierAboveGuyPositions( pSoldier, &sXPos, &sYPos, TRUE ); + // anv: if soldier is in vehicle, draw above middle of the vehicle + if( !(pSoldier->flags.uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER ) ) ) + { + GetSoldierAboveGuyPositions( pSoldier, &sXPos, &sYPos, TRUE ); + } + else + { + SOLDIERTYPE *pVehicle = GetSoldierStructureForVehicle( pSoldier->iVehicleId ); + GetSoldierAboveGuyPositions( pVehicle, &sXPos, &sYPos, TRUE ); + } // Adjust for bars! sXPos += 25; @@ -1901,7 +1930,16 @@ void DrawSelectedUIAboveGuy( UINT16 usSoldierID ) return; } - GetSoldierAboveGuyPositions( pSoldier, &sXPos, &sYPos, FALSE ); + // anv: if soldier is in vehicle, draw above middle of the vehicle + if( !(pSoldier->flags.uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER ) ) ) + { + GetSoldierAboveGuyPositions( pSoldier, &sXPos, &sYPos, FALSE ); + } + else + { + SOLDIERTYPE *pVehicle = GetSoldierStructureForVehicle( pSoldier->iVehicleId ); + GetSoldierAboveGuyPositions( pVehicle, &sXPos, &sYPos, FALSE ); + } // Display name SetFont( TINYFONT1 ); diff --git a/Tactical/LOS.cpp b/Tactical/LOS.cpp index 6de372a4..bc70ebc2 100644 --- a/Tactical/LOS.cpp +++ b/Tactical/LOS.cpp @@ -43,6 +43,7 @@ #include "Quests.h" #include "items.h" #include "Item Types.h" +#include "Vehicles.h" #endif #include "fresh_header.h" #include "WorldDat.h" @@ -902,6 +903,16 @@ INT16 GetSightAdjustment( SOLDIERTYPE* pSoldier, INT32 sGridNo, INT16 bLevel, IN iSightAdjustment += GetSightAdjustmentCamouflageOnTerrain( pSoldier, bStance, ubTerrainType ); } + // anv: some places in vehicle completely obscure passenger from outside + INT8 bSeatIndex = GetSeatIndexFromSoldier( pSoldier ); + if( bSeatIndex != (-1) ) + { + if( gNewVehicle[ pVehicleList[ pSoldier->iVehicleId ].ubVehicleType ].VehicleSeats[ bSeatIndex ].fHidden ) + { + iSightAdjustment = (-100); + } + } + return MINMAX100N(iSightAdjustment); } @@ -2316,6 +2327,32 @@ INT32 SoldierToSoldierLineOfSightTest( SOLDIERTYPE * pStartSoldier, SOLDIERTYPE iTileSightLimit += iTileSightLimit * GetSightAdjustment(pEndSoldier) / 100; } + // anv: special check for vehicles - since they're no longer transparent, we need to check for visibility + // of all substructures, also vehicle will be noticed even if just part of it is sticking around the corner + if( pEndSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE && !TANK( pEndSoldier ) ) + { + STRUCTURE *pBase = pEndSoldier->pLevelNode->pStructureData; + if( pBase == NULL ) + { + return( FALSE ); + } + DB_STRUCTURE_TILE ** ppTile = pBase->pDBStructureRef->ppTile; + UINT8 ubNumberOfTiles = pBase->pDBStructureRef->pDBStructure->ubNumberOfTiles; + + INT32 sStructGridNo; + + // loop through all tiles + for (UINT8 ubLoop = BASE_TILE; ubLoop < ubNumberOfTiles; ubLoop++) + { + sStructGridNo = AddPosRelToBase(pBase->sGridNo, ppTile[ubLoop]); + if( LineOfSightTest( (FLOAT) CenterX( pStartSoldier->sGridNo ), (FLOAT) CenterY( pStartSoldier->sGridNo ), dStartZPos, (FLOAT) CenterX( sStructGridNo ), (FLOAT) CenterY( sStructGridNo ), dEndZPos, iTileSightLimit, bAware, fSmell, NULL, adjustForSight, cthCalc ) ) + { + return( TRUE ); + } + } + return( FALSE ); + } + return( LineOfSightTest( (FLOAT) CenterX( pStartSoldier->sGridNo ), (FLOAT) CenterY( pStartSoldier->sGridNo ), dStartZPos, (FLOAT) CenterX( pEndSoldier->sGridNo ), (FLOAT) CenterY( pEndSoldier->sGridNo ), dEndZPos, iTileSightLimit, bAware, fSmell, NULL, adjustForSight, cthCalc ) ); } diff --git a/Tactical/Overhead.cpp b/Tactical/Overhead.cpp index 0f38ebc8..7c927af4 100644 --- a/Tactical/Overhead.cpp +++ b/Tactical/Overhead.cpp @@ -1512,7 +1512,7 @@ BOOLEAN ExecuteOverhead( ) } else if ( pSoldier->aiData.ubPendingAction == MERC_ENTER_VEHICLE ) { - pSoldier->EVENT_SoldierEnterVehicle( pSoldier->aiData.sPendingActionData2, pSoldier->aiData.bPendingActionData3 ); + pSoldier->EVENT_SoldierEnterVehicle( pSoldier->aiData.sPendingActionData2, pSoldier->aiData.bPendingActionData3, pSoldier->aiData.uiPendingActionData4 ); pSoldier->aiData.ubPendingAction = NO_PENDING_ACTION; continue; } @@ -3104,8 +3104,15 @@ void InternalSelectSoldier( UINT16 usSoldierID, BOOLEAN fAcknowledge, BOOLEAN fF if( ( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) ) { - pSoldier = GetDriver( pSoldier->iVehicleId ); - usSoldierID = pSoldier->ubID; + pSoldier = GetDriver( pSoldier->bVehicleID ); + if( pSoldier == NULL ) + { + return; + } + else + { + usSoldierID = pSoldier->ubID; + } } // If we are dead, ignore diff --git a/Tactical/Real Time Input.cpp b/Tactical/Real Time Input.cpp index fe35385d..9fe82c0d 100644 --- a/Tactical/Real Time Input.cpp +++ b/Tactical/Real Time Input.cpp @@ -62,6 +62,7 @@ #include "SkillMenu.h" // sevenfm: need this for TraitsMenu #include "Vehicles.h" // anv: for switching from soldier to vehicle +#include "VehicleMenu.h" #endif @@ -1249,6 +1250,16 @@ void QueryRTRightButton( UINT32 *puiNewEvent ) break; } } + // anv: CTRL+RMB - VehicleMenu + else if(_KeyDown(CTRL)) + { + switch( gCurrentUIMode ) + { + case HANDCURSOR_MODE: + HandleHandCursorRightClick( usMapPos, puiNewEvent ); + break; + } + } else { // Switch on UI mode @@ -1261,7 +1272,18 @@ void QueryRTRightButton( UINT32 *puiNewEvent ) case CONFIRM_MOVE_MODE: case MOVE_MODE: case TALKCURSOR_MODE: - + // anv: don't switch if passengers are blocked from attacking + pSoldier = MercPtrs[ gusSelectedSoldier ]; + if( pSoldier->flags.uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER ) ) + { + SOLDIERTYPE *pVehicle = GetSoldierStructureForVehicle( pSoldier->iVehicleId ); + INT8 bSeatIndex = GetSeatIndexFromSoldier( pSoldier ); + if( gNewVehicle[ pVehicleList[ pSoldier->iVehicleId ].ubVehicleType ].VehicleSeats[bSeatIndex].fBlockedShots == TRUE ) + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, pVehicleSeatsStrings[0] ); + break; + } + } // We have here a change to action mode *puiNewEvent = M_CHANGE_TO_ACTION; fClickIntercepted = TRUE; diff --git a/Tactical/Soldier Control.cpp b/Tactical/Soldier Control.cpp index 7cf2070b..261a1483 100644 --- a/Tactical/Soldier Control.cpp +++ b/Tactical/Soldier Control.cpp @@ -1097,6 +1097,7 @@ void SOLDIERTYPE::initialize() memset( this, 0, SIZEOF_SOLDIERTYPE_POD); inv.clear(); ai_masterplan_ = 0; + this->iVehicleId = (-1); memset( &aiData, 0, sizeof(STRUCT_AIData) ); memset( &flags, 0, sizeof(STRUCT_Flags) ); @@ -8210,6 +8211,7 @@ void SOLDIERTYPE::TurnSoldier( void ) pVehicleList[ iId ].pPassengers[ iCounter ]->EVENT_SetSoldierDesiredDirection( ( pVehicleList[ iId ].pPassengers[ iCounter ]->pathing.bDesiredDirection + bDirectionChange + NUM_WORLD_DIRECTIONS ) % NUM_WORLD_DIRECTIONS ); } } + UpdateAllVehiclePassengersGridNo( this ); } // If the soldier is not crawling or multi-tiled, he should be allowed to turn in place. Even if there is some @@ -12643,7 +12645,7 @@ void SOLDIERTYPE::EVENT_SoldierBeginFirstAid( INT32 sGridNo, UINT8 ubDirection ) } -void SOLDIERTYPE::EVENT_SoldierEnterVehicle( INT32 sGridNo, UINT8 ubDirection ) +void SOLDIERTYPE::EVENT_SoldierEnterVehicle( INT32 sGridNo, UINT8 ubDirection, UINT8 ubSeatIndex ) { SOLDIERTYPE *pTSoldier; UINT32 uiMercFlags; @@ -12654,7 +12656,7 @@ void SOLDIERTYPE::EVENT_SoldierEnterVehicle( INT32 sGridNo, UINT8 ubDirection ) pTSoldier = MercPtrs[ usSoldierIndex ]; // Enter vehicle... - EnterVehicle( pTSoldier, this ); + EnterVehicle( pTSoldier, this, ubSeatIndex ); } UnSetUIBusy( this->ubID ); @@ -20497,6 +20499,10 @@ void InternalPlaySoldierFootstepSound( SOLDIERTYPE * pSoldier ) { // anv: vehicle sounds //PlaySoldierJA2Sample( pSoldier->ubID, S_VECH1_MOVE, RATE_11025, SoundVolume( bVolume, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); + if ( pSoldier->usAnimState == RUNNING ) + { + bVolume = HIGHVOLUME; + } PlaySoldierJA2Sample( pSoldier->ubID, pVehicleList[ pSoldier->bVehicleID ].iMoveSound, RATE_11025, SoundVolume( bVolume, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); } } diff --git a/Tactical/Soldier Control.h b/Tactical/Soldier Control.h index cc731130..2f1f4aaf 100644 --- a/Tactical/Soldier Control.h +++ b/Tactical/Soldier Control.h @@ -1546,7 +1546,7 @@ public: void EVENT_SoldierBeginUseDetonator( void ); void EVENT_SoldierBeginDropBomb( ); void EVENT_SoldierDefuseTripwire( INT32 sGridNo, INT32 sItem ); - void EVENT_SoldierEnterVehicle( INT32 sGridNo, UINT8 ubDirection ); + void EVENT_SoldierEnterVehicle( INT32 sGridNo, UINT8 ubDirection, UINT8 ubSeatIndex = 0 ); void EVENT_SoldierBeginGiveItem( void ); void EVENT_SetSoldierPositionAndMaybeFinalDest( FLOAT dNewXPos, FLOAT dNewYPos, BOOLEAN fUpdateFinalDest ); void EVENT_SetSoldierPositionForceDelete( FLOAT dNewXPos, FLOAT dNewYPos ); diff --git a/Tactical/Tactical_VS2005.vcproj b/Tactical/Tactical_VS2005.vcproj index f3f745e3..732cff86 100644 --- a/Tactical/Tactical_VS2005.vcproj +++ b/Tactical/Tactical_VS2005.vcproj @@ -666,6 +666,10 @@ RelativePath=".\Vehicles.h" > + + @@ -992,6 +996,10 @@ RelativePath=".\Vehicles.cpp" > + + diff --git a/Tactical/Tactical_VS2008.vcproj b/Tactical/Tactical_VS2008.vcproj index e8869040..2e584bf0 100644 --- a/Tactical/Tactical_VS2008.vcproj +++ b/Tactical/Tactical_VS2008.vcproj @@ -670,6 +670,10 @@ RelativePath="Vehicles.h" > + + @@ -994,6 +998,10 @@ RelativePath="Vehicles.cpp" > + + diff --git a/Tactical/Tactical_VS2010.vcxproj b/Tactical/Tactical_VS2010.vcxproj index 10fc0d52..d1c3a9da 100644 --- a/Tactical/Tactical_VS2010.vcxproj +++ b/Tactical/Tactical_VS2010.vcxproj @@ -186,6 +186,7 @@ + diff --git a/Tactical/Tactical_VS2010.vcxproj.filters b/Tactical/Tactical_VS2010.vcxproj.filters index b92577d8..ed9dc3a4 100644 --- a/Tactical/Tactical_VS2010.vcxproj.filters +++ b/Tactical/Tactical_VS2010.vcxproj.filters @@ -668,5 +668,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/Tactical/Tactical_VS2013.vcxproj b/Tactical/Tactical_VS2013.vcxproj index ecbfab1f..b0f77f76 100644 --- a/Tactical/Tactical_VS2013.vcxproj +++ b/Tactical/Tactical_VS2013.vcxproj @@ -105,6 +105,7 @@ + @@ -187,6 +188,7 @@ + diff --git a/Tactical/Tactical_VS2013.vcxproj.filters b/Tactical/Tactical_VS2013.vcxproj.filters index cea304fe..ec81aea1 100644 --- a/Tactical/Tactical_VS2013.vcxproj.filters +++ b/Tactical/Tactical_VS2013.vcxproj.filters @@ -245,6 +245,9 @@ Header Files + + + Header Files Header Files @@ -484,6 +487,9 @@ Source Files + + + Source Files Source Files diff --git a/Tactical/Turn Based Input.cpp b/Tactical/Turn Based Input.cpp index 394977f0..94d333f2 100644 --- a/Tactical/Turn Based Input.cpp +++ b/Tactical/Turn Based Input.cpp @@ -107,6 +107,7 @@ #include "Militia Control.h" #include "Ambient Control.h" #include "Strategic AI.h" +#include "VehicleMenu.h" #endif #include "Quest Debug System.h" @@ -1012,6 +1013,16 @@ void QueryTBRightButton( UINT32 *puiNewEvent ) break; } } + // anv: CTRL+RMB - VehicleMenu + else if(_KeyDown(CTRL)) + { + switch( gCurrentUIMode ) + { + case HANDCURSOR_MODE: + HandleHandCursorRightClick( usMapPos, puiNewEvent ); + break; + } + } else { // Switch on UI mode @@ -1022,7 +1033,18 @@ void QueryTBRightButton( UINT32 *puiNewEvent ) break; case MOVE_MODE: - + // anv: don't switch if passengers are blocked from attacking + pSoldier = MercPtrs[ gusSelectedSoldier ]; + if( pSoldier->flags.uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER ) ) + { + SOLDIERTYPE *pVehicle = GetSoldierStructureForVehicle( pSoldier->iVehicleId ); + INT8 bSeatIndex = GetSeatIndexFromSoldier( pSoldier ); + if( gNewVehicle[ pVehicleList[ pSoldier->iVehicleId ].ubVehicleType ].VehicleSeats[bSeatIndex].fBlockedShots == TRUE ) + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, pVehicleSeatsStrings[0] ); + break; + } + } // We have here a change to action mode *puiNewEvent = M_CHANGE_TO_ACTION; fClickIntercepted = TRUE; @@ -5308,7 +5330,7 @@ void CreatePlayerControlledMonster() } -INT8 CheckForAndHandleHandleVehicleInteractiveClick( SOLDIERTYPE *pSoldier, UINT16 usMapPos, BOOLEAN fMovementMode ) +INT8 CheckForAndHandleHandleVehicleInteractiveClick( SOLDIERTYPE *pSoldier, UINT16 usMapPos, BOOLEAN fMovementMode, UINT8 ubSeatIndex ) { // Look for an item pool INT32 sActionGridNo; @@ -5320,7 +5342,9 @@ INT8 CheckForAndHandleHandleVehicleInteractiveClick( SOLDIERTYPE *pSoldier, UINT { pTSoldier = MercPtrs[ gusUIFullTargetID ]; - if ( OK_ENTERABLE_VEHICLE( pTSoldier ) && pTSoldier->bVisible != -1 && OKUseVehicle( pTSoldier->ubProfile ) ) + // anv: added condition - make sure we won't put vehicle in another vehicle + if ( OK_ENTERABLE_VEHICLE( pTSoldier ) && pTSoldier->bVisible != -1 && OKUseVehicle( pTSoldier->ubProfile ) && !( pSoldier->flags.uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER | SOLDIER_VEHICLE ) ) ) + //if ( OK_ENTERABLE_VEHICLE( pTSoldier ) && pTSoldier->bVisible != -1 && OKUseVehicle( pTSoldier->ubProfile ) ) { if ( ( GetNumberInVehicle( pTSoldier->bVehicleID ) == 0 ) || !fMovementMode ) { @@ -5344,6 +5368,7 @@ INT8 CheckForAndHandleHandleVehicleInteractiveClick( SOLDIERTYPE *pSoldier, UINT pSoldier->aiData.ubPendingAction = MERC_ENTER_VEHICLE; pSoldier->aiData.sPendingActionData2 = pTSoldier->sGridNo; pSoldier->aiData.bPendingActionData3 = ubDirection; + pSoldier->aiData.uiPendingActionData4 = ubSeatIndex; pSoldier->aiData.ubPendingActionAnimCount = 0; // WALK UP TO DEST FIRST @@ -5351,7 +5376,7 @@ INT8 CheckForAndHandleHandleVehicleInteractiveClick( SOLDIERTYPE *pSoldier, UINT } else { - pSoldier->EVENT_SoldierEnterVehicle( pTSoldier->sGridNo, ubDirection ); + pSoldier->EVENT_SoldierEnterVehicle( pTSoldier->sGridNo, ubDirection, ubSeatIndex ); } // OK, set UI @@ -5390,7 +5415,7 @@ void HandleHandCursorClick( INT32 usMapPos, UINT32 *puiNewEvent ) return; } - if ( CheckForAndHandleHandleVehicleInteractiveClick( pSoldier, usMapPos, FALSE ) == -1 ) + if ( CheckForAndHandleHandleVehicleInteractiveClick( pSoldier, usMapPos, FALSE, 0 ) == -1 ) { return; } @@ -5531,6 +5556,41 @@ void HandleHandCursorClick( INT32 usMapPos, UINT32 *puiNewEvent ) } } +void HandleHandCursorRightClick( INT32 usMapPos, UINT32 *puiNewEvent ) +{ + SOLDIERTYPE *pSoldier; + SOLDIERTYPE *pTSoldier; + + if( GetSoldier( &pSoldier, gusSelectedSoldier ) ) + { + // If we are out of breath, no cursor... + if( pSoldier->bBreath < OKBREATH && pSoldier->bCollapsed ) + { + return; + } + + if( gfUIFullTargetFound ) + { + pTSoldier = MercPtrs[ gusUIFullTargetID ]; + if( OK_ENTERABLE_VEHICLE( pTSoldier ) && pTSoldier->bVisible != -1 && OKUseVehicle( pTSoldier->ubProfile ) ) + { + // anv: if we are passengers, only show menu when clicking on vehicle we're in + if( pSoldier->flags.uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER ) ) + { + if( pSoldier->iVehicleId == pTSoldier->bVehicleID ) + { + VehicleMenu(usMapPos, pSoldier, pTSoldier); + } + } + else + { + VehicleMenu(usMapPos, pSoldier, pTSoldier); + } + return; + } + } + } +} extern BOOLEAN AnyItemsVisibleOnLevel( ITEM_POOL *pItemPool, INT8 bZLevel ); @@ -5596,7 +5656,7 @@ INT8 HandleMoveModeInteractiveClick( INT32 usMapPos, UINT32 *puiNewEvent ) } // See if we are over a vehicle, and walk up to it and enter.... - if ( CheckForAndHandleHandleVehicleInteractiveClick( pSoldier, usMapPos, TRUE ) == -1 ) + if ( CheckForAndHandleHandleVehicleInteractiveClick( pSoldier, usMapPos, TRUE, 0 ) == -1 ) { return( -1 ); } @@ -6744,6 +6804,24 @@ void SwapMercPortraits ( SOLDIERTYPE *pSoldier, INT8 bDirection ) INT8 bNewPosition = bOldPosition + bDirection; SOLDIERTYPE TempMercPtr = *MercPtrs[ ubSourceMerc ]; + // anv: vehicle passengers are swapped differently + if( pSoldier->flags.uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER ) ) + { + SOLDIERTYPE *pVehicle = GetSoldierStructureForVehicle( pSoldier->iVehicleId ); + if( pVehicle != NULL && bNewPosition < gNewVehicle[pVehicle->bVehicleID].iNewSeatingCapacities ) + { + if( SwapVehicleSeat( pVehicle, pSoldier, bNewPosition ) ) + { + RebuildCurrentSquad( ); + // refresh interface + fCharacterInfoPanelDirty = TRUE; + fTeamPanelDirty = TRUE; + fInterfacePanelDirty = DIRTYLEVEL2; + } + } + return; + } + // check if new position is occupied by another merc? we won't replace an empty slot if ( gTeamPanel[ bNewPosition ].fOccupied && gTeamPanel[ bNewPosition ].ubID != NOBODY ) { @@ -6786,13 +6864,6 @@ void SwapMercPortraits ( SOLDIERTYPE *pSoldier, INT8 bDirection ) // don't forget to renew selection of merc gusSelectedSoldier = ubTargetMerc; - // anv: if swapped guy was a driver, make sure vehicle driver ubID gets updates - if( MercPtrs[ ubTargetMerc ]->flags.uiStatusFlags & SOLDIER_DRIVER ) - { - pVehicleList[ pSoldier->iVehicleId ].ubDriver = MercPtrs[ ubTargetMerc ]->ubID; - } - - // refresh interface fCharacterInfoPanelDirty = TRUE; fTeamPanelDirty = TRUE; diff --git a/Tactical/VehicleMenu.cpp b/Tactical/VehicleMenu.cpp new file mode 100644 index 00000000..072baa63 --- /dev/null +++ b/Tactical/VehicleMenu.cpp @@ -0,0 +1,222 @@ +// anv: totally not a copy of SkillMenu.cpp + +#include "VehicleMenu.h" +#include "Soldier Profile Type.h" +#include "Overhead.h" +#include "Text.h" +#include "Isometric Utils.h" +#include "DisplayCover.h" +#include "worldman.h" +#include "Vehicles.h" +#include "soldier macros.h" +#include "Soldier Add.h" +#include "PATHAI.h" +#include "Points.h" +#include "Handle UI.h" +#include "Squads.h" +#include "Font Control.h" + +// sevenfm: need this for correct calculation of vehicle menu position +extern INT16 gsInterfaceLevel; + +UINT16 usVehicleMenuPosX = 0; +UINT16 usVehicleMenuPosY = 0; + +INT32 sVehicleMenuTargetGridNo = NOWHERE; + +SOLDIERTYPE *pCurrentSoldier = NULL; +SOLDIERTYPE *pCurrentVehicle = NULL; + +void HideVehicleMenu( void ) +{ + // Dirty! + fMapPanelDirty = TRUE; +} + +// Turns an option off by always returning FALSE +BOOLEAN Popup_VehicleMenuOptionOff( void ) { return FALSE; } + +void +VehicleMenuItem::SetupPopup(CHAR* name) +{ + // create a popup + gPopup = new POPUP(name); + + // add a callback that lets the keyboard handler know we're done (and ready to pop up again) + gPopup->setCallback(POPUP_CALLBACK_HIDE, new popupCallbackFunction( &HideVehicleMenu ) ); +} + +// Different VehicleItem classes. We need wrappers for each one, as we cannot pass a pointer to a member function (we need a concrete object) + +/////////////////////////////// Vehicle Selection //////////////////////////////////////////// +VehicleSelection gVehicleSelection; + +void Wrapper_Function_VehicleSelection( UINT32 aVal ) { gVehicleSelection.Functions(aVal); } +void Wrapper_Setup_VehicleSelection( UINT32 aVal ) { gVehicleSelection.Setup(aVal); } +void Wrapper_Cancel_VehicleSelection( UINT32 aVal ) { gVehicleSelection.Cancel(); } +/////////////////////////////// Vehicle Selection //////////////////////////////////////////// + +/////////////////////////////// Vehicle Selection //////////////////////////////////////////// +void +VehicleSelection::Setup( UINT32 aVal ) +{ + Destroy(); + + if ( pCurrentSoldier == NULL ) + return; + + if ( pCurrentVehicle == NULL ) + return; + + SetupPopup("VehicleSelection"); + + POPUP_OPTION *pOption; + + CHAR16 pStr[300]; + + // create entries for each vehicle seat + INT8 bVehicleID = pCurrentVehicle->bVehicleID; + INT8 bSeatIndex = GetSeatIndexFromSoldier( pCurrentSoldier ); + INT32 iSeatingCapacity = gNewVehicle[ pVehicleList[ bVehicleID ].ubVehicleType ].iNewSeatingCapacities; + + for ( int i = 0; i < iSeatingCapacity; ++i) + { + swprintf( pStr, gNewVehicle[ pVehicleList[ bVehicleID ].ubVehicleType ].VehicleSeats[i].zSeatName ); + + pOption = new POPUP_OPTION(&std::wstring( pStr ), new popupCallbackFunction( &Wrapper_Function_VehicleSelection, i )); + + // if seat is already taken, grey it out + if ( pVehicleList[ bVehicleID ].pPassengers[ i ] != NULL ) + { + if( pCurrentSoldier->flags.uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER ) ) + { + if( pVehicleList[ bVehicleID ].pPassengers[ i ] == pCurrentSoldier ) + { + // Set this option off. + pOption->setAvail(new popupCallbackFunction( &Popup_VehicleMenuOptionOff, NULL )); + } + else + { + // keep, but colour in yellow + pOption->color_foreground = FONT_YELLOW; + } + } + else + { + // Set this option off. + pOption->setAvail(new popupCallbackFunction( &Popup_VehicleMenuOptionOff, NULL )); + } + } + + // block swapping between different compartments + if( gTacticalStatus.uiFlags & INCOMBAT ) + { + if( bSeatIndex != (-1) ) + { + if( gNewVehicle[pVehicleList[ pCurrentVehicle->bVehicleID ].ubVehicleType].VehicleSeats[bSeatIndex].ubCompartment != + gNewVehicle[pVehicleList[ pCurrentVehicle->bVehicleID ].ubVehicleType].VehicleSeats[i].ubCompartment ) + { + // Set this option off. + pOption->setAvail(new popupCallbackFunction( &Popup_VehicleMenuOptionOff, NULL )); + } + } + } + + GetPopup()->addOption( *pOption ); + } + + // cancel option + swprintf( pStr, pSkillMenuStrings[SKILLMENU_CANCEL] ); + pOption = new POPUP_OPTION(&std::wstring( pStr ), new popupCallbackFunction( &Wrapper_Cancel_VehicleSelection, 0 ) ); + GetPopup()->addOption( *pOption ); + + // grab soldier's x,y screen position + INT16 sX, sY; + GetGridNoScreenPos( sVehicleMenuTargetGridNo, gsInterfaceLevel, &sX, &sY ); + + if( sX < 0 ) sX = 0; + if( sY < 0 ) sY = 0; + + usVehicleMenuPosX = sX + 30; + usVehicleMenuPosY = sY; + + if ( ( usVehicleMenuPosX + 200 ) > SCREEN_WIDTH ) + usVehicleMenuPosX = SCREEN_WIDTH - 200; + + if ( ( usVehicleMenuPosY + 130 ) > SCREEN_HEIGHT ) + usVehicleMenuPosY = SCREEN_HEIGHT - 190; + + SetPos(usVehicleMenuPosX, usVehicleMenuPosY); +} + +void +VehicleSelection::Functions( UINT32 aVal ) +{ + INT32 sActionGridNo; + UINT8 ubDirection; + INT16 sAPCost = 0; + INT32 sTempSelectedSoldier; + + Cancel(); + + if( pCurrentSoldier->flags.uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER ) && pCurrentSoldier->iVehicleId == pCurrentVehicle->bVehicleID ) + { + if( SwapVehicleSeat( pCurrentVehicle, pCurrentSoldier, aVal ) ) + { + sTempSelectedSoldier = gusSelectedSoldier; + SetCurrentSquad( CurrentSquad(), TRUE ); + gusSelectedSoldier = sTempSelectedSoldier; + } + } + else if ( OK_ENTERABLE_VEHICLE( pCurrentVehicle ) && pCurrentVehicle->bVisible != -1 && OKUseVehicle( pCurrentVehicle->ubProfile ) ) + { + // Find a gridno closest to sweetspot... + sActionGridNo = FindGridNoFromSweetSpotWithStructDataFromSoldier( pCurrentSoldier, pCurrentSoldier->usUIMovementMode, 5, &ubDirection, 0, pCurrentVehicle, TRUE ); + + if (!TileIsOutOfBounds(sActionGridNo)) + { + // Calculate AP costs... + //sAPCost = GetAPsToBeginFirstAid( pSoldier ); + sAPCost += PlotPath( pCurrentSoldier, sActionGridNo, NO_COPYROUTE, FALSE, TEMPORARY, (UINT16)pCurrentSoldier->usUIMovementMode, NOT_STEALTH, FORWARD, pCurrentSoldier->bActionPoints); + + if ( EnoughPoints( pCurrentSoldier, sAPCost, 0, TRUE ) ) + { + pCurrentSoldier->DoMercBattleSound( BATTLE_SOUND_OK1 ); + + // CHECK IF WE ARE AT THIS GRIDNO NOW + if ( pCurrentSoldier->sGridNo != sActionGridNo ) + { + // SEND PENDING ACTION + pCurrentSoldier->aiData.ubPendingAction = MERC_ENTER_VEHICLE; + pCurrentSoldier->aiData.sPendingActionData2 = pCurrentVehicle->sGridNo; + pCurrentSoldier->aiData.bPendingActionData3 = ubDirection; + pCurrentSoldier->aiData.uiPendingActionData4 = aVal; + pCurrentSoldier->aiData.ubPendingActionAnimCount = 0; + + // WALK UP TO DEST FIRST + pCurrentSoldier->EVENT_InternalGetNewSoldierPath( sActionGridNo, pCurrentSoldier->usUIMovementMode, 3 , pCurrentSoldier->flags.fNoAPToFinishMove ); + } + else + { + pCurrentSoldier->EVENT_SoldierEnterVehicle( pCurrentVehicle->sGridNo, ubDirection, aVal ); + } + + // OK, set UI + SetUIBusy( pCurrentSoldier->ubID ); + //guiPendingOverrideEvent = A_CHANGE_TO_MOVE; + } + } + } + + Cancel(); + gVehicleSelection.Cancel(); +} +/////////////////////////////// Vehicle Selection //////////////////////////////////////////// + +void VehicleMenu( INT32 usMapPos, SOLDIERTYPE *pSoldier, SOLDIERTYPE *pVehicle ) +{ + sVehicleMenuTargetGridNo = usMapPos; + pCurrentSoldier = pSoldier; + pCurrentVehicle = pVehicle; + gVehicleSelection.Setup(0); +} \ No newline at end of file diff --git a/Tactical/VehicleMenu.h b/Tactical/VehicleMenu.h new file mode 100644 index 00000000..7d5a418c --- /dev/null +++ b/Tactical/VehicleMenu.h @@ -0,0 +1,85 @@ +#ifndef _VEHICLE_MENU_ +#define _VEHICLE_MENU_ + +#include "popup_class.h" +#include "Soldier Profile.h" + +class VehicleMenuItem +{ +public: + VehicleMenuItem() : + fInitialized(FALSE), usPosX(0), gPopup(NULL) + { + } + + virtual void Cancel() + { + // Hide the Filter Menu pop-up. + if (gPopup != NULL && fInitialized ) + { + gPopup->hide(); + } + } + + virtual void Destroy() + { + // If we already have a popup, destroy it first. This ensures we get a fresh menu each time. + if ( fInitialized ) + { + delete(gPopup); + gPopup = NULL; + fInitialized = FALSE; + } + } + + UINT16 GetMaxPosX() + { + if ( gPopup ) + return (usPosX + gPopup->getBoxDimensions().iRight); + + return usPosX; + } + + virtual void SetPos(UINT16 usX, UINT16 usY) + { + // same y, different x + usPosX = usX; + gPopup->setPosition( usPosX, usY ); + + fInitialized = TRUE; + gPopup->show(); + } + + void SetupPopup(CHAR* name); + + POPUP* GetPopup() + { + return gPopup; + } + + virtual void Setup( UINT32 aVal ) {} + virtual void Functions( UINT32 aVal ) {} + +private: + BOOLEAN fInitialized; + UINT16 usPosX; + POPUP* gPopup; +}; + +// select a vehicle seat (and possibly other options) +class VehicleSelection : public VehicleMenuItem +{ +public: + VehicleSelection() : usSector(0) {} + + void Setup( UINT32 aVal ); + void Functions( UINT32 aVal ); + +private: + UINT32 usSector; +}; + + +void VehicleMenu( INT32 usMapPos, SOLDIERTYPE *pSoldier, SOLDIERTYPE *pVehicle ); + +#endif \ No newline at end of file diff --git a/Tactical/Vehicles.cpp b/Tactical/Vehicles.cpp index bffd894a..6b07c5c3 100644 --- a/Tactical/Vehicles.cpp +++ b/Tactical/Vehicles.cpp @@ -475,10 +475,12 @@ BOOLEAN IsThisVehicleAccessibleToSoldier( SOLDIERTYPE *pSoldier, INT32 iId ) } -BOOLEAN AddSoldierToVehicle( SOLDIERTYPE *pSoldier, INT32 iId, BOOLEAN fSpecificSeat, UINT8 ubSeatIndex ) +BOOLEAN AddSoldierToVehicle( SOLDIERTYPE *pSoldier, INT32 iId, UINT8 ubSeatIndex ) { INT32 iCounter = 0; UINT32 vCount = 0; + UINT8 ubFinalSeatIndex = 0; + BOOLEAN fFoundPlace = FALSE; SOLDIERTYPE *pVehicleSoldier = NULL; @@ -571,13 +573,35 @@ BOOLEAN AddSoldierToVehicle( SOLDIERTYPE *pSoldier, INT32 iId, BOOLEAN fSpecific PlayJA2Sample( pVehicleList[ pVehicleSoldier->bVehicleID ].iOutOfSound, RATE_11025, SoundVolume( HIGHVOLUME, pVehicleSoldier->sGridNo ), 1, SoundDir( pVehicleSoldier->sGridNo ) ); } - for( iCounter = 0; iCounter < gNewVehicle[ pVehicleList[ iId ].ubVehicleType ].iNewSeatingCapacities; iCounter++ ) + + if( pVehicleList[ iId ].pPassengers[ ubSeatIndex ] == NULL ) + { + ubFinalSeatIndex = ubSeatIndex; + fFoundPlace = TRUE; + } + else + { + for( iCounter = 0; !fFoundPlace && iCounter < gNewVehicle[ pVehicleList[ iId ].ubVehicleType ].iNewSeatingCapacities; iCounter++ ) + { + if( pVehicleList[ iId ].pPassengers[ iCounter ] == NULL ) + { + ubFinalSeatIndex = iCounter; + fFoundPlace = TRUE; + } + } + + } + + if( fFoundPlace ) { // check if slot free - if( pVehicleList[ iId ].pPassengers[ iCounter ] == NULL ) + if( pVehicleList[ iId ].pPassengers[ ubFinalSeatIndex ] == NULL ) { + // anv: since now they can shoot it's important to set passenger to proper stance + SendChangeSoldierStanceEvent( pSoldier, ANIM_CROUCH ); + // add person in - pVehicleList[ iId ].pPassengers[ iCounter ] = pSoldier; + pVehicleList[ iId ].pPassengers[ ubFinalSeatIndex ] = pSoldier; if( pSoldier->bAssignment == VEHICLE ) { @@ -624,17 +648,27 @@ BOOLEAN AddSoldierToVehicle( SOLDIERTYPE *pSoldier, INT32 iId, BOOLEAN fSpecific } // Are we the first? - if ( GetNumberInVehicle( iId ) == 1 ) + //if ( GetNumberInVehicle( iId ) == 1 ) + //{ + // // Set as driver... + // pSoldier->flags.uiStatusFlags |= SOLDIER_DRIVER; + + // SetDriver( iId , pSoldier->ubID ); + + //} + //else + //{ + // // Set as driver... + // pSoldier->flags.uiStatusFlags |= SOLDIER_PASSENGER; + //} + + // anv: are we taking driver's seat + if( gNewVehicle[ pVehicleList[ iId ].ubVehicleType ].VehicleSeats[ubFinalSeatIndex].fDriver ) { - // Set as driver... - pSoldier->flags.uiStatusFlags |= SOLDIER_DRIVER; - SetDriver( iId , pSoldier->ubID ); - } else { - // Set as driver... pSoldier->flags.uiStatusFlags |= SOLDIER_PASSENGER; } @@ -643,8 +677,16 @@ BOOLEAN AddSoldierToVehicle( SOLDIERTYPE *pSoldier, INT32 iId, BOOLEAN fSpecific if ( pVehicleSoldier ) { + // bInitialActionPoints - point in time where soldier and vehicle start sharing timeline + pSoldier->bInitialActionPoints = pSoldier->bActionPoints; + // set proper initial rotation + UINT8 ubRotation = gNewVehicle[ pVehicleList[ pVehicleSoldier->bVehicleID ].ubVehicleType ].VehicleSeats[ ubSeatIndex ].ubRotation; + pSoldier->flags.fDontChargeTurningAPs = TRUE; + pSoldier->EVENT_SetSoldierDesiredDirection( ( pVehicleSoldier->pathing.bDesiredDirection + ubRotation ) % NUM_WORLD_DIRECTIONS ); + // Set gridno for vehicle..... - pSoldier->EVENT_SetSoldierPosition( pVehicleSoldier->dXPos, pVehicleSoldier->dYPos ); + //pSoldier->EVENT_SetSoldierPosition( pVehicleSoldier->dXPos, pVehicleSoldier->dYPos ); + UpdateAllVehiclePassengersGridNo( pVehicleSoldier ); // Stop from any movement..... pSoldier->EVENT_StopMerc( pSoldier->sGridNo, pSoldier->ubDirection ); @@ -754,6 +796,7 @@ BOOLEAN RemoveSoldierFromVehicle( SOLDIERTYPE *pSoldier, INT32 iId ) if( pSoldier->flags.uiStatusFlags & SOLDIER_DRIVER ) { fNewDriverNeeded = TRUE; + pVehicleList[ iId ].ubDriver = NOBODY; } pSoldier->flags.uiStatusFlags &= ( ~( SOLDIER_DRIVER | SOLDIER_PASSENGER ) ); @@ -765,14 +808,14 @@ BOOLEAN RemoveSoldierFromVehicle( SOLDIERTYPE *pSoldier, INT32 iId ) if( pVehicleList[ iId ].pPassengers[ iCounter ] != NULL ) { fSoldierLeft = TRUE; - if( fNewDriverNeeded ) - { - SOLDIERTYPE* pNewDriver = pVehicleList[ iId ].pPassengers[ iCounter ]; - pNewDriver->flags.uiStatusFlags |= SOLDIER_DRIVER; - pNewDriver->flags.uiStatusFlags &= ~(SOLDIER_PASSENGER); - SetDriver( iId, pNewDriver->ubID ); - fNewDriverNeeded = FALSE; - } + //if( fNewDriverNeeded ) + //{ + // SOLDIERTYPE* pNewDriver = pVehicleList[ iId ].pPassengers[ iCounter ]; + // pNewDriver->flags.uiStatusFlags |= SOLDIER_DRIVER; + // pNewDriver->flags.uiStatusFlags &= ~(SOLDIER_PASSENGER); + // SetDriver( iId, pNewDriver->ubID ); + // fNewDriverNeeded = FALSE; + //} } } @@ -1526,12 +1569,46 @@ BOOLEAN AnyAccessibleVehiclesInSoldiersSector( SOLDIERTYPE *pSoldier ) SOLDIERTYPE *GetDriver( INT32 iID ) { - return( MercPtrs[ pVehicleList[ iID ].ubDriver ] ); + INT32 iCounter; + if( pVehicleList[ iID ].ubDriver != NOBODY ) + { + return( MercPtrs[ pVehicleList[ iID ].ubDriver ] ); + } + else + { + // anv: if vehicle has no driver, return any passenger + for( iCounter = 0; iCounter < gNewVehicle[ pVehicleList[ iID ].ubVehicleType ].iNewSeatingCapacities; iCounter++ ) + { + if( pVehicleList[ iID ].pPassengers[ iCounter ] != NULL ) + { + return( pVehicleList[ iID ].pPassengers[ iCounter ] ); + } + } + } + return( NULL ); } void SetDriver( INT32 iID, UINT8 ubID ) { + // anv: first make sure previous driver won't be driver anymore + if( pVehicleList[ iID ].ubDriver != NOBODY ) + { + if( MercPtrs[ pVehicleList[ iID ].ubDriver ] ) + { + MercPtrs[ pVehicleList[ iID ].ubDriver ]->flags.uiStatusFlags &= ~(SOLDIER_DRIVER); + if( GetSeatIndexFromSoldier( MercPtrs[ pVehicleList[ iID ].ubDriver ] ) != (-1) ) + { + MercPtrs[ pVehicleList[ iID ].ubDriver ]->flags.uiStatusFlags |= SOLDIER_PASSENGER; + } + } + } + // set proper flags + if( ubID != NOBODY ) + { + MercPtrs[ ubID ]->flags.uiStatusFlags |= SOLDIER_DRIVER; + MercPtrs[ ubID ]->flags.uiStatusFlags &= ~(SOLDIER_PASSENGER); + } pVehicleList[ iID ].ubDriver = ubID; } @@ -1611,7 +1688,7 @@ BOOLEAN TakeSoldierOutOfVehicle( SOLDIERTYPE *pSoldier ) -BOOLEAN EnterVehicle( SOLDIERTYPE *pVehicle, SOLDIERTYPE *pSoldier, BOOLEAN fSpecificSeat, UINT8 ubSeatIndex ) +BOOLEAN EnterVehicle( SOLDIERTYPE *pVehicle, SOLDIERTYPE *pSoldier, UINT8 ubSeatIndex ) { // TEST IF IT'S VALID... @@ -1621,13 +1698,9 @@ BOOLEAN EnterVehicle( SOLDIERTYPE *pVehicle, SOLDIERTYPE *pSoldier, BOOLEAN fSpe if ( IsEnoughSpaceInVehicle( pVehicle->bVehicleID ) ) { // anv: check if preferred seat is already taken, if so automatically choose another - if( fSpecificSeat ) + if ( pVehicleList[ pVehicle->bVehicleID ].pPassengers[ubSeatIndex] != NULL ) { - if ( pVehicleList[ pVehicle->bVehicleID ].pPassengers[ubSeatIndex] != NULL ) - { - fSpecificSeat = FALSE; - ubSeatIndex = 0; - } + ubSeatIndex = 0; } INT16 sAPCost = APBPConstants[AP_ENTER_VEHICLE]; @@ -1640,16 +1713,8 @@ BOOLEAN EnterVehicle( SOLDIERTYPE *pVehicle, SOLDIERTYPE *pSoldier, BOOLEAN fSpe return( FALSE ); } - // anv: since now they can shoot it's important to set passenger to proper stance - SendChangeSoldierStanceEvent( pSoldier, ANIM_CROUCH ); - // bInitialActionPoints - point in time where soldier and vehicle start sharing timeline - pSoldier->bInitialActionPoints = pSoldier->bActionPoints; - // set proper rotation - pSoldier->flags.fDontChargeTurningAPs = TRUE; - pSoldier->EVENT_SetSoldierDesiredDirection( pVehicle->pathing.bDesiredDirection ); - // OK, add.... - AddSoldierToVehicle( pSoldier, pVehicle->bVehicleID, fSpecificSeat, ubSeatIndex ); + AddSoldierToVehicle( pSoldier, pVehicle->bVehicleID, ubSeatIndex ); if ( !(guiTacticalInterfaceFlags & INTERFACE_MAPSCREEN ) ) { @@ -1742,6 +1807,7 @@ BOOLEAN ExitVehicle( SOLDIERTYPE *pSoldier ) // anv: since now they can shoot it's important to set passenger to proper stance // namely, back to standing, because we set them to crouching when entering SendChangeSoldierStanceEvent( pSoldier, ANIM_STAND ); + pSoldier->EVENT_SetSoldierDesiredDirection( pSoldier->ubDirection ); // Update visiblity..... HandleSight(pSoldier,SIGHT_LOOK | SIGHT_RADIO ); @@ -1783,6 +1849,138 @@ BOOLEAN ExitVehicle( SOLDIERTYPE *pSoldier ) return( FALSE ); } +BOOLEAN ChangeVehicleSeat( SOLDIERTYPE *pVehicle, SOLDIERTYPE *pSoldier, UINT8 ubSeatIndex ) +{ + // TEST IF IT'S VALID... + if ( pVehicle->flags.uiStatusFlags & SOLDIER_VEHICLE ) + { + // anv: check if preferred seat is available + if ( pVehicleList[ pVehicle->bVehicleID ].pPassengers[ubSeatIndex] == NULL ) + { + + INT8 bCurrentSeatIndex = GetSeatIndexFromSoldier( pSoldier ); + if( bCurrentSeatIndex == (-1) ) + { + return( FALSE ); + } + + INT16 sAPCost = APBPConstants[AP_CHANGE_SEAT_VEHICLE]; + + //Are we currently in combat? + if(gTacticalStatus.uiFlags & INCOMBAT) + { + if( gNewVehicle[pVehicleList[ pVehicle->bVehicleID ].ubVehicleType].VehicleSeats[bCurrentSeatIndex].ubCompartment != + gNewVehicle[pVehicleList[ pVehicle->bVehicleID ].ubVehicleType].VehicleSeats[ubSeatIndex].ubCompartment ) + { + // different compartment! + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, pVehicleSeatsStrings[1] ); + return( FALSE ); + } + + if(EnoughPoints(pSoldier, sAPCost, 0, TRUE)) + DeductPoints(pSoldier, sAPCost, 0); + else + return( FALSE ); + } + + pVehicleList[ pVehicle->bVehicleID ].pPassengers[ubSeatIndex] = pSoldier; + pVehicleList[ pVehicle->bVehicleID ].pPassengers[bCurrentSeatIndex] = NULL; + + if( gNewVehicle[pVehicleList[ pVehicle->bVehicleID ].ubVehicleType].VehicleSeats[bCurrentSeatIndex].fDriver ) + { + SetDriver( pVehicle->bVehicleID, NOBODY ); + } + + if( gNewVehicle[pVehicleList[ pVehicle->bVehicleID ].ubVehicleType].VehicleSeats[ubSeatIndex].fDriver ) + { + SetDriver( pVehicle->bVehicleID, pSoldier->ubID ); + } + + // set proper initial rotation + UINT8 ubRotation = gNewVehicle[ pVehicleList[ pVehicle->bVehicleID ].ubVehicleType ].VehicleSeats[ ubSeatIndex ].ubRotation; + pSoldier->flags.fDontChargeTurningAPs = TRUE; + pSoldier->EVENT_SetSoldierDesiredDirection( ( pVehicle->pathing.bDesiredDirection + ubRotation ) % NUM_WORLD_DIRECTIONS ); + + UpdateAllVehiclePassengersGridNo( pVehicle ); + + return( TRUE ); + } + } + + return( FALSE ); +} + +BOOLEAN SwapVehicleSeat( SOLDIERTYPE *pVehicle, SOLDIERTYPE *pSoldier, UINT8 ubSeatIndex ) +{ + // TEST IF IT'S VALID... + if ( pVehicle->flags.uiStatusFlags & SOLDIER_VEHICLE ) + { + SOLDIERTYPE *pSoldier2 = pVehicleList[ pVehicle->bVehicleID ].pPassengers[ubSeatIndex]; + + if ( pSoldier2 != NULL ) + { + INT8 bCurrentSeatIndex = GetSeatIndexFromSoldier( pSoldier ); + if( bCurrentSeatIndex == (-1) ) + { + return( FALSE ); + } + + INT16 sAPCost = APBPConstants[AP_CHANGE_SEAT_VEHICLE]; + + //Are we currently in combat? + if(gTacticalStatus.uiFlags & INCOMBAT) + { + if( gNewVehicle[pVehicleList[ pVehicle->bVehicleID ].ubVehicleType].VehicleSeats[bCurrentSeatIndex].ubCompartment != + gNewVehicle[pVehicleList[ pVehicle->bVehicleID ].ubVehicleType].VehicleSeats[ubSeatIndex].ubCompartment ) + { + // different compartment! + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, pVehicleSeatsStrings[1] ); + return( FALSE ); + } + + if( EnoughPoints(pSoldier, sAPCost, 0, TRUE) && EnoughPoints(pSoldier2, sAPCost, 0, TRUE) ) + { + DeductPoints(pSoldier, sAPCost, 0); + DeductPoints(pSoldier2, sAPCost, 0); + } + else + return( FALSE ); + } + + pVehicleList[ pVehicle->bVehicleID ].pPassengers[ubSeatIndex] = pSoldier; + pVehicleList[ pVehicle->bVehicleID ].pPassengers[bCurrentSeatIndex] = pSoldier2; + + if( gNewVehicle[pVehicleList[ pVehicle->bVehicleID ].ubVehicleType].VehicleSeats[bCurrentSeatIndex].fDriver ) + { + SetDriver( pVehicle->bVehicleID, pSoldier2->ubID ); + } + + if( gNewVehicle[pVehicleList[ pVehicle->bVehicleID ].ubVehicleType].VehicleSeats[ubSeatIndex].fDriver ) + { + SetDriver( pVehicle->bVehicleID, pSoldier->ubID ); + } + + // set proper initial rotations + UINT8 ubRotation = gNewVehicle[ pVehicleList[ pVehicle->bVehicleID ].ubVehicleType ].VehicleSeats[ ubSeatIndex ].ubRotation; + pSoldier->flags.fDontChargeTurningAPs = TRUE; + pSoldier->EVENT_SetSoldierDesiredDirection( ( pVehicle->pathing.bDesiredDirection + ubRotation ) % NUM_WORLD_DIRECTIONS ); + + ubRotation = gNewVehicle[ pVehicleList[ pVehicle->bVehicleID ].ubVehicleType ].VehicleSeats[ bCurrentSeatIndex ].ubRotation; + pSoldier2->flags.fDontChargeTurningAPs = TRUE; + pSoldier2->EVENT_SetSoldierDesiredDirection( ( pVehicle->pathing.bDesiredDirection + ubRotation ) % NUM_WORLD_DIRECTIONS ); + + UpdateAllVehiclePassengersGridNo( pVehicle ); + + return( TRUE ); + } + else + { + return( ChangeVehicleSeat( pVehicle, pSoldier, ubSeatIndex ) ); + } + } + + return( FALSE ); +} void AddPassangersToTeamPanel( INT32 iId ) { @@ -2009,6 +2207,11 @@ INT16 GetOrigInternalArmorValueForVehicleInLocation( UINT8 ubID, UINT8 ubLocatio SOLDIERTYPE * GetSoldierStructureForVehicle( INT32 iId ) { + if( iId == (-1) ) + { + return( 0 ); + } + for( INT32 iCounter = 0; iCounter < TOTAL_SOLDIERS; iCounter++ ) { SOLDIERTYPE *pSoldier = &Menptr[ iCounter ]; @@ -2357,8 +2560,88 @@ void UpdateAllVehiclePassengersGridNo( SOLDIERTYPE *pSoldier ) { pPassenger = pVehicleList[ iId ].pPassengers[ iCounter ]; + INT8 bOffsetX = gNewVehicle[ pVehicleList[ iId ].ubVehicleType ].VehicleSeats[ iCounter ].bOffsetX; + INT8 bOffsetY = gNewVehicle[ pVehicleList[ iId ].ubVehicleType ].VehicleSeats[ iCounter ].bOffsetY; + + FLOAT dXOffset = 0; + FLOAT dYOffset = 0; + INT8 dX, dY; + INT8 bDiagonalX = 0; + INT8 bDiagonalY = 0; + + switch( pSoldier->ubBodyType ) + { + case ELDORADO: + case HUMVEE: + case JEEP: + bDiagonalY = -1; + } + + switch( pSoldier->ubDirection ) + { + case 0: + dYOffset = -10 * ( bOffsetY + bDiagonalY ); + dXOffset = 10 * bOffsetX; + break; + case 1: + if( bOffsetX < 0 ) + { + dXOffset = - 10 + 10 * bOffsetY; + dYOffset = - 10 * bOffsetY; + } + else + { + dYOffset = 10 + - 10 * bOffsetY; + dXOffset = 10 * bOffsetY; + } + break; + case 2: + dXOffset = 10 * ( bOffsetY + bDiagonalY); + dYOffset = 10 * bOffsetX; + break; + case 3: + dX = bOffsetY; + dY = bOffsetY; + if( bOffsetX > 0 ) + dX -= 1; + else if( bOffsetX < 0 ) + dY -= 1; + dXOffset = 10 * dX; + dYOffset = 10 * dY; + break; + case 4: + dYOffset = 10 * ( bOffsetY + bDiagonalY ); + dXOffset = -10 * bOffsetX; + break; + case 5: + if( bOffsetX < 0 ) + { + dXOffset = 10 + - 10 * bOffsetY; + dYOffset = 10 * bOffsetY; + } + else + { + dYOffset = - 10 + 10 * bOffsetY; + dXOffset = - 10 * bOffsetY; + } + break; + case 6: + dXOffset = -10 * ( bOffsetY + bDiagonalY ); + dYOffset = -10 * bOffsetX; + break; + case 7: + dX = bOffsetY; + dY = bOffsetY; + if( bOffsetX > 0 ) + dX -= 1; + else if( bOffsetX < 0 ) + dY -= 1; + dXOffset = - 10 * dX; + dYOffset = - 10 * dY; + break; + } // Set gridno..... - pPassenger->EVENT_SetSoldierPosition( pSoldier->dXPos, pSoldier->dYPos ); + pPassenger->EVENT_SetSoldierPosition( pSoldier->dXPos + dXOffset, pSoldier->dYPos + dYOffset); } } } @@ -2595,6 +2878,12 @@ BOOLEAN CanSoldierDriveVehicle( SOLDIERTYPE *pSoldier, INT32 iVehicleId, BOOLEAN return (FALSE); } + // anv: only driver on driver's seat can drive + INT8 bSeatIndex = GetSeatIndexFromSoldier( pSoldier ); + if( bSeatIndex == (-1) || gNewVehicle[ pVehicleList[ iVehicleId ].ubVehicleType ].VehicleSeats[bSeatIndex].fDriver == FALSE ) + { + return (FALSE); + } // yup, he could drive this vehicle return( TRUE ); @@ -2708,6 +2997,38 @@ BOOLEAN IsSoldierInThisVehicleSquad( SOLDIERTYPE *pSoldier, INT8 bSquadNumber ) } +INT8 GetSeatIndexFromSoldier( SOLDIERTYPE *pSoldier ) +{ + INT32 iVehicleId; + SOLDIERTYPE *pVehicleSoldier; + INT32 iCounter; + + iVehicleId = pSoldier->iVehicleId; + + if( iVehicleId == (-1) ) + { + return( -1 ); + } + + pVehicleSoldier = GetSoldierStructureForVehicle( iVehicleId ); + + if( pVehicleSoldier == NULL ) + { + return( -1 ); + } + + // Loop through passengers + for( iCounter = 0; iCounter < gNewVehicle[ pVehicleList[ iVehicleId ].ubVehicleType ].iNewSeatingCapacities; iCounter++ ) + { + if( pVehicleList[ iVehicleId ].pPassengers[ iCounter ] == pSoldier ) + { + return( iCounter ); + } + } + + return( -1 ); +} + SOLDIERTYPE* PickRandomPassengerFromVehicle( SOLDIERTYPE *pSoldier ) { // WDS - make number of mercenaries, etc. be configurable diff --git a/Tactical/Vehicles.h b/Tactical/Vehicles.h index f77db1a4..f5ceed94 100644 --- a/Tactical/Vehicles.h +++ b/Tactical/Vehicles.h @@ -11,6 +11,25 @@ extern std::vector gubVehicleMovementGroups; #define MAX_MAIN_VEHICLE_CHARS 500 +typedef struct +{ + UINT8 ubSeatIndex; // index inside a vehicle (corresponding to .pPassengers[counter]) + CHAR16 zSeatName[20]; // name (to display on entering menu and on team panel) + BOOLEAN fDriver; // seat has to be taken to steer the vehicle + BOOLEAN fBlockedView; // can't look out of vehicle + BOOLEAN fBlockedShots; // can't shoot from this seat + BOOLEAN fSeatBelt; // for collisions + BOOLEAN fHidden; // merc on this seat is invisible from outside - spy as a driver smuggling in others? + UINT8 ubRotation; // initial rotation in relation to vehicle + INT8 bOffsetX; // X offset of seat grid, relative to vehicle middle + INT8 bOffsetY; // Y offset of seat grid, relative to vehicle middle + UINT8 ubCoverage; // influence probability vehicle will be hit instead of passenger + UINT8 ubCompartment; // passenger can switch to another seat in the same compartment without exiting vehicle + UINT8 ubStructureLink; // link to physical part of structure (for hit calculations) + UINT32 usMountedGun; // passenger on this seat will use this gun instead of his own, link to Items.xml + +} VEHICLE_SEAT; + typedef struct { UINT8 uiIndex; @@ -30,27 +49,10 @@ typedef struct CHAR16 NewShortVehicleStrings[128]; INT32 NewCarPortraits; BOOLEAN NewUsed; + VEHICLE_SEAT VehicleSeats[10]; } NEW_CAR; -typedef struct -{ - UINT8 ubSeatIndex; // index inside a vehicle (corresponding to .pPassengers[counter]) - CHAR16 zSeatName[16]; // name (to display on entering menu and on team panel) - BOOLEAN fDriver; // seat has to be taken to steer the vehicle - BOOLEAN fView; // can look out of vehicle - BOOLEAN fDriveBy; // can shoot from this seat - BOOLEAN fSeatBelt; // for collisions - BOOLEAN fHidden; // merc on this seat is invisible from outside - spy as a driver smuggling in others? - UINT8 ubRotation; // rotation in relation to vehicle - UINT8 ubTunnelVision; // tunnel vision (small windows, etc.) - UINT8 ubProtection; // influence probability vehicle will be hit instead of passenger - UINT8 ubCompartment; // passenger can switch to another seat in the same compartment without exiting vehicle - UINT8 ubStructureLink; // link to physical part of structure (for hit calculations) - UINT32 usMountedGun; // passenger on this seat will use this gun instead of his own, link to Items.xml - -} VEHICLE_SEAT; - extern NEW_CAR gNewVehicle[NUM_PROFILES]; extern BOOLEAN LoadNewVehiclesToSaveGameFile( HWFILE hFile ); @@ -331,7 +333,7 @@ BOOLEAN AnyAccessibleVehiclesInSoldiersSector( SOLDIERTYPE *pSoldier ); BOOLEAN IsThisVehicleAccessibleToSoldier( SOLDIERTYPE *pSoldier, INT32 iId ); // add soldier to Vehicle -BOOLEAN AddSoldierToVehicle( SOLDIERTYPE *pSoldier, INT32 iId, BOOLEAN fSpecificSeat = FALSE, UINT8 ubSeatIndex = 0 ); +BOOLEAN AddSoldierToVehicle( SOLDIERTYPE *pSoldier, INT32 iId, UINT8 ubSeatIndex = 0 ); // remove soldier from vehicle BOOLEAN RemoveSoldierFromVehicle( SOLDIERTYPE *pSoldier, INT32 iId ); @@ -387,7 +389,7 @@ INT32 GetNumberInVehicle( INT32 iId ); // grab # in vehicle skipping EPCs (who aren't allowed to drive :-) INT32 GetNumberOfNonEPCsInVehicle( INT32 iId ); -BOOLEAN EnterVehicle( SOLDIERTYPE *pVehicle, SOLDIERTYPE *pSoldier, BOOLEAN fSpecificSeat = FALSE, UINT8 ubSeatIndex = 0 ); +BOOLEAN EnterVehicle( SOLDIERTYPE *pVehicle, SOLDIERTYPE *pSoldier, UINT8 ubSeatIndex = 0 ); SOLDIERTYPE *GetDriver( INT32 iID ); @@ -395,6 +397,9 @@ void SetVehicleName( SOLDIERTYPE *pVehicle ); BOOLEAN ExitVehicle( SOLDIERTYPE *pSoldier ); +BOOLEAN ChangeVehicleSeat( SOLDIERTYPE *pVehicle, SOLDIERTYPE *pSoldier, UINT8 ubSeatIndex ); +BOOLEAN SwapVehicleSeat( SOLDIERTYPE *pVehicle, SOLDIERTYPE *pSoldier, UINT8 ubSeatIndex ); + void AddPassangersToTeamPanel( INT32 iId ); @@ -456,6 +461,8 @@ BOOLEAN IsEnoughSpaceInVehicle( INT32 iID ); BOOLEAN IsSoldierInThisVehicleSquad( SOLDIERTYPE *pSoldier, INT8 bSquadNumber ); +INT8 GetSeatIndexFromSoldier( SOLDIERTYPE *pSoldier ); + SOLDIERTYPE* PickRandomPassengerFromVehicle( SOLDIERTYPE *pSoldier ); BOOLEAN DoesVehicleHaveAnyPassengers( INT32 iVehicleID ); diff --git a/Tactical/XML_Vehicles.cpp b/Tactical/XML_Vehicles.cpp index 66c112b3..fd4b4127 100644 --- a/Tactical/XML_Vehicles.cpp +++ b/Tactical/XML_Vehicles.cpp @@ -19,6 +19,7 @@ struct UINT32 maxArraySize; UINT32 curIndex; + UINT32 curSeatIndex; UINT32 currentDepth; UINT32 maxReadDepth; } @@ -65,6 +66,28 @@ newCarStartElementHandle(void *userData, const XML_Char *name, const XML_Char ** pData->curElement = ELEMENT_PROPERTY; pData->maxReadDepth++; } + else if(strcmp(name, "SEAT") == 0 && pData->curElement == ELEMENT) + { + pData->curElement = ELEMENT_SUBLIST; + pData->maxReadDepth++; + } + else if(pData->curElement == ELEMENT_SUBLIST && + (strcmp(name, "SeatIndex") == 0 || + strcmp(name, "SeatName") == 0 || + strcmp(name, "Driver") == 0 || + strcmp(name, "Hidden") == 0 || + strcmp(name, "BlockedView") == 0 || + strcmp(name, "BlockedShots") == 0 || + strcmp(name, "Rotation") == 0 || + strcmp(name, "OffsetX") == 0 || + strcmp(name, "OffsetY") == 0 || + strcmp(name, "Coverage") == 0 || + strcmp(name, "Compartment") == 0 || + strcmp(name, "MountedGun") == 0 )) + { + pData->curElement = ELEMENT_SUBLIST_PROPERTY; + pData->maxReadDepth++; //we are not skipping this element + } pData->szCharData[0] = '\0'; } @@ -121,13 +144,16 @@ newCarEndElementHandle(void *userData, const XML_Char *name) wcscpy(gNewVehicle[pData->curNewCar.uiIndex].NewVehicleName, pData->curNewCar.NewVehicleName); wcscpy(gNewVehicle[pData->curNewCar.uiIndex].NewShortVehicleStrings, pData->curNewCar.NewShortVehicleStrings); gNewVehicle[ pData->curNewCar.uiIndex ].NewUsed = FALSE; + memcpy( gNewVehicle[ pData->curNewCar.uiIndex ].VehicleSeats, pData->curNewCar.VehicleSeats, sizeof(pData->curNewCar.VehicleSeats) ); + } else { wcscpy(gNewVehicle[pData->curNewCar.uiIndex].NewVehicleStrings, pData->curNewCar.NewVehicleStrings); wcscpy(gNewVehicle[pData->curNewCar.uiIndex].NewVehicleName, pData->curNewCar.NewVehicleName); - wcscpy(gNewVehicle[pData->curNewCar.uiIndex].NewShortVehicleStrings, pData->curNewCar.NewShortVehicleStrings); - } + wcscpy(gNewVehicle[pData->curNewCar.uiIndex].NewShortVehicleStrings, pData->curNewCar.NewShortVehicleStrings); + } + memset( pData->curNewCar.VehicleSeats, 0, sizeof(pData->curNewCar.VehicleSeats) ); } else if(strcmp(name, "uiIndex") == 0) { @@ -213,6 +239,81 @@ newCarEndElementHandle(void *userData, const XML_Char *name) pData->curNewCar.szIconFace[i] = temp; } } + else if(strcmp(name, "SEAT") == 0 ) + { + pData->curElement = ELEMENT; + + if (!NewCar_TextOnly) + { + memcpy( gNewVehicle[pData->curNewCar.uiIndex].VehicleSeats, pData->curNewCar.VehicleSeats, sizeof(pData->curNewCar.VehicleSeats) ); + } + else + { + wcscpy( gNewVehicle[pData->curNewCar.uiIndex].VehicleSeats[pData->curSeatIndex].zSeatName, pData->curNewCar.VehicleSeats[pData->curSeatIndex].zSeatName ); + } + } + else if(strcmp(name, "SeatIndex") == 0) + { + pData->curElement = ELEMENT_SUBLIST; + pData->curSeatIndex = (int) atol(pData->szCharData); + pData->curNewCar.VehicleSeats[pData->curSeatIndex].ubSeatIndex = pData->curSeatIndex; + } + else if(strcmp(name, "SeatName") == 0) + { + pData->curElement = ELEMENT_SUBLIST; + MultiByteToWideChar( CP_UTF8, 0, pData->szCharData, -1, pData->curNewCar.VehicleSeats[pData->curSeatIndex].zSeatName, sizeof(pData->curNewCar.VehicleSeats[pData->curSeatIndex].zSeatName)/sizeof( pData->curNewCar.VehicleSeats[pData->curSeatIndex].zSeatName[0]) ); + pData->curNewCar.VehicleSeats[pData->curSeatIndex].zSeatName[sizeof(pData->curNewCar.VehicleSeats[pData->curSeatIndex].zSeatName)/sizeof(pData->curNewCar.VehicleSeats[pData->curSeatIndex].zSeatName[0]) - 1] = '\0'; + } + else if(strcmp(name, "Driver") == 0) + { + pData->curElement = ELEMENT_SUBLIST; + pData->curNewCar.VehicleSeats[pData->curSeatIndex].fDriver = (BOOLEAN) atol(pData->szCharData); + } + else if(strcmp(name, "Hidden") == 0) + { + pData->curElement = ELEMENT_SUBLIST; + pData->curNewCar.VehicleSeats[pData->curSeatIndex].fHidden = (BOOLEAN) atol(pData->szCharData); + } + else if(strcmp(name, "BlockedView") == 0) + { + pData->curElement = ELEMENT_SUBLIST; + pData->curNewCar.VehicleSeats[pData->curSeatIndex].fBlockedView = (BOOLEAN) atol(pData->szCharData); + } + else if(strcmp(name, "BlockedShots") == 0) + { + pData->curElement = ELEMENT_SUBLIST; + pData->curNewCar.VehicleSeats[pData->curSeatIndex].fBlockedShots = (BOOLEAN) atol(pData->szCharData); + } + else if(strcmp(name, "Rotation") == 0) + { + pData->curElement = ELEMENT_SUBLIST; + pData->curNewCar.VehicleSeats[pData->curSeatIndex].ubRotation = (UINT8) atol(pData->szCharData); + } + else if(strcmp(name, "OffsetX") == 0) + { + pData->curElement = ELEMENT_SUBLIST; + pData->curNewCar.VehicleSeats[pData->curSeatIndex].bOffsetX = (INT8) atol(pData->szCharData); + } + else if(strcmp(name, "OffsetY") == 0) + { + pData->curElement = ELEMENT_SUBLIST; + pData->curNewCar.VehicleSeats[pData->curSeatIndex].bOffsetY = (INT8) atol(pData->szCharData); + } + else if(strcmp(name, "Coverage") == 0) + { + pData->curElement = ELEMENT_SUBLIST; + pData->curNewCar.VehicleSeats[pData->curSeatIndex].ubCoverage = (UINT8) atol(pData->szCharData); + } + else if(strcmp(name, "Compartment") == 0) + { + pData->curElement = ELEMENT_SUBLIST; + pData->curNewCar.VehicleSeats[pData->curSeatIndex].ubCompartment = (UINT8) atol(pData->szCharData); + } + else if(strcmp(name, "MountedGun") == 0) + { + pData->curElement = ELEMENT_SUBLIST; + pData->curNewCar.VehicleSeats[pData->curSeatIndex].usMountedGun = (UINT32) atol(pData->szCharData); + } pData->maxReadDepth--; @@ -301,6 +402,7 @@ void InitNewVehicles () gNewVehicle[ iCount ].NewVehicleName[127] = '\0'; gNewVehicle[ iCount ].NewShortVehicleStrings[127] = '\0'; gNewVehicle[ iCount ].NewUsed = FALSE; + memset( &gNewVehicle[ iCount ].VehicleSeats, 0, sizeof(gNewVehicle[ iCount ].VehicleSeats) ); } } diff --git a/Tactical/opplist.cpp b/Tactical/opplist.cpp index 6f241116..9f3e38da 100644 --- a/Tactical/opplist.cpp +++ b/Tactical/opplist.cpp @@ -48,6 +48,7 @@ #include "drugs and alcohol.h" #include "Interface.h" #include "Explosion Control.h"//dnl ch40 200909 + #include "Vehicles.h" #endif #ifdef JA2UB @@ -1217,6 +1218,18 @@ INT16 DistanceVisible( SOLDIERTYPE *pSoldier, INT8 bFacingDir, INT8 bSubjectDir, return( 0 ); } + // anv: some places in vehicle don't give passenger any view outside + INT8 bSeatIndex = GetSeatIndexFromSoldier( pSoldier ); + if( bSeatIndex != (-1) ) + { + SOLDIERTYPE *pVehicle = GetSoldierStructureForVehicle( pSoldier ->iVehicleId ); + // need to check this even if bSubjectDir is DIRECTION_IRRELEVANT + if( gNewVehicle[ pVehicleList[ pSoldier->iVehicleId ].ubVehicleType ].VehicleSeats[ bSeatIndex ].fBlockedView ) + { + return( 0 ); + } + } + if ( bFacingDir == DIRECTION_IRRELEVANT && TANK( pSoldier ) ) { // always calculate direction for tanks so we have something to work with @@ -5296,6 +5309,8 @@ void DebugSoldierPage4( ) // #define MAX_MOVEMENT_NOISE 9 +#define VEHICLE_FAST_MOVEMENT_NOISE 25 +#define VEHICLE_NORMAL_MOVEMENT_NOISE 15 UINT8 MovementNoise( SOLDIERTYPE *pSoldier ) { @@ -5303,6 +5318,25 @@ UINT8 MovementNoise( SOLDIERTYPE *pSoldier ) UINT8 ubMaxVolume, ubVolume, ubBandaged, ubEffLife; INT8 bInWater = FALSE; + // anv: vehicle and passengers + if( pSoldier->flags.uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER ) ) + { + return( 0 ); + } + else if( pSoldier->flags.uiStatusFlags & ( SOLDIER_VEHICLE ) ) + { + if( pSoldier->usAnimState == RUNNING ) + { + // driving fast makes engine work louder + return( VEHICLE_FAST_MOVEMENT_NOISE ); + } + else + { + return( VEHICLE_NORMAL_MOVEMENT_NOISE ); + } + } + + // anv: additional tile properties // modify amount of noise and stealth difficulty depending on surface type diff --git a/Utils/ExportStrings.cpp b/Utils/ExportStrings.cpp index 7b02a982..643dba84 100644 --- a/Utils/ExportStrings.cpp +++ b/Utils/ExportStrings.cpp @@ -177,6 +177,7 @@ bool Loc::ExportStrings() ExportSection(props, L"Vehicle", Loc::pVehicleStrings, 0, 6); ExportSection(props, L"ShortVehicle", Loc::pShortVehicleStrings, 0, 6); ExportSection(props, L"VehicleName", Loc::zVehicleName, 0, 6); + ExportSection(props, L"VehicleSeatsStrings", Loc::pVehicleSeatsStrings, 0, 2); ExportSection(props, L"Tactical", Loc::TacticalStr, 0, TEXT_NUM_TACTICAL_STR); ExportSection(props, L"ExitingSectorHelp", Loc::pExitingSectorHelpText, 0, TEXT_NUM_EXIT_GUI); diff --git a/Utils/Text.h b/Utils/Text.h index a3a41c9d..e89daec8 100644 --- a/Utils/Text.h +++ b/Utils/Text.h @@ -740,6 +740,7 @@ extern STR16 sKeyDescriptionStrings[2]; extern CHAR16 zHealthStr[][13]; extern STR16 gzHiddenHitCountStr[1]; extern STR16 zVehicleName[ 6 ]; +extern STR16 pVehicleSeatsStrings[ 2 ] ; // Flugente: externalised texts for some features enum diff --git a/Utils/_ChineseText.cpp b/Utils/_ChineseText.cpp index 5fa315d0..e2ca5ea3 100644 --- a/Utils/_ChineseText.cpp +++ b/Utils/_ChineseText.cpp @@ -3072,6 +3072,11 @@ STR16 zVehicleName[] = L"直升飞机", //an abbreviation for Helicopter }; +STR16 pVehicleSeatsStrings[] = +{ + L"You cannot shoot from this seat.", // TODO.Translate + L"You cannot swap those two seats in combat without exiting vehicle first.", // TODO.Translate +}; //These are messages Used in the Tactical Screen diff --git a/Utils/_DutchText.cpp b/Utils/_DutchText.cpp index 5690fcb3..b29f6e5f 100644 --- a/Utils/_DutchText.cpp +++ b/Utils/_DutchText.cpp @@ -3070,6 +3070,11 @@ STR16 zVehicleName[] = L"Heli", //an abbreviation for Helicopter }; +STR16 pVehicleSeatsStrings[] = +{ + L"You cannot shoot from this seat.", // TODO.Translate + L"You cannot swap those two seats in combat without exiting vehicle first.", // TODO.Translate +}; //These are messages Used in the Tactical Screen diff --git a/Utils/_EnglishText.cpp b/Utils/_EnglishText.cpp index af7ce5d2..13984f08 100644 --- a/Utils/_EnglishText.cpp +++ b/Utils/_EnglishText.cpp @@ -3072,6 +3072,11 @@ STR16 zVehicleName[] = L"Heli", //an abbreviation for Helicopter }; +STR16 pVehicleSeatsStrings[] = +{ + L"You cannot shoot from this seat.", + L"You cannot swap those two seats in combat without exiting vehicle first.", +}; //These are messages Used in the Tactical Screen diff --git a/Utils/_FrenchText.cpp b/Utils/_FrenchText.cpp index fe116fec..07449292 100644 --- a/Utils/_FrenchText.cpp +++ b/Utils/_FrenchText.cpp @@ -3074,6 +3074,11 @@ STR16 zVehicleName[] = L"Hélico", //an abbreviation for Helicopter }; +STR16 pVehicleSeatsStrings[] = +{ + L"You cannot shoot from this seat.", // TODO.Translate + L"You cannot swap those two seats in combat without exiting vehicle first.", // TODO.Translate +}; //These are messages Used in the Tactical Screen diff --git a/Utils/_GermanText.cpp b/Utils/_GermanText.cpp index 0499f1c5..93bc94e3 100644 --- a/Utils/_GermanText.cpp +++ b/Utils/_GermanText.cpp @@ -3075,6 +3075,12 @@ STR16 zVehicleName[] = L"Heli", //an abbreviation for Helicopter }; +STR16 pVehicleSeatsStrings[] = +{ + L"You cannot shoot from this seat.", // TODO.Translate + L"You cannot swap those two seats in combat without exiting vehicle first.", // TODO.Translate +}; + //These are messages Used in the Tactical Screen CHAR16 TacticalStr[][ MED_STRING_LENGTH ] = { diff --git a/Utils/_ItalianText.cpp b/Utils/_ItalianText.cpp index f3369609..9aaa3c66 100644 --- a/Utils/_ItalianText.cpp +++ b/Utils/_ItalianText.cpp @@ -3066,6 +3066,11 @@ STR16 zVehicleName[] = L"Eli", //an abbreviation for Helicopter }; +STR16 pVehicleSeatsStrings[] = +{ + L"You cannot shoot from this seat.", // TODO.Translate + L"You cannot swap those two seats in combat without exiting vehicle first.", // TODO.Translate +}; //These are messages Used in the Tactical Screen diff --git a/Utils/_PolishText.cpp b/Utils/_PolishText.cpp index 2624b457..9b691c04 100644 --- a/Utils/_PolishText.cpp +++ b/Utils/_PolishText.cpp @@ -3079,6 +3079,11 @@ STR16 zVehicleName[] = L"Heli.", //an abbreviation for Helicopter }; +STR16 pVehicleSeatsStrings[] = +{ + L"Nie jesteś w stanie strzelać z tego miejsca.", + L"Nie możesz sie przesiąść między tymi dwoma miejscami bez opuszczania pojazdu.", +}; //These are messages Used in the Tactical Screen diff --git a/Utils/_RussianText.cpp b/Utils/_RussianText.cpp index f30569f6..04d2d6d4 100644 --- a/Utils/_RussianText.cpp +++ b/Utils/_RussianText.cpp @@ -3072,6 +3072,11 @@ STR16 zVehicleName[] = L"Вертолёт", //an abbreviation for Helicopter }; +STR16 pVehicleSeatsStrings[] = +{ + L"You cannot shoot from this seat.", // TODO.Translate + L"You cannot swap those two seats in combat without exiting vehicle first.", // TODO.Translate +}; //These are messages Used in the Tactical Screen diff --git a/Utils/_TaiwaneseText.cpp b/Utils/_TaiwaneseText.cpp index ef210299..4f7f54b4 100644 --- a/Utils/_TaiwaneseText.cpp +++ b/Utils/_TaiwaneseText.cpp @@ -3075,6 +3075,11 @@ STR16 zVehicleName[] = L"Heli", //an abbreviation for Helicopter }; +STR16 pVehicleSeatsStrings[] = +{ + L"You cannot shoot from this seat.", // TODO.Translate + L"You cannot swap those two seats in combat without exiting vehicle first.", // TODO.Translate +}; //These are messages Used in the Tactical Screen