diff --git a/GameSettings.cpp b/GameSettings.cpp index 486edfb8..d62ed292 100644 --- a/GameSettings.cpp +++ b/GameSettings.cpp @@ -1381,6 +1381,9 @@ void LoadGameExternalOptions() else gGameExternalOptions.fSoldierProfiles_Militia = FALSE; + gGameExternalOptions.ubAPSharedAmongPassengersAndVehicleMode = iniReader.ReadInteger("Tactical Gameplay Settings","AP_SHARED_AMONG_PASSENGERS_AND_VEHICLE_MODE", 3, 0, 3); + gGameExternalOptions.ubAPSharedAmongPassengersAndVehicleScale = iniReader.ReadInteger("Tactical Gameplay Settings","AP_SHARED_AMONG_PASSENGERS_AND_VEHICLE_SCALE", 100, 0, 200); + // *** ddd - BEGIN gGameExternalOptions.fExtMouseKeyEnabled = iniReader.ReadBoolean("Tactical Interface Settings", "ENABLE_EXT_MOUSE_KEYS", FALSE); @@ -3159,6 +3162,10 @@ void LoadGameAPBPConstants() APBPConstants[AP_APPLYITEM] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_APPLYITEM",50),50); APBPConstants[AP_INVENTORY_ARM] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_INVENTORY_ARM",50),50); APBPConstants[AP_SPOTTER] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_SPOTTER",20),20); + + APBPConstants[AP_ENTER_VEHICLE] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_ENTER_VEHICLE",30),30); + APBPConstants[AP_EXIT_VEHICLE] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_EXIT_VEHICLE",30),30); + APBPConstants[AP_CHANGE_SEAT_VEHICLE] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_CHANGE_SEAT_VEHICLE",20),20); APBPConstants[DEFAULT_APS] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","DEFAULT_APS",80),80); APBPConstants[DEFAULT_AIMSKILL] = iniReader.ReadInteger("APConstants","DEFAULT_AIMSKILL",80); diff --git a/GameSettings.h b/GameSettings.h index 2c9ac359..78246df5 100644 --- a/GameSettings.h +++ b/GameSettings.h @@ -1451,6 +1451,9 @@ typedef struct UINT8 ubExtremeIronManSavingTimeNotification; UINT8 ubExtremeIronManSavingHour; + UINT8 ubAPSharedAmongPassengersAndVehicleMode; + UINT8 ubAPSharedAmongPassengersAndVehicleScale; + } GAME_EXTERNAL_OPTIONS; typedef struct diff --git a/Init.h b/Init.h index d3f40eba..2d7f65fb 100644 --- a/Init.h +++ b/Init.h @@ -156,6 +156,10 @@ AP_APPLYITEM, AP_INVENTORY_ARM, AP_SPOTTER, +AP_ENTER_VEHICLE, +AP_EXIT_VEHICLE, +AP_CHANGE_SEAT_VEHICLE, + DEFAULT_APS, DEFAULT_AIMSKILL, BP_RATIO_RED_PTS_TO_NORMAL, diff --git a/Tactical/Animation Control.cpp b/Tactical/Animation Control.cpp index 01429eb9..18f6b35d 100644 --- a/Tactical/Animation Control.cpp +++ b/Tactical/Animation Control.cpp @@ -3496,12 +3496,15 @@ void InitAnimationSurfacesPerBodytype( ) // HUMVEE gubAnimSurfaceIndex[ HUMVEE ][ STANDING ] = HUMVEE_BASIC; gubAnimSurfaceIndex[ HUMVEE ][ WALKING ] = HUMVEE_BASIC; + gubAnimSurfaceIndex[ HUMVEE ][ RUNNING ] = HUMVEE_BASIC; + gubAnimSurfaceIndex[ HUMVEE ][ WALK_BACKWARDS ] = HUMVEE_BASIC; gubAnimSurfaceIndex[ HUMVEE ][ VEHICLE_DIE ] = HUMVEE_DIE; gubAnimSurfaceCorpseID[ HUMVEE ][ STANDING ] = HUMMER_DEAD; // TANK gubAnimSurfaceIndex[ TANK_NW ][ STANDING ] = TANKNW_READY; - gubAnimSurfaceIndex[ TANK_NW ][ WALKING ] = TANKNW_READY; + gubAnimSurfaceIndex[ TANK_NW ][ WALKING ] = TANKNW_READY; + gubAnimSurfaceIndex[ TANK_NW ][ WALK_BACKWARDS ] = TANKNW_READY; gubAnimSurfaceIndex[ TANK_NW ][ TANK_SHOOT ] = TANKNW_SHOOT; gubAnimSurfaceIndex[ TANK_NW ][ TANK_BURST ] = TANKNW_SHOOT; gubAnimSurfaceIndex[ TANK_NW ][ VEHICLE_DIE ] = TANKNW_DIE; @@ -3509,7 +3512,8 @@ void InitAnimationSurfacesPerBodytype( ) // TANK gubAnimSurfaceIndex[ TANK_NE ][ STANDING ] = TANKNE_READY; - gubAnimSurfaceIndex[ TANK_NE ][ WALKING ] = TANKNE_READY; + gubAnimSurfaceIndex[ TANK_NE ][ WALKING ] = TANKNE_READY; + gubAnimSurfaceIndex[ TANK_NE ][ WALK_BACKWARDS ] = TANKNE_READY; gubAnimSurfaceIndex[ TANK_NE ][ TANK_SHOOT ] = TANKNE_SHOOT; gubAnimSurfaceIndex[ TANK_NE ][ TANK_BURST ] = TANKNE_SHOOT; gubAnimSurfaceIndex[ TANK_NE ][ VEHICLE_DIE ] = TANKNE_DIE; @@ -3518,17 +3522,23 @@ void InitAnimationSurfacesPerBodytype( ) // ELDORADO gubAnimSurfaceIndex[ ELDORADO ][ STANDING ] = ELDORADO_BASIC; gubAnimSurfaceIndex[ ELDORADO ][ WALKING ] = ELDORADO_BASIC; + gubAnimSurfaceIndex[ ELDORADO ][ RUNNING ] = ELDORADO_BASIC; + gubAnimSurfaceIndex[ ELDORADO ][ WALK_BACKWARDS ] = ELDORADO_BASIC; gubAnimSurfaceIndex[ ELDORADO ][ VEHICLE_DIE ] = ELDORADO_DIE; // ICECREAMTRUCK gubAnimSurfaceIndex[ ICECREAMTRUCK ][ STANDING ] = ICECREAMTRUCK_BASIC; gubAnimSurfaceIndex[ ICECREAMTRUCK ][ WALKING ] = ICECREAMTRUCK_BASIC; + gubAnimSurfaceIndex[ ICECREAMTRUCK ][ RUNNING ] = ICECREAMTRUCK_BASIC; + gubAnimSurfaceIndex[ ICECREAMTRUCK ][ WALK_BACKWARDS ] = ICECREAMTRUCK_BASIC; gubAnimSurfaceIndex[ ICECREAMTRUCK ][ VEHICLE_DIE ] = HUMVEE_DIE; gubAnimSurfaceCorpseID[ ICECREAMTRUCK ][ STANDING ] = ICECREAM_DEAD; // JEEP gubAnimSurfaceIndex[ JEEP ][ STANDING ] = JEEP_BASIC; gubAnimSurfaceIndex[ JEEP ][ WALKING ] = JEEP_BASIC; + gubAnimSurfaceIndex[ JEEP ][ RUNNING ] = JEEP_BASIC; + gubAnimSurfaceIndex[ JEEP ][ WALK_BACKWARDS ] = JEEP_BASIC; gubAnimSurfaceIndex[ JEEP ][ VEHICLE_DIE ] = JEEP_DIE; } diff --git a/Tactical/Handle UI.cpp b/Tactical/Handle UI.cpp index 20311157..4851bc62 100644 --- a/Tactical/Handle UI.cpp +++ b/Tactical/Handle UI.cpp @@ -1477,9 +1477,22 @@ UINT32 UIHandleMOnTerrain( UI_EVENT *pUIEvent ) gUIActionModeChangeDueToMouseOver = FALSE; // If we are a vehicle..... just show an X + //if ( GetSoldier( &pSoldier, gusSelectedSoldier ) ) + //{ + // if ( ( OK_ENTERABLE_VEHICLE( pSoldier ) ) ) + // { + // if ( !UIHandleOnMerc( TRUE ) ) + // { + // guiNewUICursor = FLOATING_X_UICURSOR; + // return( GAME_SCREEN ); + // } + // } + //} + + // If we are a passenger or driver just show an X if ( GetSoldier( &pSoldier, gusSelectedSoldier ) ) { - if ( ( OK_ENTERABLE_VEHICLE( pSoldier ) ) ) + if ( ( pSoldier->flags.uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER )) ) { if ( !UIHandleOnMerc( TRUE ) ) { diff --git a/Tactical/Interface Panels.cpp b/Tactical/Interface Panels.cpp index 9caae596..7e039300 100644 --- a/Tactical/Interface Panels.cpp +++ b/Tactical/Interface Panels.cpp @@ -6287,13 +6287,14 @@ void MercFacePanelCallback( MOUSE_REGION * pRegion, INT32 iReason ) { if ( !gfInItemPickupMenu && gpItemPointer == NULL ) { - if ( MercPtrs[ ubSoldierID ]->flags.uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER ) ) - { - pVehicle = GetSoldierStructureForVehicle( MercPtrs[ ubSoldierID ]->iVehicleId ); + //if ( MercPtrs[ ubSoldierID ]->flags.uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER ) ) + //if ( MercPtrs[ ubSoldierID ]->flags.uiStatusFlags & ( SOLDIER_DRIVER ) ) + //{ + // pVehicle = GetSoldierStructureForVehicle( MercPtrs[ ubSoldierID ]->iVehicleId ); - HandleLocateSelectMerc( pVehicle->ubID, 0 ); - } - else + // HandleLocateSelectMerc( pVehicle->ubID, 0 ); + //} + //else { if ( !InOverheadMap( ) ) { @@ -6350,7 +6351,8 @@ void MercFacePanelCallback( MOUSE_REGION * pRegion, INT32 iReason ) if ( !InOverheadMap( ) ) { // Only if guy is not dead! - if ( !( MercPtrs[ ubSoldierID ]->flags.uiStatusFlags & SOLDIER_DEAD ) && !AM_AN_EPC( MercPtrs[ ubSoldierID ] ) && !( MercPtrs[ ubSoldierID ]->flags.uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER ) ) ) + //if ( !( MercPtrs[ ubSoldierID ]->flags.uiStatusFlags & SOLDIER_DEAD ) && !AM_AN_EPC( MercPtrs[ ubSoldierID ] ) && !( MercPtrs[ ubSoldierID ]->flags.uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER ) ) ) + if ( !( MercPtrs[ ubSoldierID ]->flags.uiStatusFlags & SOLDIER_DEAD ) && !AM_AN_EPC( MercPtrs[ ubSoldierID ] ) ) { gfSwitchPanel = TRUE; gbNewPanel = SM_PANEL; @@ -6846,8 +6848,17 @@ void TMClickFirstHandInvCallback( MOUSE_REGION * pRegion, INT32 iReason ) if (iReason == MSYS_CALLBACK_REASON_LBUTTON_UP ) { - // Change to use cursor mode... - guiPendingOverrideEvent = A_ON_TERRAIN; + // anv: select vehicle by clicking on the steering wheel + if ( MercPtrs[ ubSoldierID ]->flags.uiStatusFlags & SOLDIER_DRIVER ) + { + SOLDIERTYPE *pVehicle = GetSoldierStructureForVehicle( MercPtrs[ ubSoldierID ]->iVehicleId ); + HandleLocateSelectMerc( pVehicle->ubID, 0 ); + } + else + { + // Change to use cursor mode... + guiPendingOverrideEvent = A_ON_TERRAIN; + } } if (iReason == MSYS_CALLBACK_REASON_RBUTTON_UP ) diff --git a/Tactical/Interface.cpp b/Tactical/Interface.cpp index d3de1c08..9962831a 100644 --- a/Tactical/Interface.cpp +++ b/Tactical/Interface.cpp @@ -916,7 +916,7 @@ void PopupMovementMenu( UI_EVENT *pUIEvent ) //SetButtonSavedRect( iActionIcons[ RUN_ICON ] ); ButtonList[ iActionIcons[ RUN_ICON ] ]->UserData[0] = (UINT32)pUIEvent; - if ( pSoldier->MercInWater( ) || ( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) || ( pSoldier->flags.uiStatusFlags & SOLDIER_ROBOT ) ) + if ( pSoldier->MercInWater( ) || ( pSoldier->flags.uiStatusFlags & SOLDIER_ROBOT ) ) { DisableButton( iActionIcons[ RUN_ICON ] ); } diff --git a/Tactical/Overhead.cpp b/Tactical/Overhead.cpp index c9d502e4..eef99239 100644 --- a/Tactical/Overhead.cpp +++ b/Tactical/Overhead.cpp @@ -2504,6 +2504,41 @@ BOOLEAN HandleGotoNewGridNo( SOLDIERTYPE *pSoldier, BOOLEAN *pfKeepMoving, BOOLE { // Adjust AP/Breathing points to move DeductPoints( pSoldier, sAPCost, sBPCost, MOVEMENT_INTERRUPT ); + + // anv: deduct points from vehicle passengers to prevent time travel paradoxes... yeah yeah, you get the idea + if ( gTacticalStatus.uiFlags & TURNBASED && pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE && gGameExternalOptions.ubAPSharedAmongPassengersAndVehicleMode ) + { + INT32 iId = pSoldier->bVehicleID; + // Loop through passengers and update each guy's AP + for( INT32 iCounter = 0; iCounter < gNewVehicle[ pVehicleList[ iId ].ubVehicleType ].iNewSeatingCapacities; iCounter++ ) + { + SOLDIERTYPE *pPassenger = pVehicleList[ iId ].pPassengers[ iCounter ]; + if( pPassenger != NULL ) + { + //INT16 sPassengerAPCost = pPassenger->bInitialActionPoints * sAPCost / max(1, pSoldier->bInitialActionPoints) * gGameExternalOptions.ubAPSharedAmongPassengersAndVehicleScale / 100; + INT16 sPassengerAPCost = 0; + switch( gGameExternalOptions.ubAPSharedAmongPassengersAndVehicleMode ) + { + case 1: + sPassengerAPCost = sAPCost; + break; + case 2: + sPassengerAPCost = pPassenger->bInitialActionPoints * sAPCost / max(1, pSoldier->bInitialActionPoints); + break; + case 3: + INT16 sPassengerAPTreshold = pPassenger->bInitialActionPoints * ( pSoldier->bActionPoints - sAPCost ) / max(1, pSoldier->bInitialActionPoints); + sPassengerAPCost = pPassenger->bInitialActionPoints * sAPCost / max(1, pSoldier->bInitialActionPoints) ; + if( pPassenger->bActionPoints - sPassengerAPCost > sPassengerAPTreshold ) + sPassengerAPCost = max( sPassengerAPCost, ( pPassenger->bActionPoints - sPassengerAPCost ) - sPassengerAPTreshold ); + else + sPassengerAPCost = 0; + break; + } + sPassengerAPCost = sPassengerAPCost * gGameExternalOptions.ubAPSharedAmongPassengersAndVehicleScale / 100; + DeductPoints( pPassenger, sPassengerAPCost, 0, MOVEMENT_INTERRUPT ); + } + } + } } // OK, let's check for monsters.... @@ -4449,7 +4484,7 @@ UINT8 FindNextActiveAndAliveMerc( SOLDIERTYPE *pSoldier, BOOLEAN fGoodForLessOKL if ( fGoodForLessOKLife ) { - if ( pTeamSoldier->stats.bLife > 0 && pTeamSoldier->bActive && pTeamSoldier->bInSector && pTeamSoldier->bTeam == gbPlayerNum && pTeamSoldier->bAssignment < ON_DUTY && OK_INTERRUPT_MERC( pTeamSoldier ) && pSoldier->bAssignment == pTeamSoldier->bAssignment ) + if ( pTeamSoldier->stats.bLife > 0 && pTeamSoldier->bActive && pTeamSoldier->bInSector && pTeamSoldier->bTeam == gbPlayerNum && ( pTeamSoldier->bAssignment < ON_DUTY || pTeamSoldier->bAssignment == VEHICLE ) && OK_INTERRUPT_MERC( pTeamSoldier ) && pSoldier->bAssignment == pTeamSoldier->bAssignment ) { return( (UINT8)cnt ); } @@ -4480,7 +4515,7 @@ UINT8 FindNextActiveAndAliveMerc( SOLDIERTYPE *pSoldier, BOOLEAN fGoodForLessOKL if ( fGoodForLessOKLife ) { - if ( pTeamSoldier->stats.bLife > 0 && pTeamSoldier->bActive && pTeamSoldier->bInSector && pTeamSoldier->bTeam == gbPlayerNum && pTeamSoldier->bAssignment < ON_DUTY && OK_INTERRUPT_MERC( pTeamSoldier ) && pSoldier->bAssignment == pTeamSoldier->bAssignment ) + if ( pTeamSoldier->stats.bLife > 0 && pTeamSoldier->bActive && pTeamSoldier->bInSector && pTeamSoldier->bTeam == gbPlayerNum && ( pTeamSoldier->bAssignment < ON_DUTY || pTeamSoldier->bAssignment == VEHICLE ) && OK_INTERRUPT_MERC( pTeamSoldier ) && pSoldier->bAssignment == pTeamSoldier->bAssignment ) { return( (UINT8)cnt ); } @@ -4559,7 +4594,7 @@ UINT8 FindPrevActiveAndAliveMerc( SOLDIERTYPE *pSoldier, BOOLEAN fGoodForLessOKL if ( fGoodForLessOKLife ) { // Check for bLife > 0 - if ( pTeamSoldier->stats.bLife > 0 && pTeamSoldier->bActive && pTeamSoldier->bInSector && pTeamSoldier->bTeam == gbPlayerNum && pTeamSoldier->bAssignment < ON_DUTY && OK_INTERRUPT_MERC( pTeamSoldier ) && pSoldier->bAssignment == pTeamSoldier->bAssignment ) + if ( pTeamSoldier->stats.bLife > 0 && pTeamSoldier->bActive && pTeamSoldier->bInSector && pTeamSoldier->bTeam == gbPlayerNum && ( pTeamSoldier->bAssignment < ON_DUTY || pTeamSoldier->bAssignment == VEHICLE ) && OK_INTERRUPT_MERC( pTeamSoldier ) && pSoldier->bAssignment == pTeamSoldier->bAssignment ) { return( (UINT8)cnt ); } @@ -4589,7 +4624,7 @@ UINT8 FindPrevActiveAndAliveMerc( SOLDIERTYPE *pSoldier, BOOLEAN fGoodForLessOKL if ( fGoodForLessOKLife ) { - if ( pTeamSoldier->stats.bLife > 0 && pTeamSoldier->bActive && pTeamSoldier->bInSector && pTeamSoldier->bTeam == gbPlayerNum && pTeamSoldier->bAssignment < ON_DUTY && OK_INTERRUPT_MERC( pTeamSoldier ) && pSoldier->bAssignment == pTeamSoldier->bAssignment ) + if ( pTeamSoldier->stats.bLife > 0 && pTeamSoldier->bActive && pTeamSoldier->bInSector && pTeamSoldier->bTeam == gbPlayerNum && ( pTeamSoldier->bAssignment < ON_DUTY || pTeamSoldier->bAssignment == VEHICLE ) && OK_INTERRUPT_MERC( pTeamSoldier ) && pSoldier->bAssignment == pTeamSoldier->bAssignment ) { return( (UINT8)cnt ); } diff --git a/Tactical/PATHAI.cpp b/Tactical/PATHAI.cpp index a18dd476..5c678a6e 100644 --- a/Tactical/PATHAI.cpp +++ b/Tactical/PATHAI.cpp @@ -4849,19 +4849,19 @@ INT32 PlotPath( SOLDIERTYPE *pSold, INT32 sDestGridNo, INT8 bCopyRoute, INT8 bPl } // Are we a vehicle? - if ( pSold->flags.uiStatusFlags & SOLDIER_VEHICLE ) - { - // did we exceed WALK cost? - if ( sPointsSwat > sAPBudget) - { - sFootOrderIndex = 4; - } - else - { - sFootOrderIndex = 3; - } - } - else + //if ( pSold->flags.uiStatusFlags & SOLDIER_VEHICLE ) + //{ + // // did we exceed WALK cost? + // if ( sPointsSwat > sAPBudget) + // { + // sFootOrderIndex = 4; + // } + // else + // { + // sFootOrderIndex = 3; + // } + //} + //else { // did we exceed CRAWL cost? if (sFootOrderIndex == 0 && sPointsCrawl > sAPBudget) diff --git a/Tactical/Points.cpp b/Tactical/Points.cpp index e4f756c3..b8608168 100644 --- a/Tactical/Points.cpp +++ b/Tactical/Points.cpp @@ -880,6 +880,12 @@ void DeductPoints( SOLDIERTYPE *pSoldier, INT16 sAPCost, INT32 iBPCost, UINT8 ub sAPCost = 0; } + // anv: there were weird things going on here, deducting fuel for strategic travel happens elsewhere anyway + if ( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) + { + iBPCost = 0; + } + // Get New points sNewAP = pSoldier->bActionPoints - sAPCost; diff --git a/Tactical/Soldier Control.cpp b/Tactical/Soldier Control.cpp index c13fd4f8..088d891e 100644 --- a/Tactical/Soldier Control.cpp +++ b/Tactical/Soldier Control.cpp @@ -1728,7 +1728,8 @@ void HandleVehicleMovementSound( SOLDIERTYPE *pSoldier, BOOLEAN fOn ) { if ( pVehicle->iMovementSoundID == NO_SAMPLE ) { - pVehicle->iMovementSoundID = PlayJA2Sample( pVehicle->iMoveSound, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) ); + // anv: will be played in InternalPlaySoldierFootstepSound + //pVehicle->iMovementSoundID = PlayJA2Sample( pVehicle->iMoveSound, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) ); } } else @@ -3384,7 +3385,7 @@ BOOLEAN SOLDIERTYPE::EVENT_InitNewSoldierAnim( UINT16 usNewState, UINT16 usStart || usNewState == SWATTING_WK) { // CHECK FOR SIDEWAYS! - if ( this->ubDirection == gPurpendicularDirection[ this->ubDirection ][ this->pathing.usPathingData[ this->pathing.usPathIndex ] ] ) + if ( !( this->flags.uiStatusFlags & SOLDIER_VEHICLE ) && this->ubDirection == gPurpendicularDirection[ this->ubDirection ][ this->pathing.usPathingData[ this->pathing.usPathIndex ] ] ) { // We are perpendicular! // SANDRO - wait wait wait!!! We need to determine if gonna sidestep with weapon raised @@ -5289,9 +5290,10 @@ UINT16 SOLDIERTYPE::GetMoveStateBasedOnStance( UINT8 ubStanceHeight ) switch ( ubStanceHeight ) { case ANIM_STAND: - if ( this->flags.fUIMovementFast && !( this->flags.uiStatusFlags & SOLDIER_VEHICLE ) ) + //if ( this->flags.fUIMovementFast && !( this->flags.uiStatusFlags & SOLDIER_VEHICLE ) ) + if ( this->flags.fUIMovementFast ) { - return( RUNNING ); + return( RUNNING ); } else { @@ -7876,14 +7878,29 @@ void SOLDIERTYPE::TurnSoldier( void ) INT32 cnt; // If we are a vehicle... DON'T TURN! + // anv: YES PLIZ DO if ( this->flags.uiStatusFlags & SOLDIER_VEHICLE ) { - if ( this->ubBodyType != TANK_NW && this->ubBodyType != TANK_NE ) + //if ( this->ubBodyType != TANK_NW && this->ubBodyType != TANK_NE ) + //{ + // return; + //} + + // need to turn around passengers inside + INT32 iId = this->bVehicleID; + + // Loop through passengers and update each guy's rotation + for( INT32 iCounter = 0; iCounter < gNewVehicle[ pVehicleList[ iId ].ubVehicleType ].iNewSeatingCapacities; iCounter++ ) { - return; + if( pVehicleList[ iId ].pPassengers[ iCounter ] != NULL ) + { + pVehicleList[ iId ].pPassengers[ iCounter ]->flags.fDontChargeTurningAPs = TRUE; + pVehicleList[ iId ].pPassengers[ iCounter ]->EVENT_SetSoldierDesiredDirection( this->pathing.bDesiredDirection ); + //pVehicleList[ iId ].pPassengers[ iCounter ]->pathing.bDesiredDirection = this->pathing.bDesiredDirection; + } } } - else // Lesh: patch for "Bug: Enemy turns around in turn based mode!" + //else // Lesh: patch for "Bug: Enemy turns around in turn based mode!" { // in case of errors in turning tasks if ( this->pathing.bDesiredDirection > 7 || this->pathing.bDesiredDirection < 0) @@ -8549,8 +8566,8 @@ void CalculateSoldierAniSpeed( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pStatsSoldier UINT32 uiTerrainDelay; UINT32 uiSpeed = 0; - INT8 bBreathDef, bLifeDef; - INT16 bAgilDef; + INT8 bBreathDef = 0, bLifeDef = 0; + INT16 bAgilDef = 0; INT8 bAdditional = 0; // for those animations which have a speed of zero, we have to calculate it @@ -8675,13 +8692,29 @@ void CalculateSoldierAniSpeed( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pStatsSoldier uiTerrainDelay = 40; // standing still } - bBreathDef = 50 - ( pStatsSoldier->bBreath / 2 ); + if( !(pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE) ) + { + bBreathDef = 50 - ( pStatsSoldier->bBreath / 2 ); - if ( bBreathDef > 30 ) - bBreathDef = 30; + if ( bBreathDef > 30 ) + bBreathDef = 30; - bAgilDef = 50 - ( EffectiveAgility( pStatsSoldier, FALSE ) / 4 ); - bLifeDef = 50 - ( pStatsSoldier->stats.bLife / 2 ); + bAgilDef = 50 - ( EffectiveAgility( pStatsSoldier, FALSE ) / 4 ); + bLifeDef = 50 - ( pStatsSoldier->stats.bLife / 2 ); + } + else + { + // anv: vehicles have no agility and making them slower with less fuel would make no sense + // instead take gear into consideration here + if ( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE && pSoldier->usAnimState == RUNNING ) + { + bAgilDef = 10; + } + else + { + bAgilDef = 30; + } + } uiTerrainDelay += ( bLifeDef + bBreathDef + bAgilDef + bAdditional ); @@ -10237,7 +10270,9 @@ BOOLEAN SOLDIERTYPE::InternalDoMercBattleSound( UINT8 ubBattleSoundID, INT8 bSpe if ( ( this->flags.uiStatusFlags & SOLDIER_VEHICLE ) ) { // Pick a passenger from vehicle.... - pSoldier = PickRandomPassengerFromVehicle( this ); + //pSoldier = PickRandomPassengerFromVehicle( this ); + // anv: as vehicles can be controlled, get a driver + pSoldier = GetDriver(this->bVehicleID); if ( pSoldier == NULL ) { @@ -20453,6 +20488,12 @@ void InternalPlaySoldierFootstepSound( SOLDIERTYPE * pSoldier ) PlaySoldierJA2Sample( pSoldier->ubID, ubSoundBase + pSoldier->ubLastFootPrintSound, RATE_11025, SoundVolume( bVolume, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); } } + else + { + // anv: vehicle sounds + //PlaySoldierJA2Sample( pSoldier->ubID, S_VECH1_MOVE, RATE_11025, SoundVolume( bVolume, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); + PlaySoldierJA2Sample( pSoldier->ubID, pVehicleList[ pSoldier->bVehicleID ].iMoveSound, RATE_11025, SoundVolume( bVolume, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ), TRUE ); + } } void PlaySoldierFootstepSound( SOLDIERTYPE *pSoldier ) diff --git a/Tactical/Soldier macros.h b/Tactical/Soldier macros.h index 83791f9c..e6acaeb3 100644 --- a/Tactical/Soldier macros.h +++ b/Tactical/Soldier macros.h @@ -18,7 +18,8 @@ #define OK_ENEMY_MERC( p ) ( !p->aiData.bNeutral && (p->bSide != gbPlayerNum ) && p->stats.bLife >= OKLIFE && (p->bTeam < 5 )) // Checks if our guy can be controllable .... checks bInSector, team, on duty, etc... -#define OK_CONTROLLABLE_MERC( p ) ( p->stats.bLife >= OKLIFE && p->bActive && p->bInSector && p->bTeam == gbPlayerNum && p->bAssignment < ON_DUTY ) +//#define OK_CONTROLLABLE_MERC( p ) ( p->stats.bLife >= OKLIFE && p->bActive && p->bInSector && p->bTeam == gbPlayerNum && p->bAssignment < ON_DUTY ) +#define OK_CONTROLLABLE_MERC( p ) ( p->stats.bLife >= OKLIFE && p->bActive && p->bInSector && p->bTeam == gbPlayerNum && ( p->bAssignment < ON_DUTY || p->bAssignment == VEHICLE ) ) // Checks if our guy can be controllable .... checks bInSector, team, on duty, etc... #define OK_INSECTOR_MERC( p ) ( p->stats.bLife >= OKLIFE && p->bActive && p->bInSector && p->bTeam == gbPlayerNum && p->bAssignment < ON_DUTY ) diff --git a/Tactical/Turn Based Input.cpp b/Tactical/Turn Based Input.cpp index 5beaf674..8faa9d49 100644 --- a/Tactical/Turn Based Input.cpp +++ b/Tactical/Turn Based Input.cpp @@ -5565,7 +5565,15 @@ INT8 HandleMoveModeInteractiveClick( INT32 usMapPos, UINT32 *puiNewEvent ) // ATE: If we are a vehicle, no moving! if ( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) { - ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, TacticalStr[ VEHICLE_CANT_MOVE_IN_TACTICAL ] ); + // anv: yes moving + //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, TacticalStr[ VEHICLE_CANT_MOVE_IN_TACTICAL ] ); + //return( -3 ); + } + + if ( pSoldier->flags.uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER ) ) + { + // anv: there's some weird bug with moving invisible passengers after loading game, that should solve it + //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, TacticalStr[ VEHICLE_CANT_MOVE_IN_TACTICAL ] ); return( -3 ); } @@ -5923,7 +5931,12 @@ void ToggleStealthMode( SOLDIERTYPE *pSoldier ) { // nothing in hand and either not in SM panel, or the matching button is enabled if we are in SM panel if ( ( gsCurInterfacePanel != SM_PANEL ) || ( ButtonList[ giSMStealthButton ]->uiFlags & BUTTON_ENABLED ) ) - { + { + if( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) + { + return; + } + // ATE: Toggle stealth if ( gpSMCurrentMerc != NULL && pSoldier->ubID == gpSMCurrentMerc->ubID ) { diff --git a/Tactical/Vehicles.cpp b/Tactical/Vehicles.cpp index 8320be28..9d7dee94 100644 --- a/Tactical/Vehicles.cpp +++ b/Tactical/Vehicles.cpp @@ -41,6 +41,9 @@ #include "Queen Command.h" #endif +#include "Points.h" +#include "Init.h" + //INT8 gubVehicleMovementGroups[ MAX_VEHICLES ]; std::vector gubVehicleMovementGroups (MAX_VEHICLES, 0); @@ -472,7 +475,7 @@ BOOLEAN IsThisVehicleAccessibleToSoldier( SOLDIERTYPE *pSoldier, INT32 iId ) } -BOOLEAN AddSoldierToVehicle( SOLDIERTYPE *pSoldier, INT32 iId ) +BOOLEAN AddSoldierToVehicle( SOLDIERTYPE *pSoldier, INT32 iId, BOOLEAN fSpecificSeat, UINT8 ubSeatIndex ) { INT32 iCounter = 0; UINT32 vCount = 0; @@ -556,8 +559,11 @@ BOOLEAN AddSoldierToVehicle( SOLDIERTYPE *pSoldier, INT32 iId ) if ( pVehicleSoldier ) { + // anv: when we enter vehicle in battle, we need to unbusy soldier BEFORE we change selected soldier or else we'll get lock + UnSetUIBusy( pSoldier->ubID ); + // can't call SelectSoldier in mapscreen, that will initialize interface panels!!! - if ( guiCurrentScreen == GAME_SCREEN ) + if ( guiCurrentScreen == GAME_SCREEN ) { SelectSoldier( pVehicleSoldier->ubID, FALSE, TRUE ); } @@ -713,6 +719,7 @@ BOOLEAN RemoveSoldierFromVehicle( SOLDIERTYPE *pSoldier, INT32 iId ) INT32 iCounter = 0; BOOLEAN fSoldierLeft = FALSE; BOOLEAN fSoldierFound = FALSE; + BOOLEAN fNewDriverNeeded = FALSE; SOLDIERTYPE *pVehicleSoldier; UINT8 iOldGroupID=0; @@ -743,6 +750,12 @@ BOOLEAN RemoveSoldierFromVehicle( SOLDIERTYPE *pSoldier, INT32 iId ) pVehicleList[ iId ].pPassengers[ iCounter ] = NULL; + // anv: make sure someone else becomes driver if he was the previous one + if( pSoldier->flags.uiStatusFlags & SOLDIER_DRIVER ) + { + fNewDriverNeeded = TRUE; + } + pSoldier->flags.uiStatusFlags &= ( ~( SOLDIER_DRIVER | SOLDIER_PASSENGER ) ); // check if anyone left in vehicle @@ -752,6 +765,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); + pVehicleList[ iId ].ubDriver = pNewDriver->ubID; + fNewDriverNeeded = FALSE; + } } } @@ -801,6 +822,8 @@ BOOLEAN RemoveSoldierFromVehicle( SOLDIERTYPE *pSoldier, INT32 iId ) CancelPathForVehicle( &( pVehicleList[ iId ] ), FALSE ); } + pVehicleSoldier->EVENT_StopMerc( pVehicleSoldier->sGridNo, pVehicleSoldier->ubDirection ); + // if the vehicle was abandoned between sectors if ( pVehicleList[ iId ].fBetweenSectors ) { @@ -1588,16 +1611,42 @@ BOOLEAN TakeSoldierOutOfVehicle( SOLDIERTYPE *pSoldier ) -BOOLEAN EnterVehicle( SOLDIERTYPE *pVehicle, SOLDIERTYPE *pSoldier ) +BOOLEAN EnterVehicle( SOLDIERTYPE *pVehicle, SOLDIERTYPE *pSoldier, BOOLEAN fSpecificSeat, UINT8 ubSeatIndex ) { + // TEST IF IT'S VALID... if ( pVehicle->flags.uiStatusFlags & SOLDIER_VEHICLE ) { // Is there room... 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 ) + { + fSpecificSeat = FALSE; + ubSeatIndex = 0; + } + } + + INT16 sAPCost = APBPConstants[AP_ENTER_VEHICLE]; + //Are we currently in combat? + if(gTacticalStatus.uiFlags & INCOMBAT) + { + if(EnoughPoints(pSoldier, sAPCost, 0, TRUE)) + DeductPoints(pSoldier, sAPCost, 0); + else + 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; + // OK, add.... - AddSoldierToVehicle( pSoldier, pVehicle->bVehicleID ); + AddSoldierToVehicle( pSoldier, pVehicle->bVehicleID, fSpecificSeat, ubSeatIndex ); if ( !(guiTacticalInterfaceFlags & INTERFACE_MAPSCREEN ) ) { @@ -1651,6 +1700,16 @@ BOOLEAN ExitVehicle( SOLDIERTYPE *pSoldier ) return( FALSE ); } + INT16 sAPCost = APBPConstants[AP_EXIT_VEHICLE]; + //Are we currently in combat? + if(gTacticalStatus.uiFlags & INCOMBAT) + { + if(EnoughPoints(pSoldier, sAPCost, 0, TRUE)) + DeductPoints(pSoldier, sAPCost, 0); + else + return( FALSE ); + } + // TEST IF IT'S VALID... if ( pVehicle->flags.uiStatusFlags & SOLDIER_VEHICLE ) { @@ -1677,6 +1736,10 @@ BOOLEAN ExitVehicle( SOLDIERTYPE *pSoldier ) // Add to sector.... pSoldier->EVENT_SetSoldierPosition( CenterX( sGridNo ), CenterY( sGridNo ) ); + // 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 ); + // Update visiblity..... HandleSight(pSoldier,SIGHT_LOOK | SIGHT_RADIO ); diff --git a/Tactical/Vehicles.h b/Tactical/Vehicles.h index d82c56eb..f77db1a4 100644 --- a/Tactical/Vehicles.h +++ b/Tactical/Vehicles.h @@ -33,6 +33,24 @@ typedef struct } 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 ); @@ -313,7 +331,7 @@ BOOLEAN AnyAccessibleVehiclesInSoldiersSector( SOLDIERTYPE *pSoldier ); BOOLEAN IsThisVehicleAccessibleToSoldier( SOLDIERTYPE *pSoldier, INT32 iId ); // add soldier to Vehicle -BOOLEAN AddSoldierToVehicle( SOLDIERTYPE *pSoldier, INT32 iId ); +BOOLEAN AddSoldierToVehicle( SOLDIERTYPE *pSoldier, INT32 iId, BOOLEAN fSpecificSeat = FALSE, UINT8 ubSeatIndex = 0 ); // remove soldier from vehicle BOOLEAN RemoveSoldierFromVehicle( SOLDIERTYPE *pSoldier, INT32 iId ); @@ -369,7 +387,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 EnterVehicle( SOLDIERTYPE *pVehicle, SOLDIERTYPE *pSoldier, BOOLEAN fSpecificSeat = FALSE, UINT8 ubSeatIndex = 0 ); SOLDIERTYPE *GetDriver( INT32 iID );