mirror of
https://github.com/1dot13/source.git
synced 2026-07-22 13:40:22 +02:00
git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@1871 3b4a5df2-a311-0410-b5c6-a8a6f20db521
477 lines
14 KiB
C++
477 lines
14 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"
|
|
#endif
|
|
|
|
|
|
extern BOOLEAN fMapScreenBottomDirty;
|
|
|
|
|
|
|
|
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;
|
|
}
|
|
|
|
// 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 ) )
|
|
{
|
|
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 )
|
|
{
|
|
// 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;
|
|
}
|
|
|
|
}
|