Files
source/Strategic/Town Militia.cpp
T
Wanne 47db604b50 *** Merged Code from Multiplayer Branch Revision 2960 ***
- Virtual File System (VFS) by birdflu. This is needed for Multiplayer and is also used for Single Player. Very neat system :-)
- Multiplayer Version 1.1 + some additional features and bugfixes
* INFO: If you compile a new EXE and want to test, be sure to also use the latest SVN GameDir files in your JA2 install directory *




git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@2961 3b4a5df2-a311-0410-b5c6-a8a6f20db521
2009-06-04 21:01:45 +00:00

1581 lines
44 KiB
C++

#include "builddefines.h"
#ifdef PRECOMPILEDHEADERS
#include "Strategic All.h"
#include "GameSettings.h"
#else
#include "Town Militia.h"
#include "Militia Control.h"
#include "Campaign Types.h"
#include "strategic.h"
#include "strategicmap.h"
#include "Overhead.h"
#include "Strategic Town Loyalty.h"
#include "Utilities.h"
#include "random.h"
#include "text.h"
#include "Map Screen Interface.h"
#include "Interface.h"
#include "Laptopsave.h"
#include "finances.h"
#include "Game Clock.h"
#include "Assignments.h"
#include "squads.h"
#include "Soldier Create.h"
#include "Dialogue Control.h"
#include "GameSettings.h"
#include "Queen Command.h"
#include "PreBattle Interface.h"
#include "Map Screen Interface Border.h"
#include "interface control.h"
#include "Map Screen Interface Map.h"
#endif
#include "MilitiaSquads.h"
#define SIZE_OF_MILITIA_COMPLETED_TRAINING_LIST 50
// temporary local global variables
UINT8 gubTownSectorServerTownId = BLANK_SECTOR;
INT16 gsTownSectorServerSkipX = -1;
INT16 gsTownSectorServerSkipY = -1;
UINT8 gubTownSectorServerIndex = 0;
BOOLEAN gfYesNoPromptIsForContinue = FALSE; // this flag remembers whether we're starting new training, or continuing
INT32 giTotalCostOfTraining = 0;
BOOLEAN gfAreWeTrainingMobile = FALSE;
BOOLEAN gfAreWePromotingGreen = FALSE;
BOOLEAN gfAreWePromotingRegular = FALSE;
//the completed list of sector soldiers for training militia
INT32 giListOfMercsInSectorsCompletedMilitiaTraining[ SIZE_OF_MILITIA_COMPLETED_TRAINING_LIST ];
SOLDIERTYPE *pMilitiaTrainerSoldier = NULL;
// note that these sector values are STRATEGIC INDEXES, not 0-255!
INT16 gsUnpaidStrategicSector[ CODE_MAXIMUM_NUMBER_OF_PLAYER_SLOTS ];
// the selected list of mercs
extern BOOLEAN fSelectedListOfMercsForMapScreen[ CODE_MAXIMUM_NUMBER_OF_PLAYER_SLOTS ];
// towns with militia training allowed
BOOLEAN gfMilitiaAllowedInTown[MAX_TOWNS] =
{
0, // blank sector
0, // omerta
1, // drassen
1, // alma
1, // grumm
0, // tixa
1, // cambria
0, // san mona
0, // estoni
0, // orta
1, // balime
1, // meduna
1, // chitzena
};
// private prototypes
void PayMilitiaTrainingYesNoBoxCallback( UINT8 bExitValue );
void CantTrainMilitiaOkBoxCallback( UINT8 bExitValue );
void MilitiaTrainingRejected( void );
void InitFriendlyTownSectorServer(UINT8 ubTownId, INT16 sSkipSectorX, INT16 sSkipSectorY);
BOOLEAN ServeNextFriendlySectorInTown( INT16 *sNeighbourX, INT16 *sNeighbourY );
void BuildListOfUnpaidTrainableSectors( void );
INT32 GetNumberOfUnpaidTrainableSectors( void );
void ContinueTrainingInThisSector( void );
void StartTrainingInAllUnpaidTrainableSectors();
void PayForTrainingInSector( UINT8 ubSector );
void ResetDoneFlagForAllMilitiaTrainersInSector( UINT8 ubSector );
#ifdef JA2BETAVERSION
void VerifyTownTrainingIsPaidFor( void );
#endif
void TownMilitiaTrainingCompleted( SOLDIERTYPE *pTrainer, INT16 sMapX, INT16 sMapY )
{
UINT8 ubMilitiaTrained = 0;
BOOLEAN fFoundOne;
INT16 sNeighbourX, sNeighbourY;
UINT8 ubTownId;
INT32 iMaxMilitiaPerSector = gGameExternalOptions.iMaxMilitiaPerSector;
INT32 iTrainingSquadSize = gGameExternalOptions.iTrainingSquadSize;
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"Militia1");
// get town index
ubTownId = StrategicMap[ sMapX + sMapY * MAP_WORLD_X ].bNameId;
if( ubTownId == BLANK_SECTOR )
{
Assert( IsThisSectorASAMSector( sMapX, sMapY, 0 ) );
}
// force tactical to update militia status
gfStrategicMilitiaChangesMade = FALSE;
// ok, so what do we do with all this training? Well, in order of decreasing priority:
// 1) If there's room in training sector, create new GREEN militia guys there
// 2) If not enough room there, create new GREEN militia guys in friendly sectors of the same town
// 3) If not enough room anywhere in town, promote a number of GREENs in this sector into regulars
// 4) If not enough GREENS there to promote, promote GREENs in other sectors.
// 5) If all friendly sectors of this town are completely filled with REGULAR militia, then training effect is wasted
// Kaiden: Roaming Militia Training:
// If we're not training roaming militia,
// then we will handle everything as normal.
if( (IsMilitiaTrainableFromSoldiersSectorMaxed( pTrainer, ELITE_MILITIA ))
&& (gGameExternalOptions.gfmusttrainroaming)
&&(GetWorldDay( ) >= gGameExternalOptions.guiAllowMilitiaGroupsDelay))
{
CreateMilitiaSquads(sMapX, sMapY );
}
else
{
while (ubMilitiaTrained < iTrainingSquadSize)
{
// is there room for another militia in the training sector itself?
if (CountAllMilitiaInSector(sMapX, sMapY) < iMaxMilitiaPerSector)
{
// great! Create a new GREEN militia guy in the training sector
StrategicAddMilitiaToSector(sMapX, sMapY, GREEN_MILITIA, 1);
if (sMapX == gWorldSectorX && sMapY == gWorldSectorY)
{
gfStrategicMilitiaChangesMade = TRUE;
}
}
else
{
fFoundOne = FALSE;
if( ubTownId != BLANK_SECTOR )
{
InitFriendlyTownSectorServer(ubTownId, sMapX, sMapY);
// check other eligible sectors in this town for room for another militia
while( ServeNextFriendlySectorInTown( &sNeighbourX, &sNeighbourY ) )
{
// is there room for another militia in this neighbouring sector ?
if (CountAllMilitiaInSector(sNeighbourX, sNeighbourY) < iMaxMilitiaPerSector)
{
// great! Create a new GREEN militia guy in the neighbouring sector
StrategicAddMilitiaToSector(sNeighbourX, sNeighbourY, GREEN_MILITIA, 1);
if (sNeighbourX == gWorldSectorX && sNeighbourY == gWorldSectorY)
{
gfStrategicMilitiaChangesMade = TRUE;
}
fFoundOne = TRUE;
break;
}
}
}
// if we still haven't been able to train anyone
if (!fFoundOne)
{
// alrighty, then. We'll have to *promote* guys instead.
// are there any GREEN militia men in the training sector itself?
if (MilitiaInSectorOfRank(sMapX, sMapY, GREEN_MILITIA) > 0)
{
// great! Promote a GREEN militia guy in the training sector to a REGULAR
StrategicPromoteMilitiaInSector(sMapX, sMapY, GREEN_MILITIA, 1);
fFoundOne = TRUE;
if (sMapX == gWorldSectorX && sMapY == gWorldSectorY)
{
gfStrategicMilitiaChangesMade = TRUE;
}
}
else
{
if( ubTownId != BLANK_SECTOR )
{
// dammit! Last chance - try to find other eligible sectors in the same town with a Green guy to be promoted
InitFriendlyTownSectorServer(ubTownId, sMapX, sMapY);
// check other eligible sectors in this town for room for another militia
while( ServeNextFriendlySectorInTown( &sNeighbourX, &sNeighbourY ) )
{
// are there any GREEN militia men in the neighbouring sector ?
if (MilitiaInSectorOfRank(sNeighbourX, sNeighbourY, GREEN_MILITIA) > 0)
{
// great! Promote a GREEN militia guy in the neighbouring sector to a REGULAR
StrategicPromoteMilitiaInSector(sNeighbourX, sNeighbourY, GREEN_MILITIA, 1);
if (sNeighbourX == gWorldSectorX && sNeighbourY == gWorldSectorY)
{
gfStrategicMilitiaChangesMade = TRUE;
}
fFoundOne = TRUE;
break;
}
}
}
// Kaiden: Veteran militia training
// This is essentially copy/pasted from above
// But the names have been changed to protect the innocent
if ((!fFoundOne) && (gGameExternalOptions.gfTrainVeteranMilitia)
&& (GetWorldDay( ) >= gGameExternalOptions.guiTrainVeteranMilitiaDelay))
{
// are there any REGULAR militia men in the training sector itself?
if (MilitiaInSectorOfRank(sMapX, sMapY, REGULAR_MILITIA) > 0)
{
// great! Promote a REGULAR militia guy in the training sector to a VETERAN
StrategicPromoteMilitiaInSector(sMapX, sMapY, REGULAR_MILITIA, 1);
if (sMapX == gWorldSectorX && sMapY == gWorldSectorY)
{
gfStrategicMilitiaChangesMade = TRUE;
}
fFoundOne = TRUE;
}
else
{
if( ubTownId != BLANK_SECTOR )
{
// dammit! Last chance - try to find other eligible sectors in the same town with a Regular guy to be promoted
InitFriendlyTownSectorServer(ubTownId, sMapX, sMapY);
// check other eligible sectors in this town for room for another militia
while( ServeNextFriendlySectorInTown( &sNeighbourX, &sNeighbourY ) )
{
// are there any REGULAR militia men in the neighbouring sector ?
if (MilitiaInSectorOfRank(sNeighbourX, sNeighbourY, REGULAR_MILITIA) > 0)
{
// great! Promote a Regular militia guy in the neighbouring sector to a Veteran
StrategicPromoteMilitiaInSector(sNeighbourX, sNeighbourY, REGULAR_MILITIA, 1);
if (sNeighbourX == gWorldSectorX && sNeighbourY == gWorldSectorY)
{
gfStrategicMilitiaChangesMade = TRUE;
}
fFoundOne = TRUE;
break;
}
}
}
}
}
// if we still haven't been able to train anyone
if (!fFoundOne)
{
// Well, that's it. All eligible sectors of this town are full of REGULARs or ELITEs.
// The training goes to waste in this situation.
break; // the main while loop
}
}
}
}
// next, please!
ubMilitiaTrained++;
}
if (gfStrategicMilitiaChangesMade)
{
ResetMilitia();
}
// if anyone actually got trained
if (ubMilitiaTrained > 0)
{
// update the screen display
fMapPanelDirty = TRUE;
if( ubTownId != BLANK_SECTOR )
{
// loyalty in this town increases a bit because we obviously care about them...
IncrementTownLoyalty( ubTownId, LOYALTY_BONUS_FOR_TOWN_TRAINING );
}
}
}
// the trainer announces to player that he's finished his assignment. Make his sector flash!
AssignmentDone( pTrainer, TRUE, FALSE );
// handle completion of town by training group
HandleCompletionOfTownTrainingByGroupWithTrainer( pTrainer );
}
// feed this a SOLDIER_CLASS_, it will return you a _MITILIA rank, or -1 if the guy's not militia
INT8 SoldierClassToMilitiaRank(UINT8 ubSoldierClass)
{
INT8 bRank = -1;
switch( ubSoldierClass )
{
case SOLDIER_CLASS_GREEN_MILITIA:
bRank = GREEN_MILITIA;
break;
case SOLDIER_CLASS_REG_MILITIA:
bRank = REGULAR_MILITIA;
break;
case SOLDIER_CLASS_ELITE_MILITIA:
bRank = ELITE_MILITIA;
break;
}
return(bRank);
}
// feed this a _MITILIA rank, it will return you a SOLDIER_CLASS_, or -1 if the guy's not militia
INT8 MilitiaRankToSoldierClass(UINT8 ubRank)
{
INT8 bSoldierClass = -1;
switch( ubRank )
{
case GREEN_MILITIA:
bSoldierClass = SOLDIER_CLASS_GREEN_MILITIA;
break;
case REGULAR_MILITIA:
bSoldierClass = SOLDIER_CLASS_REG_MILITIA;
break;
case ELITE_MILITIA:
bSoldierClass = SOLDIER_CLASS_ELITE_MILITIA;
break;
}
return(bSoldierClass);
}
void StrategicAddMilitiaToSector(INT16 sMapX, INT16 sMapY, UINT8 ubRank, UINT8 ubHowMany)
{
SECTORINFO *pSectorInfo = &( SectorInfo[ SECTOR( sMapX, sMapY ) ] );
pSectorInfo->ubNumberOfCivsAtLevel[ ubRank ] += ubHowMany;
if (ubHowMany && sMapX == gWorldSectorX && sMapY == gWorldSectorY )
{
gfStrategicMilitiaChangesMade = TRUE;
}
// update the screen display
fMapPanelDirty = TRUE;
}
void StrategicPromoteMilitiaInSector(INT16 sMapX, INT16 sMapY, UINT8 ubCurrentRank, UINT8 ubHowMany)
{
SECTORINFO *pSectorInfo = &( SectorInfo[ SECTOR( sMapX, sMapY ) ] );
// damn well better have that many around to promote!
//Assert(pSectorInfo->ubNumberOfCivsAtLevel[ ubCurrentRank ] >= ubHowMany);
//KM : July 21, 1999 patch fix
if( pSectorInfo->ubNumberOfCivsAtLevel[ ubCurrentRank ] < ubHowMany )
{
return;
}
pSectorInfo->ubNumberOfCivsAtLevel[ ubCurrentRank ] -= ubHowMany;
pSectorInfo->ubNumberOfCivsAtLevel[ ubCurrentRank + 1 ] += ubHowMany;
if (ubHowMany && sMapX == gWorldSectorX && sMapY == gWorldSectorY )
{
gfStrategicMilitiaChangesMade = TRUE;
}
// update the screen display
fMapPanelDirty = TRUE;
}
void StrategicRemoveMilitiaFromSector(INT16 sMapX, INT16 sMapY, UINT8 ubRank, UINT8 ubHowMany)
{
SECTORINFO *pSectorInfo = &( SectorInfo[ SECTOR( sMapX, sMapY ) ] );
// damn well better have that many around to remove!
Assert(pSectorInfo->ubNumberOfCivsAtLevel[ ubRank ] >= ubHowMany);
//KM : July 21, 1999 patch fix
if( pSectorInfo->ubNumberOfCivsAtLevel[ ubRank ] < ubHowMany )
{
return;
}
pSectorInfo->ubNumberOfCivsAtLevel[ ubRank ] -= ubHowMany;
if (ubHowMany && sMapX == gWorldSectorX && sMapY == gWorldSectorY )
{
gfStrategicMilitiaChangesMade = TRUE;
}
// update the screen display
fMapPanelDirty = TRUE;
}
// kill pts are (2 * kills) + assists
UINT8 CheckOneMilitiaForPromotion(INT16 sMapX, INT16 sMapY, UINT8 ubCurrentRank, UINT8 ubRecentKillPts)
{
UINT32 uiChanceToLevel = 0;
switch( ubCurrentRank )
{
case GREEN_MILITIA:
// 2 kill pts minimum
if (ubRecentKillPts >= 2)
{
// 25% chance per kill pt
uiChanceToLevel = 25 * ubRecentKillPts;
}
break;
case REGULAR_MILITIA:
// 5 kill pts minimum
if (ubRecentKillPts >= 5)
{
// 10% chance per kill pt.
uiChanceToLevel = 10 * ubRecentKillPts;
}
break;
case ELITE_MILITIA:
return 0;
break;
}
// roll the bones, and see if he makes it
if (Random(100) < uiChanceToLevel)
{
StrategicPromoteMilitiaInSector(sMapX, sMapY, ubCurrentRank, 1);
if( ubCurrentRank == GREEN_MILITIA )
{ //Attempt yet another level up if sufficient points
if( ubRecentKillPts > 2 )
{
if( CheckOneMilitiaForPromotion( sMapX, sMapY, REGULAR_MILITIA, (UINT8)(ubRecentKillPts - 2) ) )
{ //success, this militia was promoted twice
return 2;
}
}
}
return 1;
}
return 0;
}
// call this if the player attacks his own militia
void HandleMilitiaDefections(INT16 sMapX, INT16 sMapY)
{
UINT8 ubRank;
UINT8 ubMilitiaCnt;
UINT8 ubCount;
UINT32 uiChanceToDefect;
for( ubRank = 0; ubRank < MAX_MILITIA_LEVELS; ubRank++ )
{
ubMilitiaCnt = MilitiaInSectorOfRank(sMapX, sMapY, ubRank);
// check each guy at each rank to see if he defects
for (ubCount = 0; ubCount < ubMilitiaCnt; ubCount++)
{
switch( ubRank )
{
case GREEN_MILITIA:
uiChanceToDefect = 50;
break;
case REGULAR_MILITIA:
uiChanceToDefect = 75;
break;
case ELITE_MILITIA:
uiChanceToDefect = 90;
break;
default:
Assert( 0 );
return;
}
// roll the bones; should I stay or should I go now? (for you music fans out there)
if (Random(100) < uiChanceToDefect)
{
//B'bye! (for you SNL fans out there)
StrategicRemoveMilitiaFromSector(sMapX, sMapY, ubRank, 1);
}
}
}
}
UINT8 CountAllMilitiaInSector(INT16 sMapX, INT16 sMapY)
{
UINT8 ubMilitiaTotal = 0;
UINT8 ubRank;
// find out if there are any town militia in this SECTOR (don't care about other sectors in same town)
for( ubRank = 0; ubRank < MAX_MILITIA_LEVELS; ubRank++ )
{
ubMilitiaTotal += MilitiaInSectorOfRank(sMapX, sMapY, ubRank);
}
return(ubMilitiaTotal);
}
UINT8 MilitiaInSectorOfRank(INT16 sMapX, INT16 sMapY, UINT8 ubRank)
{
unsigned count = SectorInfo[ SECTOR( sMapX, sMapY ) ].ubNumberOfCivsAtLevel[ ubRank ];
return count;
}
BOOLEAN SectorOursAndPeaceful( INT16 sMapX, INT16 sMapY, INT8 bMapZ )
{
// if this sector is currently loaded
if ( ( sMapX == gWorldSectorX ) && ( sMapY == gWorldSectorY ) && ( bMapZ == gbWorldSectorZ ) )
{
// and either there are enemies prowling this sector, or combat is in progress
if ( gTacticalStatus.fEnemyInSector || ( gTacticalStatus.uiFlags & INCOMBAT ) )
{
return FALSE;
}
}
// if sector is controlled by enemies, it's not ours (duh!)
if( !bMapZ && StrategicMap[ sMapX + sMapY * MAP_WORLD_X ].fEnemyControlled == TRUE )
{
return FALSE;
}
if( NumHostilesInSector( sMapX, sMapY, bMapZ ) )
{
return FALSE;
}
// safe & secure, s'far as we can tell
return(TRUE);
}
void InitFriendlyTownSectorServer(UINT8 ubTownId, INT16 sSkipSectorX, INT16 sSkipSectorY)
{
// reset globals
gubTownSectorServerTownId = ubTownId;
gsTownSectorServerSkipX = sSkipSectorX;
gsTownSectorServerSkipY = sSkipSectorY;
gubTownSectorServerIndex = 0;
}
// this feeds the X,Y of the next town sector on the town list for the town specified at initialization
// it will skip an entry that matches the skip X/Y value if one was specified at initialization
// MUST CALL InitFriendlyTownSectorServer() before using!!!
BOOLEAN ServeNextFriendlySectorInTown( INT16 *sNeighbourX, INT16 *sNeighbourY )
{
INT32 iTownSector;
INT16 sMapX, sMapY;
BOOLEAN fStopLooking = FALSE;
do
{
// have we reached the end of the town list?
if (pTownNamesList[ gubTownSectorServerIndex ] == BLANK_SECTOR)
{
// end of list reached
return(FALSE);
}
iTownSector = pTownLocationsList[ gubTownSectorServerIndex ];
// if this sector is in the town we're looking for
if( StrategicMap[ iTownSector ].bNameId == gubTownSectorServerTownId )
{
// A sector in the specified town. Calculate its X & Y sector compotents
sMapX = iTownSector % MAP_WORLD_X;
sMapY = iTownSector / MAP_WORLD_X;
// Make sure we're not supposed to skip it
if ( ( sMapX != gsTownSectorServerSkipX ) || ( sMapY != gsTownSectorServerSkipY ) )
{
// check if it's "friendly" - not enemy controlled, no enemies in it, no combat in progress
if (SectorOursAndPeaceful( sMapX, sMapY, 0 ))
{
// then that's it!
*sNeighbourX = sMapX;
*sNeighbourY = sMapY;
fStopLooking = TRUE;
}
}
}
// advance to next entry in town list
gubTownSectorServerIndex++;
} while ( !fStopLooking );
// found & returning a valid sector
return(TRUE);
}
void HandleInterfaceMessageForCostOfTrainingMilitia( SOLDIERTYPE *pSoldier )
{
INT32 iMilitiaTrainingCost = gGameExternalOptions.iMilitiaTrainingCost;
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"Militia2");
CHAR16 sString[ 128 ];
SGPRect pCenteringRect= {0, 0, 640, INV_INTERFACE_START_Y };
INT32 iNumberOfSectors = 0;
pMilitiaTrainerSoldier = pSoldier;
// grab total number of sectors
iNumberOfSectors = GetNumberOfUnpaidTrainableSectors( );
Assert( iNumberOfSectors > 0 );
// Kaiden: Roaming Militia Training:
// We want to charge more for Roaming
// get total cost
if( IsMilitiaTrainableFromSoldiersSectorMaxed( pSoldier, ELITE_MILITIA )
&& (gGameExternalOptions.gfmusttrainroaming)
&& (GetWorldDay( ) >= gGameExternalOptions.guiAllowMilitiaGroupsDelay))
{
giTotalCostOfTraining = (iMilitiaTrainingCost*gGameExternalOptions.iMilitiaCostModifier) * iNumberOfSectors;
Assert( giTotalCostOfTraining > 0 );
gfAreWeTrainingMobile = TRUE;
}
else if (IsMilitiaTrainableFromSoldiersSectorMaxed( pSoldier, REGULAR_MILITIA )
&& (gGameExternalOptions.gfTrainVeteranMilitia)
&& (GetWorldDay( ) >= gGameExternalOptions.guiTrainVeteranMilitiaDelay))
{
giTotalCostOfTraining = (iMilitiaTrainingCost*gGameExternalOptions.iVeteranCostModifier) * iNumberOfSectors;
Assert( giTotalCostOfTraining > 0 );
gfAreWePromotingRegular = TRUE;
}
else if (IsMilitiaTrainableFromSoldiersSectorMaxed( pSoldier, GREEN_MILITIA ))
{
giTotalCostOfTraining = (iMilitiaTrainingCost*gGameExternalOptions.iRegularCostModifier) * iNumberOfSectors;
Assert( giTotalCostOfTraining > 0 );
gfAreWePromotingGreen = TRUE;
}
else
{
giTotalCostOfTraining = iMilitiaTrainingCost * iNumberOfSectors;
Assert( giTotalCostOfTraining > 0 );
}
gfYesNoPromptIsForContinue = FALSE;
if( LaptopSaveInfo.iCurrentBalance < giTotalCostOfTraining )
{
swprintf( sString, pMilitiaConfirmStrings[ 8 ], giTotalCostOfTraining );
DoScreenIndependantMessageBox( sString, MSG_BOX_FLAG_OK, CantTrainMilitiaOkBoxCallback );
return;
}
// ok to start training, ask player
if( iNumberOfSectors > 1 )
{
swprintf( sString, pMilitiaConfirmStrings[ 7 ], iNumberOfSectors, giTotalCostOfTraining, pMilitiaConfirmStrings[ 1 ] );
}
else
{
swprintf( sString, L"%s%d. %s", pMilitiaConfirmStrings[ 0 ], giTotalCostOfTraining, pMilitiaConfirmStrings[ 1 ] );
}
// if we are in mapscreen, make a pop up
if( guiCurrentScreen == MAP_SCREEN )
{
DoMapMessageBox( MSG_BOX_BASIC_STYLE, sString, MAP_SCREEN, MSG_BOX_FLAG_YESNO, PayMilitiaTrainingYesNoBoxCallback );
}
else
{
DoMessageBox( MSG_BOX_BASIC_STYLE, sString, GAME_SCREEN, MSG_BOX_FLAG_YESNO, PayMilitiaTrainingYesNoBoxCallback, &pCenteringRect );
}
return;
}
void DoContinueMilitiaTrainingMessageBox( INT16 sSectorX, INT16 sSectorY, const STR16 str, UINT16 usFlags, MSGBOX_CALLBACK ReturnCallback )
{
if( sSectorX <= 10 && sSectorY >= 6 && sSectorY <= 11 )
{
DoLowerScreenIndependantMessageBox( str, usFlags, ReturnCallback );
}
else
{
DoScreenIndependantMessageBox( str, usFlags, ReturnCallback );
}
}
void HandleInterfaceMessageForContinuingTrainingMilitia( SOLDIERTYPE *pSoldier )
{
CHAR16 sString[ 128 ];
INT16 sSectorX = 0, sSectorY = 0;
CHAR16 sStringB[ 128 ];
INT8 bTownId;
BOOLEAN fIsFull = FALSE;
INT32 iMinLoyaltyToTrain = gGameExternalOptions.iMinLoyaltyToTrain;
INT32 iMilitiaTrainingCost = gGameExternalOptions.iMilitiaTrainingCost;
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"Militia3");
sSectorX = pSoldier->sSectorX;
sSectorY = pSoldier->sSectorY;
Assert( SectorInfo[ SECTOR( sSectorX, sSectorY ) ].fMilitiaTrainingPaid == FALSE );
pMilitiaTrainerSoldier = pSoldier;
gfYesNoPromptIsForContinue = TRUE;
// is there enough loyalty to continue training
if( DoesSectorMercIsInHaveSufficientLoyaltyToTrainMilitia( pSoldier ) == FALSE )
{
// loyalty too low to continue training
swprintf( sString, pMilitiaConfirmStrings[ 9 ], pTownNames[ GetTownIdForSector( sSectorX, sSectorY )], iMinLoyaltyToTrain );
DoContinueMilitiaTrainingMessageBox( sSectorX, sSectorY, sString, MSG_BOX_FLAG_OK, CantTrainMilitiaOkBoxCallback );
return;
}
// Kaiden: Roaming Militia Training:
// Changed the if condition from
// if ( IsMilitiaTrainableFromSoldiersSectorMaxed( pSoldier ) )
// And we're not training mobile militia from a SAM Site
if (IsMilitiaTrainableFromSoldiersSectorMaxed( pSoldier, ELITE_MILITIA ))
if (!gGameExternalOptions.gfmusttrainroaming)
fIsFull = TRUE;
else if (GetWorldDay( ) < gGameExternalOptions.guiAllowMilitiaGroupsDelay)
fIsFull = TRUE;
else if (IsThisSectorASAMSector(sSectorX,sSectorY,0 ))
fIsFull = TRUE;
else
fIsFull = FALSE;
if (fIsFull)
{
// we're full!!! go home!
bTownId = GetTownIdForSector( sSectorX, sSectorY );
if ( bTownId == BLANK_SECTOR )
{
// wilderness SAM site
GetSectorIDString( sSectorX, sSectorY, 0, sStringB, TRUE );
void (*tempFptr)(INT16 , INT16 , INT8 , CHAR16 *, BOOLEAN) = GetSectorIDString;
swprintf( sString, pMilitiaConfirmStrings[ 10 ], sStringB, tempFptr, iMinLoyaltyToTrain );
}
else
{
// town
swprintf( sString, pMilitiaConfirmStrings[ 10 ], pTownNames[ bTownId ], iMinLoyaltyToTrain );
}
DoContinueMilitiaTrainingMessageBox( sSectorX, sSectorY, sString, MSG_BOX_FLAG_OK, CantTrainMilitiaOkBoxCallback );
return;
}
// Kaiden: Roaming Militia Training:
// Charging more to train Roaming Militia
// Also Charging more for promotions over Training
if( IsMilitiaTrainableFromSoldiersSectorMaxed( pSoldier, ELITE_MILITIA )
&& (gGameExternalOptions.gfmusttrainroaming)
&&(GetWorldDay( ) >= gGameExternalOptions.guiAllowMilitiaGroupsDelay))
{
giTotalCostOfTraining = (iMilitiaTrainingCost*gGameExternalOptions.iMilitiaCostModifier);
gfAreWeTrainingMobile = TRUE;
}
else if (IsMilitiaTrainableFromSoldiersSectorMaxed( pSoldier, REGULAR_MILITIA )
&& (gGameExternalOptions.gfTrainVeteranMilitia)
&& (GetWorldDay( ) >= gGameExternalOptions.guiTrainVeteranMilitiaDelay))
{
giTotalCostOfTraining = (iMilitiaTrainingCost*gGameExternalOptions.iVeteranCostModifier);
gfAreWePromotingRegular = TRUE;
}
else if (IsMilitiaTrainableFromSoldiersSectorMaxed( pSoldier, GREEN_MILITIA ))
{
giTotalCostOfTraining = (iMilitiaTrainingCost*gGameExternalOptions.iRegularCostModifier);
gfAreWePromotingGreen = TRUE;
}
else
{
giTotalCostOfTraining = (iMilitiaTrainingCost);
}
// can player afford to continue training?
if( LaptopSaveInfo.iCurrentBalance < giTotalCostOfTraining )
{
// can't afford to continue training
swprintf( sString, pMilitiaConfirmStrings[ 8 ], giTotalCostOfTraining );
DoContinueMilitiaTrainingMessageBox( sSectorX, sSectorY, sString, MSG_BOX_FLAG_OK, CantTrainMilitiaOkBoxCallback );
return;
}
// ok to continue, ask player
GetSectorIDString( sSectorX, sSectorY, 0, sStringB, TRUE );
swprintf( sString, pMilitiaConfirmStrings[ 3 ], sStringB, pMilitiaConfirmStrings[ 4 ], giTotalCostOfTraining );
// ask player whether he'd like to continue training
//DoContinueMilitiaTrainingMessageBox( sSectorX, sSectorY, sString, MSG_BOX_FLAG_YESNO, PayMilitiaTrainingYesNoBoxCallback );
DoMapMessageBox( MSG_BOX_BASIC_STYLE, sString, MAP_SCREEN, MSG_BOX_FLAG_YESNO, PayMilitiaTrainingYesNoBoxCallback );
}
// IMPORTANT: This same callback is used both for initial training and for continue training prompt
// use 'gfYesNoPromptIsForContinue' flag to tell them apart
void PayMilitiaTrainingYesNoBoxCallback( UINT8 bExitValue )
{
CHAR16 sString[ 128 ];
Assert( giTotalCostOfTraining > 0 );
// yes
if( bExitValue == MSG_BOX_RETURN_YES )
{
// does the player have enough
if( LaptopSaveInfo.iCurrentBalance >= giTotalCostOfTraining )
{
if( gfYesNoPromptIsForContinue )
{
ContinueTrainingInThisSector();
}
else
{
StartTrainingInAllUnpaidTrainableSectors();
}
#ifdef JA2BETAVERSION
// put this BEFORE training gets handled to avoid detecting an error everytime a sector completes training
VerifyTownTrainingIsPaidFor();
#endif
// this completes the training prompt sequence
pMilitiaTrainerSoldier = NULL;
}
else // can't afford it
{
StopTimeCompression();
swprintf( sString, L"%s", pMilitiaConfirmStrings[ 2 ] );
DoMapMessageBox( MSG_BOX_BASIC_STYLE, sString, MAP_SCREEN, MSG_BOX_FLAG_OK, CantTrainMilitiaOkBoxCallback );
}
}
else if( bExitValue == MSG_BOX_RETURN_NO )
{
StopTimeCompression();
MilitiaTrainingRejected();
}
return;
}
void CantTrainMilitiaOkBoxCallback( UINT8 bExitValue )
{
MilitiaTrainingRejected();
return;
}
// IMPORTANT: This same callback is used both for initial training and for continue training prompt
// use 'gfYesNoPromptIsForContinue' flag to tell them apart
void MilitiaTrainingRejected( void )
{
if( gfYesNoPromptIsForContinue )
{
// take all mercs in that sector off militia training
ResetAssignmentOfMercsThatWereTrainingMilitiaInThisSector( pMilitiaTrainerSoldier->sSectorX, pMilitiaTrainerSoldier->sSectorY );
}
else
{
// take all mercs in unpaid sectors EVERYWHERE off militia training
ResetAssignmentsForMercsTrainingUnpaidSectorsInSelectedList( 0 );
}
#ifdef JA2BETAVERSION
// put this BEFORE training gets handled to avoid detecting an error everytime a sector completes training
VerifyTownTrainingIsPaidFor();
#endif
// this completes the training prompt sequence
pMilitiaTrainerSoldier = NULL;
}
void HandleMilitiaStatusInCurrentMapBeforeLoadingNewMap( void )
{
if ( gTacticalStatus.Team[ MILITIA_TEAM ].bSide != 0 )
{
// handle militia defections and reset team to friendly
HandleMilitiaDefections( gWorldSectorX, gWorldSectorY );
gTacticalStatus.Team[ MILITIA_TEAM ].bSide = 0;
}
else if( !gfAutomaticallyStartAutoResolve )
{ //Don't promote militia if we are going directly to autoresolve to finish the current battle.
HandleMilitiaPromotions();
}
}
BOOLEAN CanNearbyMilitiaScoutThisSector( INT16 sSectorX, INT16 sSectorY )
{
INT16 sSectorValue = 0, sSector = 0;
INT16 sCounterA = 0, sCounterB = 0;
UINT8 ubScoutingRange = 1;
// get the sector value
sSector = sSectorX + sSectorY * MAP_WORLD_X;
for( sCounterA = sSectorX - ubScoutingRange; sCounterA <= sSectorX + ubScoutingRange; sCounterA++ )
{
for( sCounterB = sSectorY - ubScoutingRange; sCounterB <= sSectorY + ubScoutingRange; sCounterB++ )
{
// skip out of bounds sectors
if ( ( sCounterA < 1 ) || ( sCounterA > 16 ) || ( sCounterB < 1 ) || ( sCounterB > 16 ) )
{
continue;
}
sSectorValue = SECTOR( sCounterA, sCounterB );
// check if any sort of militia here
if( SectorInfo[ sSectorValue ].ubNumberOfCivsAtLevel[ GREEN_MILITIA ] )
{
return( TRUE );
}
else if( SectorInfo[ sSectorValue ].ubNumberOfCivsAtLevel[ REGULAR_MILITIA ] )
{
return( TRUE );
}
else if( SectorInfo[ sSectorValue ].ubNumberOfCivsAtLevel[ ELITE_MILITIA ] )
{
return( TRUE );
}
}
}
return( FALSE );
}
BOOLEAN IsTownFullMilitia( INT8 bTownId, INT8 iMilitiaType )
{
INT32 iMaxMilitiaPerSector = gGameExternalOptions.iMaxMilitiaPerSector;
INT32 iCounter = 0;
INT16 sSectorX = 0, sSectorY = 0;
INT32 iNumberOfMilitia = 0;
INT32 iMaxNumber = 0;
BOOLEAN fIncreaseCost = FALSE;
while( pTownNamesList[ iCounter ] != 0 )
{
if( pTownNamesList[ iCounter ] == bTownId )
{
// get the sector x and y
sSectorX = pTownLocationsList[ iCounter ] % MAP_WORLD_X;
sSectorY = pTownLocationsList[ iCounter ] / MAP_WORLD_X;
// if sector is ours get number of militia here
if( SectorOursAndPeaceful( sSectorX, sSectorY, 0 ) )
{
//Kaiden: Checking for Price Hikes.
if (iMilitiaType == GREEN_MILITIA)
{
iNumberOfMilitia += MilitiaInSectorOfRank( sSectorX, sSectorY, GREEN_MILITIA );
iNumberOfMilitia += MilitiaInSectorOfRank( sSectorX, sSectorY, REGULAR_MILITIA );
iNumberOfMilitia += MilitiaInSectorOfRank( sSectorX, sSectorY, ELITE_MILITIA );
iMaxNumber += iMaxMilitiaPerSector;
if (MilitiaInSectorOfRank( sSectorX, sSectorY, GREEN_MILITIA ) > 0)
fIncreaseCost = TRUE;
}
else if (iMilitiaType == REGULAR_MILITIA)
{
iNumberOfMilitia += MilitiaInSectorOfRank( sSectorX, sSectorY, REGULAR_MILITIA );
iNumberOfMilitia += MilitiaInSectorOfRank( sSectorX, sSectorY, ELITE_MILITIA );
iMaxNumber += iMaxMilitiaPerSector;
if (MilitiaInSectorOfRank( sSectorX, sSectorY, REGULAR_MILITIA ) > 0)
fIncreaseCost = TRUE;
}
//Kaiden: OK So iMilitiaType should be ELITE_MILITIA
// and we're just checking sectors for purposes
// of training mobile militia or ending training
// don't count GREEN militia, they can be trained into regulars first
// Kaiden: Veteran Militia Training:
// And we don't count regulars either if we're training veterans
if (gGameExternalOptions.gfTrainVeteranMilitia && (iMilitiaType == ELITE_MILITIA)
&& (GetWorldDay( ) >= gGameExternalOptions.guiTrainVeteranMilitiaDelay))
{
iNumberOfMilitia += MilitiaInSectorOfRank( sSectorX, sSectorY, ELITE_MILITIA );
iMaxNumber += iMaxMilitiaPerSector;
}
else if (iMilitiaType == ELITE_MILITIA)
{
iNumberOfMilitia += MilitiaInSectorOfRank( sSectorX, sSectorY, REGULAR_MILITIA );
iNumberOfMilitia += MilitiaInSectorOfRank( sSectorX, sSectorY, ELITE_MILITIA );
iMaxNumber += iMaxMilitiaPerSector;
}
}
}
iCounter++;
}
if (iMilitiaType == GREEN_MILITIA)
{
if (( iNumberOfMilitia == iMaxNumber ) && (fIncreaseCost))
return( TRUE );
else
return( FALSE );
}
else if (iMilitiaType == REGULAR_MILITIA)
{
if (( iNumberOfMilitia == iMaxNumber ) && (fIncreaseCost))
return( TRUE );
else
return( FALSE );
}
// now check the number of militia
if ( iMaxNumber > iNumberOfMilitia )
{
return( FALSE );
}
return( TRUE );
}
BOOLEAN IsSAMSiteFullOfMilitia( INT16 sSectorX, INT16 sSectorY, INT8 iMilitiaType )
{
BOOLEAN fSamSitePresent = FALSE;
INT32 iNumberOfMilitia = 0;
INT32 iMaxNumber = 0;
INT32 iMaxMilitiaPerSector = gGameExternalOptions.iMaxMilitiaPerSector;
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"Militia5");
// check if SAM site is ours?
fSamSitePresent = IsThisSectorASAMSector( sSectorX, sSectorY, 0 );
if( fSamSitePresent == FALSE )
{
return( FALSE );
}
if( SectorOursAndPeaceful( sSectorX, sSectorY, 0 ) )
{
//Kaiden: If we're checking for specific Militia for Price Hikes:
if (iMilitiaType == GREEN_MILITIA)
{
iNumberOfMilitia += MilitiaInSectorOfRank( sSectorX, sSectorY, GREEN_MILITIA );
iNumberOfMilitia += MilitiaInSectorOfRank( sSectorX, sSectorY, REGULAR_MILITIA );
iNumberOfMilitia += MilitiaInSectorOfRank( sSectorX, sSectorY, ELITE_MILITIA );
if (( iNumberOfMilitia == iMaxMilitiaPerSector) &&
(MilitiaInSectorOfRank( sSectorX, sSectorY, GREEN_MILITIA ) > 0))
return( TRUE );
else
return( FALSE );
}
else if (iMilitiaType == REGULAR_MILITIA)
{
iNumberOfMilitia += MilitiaInSectorOfRank( sSectorX, sSectorY, REGULAR_MILITIA );
iNumberOfMilitia += MilitiaInSectorOfRank( sSectorX, sSectorY, ELITE_MILITIA );
if (( iNumberOfMilitia == iMaxMilitiaPerSector) &&
(MilitiaInSectorOfRank( sSectorX, sSectorY, REGULAR_MILITIA ) > 0))
return( TRUE );
else
return( FALSE );
}
// Kaiden: Ok we're not checking for militia promotions now,
// so MilitiaType should be ELITE_MILITIA for purposes
// of training Roaming or not.
// don't count GREEN militia, they can be trained into regulars first
// Kaiden: Veteran Militia Training:
// And we don't count regulars either if we're training veterans
if (gGameExternalOptions.gfTrainVeteranMilitia && (iMilitiaType == ELITE_MILITIA)
&& (GetWorldDay( ) >= gGameExternalOptions.guiTrainVeteranMilitiaDelay))
{
iNumberOfMilitia += MilitiaInSectorOfRank( sSectorX, sSectorY, ELITE_MILITIA );
iMaxNumber += iMaxMilitiaPerSector;
}
else if (iMilitiaType == ELITE_MILITIA)
{
iNumberOfMilitia += MilitiaInSectorOfRank( sSectorX, sSectorY, REGULAR_MILITIA );
iNumberOfMilitia += MilitiaInSectorOfRank( sSectorX, sSectorY, ELITE_MILITIA );
iMaxNumber += iMaxMilitiaPerSector;
}
}
// now check the number of militia
if ( iMaxNumber > iNumberOfMilitia )
{
return( FALSE );
}
return( TRUE );
}
void HandleCompletionOfTownTrainingByGroupWithTrainer( SOLDIERTYPE *pTrainer )
{
INT16 sSectorX = 0, sSectorY = 0;
INT8 bSectorZ = 0;
SOLDIERTYPE *pSoldier = NULL;
INT32 iCounter = 0;
// get the sector values
sSectorX = pTrainer->sSectorX;
sSectorY = pTrainer->sSectorY;
bSectorZ = pTrainer->bSectorZ;
for( iCounter = 0; iCounter < giMAXIMUM_NUMBER_OF_PLAYER_SLOTS; iCounter++ )
{
// valid character?
if( gCharactersList[ iCounter ].fValid == FALSE )
{
// nope
continue;
}
pSoldier = &Menptr[ gCharactersList[ iCounter ].usSolID ];
// valid soldier?
if( pSoldier->bActive == FALSE )
{
continue;
}
if( ( pSoldier->bAssignment == TRAIN_TOWN ) && ( pSoldier->sSectorX == sSectorX )&&( pSoldier->sSectorY == sSectorY )&&( pSoldier->bSectorZ == bSectorZ ) )
{
// done assignment
AssignmentDone( pSoldier, FALSE, FALSE );
}
}
return;
}
void AddSectorForSoldierToListOfSectorsThatCompletedMilitiaTraining( SOLDIERTYPE *pSoldier )
{
INT32 iCounter = 0;
INT16 sSector = 0, sCurrentSector = 0;
SOLDIERTYPE *pCurrentSoldier = NULL;
// get the sector value
sSector = pSoldier->sSectorX + pSoldier->sSectorY * MAP_WORLD_X;
while( giListOfMercsInSectorsCompletedMilitiaTraining[ iCounter ] != -1 )
{
// get the current soldier
pCurrentSoldier = &Menptr[ giListOfMercsInSectorsCompletedMilitiaTraining[ iCounter ] ];
// get the current sector value
sCurrentSector = pCurrentSoldier->sSectorX + pCurrentSoldier->sSectorY * MAP_WORLD_X;
// is the merc's sector already in the list?
if( sCurrentSector == sSector )
{
// already here
return;
}
iCounter++;
Assert( iCounter < SIZE_OF_MILITIA_COMPLETED_TRAINING_LIST );
}
// add merc to the list
giListOfMercsInSectorsCompletedMilitiaTraining[ iCounter ] = pSoldier->ubID;
return;
}
// clear out the list of training sectors...should be done once the list is posted
void ClearSectorListForCompletedTrainingOfMilitia( void )
{
INT32 iCounter = 0;
for( iCounter = 0; iCounter < SIZE_OF_MILITIA_COMPLETED_TRAINING_LIST; iCounter++ )
{
giListOfMercsInSectorsCompletedMilitiaTraining[ iCounter ] = -1;
}
return;
}
void HandleContinueOfTownTraining( void )
{
SOLDIERTYPE *pSoldier = NULL;
INT32 iCounter = 0;
BOOLEAN fContinueEventPosted = FALSE;
while( giListOfMercsInSectorsCompletedMilitiaTraining[ iCounter ] != -1 )
{
// get the soldier
pSoldier = &Menptr[ giListOfMercsInSectorsCompletedMilitiaTraining[ iCounter ] ];
if( pSoldier->bActive )
{
fContinueEventPosted = TRUE;
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_CONTINUE_TRAINING_MILITIA, pSoldier->ubProfile, 0, 0, 0, 0 );
// now set all of these peoples assignment done too
//HandleInterfaceMessageForContinuingTrainingMilitia( pSoldier );
}
// next entry
iCounter++;
}
// now clear the list
ClearSectorListForCompletedTrainingOfMilitia( );
if( fContinueEventPosted )
{
// ATE: If this event happens in tactical mode we will be switching at some time to mapscreen...
if ( guiCurrentScreen == GAME_SCREEN )
{
gfEnteringMapScreen = TRUE;
}
//If the militia view isn't currently active, then turn it on when prompting to continue training.
if ( !fShowMilitia )
{
ToggleShowMilitiaMode();
}
}
return;
}
void BuildListOfUnpaidTrainableSectors( void )
{
INT32 iCounter = 0, iCounterB = 0;
SOLDIERTYPE *pSoldier = NULL;
// WDS - make number of mercenaries, etc. be configurable
memset( gsUnpaidStrategicSector, 0, sizeof(gsUnpaidStrategicSector) );
if( guiTacticalInterfaceFlags & INTERFACE_MAPSCREEN )
{
for( iCounter = 0; iCounter < giMAXIMUM_NUMBER_OF_PLAYER_SLOTS; iCounter++ )
{
// valid character?
if( gCharactersList[ iCounter ].fValid )
{
// selected?
if( ( fSelectedListOfMercsForMapScreen[ iCounter ] == TRUE ) || ( iCounter == bSelectedAssignChar ) )
{
pSoldier = &Menptr[ gCharactersList[ iCounter ].usSolID ];
if( CanCharacterTrainMilitia( pSoldier ) == TRUE )
{
if( SectorInfo[ SECTOR( pSoldier->sSectorX, pSoldier->sSectorY ) ].fMilitiaTrainingPaid == FALSE )
{
// check to see if this sector is a town and needs equipment
gsUnpaidStrategicSector[ iCounter ] = CALCULATE_STRATEGIC_INDEX( pSoldier->sSectorX, pSoldier->sSectorY );
}
}
}
}
}
}
else
{
// handle for tactical
pSoldier = &Menptr[ gusUIFullTargetID ];
iCounter = 0;
if( CanCharacterTrainMilitia( pSoldier ) == TRUE )
{
if( SectorInfo[ SECTOR( pSoldier->sSectorX, pSoldier->sSectorY ) ].fMilitiaTrainingPaid == FALSE )
{
// check to see if this sector is a town and needs equipment
gsUnpaidStrategicSector[ iCounter ] = CALCULATE_STRATEGIC_INDEX( pSoldier->sSectorX, pSoldier->sSectorY );
}
}
}
// now clean out repeated sectors
for( iCounter = 0; iCounter < giMAXIMUM_NUMBER_OF_PLAYER_SLOTS - 1; iCounter++ )
{
if( gsUnpaidStrategicSector[ iCounter ] > 0 )
{
for( iCounterB = iCounter + 1 ; iCounterB < giMAXIMUM_NUMBER_OF_PLAYER_SLOTS; iCounterB++ )
{
if( gsUnpaidStrategicSector[ iCounterB ] == gsUnpaidStrategicSector[ iCounter ] )
{
gsUnpaidStrategicSector[ iCounterB ] = 0;
}
}
}
}
}
INT32 GetNumberOfUnpaidTrainableSectors( void )
{
INT32 iCounter = 0;
INT32 iNumberOfSectors = 0;
BuildListOfUnpaidTrainableSectors();
// now count up the results
for( iCounter = 0; iCounter < giMAXIMUM_NUMBER_OF_PLAYER_SLOTS; iCounter++ )
{
if( gsUnpaidStrategicSector[ iCounter ] > 0 )
{
iNumberOfSectors++;
}
}
// return the result
return( iNumberOfSectors );
}
void StartTrainingInAllUnpaidTrainableSectors()
{
INT32 iCounter = 0;
UINT8 ubSector;
SetAssignmentForList( TRAIN_TOWN, 0 );
BuildListOfUnpaidTrainableSectors();
// pay up in each sector
for( iCounter = 0; iCounter < giMAXIMUM_NUMBER_OF_PLAYER_SLOTS; iCounter++ )
{
if( gsUnpaidStrategicSector[ iCounter ] > 0 )
{
// convert strategic sector to 0-255 system
ubSector = STRATEGIC_INDEX_TO_SECTOR_INFO( gsUnpaidStrategicSector[ iCounter ] );
PayForTrainingInSector( ubSector );
}
}
}
void ContinueTrainingInThisSector( void )
{
UINT8 ubSector;
Assert( pMilitiaTrainerSoldier );
// pay up in the sector where pMilitiaTrainerSoldier is
ubSector = SECTOR( pMilitiaTrainerSoldier->sSectorX, pMilitiaTrainerSoldier->sSectorY );
PayForTrainingInSector( ubSector );
}
void PayForTrainingInSector( UINT8 ubSector )
{
INT32 iMilitiaTrainingCost = gGameExternalOptions.iMilitiaTrainingCost;
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"Militia6");
Assert( SectorInfo[ ubSector ].fMilitiaTrainingPaid == FALSE );
INT32 CostMultiplyer = 0;
// spend the money
// Kaiden: Roaming Militia Training:
// Charging more to train Roaming Militia
// Or for promotions.
if ( gfAreWeTrainingMobile)
{
CostMultiplyer = gGameExternalOptions.iMilitiaCostModifier;
gfAreWeTrainingMobile = FALSE;
}
else if ( gfAreWePromotingGreen)
{
CostMultiplyer = gGameExternalOptions.iRegularCostModifier;
gfAreWePromotingGreen = FALSE;
}
else if ( gfAreWePromotingRegular)
{
CostMultiplyer = gGameExternalOptions.iVeteranCostModifier;
gfAreWePromotingRegular = FALSE;
}
else
{
CostMultiplyer = 1;
}
AddTransactionToPlayersBook( TRAIN_TOWN_MILITIA, ubSector, GetWorldTotalMin(), -( iMilitiaTrainingCost*CostMultiplyer ) );
// mark this sector sectors as being paid up
SectorInfo[ ubSector ].fMilitiaTrainingPaid = TRUE;
// reset done flags
ResetDoneFlagForAllMilitiaTrainersInSector( ubSector );
}
void ResetDoneFlagForAllMilitiaTrainersInSector( UINT8 ubSector )
{
INT32 iCounter = 0;
SOLDIERTYPE *pSoldier = NULL;
for( iCounter = 0; iCounter <= gTacticalStatus.Team[ OUR_TEAM ].bLastID; iCounter++ )
{
pSoldier = &Menptr[ iCounter ];
if( pSoldier->bActive )
{
if( pSoldier->bAssignment == TRAIN_TOWN )
{
if( ( SECTOR( pSoldier->sSectorX, pSoldier->sSectorY ) == ubSector ) && ( pSoldier->bSectorZ == 0 ) )
{
pSoldier->flags.fDoneAssignmentAndNothingToDoFlag = FALSE;
pSoldier->usQuoteSaidExtFlags &= ~SOLDIER_QUOTE_SAID_DONE_ASSIGNMENT;
}
}
}
}
}
BOOLEAN MilitiaTrainingAllowedInSector( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ )
{
INT8 bTownId;
BOOLEAN fSamSitePresent = FALSE;
if( bSectorZ != 0 )
{
return( FALSE );
}
fSamSitePresent = IsThisSectorASAMSector( sSectorX, sSectorY, bSectorZ );
if( fSamSitePresent )
{
// all SAM sites may have militia trained at them
return(TRUE);
}
bTownId = GetTownIdForSector( sSectorX, sSectorY );
return( MilitiaTrainingAllowedInTown( bTownId ) );
}
BOOLEAN MilitiaTrainingAllowedInTown( INT8 bTownId )
{
return( gfMilitiaAllowedInTown[bTownId] );
}
void BuildMilitiaPromotionsString( STR16 str )
{
CHAR16 pStr[256];
BOOLEAN fAddSpace = FALSE;
swprintf( str, L"" );
if( !gbMilitiaPromotions )
{
return;
}
if( gbGreenToElitePromotions > 1 )
{
swprintf( pStr, gzLateLocalizedString[22], gbGreenToElitePromotions );
wcscat( str, pStr );
fAddSpace = TRUE;
}
else if( gbGreenToElitePromotions == 1 )
{
wcscat( str, gzLateLocalizedString[29] );
fAddSpace = TRUE;
}
if( gbGreenToRegPromotions > 1 )
{
if( fAddSpace )
{
wcscat( str, L" " );
}
swprintf( pStr, gzLateLocalizedString[23], gbGreenToRegPromotions );
wcscat( str, pStr );
fAddSpace = TRUE;
}
else if( gbGreenToRegPromotions == 1 )
{
if( fAddSpace )
{
wcscat( str, L" " );
}
wcscat( str, gzLateLocalizedString[30] );
fAddSpace = TRUE;
}
if( gbRegToElitePromotions > 1 )
{
if( fAddSpace )
{
wcscat( str, L" " );
}
swprintf( pStr, gzLateLocalizedString[24], gbRegToElitePromotions );
wcscat( str, pStr );
}
else if( gbRegToElitePromotions == 1 )
{
if( fAddSpace )
{
wcscat( str, L" " );
}
wcscat( str, gzLateLocalizedString[31] );
fAddSpace = TRUE;
}
//Clear the fields
gbGreenToElitePromotions = 0;
gbGreenToRegPromotions = 0;
gbRegToElitePromotions = 0;
gbMilitiaPromotions = 0;
}