Files
source/Strategic/Player Command.cpp
T
Wanne 826340978a - Bugfix: If user changes shipping destination location in "ShippingDestinations.xml", Bobby Ray was still under construction if the "original" shipping destination was not under players control.
This occured because of hardcoded DRASSEN AIRPORT COORDINATES (BOBBYR_SHIPPING_DEST_SECTOR_X, BOBBYR_SHIPPING_DEST_SECTOR_Y, BOBBYR_SHIPPING_DEST_SECTOR_Z)

git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@3102 3b4a5df2-a311-0410-b5c6-a8a6f20db521
2009-07-11 12:01:26 +00:00

493 lines
15 KiB
C++

#ifdef PRECOMPILEDHEADERS
#include "Strategic All.h"
#else
#include "Player Command.h"
#include "Queen Command.h"
#include "Campaign Types.h"
#include "Strategic.h"
#include "Strategic Town Loyalty.h"
#include "Strategic Mines.h"
#include "text.h"
#include "laptopsave.h"
#include "quests.h"
#include "Morale.h"
#include "Overhead.h"
#include "strategicmap.h"
#include "Map Screen Helicopter.h"
#include "Game Clock.h"
#include "meanwhile.h"
#include "email.h"
#include "GameSettings.h"
#include "Strategic Status.h"
#include "Strategic AI.h"
#include "PreBattle Interface.h"
#include "Map Screen Interface.h"
#include "Tactical Save.h"
#include "interface Dialogue.h"
#include "Random.h"
#endif
#include "postalservice.h"
extern BOOLEAN fMapScreenBottomDirty;
extern CPostalService gPostalService;
void GetSectorFacilitiesFlags( INT16 sMapX, INT16 sMapY, STR16 sFacilitiesString )
{
// will build a string stating current facilities present in sector
if( SectorInfo[ SECTOR( sMapX, sMapY ) ].uiFacilitiesFlags == 0 )
{
// none
swprintf( sFacilitiesString, L"%s", sFacilitiesStrings[ 0 ] );
return;
}
// hospital
if( SectorInfo[ SECTOR( sMapX, sMapY ) ].uiFacilitiesFlags & SFCF_HOSPITAL )
{
swprintf( sFacilitiesString, L"%s", sFacilitiesStrings[ 1 ] );
}
// industry
if( SectorInfo[ SECTOR( sMapX, sMapY ) ].uiFacilitiesFlags & SFCF_INDUSTRY )
{
if( wcslen( sFacilitiesString ) == 0 )
{
swprintf( sFacilitiesString, L"%s", sFacilitiesStrings[ 2 ] );
}
else
{
wcscat( sFacilitiesString, L",");
wcscat( sFacilitiesString, sFacilitiesStrings[ 2 ]);
}
}
// prison
if( SectorInfo[ SECTOR( sMapX, sMapY ) ].uiFacilitiesFlags & SFCF_PRISON )
{
if( wcslen( sFacilitiesString ) == 0 )
{
swprintf( sFacilitiesString, L"%s", sFacilitiesStrings[ 3 ] );
}
else
{
wcscat( sFacilitiesString, L",");
wcscat( sFacilitiesString, sFacilitiesStrings[ 3 ]);
}
}
// airport
if( SectorInfo[ SECTOR( sMapX, sMapY ) ].uiFacilitiesFlags & SFCF_AIRPORT )
{
if( wcslen( sFacilitiesString ) == 0 )
{
swprintf( sFacilitiesString, L"%s", sFacilitiesStrings[ 5 ] );
}
else
{
wcscat( sFacilitiesString, L",");
wcscat( sFacilitiesString, sFacilitiesStrings[ 5 ]);
}
}
// gun range
if( SectorInfo[ SECTOR( sMapX, sMapY ) ].uiFacilitiesFlags & SFCF_GUN_RANGE )
{
if( wcslen( sFacilitiesString ) == 0 )
{
swprintf( sFacilitiesString, L"%s", sFacilitiesStrings[ 6 ] );
}
else
{
wcscat( sFacilitiesString, L",");
wcscat( sFacilitiesString, sFacilitiesStrings[ 6 ]);
}
}
sFacilitiesString[ wcslen( sFacilitiesString ) ] = 0;
return;
}
// ALL changes of control to player must be funneled through here!
BOOLEAN SetThisSectorAsPlayerControlled( INT16 sMapX, INT16 sMapY, INT8 bMapZ, BOOLEAN fContested )
{
// NOTE: MapSector must be 16-bit, cause MAX_WORLD_X is actually 18, so the sector numbers exceed 256 although we use only 16x16
UINT16 usMapSector = 0;
BOOLEAN fWasEnemyControlled = FALSE;
INT8 bTownId = 0;
UINT8 ubSectorID;
if( AreInMeanwhile( ) )
{
return FALSE;
}
if( bMapZ == 0 )
{
usMapSector = sMapX + ( sMapY * MAP_WORLD_X );
/*
// if enemies formerly controlled this sector
if (StrategicMap[ usMapSector ].fEnemyControlled)
{
// remember that the enemies have lost it
StrategicMap[ usMapSector ].fLostControlAtSomeTime = TRUE;
}
*/
if( NumHostilesInSector( sMapX, sMapY, bMapZ ) )
{ //too premature: enemies still in sector.
return FALSE;
}
if (LaptopSaveInfo.fBobbyRSiteCanBeAccessed == FALSE)
{
// Check if the sector is a shipment sector
BOOLEAN isShipmentSector = gPostalService.IsSectorAShipmentSector((UINT8)sMapX, (UINT8)sMapY, (UINT8)bMapZ);
if (isShipmentSector)
LaptopSaveInfo.fBobbyRSiteCanBeAccessed = TRUE;
}
// WANNE: Get Airport sector from ShippingDestination.xml file!
// check if we ever grabbed drassen airport, if so, set fact we can go to BR's
//if( ( sMapX == BOBBYR_SHIPPING_DEST_SECTOR_X ) && ( sMapY == BOBBYR_SHIPPING_DEST_SECTOR_Y ) )
if (LaptopSaveInfo.fBobbyRSiteCanBeAccessed)
{
//LaptopSaveInfo.fBobbyRSiteCanBeAccessed = TRUE;
//If the player has been to Bobbyr when it was down, and we havent already sent email, send him an email
if( LaptopSaveInfo.ubHaveBeenToBobbyRaysAtLeastOnceWhileUnderConstruction == BOBBYR_BEEN_TO_SITE_ONCE && LaptopSaveInfo.ubHaveBeenToBobbyRaysAtLeastOnceWhileUnderConstruction != BOBBYR_ALREADY_SENT_EMAIL )
{
AddEmail( BOBBYR_NOW_OPEN, BOBBYR_NOW_OPEN_LENGTH, BOBBY_R, GetWorldTotalMin(), -1);
LaptopSaveInfo.ubHaveBeenToBobbyRaysAtLeastOnceWhileUnderConstruction = BOBBYR_ALREADY_SENT_EMAIL;
}
}
fWasEnemyControlled = StrategicMap[ usMapSector ].fEnemyControlled;
StrategicMap[ usMapSector ].fEnemyControlled = FALSE;
SectorInfo[ SECTOR( sMapX, sMapY ) ].fPlayer[ bMapZ ] = TRUE;
bTownId = StrategicMap[ usMapSector ].bNameId;
// check if there's a town in the sector
if ((bTownId >= FIRST_TOWN) && (bTownId < NUM_TOWNS))
{
// yes, start tracking (& displaying) this town's loyalty if not already doing so
StartTownLoyaltyIfFirstTime( bTownId );
}
// if player took control away from enemy
if( fWasEnemyControlled && fContested )
{
// WDS - New AI
// Hook in here for some stuff
// and it's a town
if ((bTownId >= FIRST_TOWN) && (bTownId < NUM_TOWNS))
{
// don't do these for takeovers of Omerta sectors at the beginning of the game
if ((bTownId != OMERTA) || (GetWorldDay() != 1))
{
ubSectorID = (UINT8)SECTOR( sMapX, sMapY );
if( !bMapZ && ubSectorID != SEC_J9 && ubSectorID != SEC_K4 )
{
HandleMoraleEvent( NULL, MORALE_TOWN_LIBERATED, sMapX, sMapY, bMapZ );
HandleGlobalLoyaltyEvent( GLOBAL_LOYALTY_GAIN_TOWN_SECTOR, sMapX, sMapY, bMapZ );
// liberation by definition requires that the place was enemy controlled in the first place
CheckIfEntireTownHasBeenLiberated( bTownId, sMapX, sMapY );
}
}
}
// if it's a mine that's still worth something
if ( IsThereAMineInThisSector( sMapX, sMapY ) )
{
if ( GetTotalLeftInMine( GetMineIndexForSector( sMapX, sMapY ) ) > 0)
{
HandleMoraleEvent( NULL, MORALE_MINE_LIBERATED, sMapX, sMapY, bMapZ );
HandleGlobalLoyaltyEvent( GLOBAL_LOYALTY_GAIN_MINE, sMapX, sMapY, bMapZ );
}
}
// if it's a SAM site sector
if( IsThisSectorASAMSector( sMapX, sMapY, bMapZ ) )
{
if ( 1 /*!GetSectorFlagStatus( sMapX, sMapY, bMapZ, SF_SECTOR_HAS_BEEN_LIBERATED_ONCE ) */)
{
// SAM site liberated for first time, schedule meanwhile
HandleMeanWhileEventPostingForSAMLiberation( GetSAMIdFromSector( sMapX, sMapY, bMapZ ) );
}
HandleMoraleEvent( NULL, MORALE_SAM_SITE_LIBERATED, sMapX, sMapY, bMapZ );
HandleGlobalLoyaltyEvent( GLOBAL_LOYALTY_GAIN_SAM, sMapX, sMapY, bMapZ );
// if Skyrider has been delivered to chopper, and already mentioned Drassen SAM site, but not used this quote yet
if ( IsHelicopterPilotAvailable() && ( guiHelicopterSkyriderTalkState >= 1 ) && ( !gfSkyriderSaidCongratsOnTakingSAM ) )
{
SkyRiderTalk( SAM_SITE_TAKEN );
gfSkyriderSaidCongratsOnTakingSAM = TRUE;
}
if ( !SectorInfo[ SECTOR( sMapX, sMapY ) ].fSurfaceWasEverPlayerControlled )
{
// grant grace period
if ( gGameOptions.ubDifficultyLevel >= DIF_LEVEL_HARD )
{
UpdateLastDayOfPlayerActivity( ( UINT16 ) ( GetWorldDay() + 2 ) );
}
else
{
UpdateLastDayOfPlayerActivity( ( UINT16 ) ( GetWorldDay() + 1 ) );
}
}
}
// if it's a helicopter refueling site sector
if( IsRefuelSiteInSector( sMapX, sMapY) )
{
UpdateRefuelSiteAvailability( );
}
// SetSectorFlag( sMapX, sMapY, bMapZ, SF_SECTOR_HAS_BEEN_LIBERATED_ONCE );
if ( bMapZ == 0 && ( ( sMapY == MAP_ROW_M && (sMapX >= 2 && sMapX <= 6) ) || sMapY == MAP_ROW_N && sMapX == 6) )
{
HandleOutskirtsOfMedunaMeanwhileScene();
}
}
if( fContested )
{
StrategicHandleQueenLosingControlOfSector( (UINT8)sMapX, (UINT8)sMapY, (UINT8)bMapZ );
}
}
else
{
if( sMapX == 3 && sMapY == 16 && bMapZ == 1 )
{ //Basement sector (P3_b1)
gfUseAlternateQueenPosition = TRUE;
}
}
// also set fact the player knows they own it
SectorInfo[ SECTOR( sMapX, sMapY ) ].fPlayer[ bMapZ ] = TRUE;
if ( bMapZ == 0 )
{
SectorInfo[ SECTOR( sMapX, sMapY ) ].fSurfaceWasEverPlayerControlled = TRUE;
}
//KM : Aug 11, 1999 -- Patch fix: Relocated this check so it gets called everytime a sector changes hands,
// even if the sector isn't a SAM site. There is a bug _somewhere_ that fails to update the airspace,
// even though the player controls it.
UpdateAirspaceControl( );
// redraw map/income if in mapscreen
fMapPanelDirty = TRUE;
fMapScreenBottomDirty = TRUE;
return fWasEnemyControlled;
}
// ALL changes of control to enemy must be funneled through here!
BOOLEAN SetThisSectorAsEnemyControlled( INT16 sMapX, INT16 sMapY, INT8 bMapZ, BOOLEAN fContested )
{
UINT16 usMapSector = 0;
BOOLEAN fWasPlayerControlled = FALSE;
INT8 bTownId = 0;
UINT8 ubTheftChance;
UINT8 ubSectorID;
//KM : August 6, 1999 Patch fix
// This check was added because this function gets called when player mercs retreat from an unresolved
// battle between militia and enemies. It will get called again AFTER autoresolve is finished.
if( gfAutomaticallyStartAutoResolve )
{
return( FALSE );
}
if( bMapZ == 0 )
{
usMapSector = sMapX + ( sMapY * MAP_WORLD_X );
fWasPlayerControlled = !StrategicMap[ usMapSector ].fEnemyControlled;
StrategicMap[ usMapSector ].fEnemyControlled = TRUE;
// if player lost control to the enemy
if ( fWasPlayerControlled )
{
if( PlayerMercsInSector( (UINT8)sMapX, (UINT8)sMapY, (UINT8)bMapZ ) )
{ //too premature: Player mercs still in sector.
return FALSE;
}
// check if there's a town in the sector
bTownId = StrategicMap[ usMapSector ].bNameId;
SectorInfo[ SECTOR( sMapX, sMapY ) ].fPlayer[ bMapZ ] = FALSE;
// and it's a town
if ((bTownId >= FIRST_TOWN) && (bTownId < NUM_TOWNS))
{
ubSectorID = (UINT8)SECTOR( sMapX, sMapY );
if( !bMapZ && ubSectorID != SEC_J9 && ubSectorID != SEC_K4 )
{
HandleMoraleEvent( NULL, MORALE_TOWN_LOST, sMapX, sMapY, bMapZ );
HandleGlobalLoyaltyEvent( GLOBAL_LOYALTY_LOSE_TOWN_SECTOR, sMapX, sMapY, bMapZ );
CheckIfEntireTownHasBeenLost( bTownId, sMapX, sMapY );
}
}
// if the sector has a mine which is still worth something
if ( IsThereAMineInThisSector( sMapX, sMapY ) )
{
// if it isn't empty
if ( GetTotalLeftInMine( GetMineIndexForSector( sMapX, sMapY ) ) > 0)
{
QueenHasRegainedMineSector(GetMineIndexForSector (sMapX, sMapY));
HandleMoraleEvent( NULL, MORALE_MINE_LOST, sMapX, sMapY, bMapZ );
HandleGlobalLoyaltyEvent( GLOBAL_LOYALTY_LOSE_MINE, sMapX, sMapY, bMapZ );
}
}
// if it's a SAM site sector
if( IsThisSectorASAMSector( sMapX, sMapY, bMapZ ) )
{
HandleMoraleEvent( NULL, MORALE_SAM_SITE_LOST, sMapX, sMapY, bMapZ );
HandleGlobalLoyaltyEvent( GLOBAL_LOYALTY_LOSE_SAM, sMapX, sMapY, bMapZ );
}
// if it's a helicopter refueling site sector
if( IsRefuelSiteInSector( sMapX, sMapY) )
{
UpdateRefuelSiteAvailability( );
}
// ARM: this must be AFTER all resulting loyalty effects are resolved, or reduced mine income shown won't be accurate
NotifyPlayerWhenEnemyTakesControlOfImportantSector( sMapX, sMapY, 0, fContested );
}
// NOTE: Stealing is intentionally OUTSIDE the fWasPlayerControlled branch. This function gets called if new
// enemy reinforcements arrive, and they deserve another crack at stealing what the first group missed! :-)
// stealing should fail anyway 'cause there shouldn't be a temp file for unvisited sectors, but let's check anyway
if ( GetSectorFlagStatus( sMapX, sMapY, ( UINT8 ) bMapZ, SF_ALREADY_VISITED ) == TRUE )
{
// enemies can steal items left lying about (random chance). The more there are, the more they take!
ubTheftChance = 5 * NumEnemiesInAnySector( sMapX, sMapY, bMapZ );
// max 90%, some stuff may just simply not get found
if (ubTheftChance > 90 )
{
ubTheftChance = 90;
}
RemoveRandomItemsInSector( sMapX, sMapY, bMapZ, ubTheftChance );
}
// don't touch fPlayer flag for a surface sector lost to the enemies!
// just because player has lost the sector doesn't mean he realizes it - that's up to our caller to decide!
}
else
{
// underground sector control is always up to date, because we don't track control down there
SectorInfo[ SECTOR( sMapX, sMapY ) ].fPlayer[ bMapZ ] = FALSE;
}
//KM : Aug 11, 1999 -- Patch fix: Relocated this check so it gets called everytime a sector changes hands,
// even if the sector isn't a SAM site. There is a bug _somewhere_ that fails to update the airspace,
// even though the player controls it.
UpdateAirspaceControl( );
// redraw map/income if in mapscreen
fMapPanelDirty = TRUE;
fMapScreenBottomDirty = TRUE;
return fWasPlayerControlled;
}
#ifdef JA2TESTVERSION
void ClearMapControlledFlags( void )
{
INT32 iCounterA = 0, iCounterB = 0;
UINT16 usMapSector = 0;
for( iCounterA = 1; iCounterA < MAP_WORLD_X - 1; iCounterA++ )
{
for( iCounterB = 1; iCounterB < MAP_WORLD_Y - 1; iCounterB++ )
{
usMapSector = iCounterA + ( iCounterB * MAP_WORLD_X );
StrategicMap[ usMapSector ].fEnemyControlled = FALSE;
SectorInfo[ SECTOR( iCounterA, iCounterB ) ].fPlayer[ 0 ] = TRUE;
}
}
UpdateAirspaceControl( );
}
#endif
/*
BOOLEAN IsTheSectorPerceivedToBeUnderEnemyControl( INT16 sMapX, INT16 sMapY, INT8 bMapZ )
{
// are we in battle in this sector?
if( ( sMapX == gWorldSectorX ) && ( sMapY == gWorldSectorY ) && ( bMapZ == gbWorldSectorZ ) && ( gTacticalStatus.uiFlags & INCOMBAT ) )
{
return( TRUE );
}
// does the player believe this sector is under enemy control?
return( !( SectorInfo[ SECTOR( sMapX, sMapY ) ].fPlayer[ bMapZ ] ) );
}
void MakePlayerPerceptionOfSectorControlCorrect( INT16 sMapX, INT16 sMapY, INT8 bMapZ )
{
if (bMapZ == 0)
{
SectorInfo[ SECTOR( sMapX, sMapY ) ].fPlayer[ bMapZ ] = !( StrategicMap[ CALCULATE_STRATEGIC_INDEX( sMapX, sMapY ) ].fEnemyControlled );
}
// else nothing, underground sector control is always up to date, because we don't track control down there
fMapPanelDirty = TRUE;
}
*/
void ReplaceSoldierProfileInPlayerGroup( UINT8 ubGroupID, UINT8 ubOldProfile, UINT8 ubNewProfile )
{
GROUP *pGroup;
PLAYERGROUP *curr;
pGroup = GetGroup( ubGroupID );
if ( !pGroup )
{
return;
}
curr = pGroup->pPlayerList;
while( curr )
{
if( curr->ubProfileID == ubOldProfile )
{
// replace and return!
curr->ubProfileID = ubNewProfile;
return;
}
curr = curr->next;
}
}