- New Feature: Arulco special division controls other features to fight the player. For more info, see http://thepit.ja-galaxy-forum.com/index.php?t=tree&goto=343706&#msg_343706

- New Feature: Enemy helicopters allow the AI to rapidly deploy troops aross the map. For more info, see http://thepit.ja-galaxy-forum.com/index.php?t=tree&goto=343707&#msg_343707. GameDir <= r2279 is required.
- Fix: income of mine 0 was not correctly calculated

git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@8015 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
Flugente
2016-01-09 19:45:30 +00:00
parent 70b832d0b4
commit 7664342746
67 changed files with 3187 additions and 165 deletions
+1425
View File
File diff suppressed because it is too large Load Diff
+120
View File
@@ -0,0 +1,120 @@
#ifndef __ASD_H
#define __ASD_H
/**
* @file
* @author Flugente (bears-pit.com)
*/
#include "Types.h"
/** Flugente: Arulco special division decision code
*
* As I do not want to alter the current strategic AI (fragile and obscure as it is),
* I am leaving the control over a number of new toys to a second 'AI' - the 'Arulco Special Division'.
* This should control if, how and when new features are used by the AI.
*
* It has its own 'budget', which allows it to purchase new actions. This serves to limit the amount of the AIs actions.
* It also gives the player a way to compete with the AI - lower the AI budget, and the AI can do less harm.
* For example, part of the AI budget might come from mine income, which the player can take away.
*
* If possible, the AI should have to buy and maintain its assets.
* This way the player could harm the AI by specifically targetting those assets if he chooses so.
* Ideally this gives the player another immersive way to do sth. in the game.
* For example, enemy helicopters have to be bought, fuelled and repaired.
* In order to stop enemy heli raids, the player could
* - shoot them down
* - steal enemy fuel deliveries
* - sabotage enemy helis in their airfield
*
* There is a cyclic update of this AI. Each time the AI decides whether it wants (and can afford) new assets.
* These assets then have to be ordered and can only be used once arrived.
* The AI also decides how to use these assets.
*/
void InitASD( );
BOOLEAN SaveASDData( HWFILE hwFile );
BOOLEAN LoadASDData( HWFILE hwFile );
// when called, evaluate the current situation, and perform actions to harm the player if necessary
void UpdateASD( );
// decide whether to purchase something
void ASDDecideOnPurchases();
// decide in what to do with helicopters
void ASDDecideHeliOperations();
// various flags for the AI to remember
#define ASDFACT_HELI_UNLOCKED 0x00000001 // AI is allowed to purchase helicopters
#define ASDFACT_JEEP_UNLOCKED 0x00000002 // AI is allowed to purchase jeeps
#define ASDFACT_TANK_UNLOCKED 0x00000004 // AI is allowed to purchase tanks
void SetASDFlag( UINT32 aFlag );
UINT32 ASDResourceDeliveryTime( UINT8 aType );
UINT32 ASDResourceCostMoney( UINT8 aType );
// add resources to the AIs resource pool
void AddStrategicAIResources( UINT8 aType, INT32 aAmount );
void ASDReceiveOrderedStrategicAIResources( UINT8 aType, INT32 aAmount );
// enemy helis
class ENEMY_HELI
{
public:
// determine best heli flight path (minimising contact to hostile SAM sectors) and return number of possible SAM contacts
UINT8 SetHeliFlightPath( UINT8 aDest );
void Destroy( );
public:
UINT32 flagmask; // flags: destroyed, refueling...
UINT8 sector_current; // we are here
UINT8 sector_destination; // we want to fly here
UINT8 sector_waypoint; // a sector we travel to between our starting point and our destiantion. Choosing this gives us a way to plot a path minimising SAM-exposure
UINT8 sector_home; // this is where our base is
UINT8 troopcount; // number of troops we carry
UINT8 hp;
UINT8 fuel;
};
extern std::vector<ENEMY_HELI> gEnemyHeliVector;
void EnemyHeliInit( );
void AddNewHeli( );
// all enemy helis carrying troops in this sector drop these into combat, and get the order to head home
void EnemyHeliTroopDrop( UINT8 aSector );
std::set<UINT8> GetEnemyHeliSectors( BOOLEAN afKnownToPlayer );
void UpdateEnemyHeliRepair( INT16 id );
void UpdateEnemyHeliRefuel( INT16 id );
void UpdateEnemyHeli( INT16 id );
void EnemyHeliSAMCheck( INT16 id );
void EnemyHeliMANPADSCheck( INT16 id );
void EnemyHeliCheckPlayerKnowledge( INT16 id );
void RepairSamSite( UINT8 aSector );
BOOLEAN IsSectorAirSpacePlayerControlled( UINT8 aSector );
UINT8 NumPlayerAirSpaceOnHeliPath( UINT8 aStart, UINT8 aEnd );
// get the next sector in an enemy heli flight path.
UINT8 GetNextEnemyHeliSector( UINT8 aStart, UINT8 aDest );
void HandleEnemyHelicopterOnGroundGraphic( );
void UpdateAndDamageEnemyHeliIfFound( INT16 sSectorX, INT16 sSectorY, INT16 sSectorZ, INT32 sGridNo, UINT8 ubDamage, BOOLEAN aDestroyed = FALSE );
// enemy tanks (how and when they are used)
UINT32 ASDResourceCostFuel( UINT8 aType );
// if ASD is used, any tanks the queen uses in mobile attacks come from its pool, and we have to account for that
BOOLEAN ASDSoldierUpgradeToTank( );
#endif //__ASD_H
+38
View File
@@ -3209,6 +3209,44 @@ UINT32 CalculateSnitchPrisonGuardValue(SOLDIERTYPE *pSoldier, UINT16 *pusMaxPts
return( usValue );
}
// Flugente: Determine the best cth with SAMs in a sector, and which merc has that cth if present
FLOAT GetBestSAMOperatorCTH_Player( INT16 sSectorX, INT16 sSectorY, INT16 sSectorZ, UINT16 *pubID )
{
// if nobody is here, nobody can fire
FLOAT bestsamcth = 0.0f;
*pubID = NOBODY;
// militia can at least operate the thing, but don't count on them hitting anything...
if ( NumNonPlayerTeamMembersInSector( sSectorX, sSectorY, MILITIA_TEAM ) )
bestsamcth = 40.0f;
// loop over all mercs present. Best cth wins
UINT16 uiCnt = 0;
SOLDIERTYPE* pSoldier = NULL;
for ( uiCnt = 0, pSoldier = MercPtrs[uiCnt]; uiCnt <= gTacticalStatus.Team[gbPlayerNum].bLastID; ++uiCnt, ++pSoldier )
{
if ( pSoldier && pSoldier->bActive && pSoldier->stats.bLife >= OKLIFE && (pSoldier->sSectorX == sSectorX) && (pSoldier->sSectorY == sSectorY) && (pSoldier->bSectorZ == sSectorZ) )
{
INT16 personal_bestsamcth = 70.0f +
15 * NUM_SKILL_TRAITS( pSoldier, HEAVY_WEAPONS_NT ) +
10 * NUM_SKILL_TRAITS( pSoldier, TECHNICIAN_NT ) +
2 * NUM_SKILL_TRAITS( pSoldier, DEMOLITIONS_NT ) +
5 * NUM_SKILL_TRAITS( pSoldier, RADIO_OPERATOR_NT );
personal_bestsamcth = (personal_bestsamcth * (100.0f + pSoldier->GetBackgroundValue( BG_PERC_SAM_CTH ))) / 100.0f;
if ( personal_bestsamcth > bestsamcth )
{
bestsamcth = personal_bestsamcth;
*pubID = uiCnt;
}
}
}
return bestsamcth;
}
// anv: handle prisoners exposing snitch as a snitch
BOOL HandleSnitchExposition(SOLDIERTYPE *pSoldier)
{
+3
View File
@@ -260,6 +260,9 @@ UINT32 CalculatePrisonGuardValue(SOLDIERTYPE *pSoldier, UINT16 *pusMaxPts );
UINT32 CalculateSnitchInterrogationValue(SOLDIERTYPE *pSoldier, UINT16 *pusMaxPts );
// Flugente: Determine the best cth with SAMs in a sector, and which merc has that cth if present
FLOAT GetBestSAMOperatorCTH_Player( INT16 sSectorX, INT16 sSectorY, INT16 sSectorZ, UINT16 *pubID );
// Flugente: determine max items we can move, and the sector distance
// get bonus tarining pts due to an instructor for this student
+1
View File
@@ -441,6 +441,7 @@ typedef enum
// -------- added by Flugente: sector info flags --------
// easier than adding 32 differently named variables. DO NOT CHANGE THEM, UNLESS YOU KNOW WHAT YOU ARE DOING!!!
#define SECTORINFO_VOLUNTEERS_RECENTLY_RECRUITED 0x01 //1 // we recruited volunteers here. Until this flag is removed, newly created civilians wont be potential volunteers anymore
#define SECTORINFO_ENEMYHELI_SHOTDOWN 0x02 //2 // an enemy helicopter was shot down here. The first time after that we enter this sector, there is a chance to find a downed pilot here
typedef struct SECTORINFO
{
+1 -1
View File
@@ -717,7 +717,7 @@ void HandleManualPaymentFacilityDebt( void )
// HEADROCK HAM 3.6: Apply income bonuses from Facility Work to a specific mine.
INT32 MineIncomeModifierFromFacility( UINT8 ubMine )
{
Assert (ubMine > 0 && ubMine < MAX_NUMBER_OF_MINES);
Assert (ubMine >= 0 && ubMine < MAX_NUMBER_OF_MINES);
SOLDIERTYPE *pSoldier;
INT32 iModifier = 0;
+43 -1
View File
@@ -47,6 +47,8 @@
#include "MilitiaSquads.h"
#include "PMC.h" // added by Flugente
#include "finances.h" // added by Flugente
#include "ASD.h" // added by Flugente
#include "Player Command.h" // added by Flugente
#endif
#include "connect.h"
@@ -573,7 +575,47 @@ BOOLEAN ExecuteStrategicEvent( STRATEGICEVENT *pEvent )
EndQuest( QUEST_KINGPIN_ANGEL_MARIA, gWorldSectorX, gWorldSectorY );
break;
#endif
#endif
case EVENT_ASD_UPDATE:
UpdateASD();
break;
case EVENT_ASD_PURCHASE_FUEL:
if ( IsSectorEnemyControlled( SECTORX( gGameExternalOptions.usASDSupplyArrivalSector ), SECTORY( gGameExternalOptions.usASDSupplyArrivalSector ), 0 ) )
ASDReceiveOrderedStrategicAIResources( ASD_FUEL, pEvent->uiParam );
break;
case EVENT_ASD_PURCHASE_JEEP:
if ( IsSectorEnemyControlled( SECTORX( gGameExternalOptions.usASDSupplyArrivalSector ), SECTORY( gGameExternalOptions.usASDSupplyArrivalSector ), 0 ) )
ASDReceiveOrderedStrategicAIResources( ASD_JEEP, pEvent->uiParam );
break;
case EVENT_ASD_PURCHASE_TANK:
if ( IsSectorEnemyControlled( SECTORX( gGameExternalOptions.usASDSupplyArrivalSector ), SECTORY( gGameExternalOptions.usASDSupplyArrivalSector ), 0 ) )
ASDReceiveOrderedStrategicAIResources( ASD_TANK, pEvent->uiParam );
break;
case EVENT_ASD_PURCHASE_HELI:
if ( IsSectorEnemyControlled( SECTORX( gGameExternalOptions.usEnemyHeliBaseSector ), SECTORY( gGameExternalOptions.usEnemyHeliBaseSector ), 0 ) )
ASDReceiveOrderedStrategicAIResources( ASD_HELI, pEvent->uiParam );
break;
case EVENT_ENEMY_HELI_UPDATE:
UpdateEnemyHeli( pEvent->uiParam );
break;
case EVENT_ENEMY_HELI_REPAIR:
UpdateEnemyHeliRepair( pEvent->uiParam );
break;
case EVENT_ENEMY_HELI_REFUEL:
UpdateEnemyHeliRefuel( pEvent->uiParam );
break;
case EVENT_SAMSITE_REPAIRED:
RepairSamSite( pEvent->uiParam );
break;
}
gfPreventDeletionOfAnyEvent = fOrigPreventFlag;
return TRUE;
+12
View File
@@ -120,6 +120,18 @@ enum
EVENT_KINGPIN_BOUNTY_END_KILLEDTHEM,
EVENT_KINGPIN_BOUNTY_END_TIME_PASSED,
EVENT_ASD_UPDATE, // Flugente: the queen's special division decides it's next action
EVENT_ASD_PURCHASE_FUEL,
EVENT_ASD_PURCHASE_JEEP,
EVENT_ASD_PURCHASE_TANK,
EVENT_ASD_PURCHASE_HELI,
EVENT_ENEMY_HELI_UPDATE, // Flugente: move enemy helicopter to another sector
EVENT_ENEMY_HELI_REPAIR,
EVENT_ENEMY_HELI_REFUEL,
EVENT_SAMSITE_REPAIRED, // Flugente: have a SAM site be fully repaired
NUMBER_OF_EVENT_TYPES_PLUS_ONE,
NUMBER_OF_EVENT_TYPES = NUMBER_OF_EVENT_TYPES_PLUS_ONE - 1
};
+9
View File
@@ -115,6 +115,15 @@ CHAR16 gEventName[NUMBER_OF_EVENT_TYPES_PLUS_ONE][40]={
L"KingpinBounty1",
L"KingpinBounty2",
L"KingpinBounty3",
L"ASDUpdate",
L"ASDPurchaseFuel",
L"ASDPurchaseJeep",
L"ASDPurchaseTank",
L"ASDPurchaseHeli",
L"EnemyHeliUpdate",
L"EnemyHeliRepair",
L"EnemyHeliRefuel",
L"SAMsiteRepaired",
};
#endif
+8 -4
View File
@@ -61,6 +61,7 @@
#include "Map Screen Interface Map Inventory.h"//dnl ch51 081009
#include "CampaignStats.h" // added by Flugente
#include "PMC.h" // added by Flugente
#include "ASD.h" // added by Flugente
#endif
#include "Vehicles.h"
@@ -499,13 +500,16 @@ void InitStrategicLayer( void )
// re-set up leave list arrays for dismissed mercs
InitLeaveList( );
// Flugente: se up VIP locations
void InitVIPSectors( );
// Flugente: set up VIP locations
InitVIPSectors();
// Flugente: init special AI
InitASD();
#ifdef JA2UB
#ifdef JA2UB
LuaInitStrategicLayer(0); //JA25 UB InitStrategicLayer.lua
#endif
#endif
// reset time compression mode to X0 (this will also pause it)
SetGameTimeCompressionLevel( TIME_COMPRESS_X0 );
+65 -7
View File
@@ -43,6 +43,7 @@
#include "Debug Control.h"
#include "expat.h"
#include "merc entering.h" // added by Flugente
#include "ASD.h" // added by Flugente
#endif
#include "Vehicles.h"
@@ -106,6 +107,7 @@ INT32 iHelicopterVehicleId = -1;
// helicopter icon
UINT32 guiHelicopterIcon;
UINT32 guiEnemyHelicopterIcon;
// total distance travelled
INT32 iTotalHeliDistanceSinceRefuel = 0;
@@ -1292,6 +1294,9 @@ void LandHelicopter( void )
HandleKillChopperMeanwhileScene();
#endif
}
// Flugente: once the AI 'learns' of the player using helis, it wants some for itself
SetASDFlag( ASDFACT_HELI_UNLOCKED );
}
@@ -2670,19 +2675,19 @@ void AddHelicopterToMaps( BOOLEAN fAdd, UINT8 ubSite )
InvalidateWorldRedundency();
SetRenderFlags( RENDER_FLAG_FULL );
// ATE: If any mercs here, bump them off!
// ATE: If any mercs here, bump them off!
ConvertGridNoToXY( iGridNo, &sCentreGridX, &sCentreGridY );
for( sGridY = sCentreGridY - 5; sGridY < sCentreGridY + 5; sGridY++ )
{
for( sGridX = sCentreGridX - 5; sGridX < sCentreGridX + 5; sGridX++ )
for( sGridY = sCentreGridY - 5; sGridY < sCentreGridY + 5; sGridY++ )
{
iGridNo = MAPROWCOLTOPOS( sGridY, sGridX );
for( sGridX = sCentreGridX - 5; sGridX < sCentreGridX + 5; sGridX++ )
{
iGridNo = MAPROWCOLTOPOS( sGridY, sGridX );
BumpAnyExistingMerc( iGridNo );
BumpAnyExistingMerc( iGridNo );
}
}
}
}
else
{
// remove from the world
@@ -2695,9 +2700,62 @@ void AddHelicopterToMaps( BOOLEAN fAdd, UINT8 ubSite )
InvalidateWorldRedundency();
SetRenderFlags( RENDER_FLAG_FULL );
}
}
void AddEnemyHelicopterToMaps( BOOLEAN fAdd, BOOLEAN fDestroyed, INT32 aGridno, INT32 aTileIndex )
{
// for safety, remove the old one first
{
// remove from the world
RemoveStruct( aGridno, (UINT16)aTileIndex );
RemoveStruct( aGridno, (UINT16)(aTileIndex + 1) );
RemoveStruct( (aGridno - WORLD_COLS * 5), (UINT16)(aTileIndex + 2) );
RemoveStruct( aGridno, (UINT16)(aTileIndex + 3) );
RemoveStruct( aGridno, (UINT16)(aTileIndex + 4) );
RemoveStruct( (aGridno - WORLD_COLS * 5), (UINT16)(aTileIndex + 5) );
// for safety reasons, both versions are to be removed
RemoveStruct( aGridno, (UINT16)aTileIndex + 6 );
RemoveStruct( aGridno, (UINT16)(aTileIndex + 6 + 1) );
RemoveStruct( (aGridno - WORLD_COLS * 5), (UINT16)(aTileIndex + 6 + 2) );
RemoveStruct( aGridno, (UINT16)(aTileIndex + 6 + 3) );
RemoveStruct( aGridno, (UINT16)(aTileIndex + 6 + 4) );
RemoveStruct( (aGridno - WORLD_COLS * 5), (UINT16)(aTileIndex + 6 + 5) );
InvalidateWorldRedundency( );
SetRenderFlags( RENDER_FLAG_FULL );
}
if ( fAdd )
{
INT16 sCentreGridX, sCentreGridY;
INT16 offset = fDestroyed ? 6 : 0;
AddHeliPiece( aGridno, (UINT16)aTileIndex + offset );
AddHeliPiece( aGridno, (UINT16)(aTileIndex + offset + 1) );
AddHeliPiece( (aGridno - WORLD_COLS * 5), (UINT16)(aTileIndex + offset + 2) );
AddHeliPiece( aGridno, (UINT16)(aTileIndex + offset + 3) );
AddHeliPiece( aGridno, (UINT16)(aTileIndex + offset + 4) );
AddHeliPiece( (aGridno - WORLD_COLS * 5), (UINT16)(aTileIndex + offset + 5) );
InvalidateWorldRedundency( );
SetRenderFlags( RENDER_FLAG_FULL );
// ATE: If any mercs here, bump them off!
ConvertGridNoToXY( aGridno, &sCentreGridX, &sCentreGridY );
for ( INT16 sGridY = sCentreGridY - 5; sGridY < sCentreGridY + 5; sGridY++ )
{
for ( INT16 sGridX = sCentreGridX - 5; sGridX < sCentreGridX + 5; sGridX++ )
{
aGridno = MAPROWCOLTOPOS( sGridY, sGridX );
BumpAnyExistingMerc( aGridno );
}
}
}
}
+3
View File
@@ -99,6 +99,7 @@ extern BOOLEAN fHoveringHelicopter;
// helicopter icon
extern UINT32 guiHelicopterIcon;
extern UINT32 guiEnemyHelicopterIcon;
// helicopter destroyed
extern BOOLEAN fHelicopterDestroyed;
@@ -293,6 +294,8 @@ BOOLEAN CanHelicopterTakeOff( void );
void InitializeHelicopter( void );
void AddEnemyHelicopterToMaps( BOOLEAN fAdd, BOOLEAN fDestroyed, INT32 aGridno, INT32 aTileIndex );
BOOLEAN IsSkyriderIsFlyingInSector( INT16 sSectorX, INT16 sSectorY );
BOOLEAN IsGroupTheHelicopterGroup( GROUP *pGroup );
+72
View File
@@ -44,6 +44,7 @@
#include "Map Information.h"
#include "Air Raid.h"
#include "Auto Resolve.h"
#include "ASD.h" // added by Flugente
#endif
#include "Quests.h"
@@ -4248,6 +4249,77 @@ void DisplayPositionOfHelicopter( void )
}
}
void DisplayPositionOfEnemyHelicopter()
{
static INT16 sOldMapX = 0, sOldMapY = 0;
// INT16 sX =0, sY = 0;
FLOAT flRatio = 0.0;
UINT32 x, y;
UINT16 minX, minY, maxX, maxY;
HVOBJECT hHandle;
INT32 iNumberOfPeopleInHelicopter = 0;
CHAR16 sString[4];
INT32 MAP_MVT_ICON_FONT = TINYFONT1;
AssertMsg( (sOldMapX >= 0) && (sOldMapX < SCREEN_WIDTH), String( "DisplayPositionOfHelicopter: Invalid sOldMapX = %d", sOldMapX ) );
AssertMsg( (sOldMapY >= 0) && (sOldMapY < SCREEN_HEIGHT), String( "DisplayPositionOfHelicopter: Invalid sOldMapY = %d", sOldMapY ) );
// TODO: different icon
// HEADROCK HAM 5: Now has to be done here to get the size of the helicopter icon.
GetVideoObject( &hHandle, guiEnemyHelicopterIcon );
UINT16 usIconWidth = hHandle->pETRLEObject[0].usWidth;
UINT16 usIconHeight = hHandle->pETRLEObject[0].usHeight;
UINT16 usIconOffsetX = hHandle->pETRLEObject[0].sOffsetX;
UINT16 usIconOffsetY = hHandle->pETRLEObject[0].sOffsetY;
// restore background on map where it is
if ( sOldMapX != 0 )
{
RestoreExternBackgroundRect( sOldMapX + usIconOffsetX, sOldMapY + usIconOffsetY, usIconWidth, usIconHeight );
sOldMapX = 0;
}
std::set<UINT8> helisectorset = GetEnemyHeliSectors( TRUE ); // if set to FALSE, display helicopters regardless of player knowledge
for ( std::set<UINT8>::iterator it = helisectorset.begin( ); it != helisectorset.end( ); ++it)
{
UINT8 sector = (*it);
UINT8 sector_x = SECTORX( sector );
UINT8 sector_y = SECTORY( sector );
// grab min and max locations to interpolate sub sector position
minX = MAP_VIEW_START_X + MAP_GRID_X * (sector_x);
maxX = MAP_VIEW_START_X + MAP_GRID_X * (sector_x);
minY = MAP_VIEW_START_Y + MAP_GRID_Y * (sector_y);
maxY = MAP_VIEW_START_Y + MAP_GRID_Y * (sector_y);
AssertMsg( (minX >= 0) && (minX < SCREEN_WIDTH), String( "DisplayPositionOfHelicopter: Invalid minX = %d", minX ) );
AssertMsg( (maxX >= 0) && (maxX < SCREEN_WIDTH), String( "DisplayPositionOfHelicopter: Invalid maxX = %d", maxX ) );
AssertMsg( (minY >= 0) && (minY < SCREEN_WIDTH), String( "DisplayPositionOfHelicopter: Invalid minY = %d", minY ) );
AssertMsg( (maxY >= 0) && (maxY < SCREEN_WIDTH), String( "DisplayPositionOfHelicopter: Invalid maxY = %d", maxY ) );
// IMPORTANT: Since min can easily be larger than max, we gotta cast to as signed value
x = (UINT32)(minX + flRatio * ((INT16)maxX - (INT16)minX));
y = (UINT32)(minY + flRatio * ((INT16)maxY - (INT16)minY));
// clip blits to mapscreen region
ClipBlitsToMapViewRegion( );
BltVideoObject( FRAME_BUFFER, hHandle, HELI_ICON, x, y, VO_BLT_SRCTRANSPARENCY, NULL );
InvalidateRegion( x, y, x + usIconWidth, y + usIconHeight );
RestoreClipRegionToFullScreen( );
// now store the old stuff
sOldMapX = (INT16)x;
sOldMapY = (INT16)y;
}
}
void DisplayDestinationOfHelicopter( void )
{
+2 -1
View File
@@ -169,8 +169,9 @@ INT16 GetLastSectorOfMilitiaPath( void );
// display info about helicopter path
void DisplayDistancesForHelicopter( void );
// display where hei is
// display where heli is
void DisplayPositionOfHelicopter( void );
void DisplayPositionOfEnemyHelicopter();
// check for click
BOOLEAN CheckForClickOverHelicopterIcon( INT16 sX, INT16 sY );
+150 -28
View File
@@ -29,6 +29,8 @@
#include "GameSettings.h"
#include "debug.h"
#include "Overhead.h" // added by Flugente
#include "Game Clock.h" // added by Flugente
#include "Game Event Hook.h" // added by Flugente
#endif
#include "Strategic Mines.h"
@@ -49,8 +51,10 @@ INT8 bCurrentTownMineSectorY = 0;
INT8 bCurrentTownMineSectorZ = 0;
// inventory button
UINT32 guiMapButtonInventoryImage[2];
UINT32 guiMapButtonInventory[2];
UINT32 guiMapButtonInventoryImage[3];
UINT32 guiMapButtonInventory[3];
BOOLEAN guiSAMButtonDefined = FALSE;
UINT16 sTotalButtonWidth = 0;
@@ -91,12 +95,13 @@ void AddInventoryButtonForMapPopUpBox( void );
// now remove the above button
void RemoveInventoryButtonForMapPopUpBox( void );
// callback to turn on sector invneotry list
// callback to turn on sector inventory list
void MapTownMineInventoryButtonCallBack( GUI_BUTTON *btn, INT32 reason );
void MapTownMineExitButtonCallBack( GUI_BUTTON *btn, INT32 reason );
void MapTownSAMRepairButtonCallBack( GUI_BUTTON *btn, INT32 reason );
void MinWidthOfTownMineInfoBox( void );
extern INT32 GetCurrentBalance( void );
void DisplayTownInfo( INT16 sMapX, INT16 sMapY, INT8 bMapZ )
{
@@ -207,9 +212,19 @@ void CreateDestroyTownInfoBox( void )
// resize box to fit button
pDimensions.iRight += BOX_BUTTON_WIDTH;
}
pDimensions.iBottom += BOX_BUTTON_HEIGHT;
for ( UINT16 x = 0; x < MAX_NUMBER_OF_SAMS; ++x )
{
if ( pSamList[x] == SECTOR( bCurrentTownMineSectorX, bCurrentTownMineSectorY ) )
{
pDimensions.iBottom += BOX_BUTTON_HEIGHT;
break;
}
}
SetBoxSize( ghTownMineBox, pDimensions );
ShowBox( ghTownMineBox );
@@ -1004,13 +1019,9 @@ void PositionTownMineInfoBox( void )
{
pPosition.iY = MapScreenRect.iBottom - pDimensions.iBottom - 8;
}
// reset position
SetBoxPosition( ghTownMineBox, pPosition );
return;
}
@@ -1024,8 +1035,7 @@ void AddInventoryButtonForMapPopUpBox( void )
ETRLEObject *pTrav;
INT16 sWidthA = 0, sWidthB = 0, sTotalBoxWidth = 0;
HVOBJECT hHandle;
// load the button
VObjectDesc.fCreateFlags = VOBJECT_CREATE_FROMFILE;
FilenameForBPP("INTERFACE\\mapinvbtns.sti", VObjectDesc.ImageFile);
@@ -1070,23 +1080,39 @@ void AddInventoryButtonForMapPopUpBox( void )
(INT16)(sX ), (INT16)( sY ), BUTTON_TOGGLE , MSYS_PRIORITY_HIGHEST - 1,
DEFAULT_MOVE_CALLBACK, (GUI_CALLBACK)MapTownMineExitButtonCallBack );
// Flugente: if this is SAM site we control, we have the option to repair it if it is damagged
guiSAMButtonDefined = FALSE;
for ( UINT16 x = 0; x < MAX_NUMBER_OF_SAMS; ++x )
{
if ( pSamList[x] == SECTOR( bCurrentTownMineSectorX, bCurrentTownMineSectorY ) )
{
StrategicMapElement *pSAMStrategicMap = &(StrategicMap[SECTOR_INFO_TO_STRATEGIC_INDEX(pSamList[x])]);
sX = pPosition.iX + (pDimensions.iRight - sTotalBoxWidth) / 3;
sY = pPosition.iY + pDimensions.iBottom - ((BOX_BUTTON_HEIGHT + 5)) - BOX_BUTTON_HEIGHT;
guiMapButtonInventoryImage[2] = LoadButtonImage( "INTERFACE\\mapinvbtns.sti", -1, 1, -1, 3, -1 );
guiMapButtonInventory[2] = CreateIconAndTextButton( guiMapButtonInventoryImage[2], pMapPopUpInventoryText[2], BLOCKFONT2,
FONT_WHITE, FONT_BLACK,
FONT_WHITE, FONT_BLACK,
TEXT_CJUSTIFIED,
(INT16)(sX), (INT16)(sY), BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST - 1,
DEFAULT_MOVE_CALLBACK, (GUI_CALLBACK)MapTownSAMRepairButtonCallBack );
guiSAMButtonDefined = TRUE;
break;
}
}
// delete video object
DeleteVideoObjectFromIndex( uiObject );
/*
// if below ground disable
if( iCurrentMapSectorZ )
{
DisableButton( guiMapButtonInventory[ 0 ] );
}
*/
return;
}
void RemoveInventoryButtonForMapPopUpBox( void )
{
// get rid of button
RemoveButton( guiMapButtonInventory[0] );
UnloadButtonImage( guiMapButtonInventoryImage[0] );
@@ -1094,7 +1120,11 @@ void RemoveInventoryButtonForMapPopUpBox( void )
RemoveButton( guiMapButtonInventory[1] );
UnloadButtonImage( guiMapButtonInventoryImage[1] );
return;
if ( guiSAMButtonDefined )
{
RemoveButton( guiMapButtonInventory[2] );
UnloadButtonImage( guiMapButtonInventoryImage[2] );
}
}
@@ -1102,13 +1132,13 @@ void MapTownMineInventoryButtonCallBack( GUI_BUTTON *btn, INT32 reason )
{
if(reason & MSYS_CALLBACK_REASON_LBUTTON_DWN )
{
btn->uiFlags|=(BUTTON_CLICKED_ON);
btn->uiFlags|=(BUTTON_CLICKED_ON);
}
else if(reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
{
if (btn->uiFlags & BUTTON_CLICKED_ON)
if (btn->uiFlags & BUTTON_CLICKED_ON)
{
btn->uiFlags&=~(BUTTON_CLICKED_ON);
btn->uiFlags&=~(BUTTON_CLICKED_ON);
// done
fShowMapInventoryPool = TRUE;
@@ -1126,7 +1156,6 @@ void MapTownMineInventoryButtonCallBack( GUI_BUTTON *btn, INT32 reason )
}
}
void MapTownMineExitButtonCallBack( GUI_BUTTON *btn, INT32 reason )
{
if(reason & MSYS_CALLBACK_REASON_LBUTTON_DWN )
@@ -1148,6 +1177,99 @@ void MapTownMineExitButtonCallBack( GUI_BUTTON *btn, INT32 reason )
}
}
void SAMRepairCallBack( UINT8 bExitValue )
{
if ( bExitValue == MSG_BOX_RETURN_YES )
{
for ( UINT16 x = 0; x < MAX_NUMBER_OF_SAMS; ++x )
{
if ( pSamList[x] == SECTOR( bCurrentTownMineSectorX, bCurrentTownMineSectorY ) )
{
StrategicMapElement *pSAMStrategicMap = &(StrategicMap[SECTOR_INFO_TO_STRATEGIC_INDEX( pSamList[x] )]);
if ( !pSAMStrategicMap->fEnemyControlled && pSAMStrategicMap->bSAMCondition < 100 )
{
UINT32 cost = (100 - pSAMStrategicMap->bSAMCondition) * 100;
AddTransactionToPlayersBook( SAM_REPAIR, 0, GetWorldTotalMin( ), -cost );
// remember this, so we don't accidentally pay for repair again
pSAMStrategicMap->usFlags |= SAMSITE_REPAIR_ORDERED;
UINT32 time = (100 - pSAMStrategicMap->bSAMCondition) / 4 + 1;
AddStrategicEvent( EVENT_SAMSITE_REPAIRED, GetWorldTotalMin( ) + 60 * time, pSamList[x] );
}
break;
}
}
}
}
void MapTownSAMRepairButtonCallBack( GUI_BUTTON *btn, INT32 reason )
{
if ( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN )
{
btn->uiFlags |= (BUTTON_CLICKED_ON);
}
else if ( reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
{
if ( btn->uiFlags & BUTTON_CLICKED_ON )
{
btn->uiFlags &= ~(BUTTON_CLICKED_ON);
// done
fMapPanelDirty = TRUE;
fMapScreenBottomDirty = TRUE;
fShowTownInfo = FALSE;
for ( UINT16 x = 0; x < MAX_NUMBER_OF_SAMS; ++x )
{
if ( pSamList[x] == SECTOR( bCurrentTownMineSectorX, bCurrentTownMineSectorY ) )
{
StrategicMapElement *pSAMStrategicMap = &(StrategicMap[SECTOR_INFO_TO_STRATEGIC_INDEX( pSamList[x] )]);
if ( pSAMStrategicMap->fEnemyControlled )
{
DoMapMessageBox( MSG_BOX_BASIC_STYLE, szEnemyHeliText[1], MAP_SCREEN, MSG_BOX_FLAG_OK, NULL );
break;
}
if ( pSAMStrategicMap->bSAMCondition >= 100 )
{
DoMapMessageBox( MSG_BOX_BASIC_STYLE, szEnemyHeliText[2], MAP_SCREEN, MSG_BOX_FLAG_OK, NULL );
break;
}
if ( pSAMStrategicMap->usFlags & SAMSITE_REPAIR_ORDERED )
{
DoMapMessageBox( MSG_BOX_BASIC_STYLE, szEnemyHeliText[3], MAP_SCREEN, MSG_BOX_FLAG_OK, NULL );
break;
}
UINT32 cost = (100 - pSAMStrategicMap->bSAMCondition) * 100;
if ( cost > GetCurrentBalance( ) )
{
DoMapMessageBox( MSG_BOX_BASIC_STYLE, szEnemyHeliText[4], MAP_SCREEN, MSG_BOX_FLAG_OK, NULL );
break;
}
UINT32 time = (100 - pSAMStrategicMap->bSAMCondition) / 4 + 1;
CHAR16 sSamSiteRepairPromptText[320];
swprintf( sSamSiteRepairPromptText, szEnemyHeliText[5], cost, time );
// ask the player whether he really wants to do this
DoMapMessageBox( MSG_BOX_BASIC_STYLE, sSamSiteRepairPromptText, MAP_SCREEN, MSG_BOX_FLAG_YESNO, SAMRepairCallBack );
break;
}
}
}
}
}
// get the min width of the town mine info pop up box
void MinWidthOfTownMineInfoBox( void )
+7
View File
@@ -542,6 +542,13 @@ BOOLEAN SetThisSectorAsEnemyControlled( INT16 sMapX, INT16 sMapY, INT8 bMapZ, BO
return fWasPlayerControlled;
}
BOOLEAN IsSectorEnemyControlled( INT16 sMapX, INT16 sMapY, INT8 bMapZ )
{
if ( !bMapZ )
return StrategicMap[SECTOR( sMapX, sMapY )].fEnemyControlled;
return !SectorInfo[SECTOR( sMapX, sMapY )].fPlayer[bMapZ];
}
#ifdef JA2TESTVERSION
void ClearMapControlledFlags( void )
+1
View File
@@ -14,6 +14,7 @@ BOOLEAN SetThisSectorAsEnemyControlled( INT16 sMapX, INT16 sMapY, INT8 bMapZ, BO
// set sector as player controlled
BOOLEAN SetThisSectorAsPlayerControlled( INT16 sMapX, INT16 sMapY, INT8 bMapZ, BOOLEAN fContested );
BOOLEAN IsSectorEnemyControlled( INT16 sMapX, INT16 sMapY, INT8 bMapZ );
#ifdef JA2TESTVERSION
void ClearMapControlledFlags( void );
+14 -2
View File
@@ -181,6 +181,8 @@ UINT8 gubEnemyEncounterCode = NO_ENCOUNTER_CODE;
//would turn hostile, which would disable the ability to autoresolve the battle.
BOOLEAN gubExplicitEnemyEncounterCode = NO_ENCOUNTER_CODE;
BOOLEAN gubSpecialEncounterCodeForEnemyHeli = FALSE;
//Location of the current battle (determines where the animated icon is blitted) and if the
//icon is to be blitted.
BOOLEAN gfBlitBattleSectorLocator = FALSE;
@@ -607,8 +609,15 @@ void InitPreBattleInterface( GROUP *pBattleGroup, BOOLEAN fPersistantPBI )
{
if( !pBattleGroup )
{
//creature's attacking!
gubEnemyEncounterCode = CREATURE_ATTACK_CODE;
if ( gubSpecialEncounterCodeForEnemyHeli )
{
gubEnemyEncounterCode = ENEMY_INVASION_CODE;
}
else
{
//creature's attacking!
gubEnemyEncounterCode = CREATURE_ATTACK_CODE;
}
}
else if ( gpBattleGroup->usGroupTeam == OUR_TEAM )
{
@@ -929,6 +938,9 @@ void InitPreBattleInterface( GROUP *pBattleGroup, BOOLEAN fPersistantPBI )
DisableButton( iPBButton[0] );
#endif
DoTransitionFromMapscreenToPreBattleInterface();
// clean up
gubSpecialEncounterCodeForEnemyHeli = FALSE;
}
void DoTransitionFromMapscreenToPreBattleInterface()
+2
View File
@@ -81,6 +81,8 @@ extern UINT8 gubPBSectorY;
extern UINT8 gubPBSectorZ;
extern BOOLEAN gfCantRetreatInPBI;
extern BOOLEAN gubSpecialEncounterCodeForEnemyHeli;
//SAVE END
void WakeUpAllMercsInSectorUnderAttack( void );
+8 -1
View File
@@ -44,6 +44,7 @@
#include "Soldier macros.h"
#include "Morale.h"
#include "CampaignStats.h" // added by Flugente
#include "ASD.h" // added by Flugente
#endif
#ifdef JA2BETAVERSION
@@ -1559,11 +1560,17 @@ void AddPossiblePendingEnemiesToBattle()
return;
}
}
if ( (!PlayerMercsInSector( (UINT8)gWorldSectorX, (UINT8)gWorldSectorY, 0 ) && !NumNonPlayerTeamMembersInSector( gWorldSectorX, gWorldSectorY, MILITIA_TEAM ))
|| !NumNonPlayerTeamMembersInSector( gWorldSectorX, gWorldSectorY, ENEMY_TEAM ) )
return;
// Flugente: if there is an enemy helicopter here, it can add reinforcements
if ( gTacticalStatus.Team[ENEMY_TEAM].bAwareOfOpposition )
{
EnemyHeliTroopDrop( SECTOR( gWorldSectorX, gWorldSectorY ) );
}
ubSlots = NumFreeSlots( ENEMY_TEAM );
if(gGameExternalOptions.sMinDelayEnemyReinforcements)//dnl ch68 080913
{
+34 -37
View File
@@ -35,6 +35,7 @@
#include "Scheduling.h"
#include "Map Information.h"
#include "interface dialogue.h"
#include "ASD.h" // added by Flugente
#endif
#include "GameInitOptionsScreen.h"
@@ -1489,33 +1490,30 @@ void InitStrategicAI()
//Some of the patrol groups aren't there at the beginning of the game. This is
//based on the difficulty settings in the above patrol table.
//if( gPatrolGroup[ i ].ubUNUSEDStartIfDifficulty <= gGameOptions.ubDifficultyLevel )
{ //Add this patrol group now.
{
//Add this patrol group now.
ubNumTroops = (UINT8)(gPatrolGroup[ i ].bSize + Random( 3 ) - 1);
ubNumTroops = (UINT8)max( gubMinEnemyGroupSize, min( iMaxEnemyGroupSize, ubNumTroops ) );
ubNumTanks = 0;
if( ubNumTroops && gGameExternalOptions.fArmyUsesTanksInPatrols && HighestPlayerProgressPercentage() >= gGameExternalOptions.usTankMinimumProgress )
{
if ( ubNumTroops && gGameExternalOptions.fArmyUsesTanksInPatrols && HighestPlayerProgressPercentage() >= gGameExternalOptions.usTankMinimumProgress )
{
UINT32 val2;
if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_EASY )
val2 = 1;
else if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_MEDIUM )
val2 = 2;
else if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_HARD )
val2 = 3;
else if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_INSANE )
val2 = 4;
else
{
val2 = Random( 4 );
if (val2 == 0) val2 = 1;
}
UINT32 val2;
if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_EASY )
val2 = 1;
else if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_MEDIUM )
val2 = 2;
else if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_HARD )
val2 = 3;
else if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_INSANE )
val2 = 4;
else
{
val2 = Random( 4 );
if (val2 == 0) val2 = 1;
}
if( Random( 10 ) < val2 && i != 3 && i != 4)
//if( Random( 10 ) < gGameOptions.ubDifficultyLevel && i != 3 && i != 4)
if ( Random( 10 ) < val2 && i != 3 && i != 4 )
{
ubNumTroops--;
ubNumTanks++;
@@ -2229,14 +2227,17 @@ DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"Strategic5");
pSector->ubNumElites = (UINT8)(pSector->ubNumElites + pGroup->pEnemyGroup->ubNumElites);
pSector->ubNumTanks = (UINT8)(pSector->ubNumTanks + pGroup->pEnemyGroup->ubNumTanks);
#ifdef JA2BETAVERSION
LogStrategicEvent( "%d reinforcements have arrived to garrison sector %c%d",
pGroup->pEnemyGroup->ubNumAdmins + pGroup->pEnemyGroup->ubNumTroops +
pGroup->pEnemyGroup->ubNumElites + pGroup->pEnemyGroup->ubNumTanks, pGroup->ubSectorY + 'A' - 1, pGroup->ubSectorX );
#endif
#ifdef JA2BETAVERSION
LogStrategicEvent( "%d reinforcements have arrived to garrison sector %c%d",
pGroup->pEnemyGroup->ubNumAdmins + pGroup->pEnemyGroup->ubNumTroops +
pGroup->pEnemyGroup->ubNumElites + pGroup->pEnemyGroup->ubNumTanks, pGroup->ubSectorY + 'A' - 1, pGroup->ubSectorX );
#endif
if( IsThisSectorASAMSector( pGroup->ubSectorX, pGroup->ubSectorY, 0 ) )
{
StrategicMap[ pGroup->ubSectorX + pGroup->ubSectorY * MAP_WORLD_X ].bSAMCondition = 100;
StrategicMap[ pGroup->ubSectorX + pGroup->ubSectorY * MAP_WORLD_X ].usFlags &= ~SAMSITE_REPAIR_ORDERED;
UpdateSAMDoneRepair( pGroup->ubSectorX, pGroup->ubSectorY, 0 );
}
}
@@ -4551,8 +4552,7 @@ void ExecuteStrategicAIAction( UINT16 usActionCode, INT16 sSectorX, INT16 sSecto
grouptanks[ubCounter] = 0;
if( ubNumSoldiers && gGameExternalOptions.fArmyUsesTanksInAttacks && HighestPlayerProgressPercentage() >= gGameExternalOptions.usTankMinimumProgress )
{
if( Random(10) < val )
//if( Random(10) < gGameOptions.ubDifficultyLevel )
if ( Random( 10 ) < val && ASDSoldierUpgradeToTank( ) )
{
grouptroops[ubCounter]--;
grouptanks[ubCounter]++;
@@ -4636,7 +4636,7 @@ void ExecuteStrategicAIAction( UINT16 usActionCode, INT16 sSectorX, INT16 sSecto
grouptanks[ubCounter] = 0;
if( ubNumSoldiers && gGameExternalOptions.fArmyUsesTanksInAttacks && HighestPlayerProgressPercentage() >= gGameExternalOptions.usTankMinimumProgress )
{
if( Random(10) < value )
if ( Random( 10 ) < value && ASDSoldierUpgradeToTank( ) )
{
grouptroops[ubCounter]--;
grouptanks[ubCounter]++;
@@ -4848,7 +4848,7 @@ void ExecuteStrategicAIAction( UINT16 usActionCode, INT16 sSectorX, INT16 sSecto
ubNumSoldiers = (UINT8)( gubMinEnemyGroupSize + value2 * 3);
//ubNumSoldiers = (UINT8)( gubMinEnemyGroupSize + gGameOptions.ubDifficultyLevel * 3);
// anv: replace one of soldiers with tank
if( ubNumSoldiers && gGameExternalOptions.fArmyUsesTanksInAttacks && HighestPlayerProgressPercentage() >= gGameExternalOptions.usTankMinimumProgress )
if ( ubNumSoldiers && gGameExternalOptions.fArmyUsesTanksInAttacks && HighestPlayerProgressPercentage( ) >= gGameExternalOptions.usTankMinimumProgress && ASDSoldierUpgradeToTank( ) )
{
ubNumSoldiers--;
ubNumTanks++;
@@ -5114,8 +5114,7 @@ void ExecuteStrategicAIAction( UINT16 usActionCode, INT16 sSectorX, INT16 sSecto
// anv: replace one of soldiers with tank
if( ubNumSoldiers && gGameExternalOptions.fArmyUsesTanksInAttacks && HighestPlayerProgressPercentage() >= gGameExternalOptions.usTankMinimumProgress )
{
if( Random( 10 ) < value4 )
//if( Random( 10 ) < gGameOptions.ubDifficultyLevel )
if ( Random( 10 ) < value4 && ASDSoldierUpgradeToTank( ) )
{
ubNumSoldiers--;
ubNumTanks++;
@@ -5242,8 +5241,7 @@ void ExecuteStrategicAIAction( UINT16 usActionCode, INT16 sSectorX, INT16 sSecto
if( ubNumSoldiers && gGameExternalOptions.fArmyUsesTanksInAttacks && HighestPlayerProgressPercentage() >= gGameExternalOptions.usTankMinimumProgress )
{
if( Random( 10 * 100 ) < value5 * direness )
//if( Random( 10 * 100 ) < gGameOptions.ubDifficultyLevel * direness )
if ( Random( 10 * 100 ) < value5 * direness && ASDSoldierUpgradeToTank( ) )
{
elitesThisSquad--;
tanksThisSquad++;
@@ -5398,8 +5396,7 @@ void ExecuteStrategicAIAction( UINT16 usActionCode, INT16 sSectorX, INT16 sSecto
// anv: replace one of soldiers with tank
if( ubNumSoldiers && gGameExternalOptions.fArmyUsesTanksInAttacks && HighestPlayerProgressPercentage() >= gGameExternalOptions.usTankMinimumProgress )
{
if( Random( 10 * 100 ) < value7 * HighestPlayerProgressPercentage() )
//if( Random( 10 * 100 ) < gGameOptions.ubDifficultyLevel * HighestPlayerProgressPercentage() )
if ( Random( 10 * 100 ) < value7 * HighestPlayerProgressPercentage( ) && ASDSoldierUpgradeToTank( ) )
{
ubNumSoldiers--;
ubNumTanks++;
+33 -19
View File
@@ -22,6 +22,7 @@
#include "Campaign Types.h"
#include "history.h"
#include "Facilities.h"
#include "ASD.h" // added by Flugente
#endif
#include "GameInitOptionsScreen.h"
@@ -549,17 +550,14 @@ INT32 GetAvailableWorkForceForMineForEnemy( INT8 bMineIndex )
// if mine is shut down
if ( gMineStatus[ bMineIndex ].fShutDown)
{
return ( 0 );
}
//bTownId = gMineLocation[ bMineIndex ].bAssociatedTown;
bTownId = gMineStatus[ bMineIndex ].bAssociatedTown;
if( GetTownSectorSize( bTownId ) == 0 )
{
UINT8 townsize = GetTownSectorSize( bTownId );
if ( !townsize )
return 0;
}
// get workforce size (is 0-100 based on REVERSE of local town's loyalty)
iWorkForceSize = 100 - gTownLoyalty[ bTownId ].ubRating;
@@ -571,10 +569,10 @@ INT32 GetAvailableWorkForceForMineForEnemy( INT8 bMineIndex )
*/
// now adjust for town size.. the number of sectors you control
iWorkForceSize *= ( GetTownSectorSize( bTownId ) - GetTownSectorsUnderControl( bTownId ) );
iWorkForceSize /= GetTownSectorSize( bTownId );
iWorkForceSize *= (townsize - GetTownSectorsUnderControl( bTownId ));
iWorkForceSize /= townsize;
return ( iWorkForceSize );
return iWorkForceSize;
}
INT32 GetCurrentWorkRateOfMineForPlayer( INT8 bMineIndex )
@@ -604,8 +602,7 @@ INT32 MineAMine( INT8 bMineIndex )
// will extract ore based on available workforce, and increment players income based on amount
INT8 bMineType = 0;
INT32 iAmtExtracted = 0;
Assert( ( bMineIndex >= 0 ) && ( bMineIndex < MAX_NUMBER_OF_MINES ) );
// is mine is empty
@@ -620,7 +617,6 @@ INT32 MineAMine( INT8 bMineIndex )
return 0;
}
// who controls the PRODUCTION in the mine ? (Queen receives production unless player has spoken to the head miner)
if( PlayerControlsMine(bMineIndex) )
{
@@ -651,13 +647,16 @@ INT32 MineAMine( INT8 bMineIndex )
// we didn't want mines to run out without player ever even going to them, so now the queen doesn't reduce the
// amount remaining until the mine has produced for the player first (so she'd have to capture it).
// WANNE: We do not want to give money to the player, when the queen has captured the mine!
/*// WANNE: We do not want to give money to the player, when the queen has captured the mine!
if ( gMineStatus[ bMineIndex ].fMineHasProducedForPlayer )
{
// don't actually give her money, just take production away
//iAmtExtracted = ExtractOreFromMine( bMineIndex , GetCurrentWorkRateOfMineForEnemy( bMineIndex ) );
iAmtExtracted = 0;
}
}*/
// Flugente: if the enemy controls a mine, simply don't lower the amount of ore in the mine, so it can still run out when the player controls it
iAmtExtracted = GetCurrentWorkRateOfMineForEnemy( bMineIndex );
}
@@ -679,27 +678,42 @@ void PostEventsForMineProduction(void)
void HandleIncomeFromMines( void )
{
INT32 iIncome = 0;
INT8 bCounter = 0;
INT32 iIncome_Enemy = 0; // Flugente: new AI gets money from mines
// HEADROCK HAM 3.6: Modifier from Facilities
INT32 iFacilityModifier = 0;
// mine each mine, check if we own it and such
for( bCounter = 0; bCounter < MAX_NUMBER_OF_MINES; bCounter++ )
for ( INT8 bCounter = 0; bCounter < MAX_NUMBER_OF_MINES; ++bCounter )
{
if (bCounter)
if ( PlayerControlsMine( bCounter ) )
{
// HEADROCK HAM 3.6: Add facility modifier as a percentage
iFacilityModifier = 100 + MineIncomeModifierFromFacility( bCounter );
// mine this mine
iIncome += (MineAMine( bCounter ) * iFacilityModifier) / 100;
}
else
{
// mine this mine
iIncome_Enemy += MineAMine( bCounter );
}
// mine this mine
iIncome += (MineAMine( bCounter ) * iFacilityModifier) / 100;
}
// HEADROCK HAM B1: Affected by external INI Option.
iIncome = (iIncome * gGameExternalOptions.usMineIncomePercentage) / 100;
iIncome_Enemy = (iIncome_Enemy * gGameExternalOptions.usMineIncomePercentage) / 100;
if( iIncome )
{
AddTransactionToPlayersBook( DEPOSIT_FROM_SILVER_MINE, 0, GetWorldTotalMin( ), iIncome );
}
if ( iIncome_Enemy )
{
AddStrategicAIResources( ASD_MONEY, iIncome_Enemy );
}
}
+193
View File
@@ -50,6 +50,7 @@
#include "Interface.h" // added by Flugente for zBackground
#include "Reinforcement.h" // added by Flugente for AddPossiblePendingMilitiaToBattle()
#include "Militia Control.h" // added by Flugente for ResetMilitia()
#include "Creature Spreading.h" // added by Flugente
#endif
#include "MilitiaSquads.h"
@@ -5940,3 +5941,195 @@ GROUP* CreateNewEnemyGroupDepartingFromSectorUsingZLevel( UINT32 uiSector, UINT8
#endif
void CheckCombatInSectorDueToUnusualEnemyArrival( UINT8 aTeam, INT16 sX, INT16 sY, INT8 sZ )
{
GROUP *curr;
GROUP *pPlayerDialogGroup = NULL;
PLAYERGROUP *pPlayer;
SOLDIERTYPE *pSoldier;
BOOLEAN fBattlePending = FALSE;
BOOLEAN fAliveMerc = FALSE;
BOOLEAN fMilitiaPresent = FALSE;
BOOLEAN fCombatAbleMerc = FALSE;
BOOLEAN fBloodCatAmbush = FALSE;
gubEnemyEncounterCode = ENEMY_INVASION_CODE;
gubSectorIDOfCreatureAttack = SECTOR(sX, sY);
gubSpecialEncounterCodeForEnemyHeli = TRUE;
HandleOtherGroupsArrivingSimultaneously( sX, sY, sZ );
curr = gpGroupList;
while ( curr )
{
if ( curr->usGroupTeam == OUR_TEAM && curr->ubGroupSize )
{
if ( !curr->fBetweenSectors )
{
if ( curr->ubSectorX == sX && curr->ubSectorY == sY && !sZ )
{
if ( !GroupHasInTransitDeadOrPOWMercs( curr ) &&
(!IsGroupTheHelicopterGroup( curr ) || !fHelicopterIsAirBorne) &&
(!curr->fVehicle || NumberMercsInVehicleGroup( curr )) )
{
//Now, a player group is in this sector. Determine if the group contains any mercs that can fight.
//Vehicles, EPCs and the robot doesn't count. Mercs below OKLIFE do.
pPlayer = curr->pPlayerList;
while ( pPlayer )
{
pSoldier = pPlayer->pSoldier;
if ( !(pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE) )
{
if ( !AM_A_ROBOT( pSoldier ) &&
!AM_AN_EPC( pSoldier ) &&
pSoldier->stats.bLife >= OKLIFE )
{
fCombatAbleMerc = TRUE;
}
if ( pSoldier->stats.bLife > 0 )
{
fAliveMerc = TRUE;
}
}
pPlayer = pPlayer->next;
}
if ( !pPlayerDialogGroup && fCombatAbleMerc )
{
pPlayerDialogGroup = curr;
}
if ( fCombatAbleMerc )
{
break;
}
}
}
}
}
curr = curr->next;
}
if ( aTeam == ENEMY_TEAM )
{
if ( NumNonPlayerTeamMembersInSector( sX, sY, MILITIA_TEAM ) )
{
fMilitiaPresent = TRUE;
fBattlePending = TRUE;
}
if ( fAliveMerc )
{
fBattlePending = TRUE;
}
// huh?
if ( !NumNonPlayerTeamMembersInSector( sX, sY, ENEMY_TEAM ) )
{
fBattlePending = FALSE;
}
}
else if ( aTeam == MILITIA_TEAM )
{
if ( NumNonPlayerTeamMembersInSector( sX, sY, ENEMY_TEAM ) )
{
fMilitiaPresent = TRUE;
fBattlePending = TRUE;
}
/*if ( fBattlePending )
{
if ( PossibleToCoordinateSimultaneousGroupArrivals( pGroup ) )
{
return FALSE;
}
}*/
}
if ( !fAliveMerc && !fMilitiaPresent )
{
// empty vehicle, everyone dead, don't care. Enemies don't care.
return;
}
if ( fBattlePending )
{
//A battle is pending, but the players could be all unconcious or dead.
//Go through every group until we find at least one concious merc. The looping will determine
//if there are any live mercs and/or concious ones. If there are no concious mercs, but alive ones,
//then we will go straight to autoresolve, where the enemy will likely annihilate them or capture them.
//If there are no alive mercs, then there is nothing anybody can do. The enemy will completely ignore
//this, and continue on.
StopTimeCompression( );
if ( gubNumGroupsArrivedSimultaneously )
{
//Because this is a battle case, clear all the group flags
curr = gpGroupList;
while ( curr && gubNumGroupsArrivedSimultaneously )
{
if ( curr->uiFlags & GROUPFLAG_GROUP_ARRIVED_SIMULTANEOUSLY )
{
curr->uiFlags &= ~GROUPFLAG_GROUP_ARRIVED_SIMULTANEOUSLY;
gubNumGroupsArrivedSimultaneously--;
}
curr = curr->next;
}
}
//gpInitPrebattleGroup = pGroup;
if ( gubEnemyEncounterCode == BLOODCAT_AMBUSH_CODE || gubEnemyEncounterCode == ENTERING_BLOODCAT_LAIR_CODE )
{
NotifyPlayerOfBloodcatBattle( sX, sY );
return;
}
if ( !fCombatAbleMerc )
{
//Prepare for instant autoresolve.
gfDelayAutoResolveStart = TRUE;
gfUsePersistantPBI = TRUE;
if ( fMilitiaPresent )
{
NotifyPlayerOfInvasionByEnemyForces( sX, sY, 0, TriggerPrebattleInterface );
// trigger autoresolve if not in city, or this is a militia group
if ( aTeam == MILITIA_TEAM || GetTownIdForSector( sX, sY ) == BLANK_SECTOR )
{
// CHAR16 str[ 256 ];
// UINT16 uiSectorC = L'A' + pGroup->ubSectorY - 1;
// swprintf( str, gpStrategicString[ STR_DIALOG_ENEMIES_ATTACK_MILITIA ], uiSectorC, pGroup->ubSectorX );
// DoScreenIndependantMessageBox( str, MSG_BOX_FLAG_OK, TriggerPrebattleInterface );
TriggerPrebattleInterface( 1 );
}
}
else
{
CHAR16 str[256];
CHAR16 pSectorStr[128];
GetSectorIDString( sX, sY, sZ, pSectorStr, TRUE );
swprintf( str, gpStrategicString[STR_DIALOG_ENEMIES_ATTACK_UNCONCIOUSMERCS], pSectorStr );
DoScreenIndependantMessageBox( str, MSG_BOX_FLAG_OK, TriggerPrebattleInterface );
}
}
#ifdef JA2BETAVERSION
if ( guiCurrentScreen == AIVIEWER_SCREEN )
gfExitViewer = TRUE;
#endif
if ( pPlayerDialogGroup )
{
if ( !sZ )
MilitiaHelpFromAdjacentSectors( sX, sY );
PrepareForPreBattleInterface( pPlayerDialogGroup, NULL );
}
}
}
+2
View File
@@ -316,4 +316,6 @@ BOOLEAN GroupHasInTransitDeadOrPOWMercs( GROUP *pGroup );
BOOLEAN ScoutIsPresentInSquad( INT16 ubSectorNumX, INT16 ubSectorNumY ); // added by SANDRO
void CheckCombatInSectorDueToUnusualEnemyArrival( UINT8 aTeam, INT16 sX, INT16 sY, INT8 sZ );
#endif
+8
View File
@@ -338,6 +338,10 @@
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath=".\ASD.h"
>
</File>
<File
RelativePath=".\Assignments.h"
>
@@ -544,6 +548,10 @@
RelativePath=".\AI Viewer.cpp"
>
</File>
<File
RelativePath=".\ASD.cpp"
>
</File>
<File
RelativePath=".\Assignments.cpp"
>
+8
View File
@@ -338,6 +338,10 @@
<Filter
Name="Header Files"
>
<File
RelativePath="ASD.h"
>
</File>
<File
RelativePath="Assignments.h"
>
@@ -542,6 +546,10 @@
RelativePath="AI Viewer.cpp"
>
</File>
<File
RelativePath="ASD.cpp"
>
</File>
<File
RelativePath="Assignments.cpp"
>
+2
View File
@@ -23,6 +23,7 @@
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ASD.h" />
<ClInclude Include="Assignments.h" />
<ClInclude Include="Auto Resolve.h" />
<ClInclude Include="Campaign Init.h" />
@@ -75,6 +76,7 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="AI Viewer.cpp" />
<ClCompile Include="ASD.cpp" />
<ClCompile Include="Assignments.cpp" />
<ClCompile Include="Auto Resolve.cpp" />
<ClCompile Include="Campaign Init.cpp" />
@@ -9,6 +9,9 @@
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ASD.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Assignments.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -161,6 +164,9 @@
<ClCompile Include="AI Viewer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ASD.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Assignments.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+2
View File
@@ -23,6 +23,7 @@
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ASD.h" />
<ClInclude Include="Assignments.h" />
<ClInclude Include="Auto Resolve.h" />
<ClInclude Include="Campaign Init.h" />
@@ -75,6 +76,7 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="AI Viewer.cpp" />
<ClCompile Include="ASD.cpp" />
<ClCompile Include="Assignments.cpp" />
<ClCompile Include="Auto Resolve.cpp" />
<ClCompile Include="Campaign Init.cpp" />
@@ -156,6 +156,9 @@
<ClInclude Include="MapScreen Quotes.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ASD.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="AI Viewer.cpp">
@@ -344,5 +347,8 @@
<ClCompile Include="XML_Creatures.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ASD.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>
+5 -9
View File
@@ -1325,6 +1325,7 @@ BOOLEAN CanSomeoneNearbyScoutThisSector( INT16 sSectorX, INT16 sSectorY, BOOLEAN
{
return( TRUE );
}
// SANDRO - STOMP traits - Scouting check
if (fScoutTraitCheck && gGameOptions.fNewTraitSystem && ScoutIsPresentInSquad( sCounterA, sCounterB ))
{
@@ -1339,13 +1340,13 @@ BOOLEAN CanSomeoneNearbyScoutThisSector( INT16 sSectorX, INT16 sSectorY, BOOLEAN
}
else
{
bScout = TRUE;
return TRUE;
}
}
}
}
return( bScout );
return FALSE;
}
BOOLEAN IsTownFullMilitia( INT8 bTownId, INT8 iMilitiaType )
@@ -2477,13 +2478,8 @@ FLOAT CalcHourlyVolunteerGain()
UINT8 sector = SECTOR( sX, sY );
SECTORINFO *pSectorInfo = &(SectorInfo[sector]);
if ( !pSectorInfo )
continue;
// TODO: modifier increase for every farm we control
if ( pSectorInfo->ubTraversability[THROUGH_STRATEGIC_MOVE] == FARMLAND || pSectorInfo->ubTraversability[THROUGH_STRATEGIC_MOVE] == FARMLAND_ROAD )
// modifier increase for every farm we control
if ( IsSectorFarm( sX, sY ) )
populationmodifier += gGameExternalOptions.dMilitiaVolunteerMultiplierFarm;
UINT8 ubTownID = StrategicMap[CALCULATE_STRATEGIC_INDEX( sX, sY )].bNameId;
+16
View File
@@ -5012,6 +5012,15 @@ UINT32 MapScreenHandle(void)
CHECKF(AddVideoObject(&VObjectDesc, &guiHelicopterIcon));
if ( iResolution >= _640x480 && iResolution < _800x600 )
FilenameForBPP( "INTERFACE\\Helicopter_Map_Icon_Enemy_640.sti", VObjectDesc.ImageFile );
else if ( iResolution < _1024x768 )
FilenameForBPP( "INTERFACE\\Helicopter_Map_Icon_Enemy_800.sti", VObjectDesc.ImageFile );
else
FilenameForBPP( "INTERFACE\\Helicopter_Map_Icon_Enemy_1024.sti", VObjectDesc.ImageFile );
CHECKF( AddVideoObject( &VObjectDesc, &guiEnemyHelicopterIcon ) );
VObjectDesc.fCreateFlags=VOBJECT_CREATE_FROMFILE;
FilenameForBPP("INTERFACE\\eta_pop_up.sti", VObjectDesc.ImageFile);
CHECKF(AddVideoObject(&VObjectDesc, &guiMapBorderEtaPopUp));
@@ -5638,6 +5647,11 @@ UINT32 MapScreenHandle(void)
DisplayPositionOfHelicopter( );
}
// Flugente: enemy helicopter
if ( fShowAircraftFlag && (iCurrentMapSectorZ == 0) && !fShowMapInventoryPool )
{
DisplayPositionOfEnemyHelicopter();
}
// display town info
DisplayTownInfo( sSelMapX, sSelMapY, ( INT8 ) iCurrentMapSectorZ );
@@ -8686,6 +8700,7 @@ INT32 iCounter2 = 0;
DeleteVideoObjectFromIndex( guiMapBorderHeliSectors );
DeleteVideoObjectFromIndex( guiMapBorderHeliSectorsAlternate );
DeleteVideoObjectFromIndex( guiHelicopterIcon );
DeleteVideoObjectFromIndex( guiEnemyHelicopterIcon );
DeleteVideoObjectFromIndex( guiMINEICON );
DeleteVideoObjectFromIndex( guiSectorLocatorGraphicID );
@@ -13552,6 +13567,7 @@ void HandleRemovalOfPreLoadedMapGraphics( void )
DeleteVideoObjectFromIndex( guiMapBorderHeliSectors );
DeleteVideoObjectFromIndex( guiMapBorderHeliSectorsAlternate );
DeleteVideoObjectFromIndex( guiHelicopterIcon );
DeleteVideoObjectFromIndex( guiEnemyHelicopterIcon );
DeleteVideoObjectFromIndex( guiMINEICON );
DeleteVideoObjectFromIndex( guiSectorLocatorGraphicID );
+2 -1
View File
@@ -52,7 +52,8 @@ enum
#define MILITIA_MOVE_SOUTH 0x00000008 //8
#define ENEMY_VIP_PRESENT 0x00000010 //16 // an enemy VIP is present in this sector
#define ENEMY_VIP_PRESENT_KNOWN 0x00000020 //16 // player thinks a VIP is here
#define ENEMY_VIP_PRESENT_KNOWN 0x00000020 //32 // player thinks a VIP is here
#define SAMSITE_REPAIR_ORDERED 0x00000040 //64 // a repair for this SAM site has already been ordered (so we do not need to do that again)
#define MILITIA_MOVE_ALLDIRS 0x0000000F // 15
// -------------------------------------------------------
+40 -5
View File
@@ -138,6 +138,7 @@
#include "sgp_logger.h"
#include "Map Screen Interface Map Inventory.h" // added by Flugente
#include "ASD.h" // added by Flugente
//forward declarations of common classes to eliminate includes
class OBJECTTYPE;
@@ -2153,6 +2154,8 @@ BOOLEAN SetCurrentWorldSector( INT16 sMapX, INT16 sMapY, INT8 bMapZ )
// Check for helicopter being on the ground in this sector...
HandleHelicopterOnGroundGraphic( );
HandleEnemyHelicopterOnGroundGraphic();
// 0verhaul: Okay, it is apparent that the enemies are not reset correctly. So I will now try to add symmetry
// between enemy placement and militia placement. The enemies do have one advantage here, though: If a sector
// is in enemy hands, then their sector is not actually loaded. At least not normally. Perhaps it would be useful
@@ -2304,6 +2307,8 @@ BOOLEAN SetCurrentWorldSector( INT16 sMapX, INT16 sMapY, INT8 bMapZ )
// Check for helicopter being on the ground in this sector...
HandleHelicopterOnGroundGraphic( );
HandleEnemyHelicopterOnGroundGraphic();
}
else
return( FALSE );
@@ -4994,7 +4999,7 @@ void SetupNewStrategicGame( )
AddEveryDayStrategicEvent( EVENT_DAILY_UPDATE_BOBBY_RAY_INVENTORY, BOBBYRAY_UPDATE_TIME, 0 );
//Daily Update of the M.E.R.C. site.
AddEveryDayStrategicEvent( EVENT_DAILY_UPDATE_OF_MERC_SITE, 0, 0 );
#ifdef JA2UB
//Ja25: No insurance for mercs
//JA25: There is no mines
@@ -5021,6 +5026,9 @@ void SetupNewStrategicGame( )
// Hourly update of all sorts of things
AddPeriodStrategicEvent( EVENT_HOURLY_UPDATE, 60, 0 );
AddPeriodStrategicEvent( EVENT_QUARTER_HOUR_UPDATE, 15, 0 );
// Flugente: ASD
AddPeriodStrategicEvent( EVENT_ASD_UPDATE, 90, 0 );
//Clear any possible battle locator
gfBlitBattleSectorLocator = FALSE;
@@ -6179,6 +6187,7 @@ BOOLEAN IsSectorDesert( INT16 sSectorX, INT16 sSectorY )
return( FALSE );
}
}
// SANDRO - added function
BOOLEAN IsSectorTropical( INT16 sSectorX, INT16 sSectorY )
{
@@ -6188,12 +6197,38 @@ BOOLEAN IsSectorTropical( INT16 sSectorX, INT16 sSectorY )
{
return ( TRUE );
}
else
{
return ( FALSE );
}
return ( FALSE );
}
BOOLEAN IsSectorFarm( INT16 sSectorX, INT16 sSectorY )
{
if ( SectorInfo[SECTOR( sSectorX, sSectorY )].ubTraversability[THROUGH_STRATEGIC_MOVE] == FARMLAND ||
SectorInfo[SECTOR( sSectorX, sSectorY )].ubTraversability[THROUGH_STRATEGIC_MOVE] == FARMLAND_ROAD )
{
return (TRUE);
}
return (FALSE);
}
BOOLEAN IsSectorRoad( INT16 sSectorX, INT16 sSectorY )
{
if ( SectorInfo[SECTOR( sSectorX, sSectorY )].ubTraversability[THROUGH_STRATEGIC_MOVE] == PLAINS_ROAD ||
SectorInfo[SECTOR( sSectorX, sSectorY )].ubTraversability[THROUGH_STRATEGIC_MOVE] == SPARSE_ROAD ||
SectorInfo[SECTOR( sSectorX, sSectorY )].ubTraversability[THROUGH_STRATEGIC_MOVE] == FARMLAND_ROAD ||
SectorInfo[SECTOR( sSectorX, sSectorY )].ubTraversability[THROUGH_STRATEGIC_MOVE] == TROPICS_ROAD ||
SectorInfo[SECTOR( sSectorX, sSectorY )].ubTraversability[THROUGH_STRATEGIC_MOVE] == DENSE_ROAD ||
SectorInfo[SECTOR( sSectorX, sSectorY )].ubTraversability[THROUGH_STRATEGIC_MOVE] == HILLS_ROAD ||
SectorInfo[SECTOR( sSectorX, sSectorY )].ubTraversability[THROUGH_STRATEGIC_MOVE] == COASTAL_ROAD ||
SectorInfo[SECTOR( sSectorX, sSectorY )].ubTraversability[THROUGH_STRATEGIC_MOVE] == SAND_ROAD ||
SectorInfo[SECTOR( sSectorX, sSectorY )].ubTraversability[THROUGH_STRATEGIC_MOVE] == SWAMP_ROAD )
{
return (TRUE);
}
return (FALSE);
}
BOOLEAN HandleDefiniteUnloadingOfWorld( UINT8 ubUnloadCode )
{
+2
View File
@@ -176,6 +176,8 @@ BOOLEAN IsThereAFunctionalSAMSiteInSector( INT16 sSectorX, INT16 sSectorY, INT8
BOOLEAN IsSectorDesert( INT16 sSectorX, INT16 sSectorY );
BOOLEAN IsSectorTropical( INT16 sSectorX, INT16 sSectorY ); // added by SANDRO
BOOLEAN IsSectorFarm( INT16 sSectorX, INT16 sSectorY ); // added by Flugente
BOOLEAN IsSectorRoad( INT16 sSectorX, INT16 sSectorY ); // added by Flugente
// sam site under players control?
INT32 SAMSitesUnderPlayerControl( INT16 sX, INT16 sY );