New Feature: Militia Volunteer Pool limits the number of militia we can train. Turned off by default.

GameDir >= r2210 is recommended.

git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@7746 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
Flugente
2015-02-22 18:52:41 +00:00
parent caf482614a
commit c7c085b04f
17 changed files with 165 additions and 6 deletions
+5
View File
@@ -1994,6 +1994,11 @@ void LoadGameExternalOptions()
// HEADROCK HAM 3: Define effect of "TEACHER" trait in increasing effective leadership, for purposes of eligibility for training militia. This is a percentage value. HAM Default would be 200 = double effective leadership for each TEACHING level.
gGameExternalOptions.usTeacherTraitEffectOnLeadership = iniReader.ReadInteger("Militia Training Settings","TEACHER_TRAIT_EFFECT_ON_LEADERSHIP", 100, 1, 10000);
//################# Militia Volunteer Pool Settings ###################
gGameExternalOptions.fMilitiaVolunteerPool = iniReader.ReadBoolean( "Militia Volunteer Pool Settings", "MILITIA_VOLUNTEER_POOL", FALSE );
gGameExternalOptions.dMilitiaVolunteerGainFactorHourly = iniReader.ReadFloat( "Militia Volunteer Pool Settings", "MILITIA_VOLUNTEER_POOL_GAINFACTOR_HOURLY", 0.001f, 0.0f, 1.0f );
gGameExternalOptions.dMilitiaVolunteerGainFactorLiberation = iniReader.ReadFloat( "Militia Volunteer Pool Settings", "MILITIA_VOLUNTEER_POOL_GAINFACTOR_LIBERATION", 0.2f, 0.0f, 1.0f );
gGameExternalOptions.dMilitiaVolunteerMultiplierFarm = iniReader.ReadFloat( "Militia Volunteer Pool Settings", "MILITIA_VOLUNTEER_POOL_MULTIPLIER_FARM", 0.05f, 0.0f, 1.0f );
//################# Mobile Militia Training Settings ##################
+6
View File
@@ -287,6 +287,12 @@ typedef struct
INT32 iVeteranCostModifier;
INT32 iMinLoyaltyToTrain;
// Flugente: militia volunteer pool
BOOLEAN fMilitiaVolunteerPool;
FLOAT dMilitiaVolunteerGainFactorHourly;
FLOAT dMilitiaVolunteerGainFactorLiberation;
FLOAT dMilitiaVolunteerMultiplierFarm;
INT32 iMaxEnemyGroupSize;
BOOLEAN fMercDayOne;
+4 -1
View File
@@ -166,7 +166,10 @@ typedef struct
BOOLEAN bJohnEscorted;// and if they were at all
UINT8 ubJohnPossibleMissedFlights;// and how many flights he already missed
UINT8 bPadding[ 77 ]; // Flugente: 86->77
// Flugente: militia volunteer pool. No relation to the laptop whatsoever, but I'm not creating a new struct for one variable
FLOAT dMilitiaVolunteerPool;
UINT8 bPadding[ 72 ];
} LaptopSaveInfoStruct;
+14
View File
@@ -1412,6 +1412,10 @@ BOOLEAN CanCharacterTrainMilitia( SOLDIERTYPE *pSoldier )
{
AssertNotNIL(pSoldier);
// Flugente: militia volunteer pool
if ( !GetVolunteerPool() )
return FALSE;
// Make sure the basic sector/merc variables are still applicable. This is simply a fail-safe.
if( !BasicCanCharacterTrainMilitia( pSoldier ) )
{
@@ -2480,6 +2484,9 @@ void UpdateAssignments()
// reset scan flags in all sectors
ClearSectorScanResults();
// update militia volunteer count
UpdateVolunteers();
// run through sectors and handle each type in sector
for(sX = 0 ; sX < MAP_WORLD_X; ++sX )
{
@@ -18375,6 +18382,13 @@ BOOLEAN CanCharacterTrainMilitiaWithErrorReport( SOLDIERTYPE *pSoldier )
return( FALSE );
}
if ( !GetVolunteerPool() )
{
swprintf( sString, L"There are no volunteers for militia left!" );
DoScreenIndependantMessageBox( sString, MSG_BOX_FLAG_OK, NULL );
return (FALSE);
}
if ( 100 <= GetMobileMilitiaQuota( TRUE ) )
return ( FALSE );
+22 -1
View File
@@ -7667,6 +7667,25 @@ void MilitiaGroupBoxButtonCallback( GUI_BUTTON *btn, INT32 reason )
void DisplayMilitiaGroupBox()
{
// if we play with a limited militia pool, show us how many we have
if ( fShowMilitia && gGameExternalOptions.fMilitiaVolunteerPool )
{
CHAR16 sVolunteerString[200];
SetFont( FONT12ARIAL );
if ( GetVolunteerPool() >= 2 * gGameExternalOptions.iTrainingSquadSize )
SetFontForeground( FONT_FCOLOR_GREEN );
else if ( GetVolunteerPool( ) >= gGameExternalOptions.iTrainingSquadSize )
SetFontForeground( FONT_FCOLOR_YELLOW );
else
SetFontForeground( FONT_FCOLOR_RED );
// header
swprintf( sVolunteerString, szMilitiaStrategicMovementText[8], GetVolunteerPool( ), CalcHourlyVolunteerGain( ) );
mprintf( MapScreenRect.iLeft + 20, MapScreenRect.iBottom - 10, sVolunteerString );
}
if ( !gMilitiaGroupBoxCreated )
return;
@@ -7679,6 +7698,8 @@ void DisplayMilitiaGroupBox()
return;
}
SetFontForeground( FONT_FCOLOR_WHITE );
CreateMilitiaGroupBoxVideoObjects();
// move to defines later
@@ -7715,7 +7736,7 @@ void DisplayMilitiaGroupBox()
SetFontForeground( FONT_FCOLOR_WHITE );
SetFontBackground( FONT_MCOLOR_BLACK );
//Display the background for the drop down window
//Display the background
ColorFillVideoSurfaceArea( FRAME_BUFFER, gMilitiaGroupBoxX, gMilitiaGroupBoxY, gMilitiaGroupBoxX + MILITIAGROUPBOX_WIDTH, gMilitiaGroupBoxY + MILITIAGROUPBOX_HEIGHT, Get16BPPColor( FROMRGB( 50, 50, 50 ) ) );
// mouse region - clicking on a group name selects that group
+7 -1
View File
@@ -191,6 +191,9 @@ void GenerateMilitiaSquad(INT16 sMapX, INT16 sMapY, INT16 sTMapX, INT16 sTMapY,
ubMilitiaToTrain = CalcNumMilitiaTrained(ubBestLeadership, TRUE);
}
// Flugente: our pool of volunteers limits how many militia can be created
ubMilitiaToTrain = min( ubMilitiaToTrain, GetVolunteerPool( ) );
// HEADROCK HAM 3.4: Composition of new Mobile Militia groups is now dictated by two INI settings controlling
// the percentage of Elites and Regulars within the group. If the percentage for either is above 0, at least
// one militia of that type will be created every time. Green militia are created based on whatever remains.
@@ -302,6 +305,9 @@ void GenerateMilitiaSquad(INT16 sMapX, INT16 sMapY, INT16 sTMapX, INT16 sTMapY,
ubTargetGreen--;
}
// Flugente: substract volunteers
AddVolunteers( -ubMilitiaToTrain );
while (ubMilitiaToTrain > 0)
{
@@ -447,7 +453,7 @@ void GenerateMilitiaSquad(INT16 sMapX, INT16 sMapY, INT16 sTMapX, INT16 sTMapY,
--pTargetSector->ubNumberOfCivsAtLevel[ELITE_MILITIA];
}
}
// Update the militia if the current sector is affected
if (gfStrategicMilitiaChangesMade)
{
+10 -1
View File
@@ -28,6 +28,7 @@
// HEADROCK HAM 3.6: Added for facility string printing...
#include "PopUpBox.h"
#include "CampaignStats.h" // added by Flugente
#include "Town Militia.h" // added by Flugente
#endif
#include "postalservice.h"
@@ -391,10 +392,18 @@ BOOLEAN SetThisSectorAsPlayerControlled( INT16 sMapX, INT16 sMapY, INT8 bMapZ, B
//if ( ubTraverseType == )
if ( GetTownIdForSector( sMapX, sMapY ) != BLANK_SECTOR )
UINT8 townid = GetTownIdForSector( sMapX, sMapY );
if ( townid != BLANK_SECTOR )
{
// first liberation of a town sector -> special texts
gCurrentIncident.usIncidentFlags |= INCIDENT_FIRST_LIBERATION;
// liberating a town sector for the first time grants us an initial wave of volunteers
UINT16 population = GetSectorPopulation( sMapX, sMapY );
FLOAT loyalpopulation = gTownLoyalty[townid].ubRating * population / 100;
AddVolunteers( loyalpopulation * gGameExternalOptions.dMilitiaVolunteerGainFactorLiberation );
}
}
+69 -2
View File
@@ -127,6 +127,9 @@ void TownMilitiaTrainingCompleted( SOLDIERTYPE *pTrainer, INT16 sMapX, INT16 sMa
UINT8 ubTrainerEffectiveLeadership = FindBestMilitiaTrainingLeadershipInSector ( sMapX, sMapY, pTrainer->bSectorZ, TOWN_MILITIA );
UINT8 iTrainingSquadSize = __min(iMaxMilitiaPerSector, CalcNumMilitiaTrained(ubTrainerEffectiveLeadership, FALSE));
// Flugente: our pool of volunteers limits how many militia can be created
iTrainingSquadSize = min( iTrainingSquadSize, GetVolunteerPool( ) );
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"Militia1");
// get town index
@@ -310,6 +313,8 @@ void TownMilitiaTrainingCompleted( SOLDIERTYPE *pTrainer, INT16 sMapX, INT16 sMa
++ubMilitiaTrained;
}
AddVolunteers( -ubMilitiaTrained );
if (gfStrategicMilitiaChangesMade)
{
ResetMilitia();
@@ -2142,7 +2147,7 @@ UINT8 CalcNumMilitiaTrained(UINT8 ubBestLeadership, BOOLEAN fMobile)
ubMilitiaToTrain = __max(3, ubMilitiaToTrain);
}
}
return (ubMilitiaToTrain);
}
@@ -2428,4 +2433,66 @@ UINT32 CalcMilitiaUpkeep( void )
}
return (uiTotalPayment);
}
}
// Flugente: our militia volunteer pool is limited
INT32 GetVolunteerPool()
{
// if this feature is off, we simply assume we have reserves
if ( !gGameExternalOptions.fMilitiaVolunteerPool )
return 999999;
// the pool is actually a float number, only return full volunteers though
return (INT32)LaptopSaveInfo.dMilitiaVolunteerPool;
}
// add/remove volunteers from pool
void AddVolunteers( FLOAT asNum )
{
LaptopSaveInfo.dMilitiaVolunteerPool = max( 0, LaptopSaveInfo.dMilitiaVolunteerPool + asNum );
}
FLOAT CalcHourlyVolunteerGain()
{
FLOAT loyalpopulation = 0.0f; // the number of loyal citizens, from which we derive the hourly volunteer gain
FLOAT populationmodifier = 1.0f; // certain sectors/facilities under our control increase the volunteer gain
for ( UINT8 sX = 1; sX < MAP_WORLD_X - 1; ++sX )
{
for ( UINT8 sY = 1; sY < MAP_WORLD_X - 1; ++sY )
{
// not if the enemy controls this sector
if ( StrategicMap[CALCULATE_STRATEGIC_INDEX( sX, sY )].fEnemyControlled )
continue;
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 )
populationmodifier += gGameExternalOptions.dMilitiaVolunteerMultiplierFarm;
UINT8 ubTownID = StrategicMap[CALCULATE_STRATEGIC_INDEX( sX, sY )].bNameId;
if ( ubTownID != BLANK_SECTOR )
{
UINT16 population = GetSectorPopulation( sX, sY );
loyalpopulation += gTownLoyalty[ubTownID].ubRating * population / 100;
}
}
}
FLOAT hourlygain = loyalpopulation * populationmodifier * gGameExternalOptions.dMilitiaVolunteerGainFactorHourly;
return hourlygain;
}
// every hour, controlled sectors add to our volunteer pool
void UpdateVolunteers()
{
AddVolunteers( CalcHourlyVolunteerGain() );
}
+12
View File
@@ -112,4 +112,16 @@ typedef struct MILITIA_LIST_TYPE
// HEADROCK HAM 3.6: Calculate upkeep costs for militia
UINT32 CalcMilitiaUpkeep( void );
// Flugente: militia volunteer pool
// how many volunteers do we currently have?
INT32 GetVolunteerPool();
// add/remove volunteers from pool
void AddVolunteers( FLOAT asNum );
FLOAT CalcHourlyVolunteerGain();
// every hour, controlled sectors add to our volunteer pool
void UpdateVolunteers();
#endif
+2
View File
@@ -10042,6 +10042,8 @@ STR16 szMilitiaStrategicMovementText[] =
L"Group %d (new)",
L"Group %d",
L"Final",
L"Militia Volunteers: %d (+%5.3f)",
};
// WANNE: Some Chinese specific strings that needs to be in unicode!
+2
View File
@@ -10053,6 +10053,8 @@ STR16 szMilitiaStrategicMovementText[] =
L"Group %d (new)",
L"Group %d",
L"Final",
L"Militia Volunteers: %d (+%5.3f)",
};
#endif //DUTCH
+2
View File
@@ -10091,6 +10091,8 @@ STR16 szMilitiaStrategicMovementText[] =
L"Group %d (new)",
L"Group %d",
L"Final",
L"Militia Volunteers: %d (+%5.3f)",
};
#endif //ENGLISH
+2
View File
@@ -10039,6 +10039,8 @@ STR16 szMilitiaStrategicMovementText[] =
L"Group %d (new)",
L"Group %d",
L"Final",
L"Militia Volunteers: %d (+%5.3f)",
};
#endif //FRENCH
+2
View File
@@ -9870,6 +9870,8 @@ STR16 szMilitiaStrategicMovementText[] =
L"Group %d (new)",
L"Group %d",
L"Final",
L"Militia Volunteers: %d (+%5.3f)",
};
#endif //GERMAN
+2
View File
@@ -10049,6 +10049,8 @@ STR16 szMilitiaStrategicMovementText[] =
L"Group %d (new)",
L"Group %d",
L"Final",
L"Militia Volunteers: %d (+%5.3f)",
};
#endif //ITALIAN
+2
View File
@@ -10064,6 +10064,8 @@ STR16 szMilitiaStrategicMovementText[] =
L"Group %d (new)",
L"Group %d",
L"Final",
L"Militia Volunteers: %d (+%5.3f)",
};
#endif //POLISH
+2
View File
@@ -10037,6 +10037,8 @@ STR16 szMilitiaStrategicMovementText[] =
L"Group %d (new)",
L"Group %d",
L"Final",
L"Militia Volunteers: %d (+%5.3f)",
};