- If ALLOW_MILITIA_STRATEGIC_COMMAND is TRUE and militia can be commanded, oen can order them to retreat from autoresolve

- Final sector in a militia group's path is shown while plotting in the strategic map.


git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@7743 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
Flugente
2015-02-20 23:27:22 +00:00
parent bfe520debf
commit d4432d95c3
16 changed files with 437 additions and 69 deletions
+186 -36
View File
@@ -2637,10 +2637,13 @@ void CreateAutoResolveInterface()
gpAR->iButton[ RETREAT_BUTTON ] =
QuickCreateButton( gpAR->iButtonImage[ RETREAT_BUTTON ], (INT16)(gpAR->sCenterStartX+51), (INT16)(iScreenHeightOffset + 274+gpAR->bVerticalOffset), BUTTON_TOGGLE, MSYS_PRIORITY_HIGH,
DEFAULT_MOVE_CALLBACK, RetreatButtonCallback );
if( !gpAR->ubMercs )
// no retreat possible if no mercs are present and militia isn't present or cannot be commanded
if ( !gpAR->ubMercs && (!gpAR->ubCivs || !CanGiveStrategicMilitiaMoveOrder( gpAR->ubSectorX, gpAR->ubSectorY )) )
{
DisableButton( gpAR->iButton[ RETREAT_BUTTON ] );
}
SpecifyGeneralButtonTextAttributes( gpAR->iButton[ RETREAT_BUTTON ], gpStrategicString[STR_AR_RETREAT_BUTTON], BLOCKFONT2, 169, FONT_NEARBLACK );
gpAR->iButton[ BANDAGE_BUTTON ] =
@@ -2841,11 +2844,10 @@ DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"Autoresolve2");
}
else
{
UINT8 ubPromotions;
// this will check for promotions and handle them for you
if( fDeleteForGood && ( gpCivs[ i ].pSoldier->ubMilitiaKills > 0) && ( ubCurrentRank < ELITE_MILITIA ) )
{
ubPromotions = CheckOneMilitiaForPromotion( gpCivs[ i ].pSoldier->sSectorX, gpCivs[ i ].pSoldier->sSectorY, ubCurrentRank, gpCivs[ i ].pSoldier->ubMilitiaKills );
UINT8 ubPromotions = CheckOneMilitiaForPromotion( gpCivs[i].pSoldier->sSectorX, gpCivs[i].pSoldier->sSectorY, ubCurrentRank, gpCivs[i].pSoldier->ubMilitiaKills );
if( ubPromotions )
{
if( ubPromotions == 2 )
@@ -3025,7 +3027,7 @@ void RetreatButtonCallback( GUI_BUTTON *btn, INT32 reason )
if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
{
INT32 i;
for( i = 0; i < gpAR->ubMercs; i++ )
for ( i = 0; i < gpAR->ubMercs; ++i )
{
if( !(gpMercs[ i ].uiFlags & (CELL_RETREATING|CELL_RETREATED)) )
{
@@ -3036,8 +3038,26 @@ void RetreatButtonCallback( GUI_BUTTON *btn, INT32 reason )
gpMercs[ i ].usAttack = 0;
}
}
// Flugente: militia can be ordered to retreat
if ( gGameExternalOptions.fMilitiaStrategicCommand )
{
for ( INT32 i = 0; i < gpAR->ubCivs; ++i )
{
if ( !(gpCivs[i].uiFlags & (CELL_RETREATING | CELL_RETREATED)) )
{
gpCivs[i].uiFlags |= CELL_RETREATING | CELL_DIRTY;
//Gets to retreat after a total of 2 attacks.
gpCivs[i].usNextAttack = (UINT16)((1000 + gpCivs[i].usNextAttack * 2 + PreRandom( 2000 - gpCivs[i].usAttack )) * 2);
gpAR->usPlayerAttack -= gpCivs[i].usAttack;
gpCivs[i].usAttack = 0;
}
}
}
if( gpAR->pRobotCell )
{ //if robot is retreating, set the retreat time to be the same as the robot's controller.
{
//if robot is retreating, set the retreat time to be the same as the robot's controller.
UINT8 ubRobotControllerID;
ubRobotControllerID = gpAR->pRobotCell->pSoldier->ubRobotRemoteHolderID;
@@ -3049,10 +3069,12 @@ void RetreatButtonCallback( GUI_BUTTON *btn, INT32 reason )
gpAR->pRobotCell->usNextAttack = 0xffff;
return;
}
for( i = 0; i < gpAR->ubMercs; i++ )
for( i = 0; i < gpAR->ubMercs; ++i )
{
if( ubRobotControllerID == gpMercs[ i ].pSoldier->ubID )
{ //Found the controller, make the robot's retreat time match the contollers.
{
//Found the controller, make the robot's retreat time match the contollers.
gpAR->pRobotCell->usNextAttack = gpMercs[ i ].usNextAttack;
return;
}
@@ -4560,11 +4582,14 @@ void AttackTarget( SOLDIERCELL *pAttacker, SOLDIERCELL *pTarget )
usAttack = (UINT16)(pAttacker->usAttack + PreRandom((INT16)(gGameExternalOptions.iAutoResolveLuckFactor*1000.0) - pAttacker->usAttack ));
else
usAttack = (UINT16)(950 + PreRandom( 50 ));
if( pTarget->uiFlags & CELL_RETREATING && !(pAttacker->uiFlags & CELL_FEMALECREATURE) )
{ //Attacking a retreating merc is harder. Modify the attack value to 70% of it's value.
{
//Attacking a retreating merc is harder. Modify the attack value to 70% of it's value.
//This allows retreaters to have a better chance of escaping.
usAttack = usAttack * 7 / 10;
}
if( pTarget->usDefence < 950 )
usDefence = (UINT16)(pTarget->usDefence + PreRandom((INT16)(gGameExternalOptions.iAutoResolveLuckFactor*1000.0) - pTarget->usDefence ));
else
@@ -4739,11 +4764,11 @@ void AttackTarget( SOLDIERCELL *pAttacker, SOLDIERCELL *pTarget )
// SANDRO - increased mercs' offense/deffense rating
if ( pAttacker->uiFlags & CELL_MERC && gGameExternalOptions.sMercsAutoresolveOffenseBonus != 0 )
{
ubImpact += (iImpact * gGameExternalOptions.sMercsAutoresolveOffenseBonus / 150);
ubImpact += (ubImpact * gGameExternalOptions.sMercsAutoresolveOffenseBonus / 150);
}
else if ( pTarget->uiFlags & CELL_MERC && gGameExternalOptions.sMercsAutoresolveDeffenseBonus != 0 && (iImpact > 3) )
else if ( pTarget->uiFlags & CELL_MERC && gGameExternalOptions.sMercsAutoresolveDeffenseBonus != 0 && (ubImpact > 3) )
{
ubImpact = max( 3, ((iImpact * (100 - (gGameExternalOptions.sMercsAutoresolveDeffenseBonus / 2))) / 100) );
ubImpact = max( 3, ((ubImpact * (100 - (gGameExternalOptions.sMercsAutoresolveDeffenseBonus / 2))) / 100) );
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -4816,11 +4841,11 @@ void AttackTarget( SOLDIERCELL *pAttacker, SOLDIERCELL *pTarget )
// SANDRO - increased mercs' offense/deffense rating
if ( pAttacker->uiFlags & CELL_MERC && gGameExternalOptions.sMercsAutoresolveOffenseBonus != 0 )
{
iImpact += (iImpact * gGameExternalOptions.sMercsAutoresolveOffenseBonus / 150);
ubImpact += (ubImpact * gGameExternalOptions.sMercsAutoresolveOffenseBonus / 150);
}
else if ( pTarget->uiFlags & CELL_MERC && gGameExternalOptions.sMercsAutoresolveDeffenseBonus != 0 && (iImpact > 3) )
else if ( pTarget->uiFlags & CELL_MERC && gGameExternalOptions.sMercsAutoresolveDeffenseBonus != 0 && (ubImpact > 3) )
{
iImpact = max( 3, ((iImpact * (100 - (gGameExternalOptions.sMercsAutoresolveDeffenseBonus / 2))) / 100) );
ubImpact = max( 3, ((ubImpact * (100 - (gGameExternalOptions.sMercsAutoresolveDeffenseBonus / 2))) / 100) );
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -4950,12 +4975,14 @@ void AttackTarget( SOLDIERCELL *pAttacker, SOLDIERCELL *pTarget )
pTarget->pSoldier->DoMercBattleSound( (INT8)( BATTLE_SOUND_HIT1 + PreRandom( 2 ) ) );
}
if( !(pTarget->uiFlags & CELL_CREATURE) && iNewLife < OKLIFE && pTarget->pSoldier->stats.bLife >= OKLIFE )
{ //the hit caused the merc to fall. Play the falling sound
{
//the hit caused the merc to fall. Play the falling sound
PlayAutoResolveSample( (UINT8)FALL_1, RATE_11025, 50, 1, MIDDLEPAN );
pTarget->uiFlags &= ~CELL_RETREATING;
}
if( iNewLife <= 0 )
{ //soldier has been killed
{
//soldier has been killed
// Flugente: campaign stats
gCurrentIncident.AddStat( pTarget->pSoldier, CAMPAIGNHISTORY_TYPE_KILL );
@@ -5368,34 +5395,56 @@ BOOLEAN IsBattleOver()
INT32 i;
INT32 iNumInvolvedMercs = 0;
INT32 iNumMercsRetreated = 0;
INT32 iNumInvolvedMilitia = 0;
INT32 iNumMilitiaRetreated = 0;
BOOLEAN fOnlyEPCsLeft = TRUE;
if( gpAR->ubBattleStatus != BATTLE_IN_PROGRESS )
return TRUE;
for( i = 0; i < gpAR->ubMercs; i++ )
for( i = 0; i < gpAR->ubMercs; ++i )
{
if( !(gpMercs[ i ].uiFlags & CELL_RETREATED) && gpMercs[ i ].pSoldier->stats.bLife )
{
if( !(gpMercs[ i ].uiFlags & CELL_EPC) )
{
fOnlyEPCsLeft = FALSE;
iNumInvolvedMercs++;
++iNumInvolvedMercs;
}
}
if( gpMercs[ i ].uiFlags & CELL_RETREATED )
{
iNumMercsRetreated++;
++iNumMercsRetreated;
}
}
for ( i = 0; i < gpAR->ubCivs; ++i )
{
if ( !(gpCivs[i].uiFlags & CELL_RETREATED) && gpCivs[i].pSoldier->stats.bLife )
{
++iNumInvolvedMilitia;
}
else if ( gpCivs[i].uiFlags & CELL_RETREATED )
{
++iNumMilitiaRetreated;
}
}
if( gpAR->pRobotCell )
{ //Do special robot checks
{
//Do special robot checks
SOLDIERTYPE *pRobot;
pRobot = gpAR->pRobotCell->pSoldier;
if( pRobot->ubRobotRemoteHolderID == NOBODY )
{ //Robot can't fight anymore.
{
//Robot can't fight anymore.
gpAR->usPlayerAttack -= gpAR->pRobotCell->usAttack;
gpAR->pRobotCell->usAttack = 0;
if( iNumInvolvedMercs == 1 && !gpAR->ubAliveCivs )
{ //Robot is the only one left in battle, so instantly kill him.
{
//Robot is the only one left in battle, so instantly kill him.
pRobot->DoMercBattleSound( BATTLE_SOUND_DIE1 );
pRobot->stats.bLife = 0;
gpAR->ubAliveMercs--;
@@ -5403,8 +5452,10 @@ BOOLEAN IsBattleOver()
}
}
}
if( !gpAR->ubAliveCivs && !iNumInvolvedMercs && iNumMercsRetreated )
{ //RETREATED
{
//RETREATED
gpAR->ubBattleStatus = BATTLE_RETREAT;
// wake everyone up
@@ -5412,22 +5463,36 @@ BOOLEAN IsBattleOver()
RetreatAllInvolvedPlayerGroups( );
}
else if ( !iNumInvolvedMercs && !iNumInvolvedMilitia && iNumMilitiaRetreated && gGameExternalOptions.fMilitiaStrategicCommand )
{
//RETREATED
gpAR->ubBattleStatus = BATTLE_RETREAT;
// wake everyone up
WakeUpAllMercsInSectorUnderAttack( );
RetreatAllInvolvedMilitiaGroups( );
}
else if( !gpAR->ubAliveCivs && !iNumInvolvedMercs )
{ //DEFEAT
{
//DEFEAT
if( fOnlyEPCsLeft )
{ //Kill the EPCs.
for( i = 0; i < gpAR->ubMercs; i++ )
{
//Kill the EPCs.
for( i = 0; i < gpAR->ubMercs; ++i )
{
if( gpMercs[ i ].uiFlags & CELL_EPC )
{
gpMercs[ i ].pSoldier->DoMercBattleSound( BATTLE_SOUND_DIE1 );
gpMercs[ i ].pSoldier->stats.bLife = 0;
gpMercs[ i ].pSoldier->iHealableInjury = 0; // added by SANDRO
gpAR->ubAliveMercs--;
--gpAR->ubAliveMercs;
}
}
}
for( i = 0; i < gpAR->ubEnemies; i++ )
for( i = 0; i < gpAR->ubEnemies; ++i )
{
if( gpEnemies[ i ].pSoldier->stats.bLife )
{
@@ -5445,14 +5510,17 @@ BOOLEAN IsBattleOver()
gpAR->ubBattleStatus = BATTLE_DEFEAT;
}
else if( !gpAR->ubAliveEnemies )
{ //VICTORY
{
//VICTORY
gpAR->ubBattleStatus = BATTLE_VICTORY;
}
else
{
return FALSE;
}
SetupDoneInterface();
return TRUE;
}
@@ -5953,26 +6021,108 @@ BOOLEAN ProcessLoyalty()
void CheckForSoldiersWhoRetreatedIntoMilitiaHeldSectors()
{
for(int sX = 1; sX < ( MAP_WORLD_X - 1 ); sX++ ) {
for(int sY = 1; sY < ( MAP_WORLD_Y - 1); sY++ ) {
for( int sX = 1; sX < ( MAP_WORLD_X - 1 ); ++sX )
{
for( int sY = 1; sY < ( MAP_WORLD_Y - 1); ++sY )
{
// Check if there is a sector where enemies retreated to and there are also militia present
if ( (NumNonPlayerTeamMembersInSector( sX, sY, ENEMY_TEAM ) > 0) &&
(NumNonPlayerTeamMembersInSector( sX, sY, MILITIA_TEAM ) > 0) &&
(!gTacticalStatus.fEnemyInSector)) {
(!gTacticalStatus.fEnemyInSector))
{
unsigned mercCnt = 0;
for( int i = gTacticalStatus.Team[ OUR_TEAM ].bFirstID; i <= gTacticalStatus.Team[ OUR_TEAM ].bLastID; i++ ) {
for( int i = gTacticalStatus.Team[ OUR_TEAM ].bFirstID; i <= gTacticalStatus.Team[ OUR_TEAM ].bLastID; ++i )
{
if( MercPtrs[ i ]->bActive && MercPtrs[ i ]->stats.bLife && !(MercPtrs[ i ]->flags.uiStatusFlags & SOLDIER_VEHICLE) && !AM_A_ROBOT( MercPtrs[ i ] ) )
{ //Merc is active and alive, and not a vehicle or robot
if ((MercPtrs[ i ]->sSectorX == sX) &&(MercPtrs[ i ]->sSectorY == sY) && (MercPtrs[ i ]->bSectorZ == 0)) {
{
//Merc is active and alive, and not a vehicle or robot
if ((MercPtrs[ i ]->sSectorX == sX) &&(MercPtrs[ i ]->sSectorY == sY) && (MercPtrs[ i ]->bSectorZ == 0))
{
++mercCnt;
}
}
}
// If there are PC mercs here the player will have to handle the battle
if (mercCnt == 0) {
if (mercCnt == 0)
{
// EnterAutoResolveMode ((UINT8)sX, (UINT8)sY);
}
}
}
}
}
// Flugente: have all militia in autoresolve drop their gear and be promoted in necessary
void AutoResolveMilitiaDropAndPromote()
{
gbGreenToElitePromotions = 0;
gbGreenToRegPromotions = 0;
gbRegToElitePromotions = 0;
gbMilitiaPromotions = 0;
for ( INT32 i = 0; i < MAX_AR_TEAM_SIZE; ++i )
{
if ( gpCivs[i].pSoldier )
{
UINT8 ubCurrentRank = GREEN_MILITIA;
switch ( gpCivs[i].pSoldier->ubSoldierClass )
{
case SOLDIER_CLASS_GREEN_MILITIA: ubCurrentRank = GREEN_MILITIA; break;
case SOLDIER_CLASS_REG_MILITIA: ubCurrentRank = REGULAR_MILITIA; break;
case SOLDIER_CLASS_ELITE_MILITIA: ubCurrentRank = ELITE_MILITIA; break;
default:
#ifdef JA2BETAVERSION
ScreenMsg( FONT_RED, MSG_ERROR, L"Removing autoresolve militia with invalid ubSoldierClass %d.", gpCivs[i].pSoldier->ubSoldierClass );
#endif
break;
}
// Flugente: drop sector equipment
gpCivs[i].pSoldier->DropSectorEquipment( );
if ( gpCivs[i].pSoldier->stats.bLife < OKLIFE / 2 )
{
StrategicRemoveMilitiaFromSector( gpCivs[i].pSoldier->sSectorX, gpCivs[i].pSoldier->sSectorY, ubCurrentRank, 1 );
}
else if ( gpCivs[i].pSoldier->stats.bLife >= OKLIFE / 2 )
{
// this will check for promotions and handle them for you
if ( gpCivs[i].pSoldier->ubMilitiaKills && ubCurrentRank < ELITE_MILITIA )
{
UINT8 ubPromotions = CheckOneMilitiaForPromotion( gpCivs[i].pSoldier->sSectorX, gpCivs[i].pSoldier->sSectorY, ubCurrentRank, gpCivs[i].pSoldier->ubMilitiaKills );
if ( ubPromotions )
{
if ( ubPromotions == 2 )
{
++gbGreenToElitePromotions;
++gbMilitiaPromotions;
ubCurrentRank = ELITE_MILITIA;
}
else if ( gpCivs[i].pSoldier->ubSoldierClass == SOLDIER_CLASS_GREEN_MILITIA )
{
++gbGreenToRegPromotions;
++gbMilitiaPromotions;
ubCurrentRank = REGULAR_MILITIA;
}
else if ( gpCivs[i].pSoldier->ubSoldierClass == SOLDIER_CLASS_REG_MILITIA )
{
++gbRegToElitePromotions;
++gbMilitiaPromotions;
ubCurrentRank = ELITE_MILITIA;
}
}
}
// in any case, we had our chance to be promoted, clear the counter
gpCivs[i].pSoldier->ubMilitiaKills = 0;
}
// DO NOT DELETE HERE!!!!
//TacticalRemoveSoldierPointer( gpCivs[i].pSoldier, FALSE );
//memset( &gpCivs[i], 0, sizeof(SOLDIERCELL) );
}
}
}
+3
View File
@@ -21,4 +21,7 @@ BOOLEAN GetCurrentBattleSectorXYZ( INT16 *psSectorX, INT16 *psSectorY, INT16 *ps
void CheckForSoldiersWhoRetreatedIntoMilitiaHeldSectors();
// Flugente: have all militia in autoresolve drop their gear and be promoted in necessary
void AutoResolveMilitiaDropAndPromote();
#endif
+34 -2
View File
@@ -960,7 +960,8 @@ UINT32 DrawMap( void )
RestoreClipRegionToFullScreen( );
CheckForSoldiersWhoRetreatedIntoMilitiaHeldSectors();
// Flugente: this function does not do anything... so I'm commenting its use out
//CheckForSoldiersWhoRetreatedIntoMilitiaHeldSectors();
return( TRUE );
}
@@ -7688,7 +7689,7 @@ void DisplayMilitiaGroupBox()
UINT16 MILITIAGROUPBOX_HEIGHT_LINE = 14;
UINT16 MILITIAGROUPBOX_WIDTH = MILITIAGROUPBOX_WIDTH_NAME + 3 * MILITIAGROUPBOX_WIDTH_TYPEBOX + MILITIAGROUPBOX_WIDTH_SECTOR + MILITIAGROUPBOX_WIDTH_ETA;
UINT16 MILITIAGROUPBOX_WIDTH = MILITIAGROUPBOX_WIDTH_NAME + 3 * MILITIAGROUPBOX_WIDTH_TYPEBOX + 2 * MILITIAGROUPBOX_WIDTH_SECTOR + MILITIAGROUPBOX_WIDTH_ETA;
// we need a header line, one for the sector, and one for each group present
UINT8 usMapX = GET_X_FROM_STRATEGIC_INDEX( gMilitiaPlotStartSector );
@@ -7750,6 +7751,11 @@ void DisplayMilitiaGroupBox()
swprintf( sString, szMilitiaStrategicMovementText[4] );
mprintf( dispX, dispY, sString );
dispX += MILITIAGROUPBOX_WIDTH_ETA;
swprintf( sString, szMilitiaStrategicMovementText[7] );
mprintf( dispX, dispY, sString );
dispX += MILITIAGROUPBOX_WIDTH_SECTOR;
dispX = gMilitiaGroupBoxX;
dispY += MILITIAGROUPBOX_HEIGHT_LINE;
@@ -7783,6 +7789,11 @@ void DisplayMilitiaGroupBox()
swprintf( sString, L"--:--" );
mprintf( dispX, dispY, sString );
dispX += MILITIAGROUPBOX_WIDTH_ETA;
swprintf( sString, L"--" );
mprintf( dispX, dispY, sString );
dispX += MILITIAGROUPBOX_WIDTH_SECTOR;
dispY += MILITIAGROUPBOX_HEIGHT_LINE;
@@ -7808,6 +7819,22 @@ void DisplayMilitiaGroupBox()
CHAR16 wSectorName[64];
GetShortSectorString( pGroup->ubNextX, pGroup->ubNextY, wSectorName );
CHAR16 wFinalSectorName[64];
swprintf( sString, L"--" );
// determine the final destination of this group
{
INT16 finalsector = GetLastSectorIdInMilitiaGroupPath( pGroup->ubGroupID );
if ( finalsector > -1 )
{
GetShortSectorString( SECTORX( finalsector ), SECTORY( finalsector ), wFinalSectorName );
}
else
{
GetShortSectorString( pGroup->ubNextX, pGroup->ubNextY, wFinalSectorName );
}
}
// show ETA
CHAR16 timestring[64];
UINT32 uiArrivalTime = GetWorldTotalMin( ) + CalculateTravelTimeOfGroup( pGroup );
@@ -7920,6 +7947,11 @@ void DisplayMilitiaGroupBox()
swprintf( sString, L"%s", timestring );
mprintf( dispX, dispY, sString );
dispX += MILITIAGROUPBOX_WIDTH_ETA;
swprintf( sString, L"%s", wFinalSectorName );
mprintf( dispX, dispY, sString );
dispX += MILITIAGROUPBOX_WIDTH_SECTOR;
dispY += MILITIAGROUPBOX_HEIGHT_LINE;
+138 -1
View File
@@ -48,6 +48,7 @@
#include "Tactical Save.h"
#include "message.h"
#include "CampaignStats.h" // added by Flugente
#include "militiasquads.h" // added by Flugente
#endif
#ifdef JA2UB
@@ -2011,7 +2012,6 @@ void RetreatAllInvolvedPlayerGroups( void )
{
GROUP *pGroup;
// make sure guys stop their off duty assignments, like militia training!
// but don't exit vehicles - drive off in them!
PutNonSquadMercsInBattleSectorOnSquads( FALSE );
@@ -2032,6 +2032,123 @@ void RetreatAllInvolvedPlayerGroups( void )
}
}
void RetreatAllInvolvedMilitiaGroups()
{
// first, determine in which sector we are
// pick the non-hostile-occupied, reachable adjacent sector with the shortest travel time
INT16 sBattleSectorX, sBattleSectorY, sBattleSectorZ;
if ( !GetCurrentBattleSectorXYZ( &sBattleSectorX, &sBattleSectorY, &sBattleSectorZ ) )
{
// well... this sucks. We are in retreat code, but no battle is on... abort this
return;
}
// as we move the militia to another sector, anything that modifies them has to be done now - RemoveAutoResolveInterface is too late
// as we don't want to make the location of that dependend on some state, we use a trick:
// we drop their gear here, and promote them right now. They can then be properly deleted later on.
AutoResolveMilitiaDropAndPromote();
// dissolve all militia groups here
INT16 newX = 0;
INT16 newY = 0;
BOOLEAN found = FALSE;
GROUP* pGroup = gpGroupList;
while ( pGroup )
{
if ( MilitiaGroupInvolvedInThisCombat( pGroup ) )
{
// if a group's previous sector was different, pick it
if ( pGroup->ubPrevX != 0 && pGroup->ubPrevY != 0 && ( pGroup->ubPrevX != pGroup->ubSectorX || pGroup->ubPrevY != pGroup->ubSectorY ) )
{
newX = pGroup->ubPrevX;
newY = pGroup->ubPrevY;
found = TRUE;
}
GROUP* pDeleteGroup = pGroup;
pGroup = pGroup->next;
ClearMercPathsAndWaypointsForAllInGroup( pDeleteGroup );
DissolveMilitiaGroup( pDeleteGroup->ubGroupID );
}
else
pGroup = pGroup->next;
}
// create new group and instantly place it in new sector
SECTORINFO *pSector = &SectorInfo[SECTOR( sBattleSectorX, sBattleSectorY )];
if ( !pSector )
return;
pGroup = CreateNewMilitiaGroupDepartingFromSector( SECTOR( sBattleSectorX, sBattleSectorY ), pSector->ubNumberOfCivsAtLevel[0], pSector->ubNumberOfCivsAtLevel[1], pSector->ubNumberOfCivsAtLevel[2] );
pSector->ubNumberOfCivsAtLevel[0] = 0;
pSector->ubNumberOfCivsAtLevel[1] = 0;
pSector->ubNumberOfCivsAtLevel[2] = 0;
// if we haven't found a good direction yet, we have to pick the best adjacent sector we can find
if ( !found )
{
INT32 besttime = 1000000;
UINT8 usDirection = NORTH_STRATEGIC_MOVE;
for ( UINT8 i = 0; i < 4; ++i )
{
INT16 loopX = sBattleSectorX;
INT16 loopY = sBattleSectorY;
if ( i == 0 )
{
++loopY;
usDirection = SOUTH_STRATEGIC_MOVE;
}
else if ( i == 1 )
{
++loopX;
usDirection = EAST_STRATEGIC_MOVE;
}
else if ( i == 2 )
{
--loopY;
usDirection = NORTH_STRATEGIC_MOVE;
}
else if ( i == 3 )
{
--loopX;
usDirection = WEST_STRATEGIC_MOVE;
}
if ( loopX < 1 || loopX >= MAP_WORLD_X - 1 || loopY < 1 || loopY >= MAP_WORLD_Y - 1 )
continue;
// don't retreat into an occupied sector!
if ( NumNonPlayerTeamMembersInSector( loopX, loopY, ENEMY_TEAM ) > 0 )
continue;
INT32 uiTraverseTime = GetSectorMvtTimeForGroup( (UINT8)SECTOR( pGroup->ubSectorX, pGroup->ubSectorY ), usDirection, pGroup );
if ( uiTraverseTime < besttime )
{
besttime = uiTraverseTime;
newX = loopX;
newY = loopY;
found = TRUE;
}
}
}
// if we found a good direction, move the group
if ( found )
{
// while militia groups travel, they are not between sectors. As a result, when we retreat a militia group, we have to move them to the next sector immediately
// do NOT check for a new battle - when calling this function, we are likely still in autoresolve, so this would cause hiccups
PlaceGroupInSector( pGroup->ubGroupID, pGroup->ubSectorX, pGroup->ubSectorY, newX, newY, 0, FALSE );
}
// delete group afterwards, if it hasn't been deleted already - the militia will become static
if ( pGroup )
DissolveMilitiaGroup( pGroup->ubGroupID );
}
BOOLEAN PlayerMercInvolvedInThisCombat( SOLDIERTYPE *pSoldier )
{
@@ -2081,6 +2198,26 @@ BOOLEAN PlayerGroupInvolvedInThisCombat( GROUP *pGroup )
return( FALSE );
}
BOOLEAN MilitiaGroupInvolvedInThisCombat( GROUP *pGroup )
{
Assert( pGroup );
// player group, non-empty, not between sectors, in the right sector, isn't a group of in transit, dead, or POW mercs,
// and either not the helicopter group, or the heli is on the ground
if ( pGroup->usGroupTeam == MILITIA_TEAM && pGroup->ubGroupSize &&
!pGroup->fBetweenSectors )
{
if ( CurrentBattleSectorIs( pGroup->ubSectorX, pGroup->ubSectorY, pGroup->ubSectorZ ) )
{
// involved
return(TRUE);
}
}
// not involved
return(FALSE);
}
BOOLEAN CurrentBattleSectorIs( INT16 sSectorX, INT16 sSectorY, INT16 sSectorZ )
{
+2
View File
@@ -85,8 +85,10 @@ void WakeUpAllMercsInSectorUnderAttack( void );
void ClearMovementForAllInvolvedPlayerGroups( void );
void RetreatAllInvolvedPlayerGroups( void );
void RetreatAllInvolvedMilitiaGroups( void );
BOOLEAN PlayerGroupInvolvedInThisCombat( GROUP *pGroup );
BOOLEAN MilitiaGroupInvolvedInThisCombat( GROUP *pGroup );
BOOLEAN PlayerMercInvolvedInThisCombat( SOLDIERTYPE *pSoldier );
BOOLEAN CurrentBattleSectorIs( INT16 sSectorX, INT16 sSectorY, INT16 sSectorZ );
+12 -9
View File
@@ -3091,16 +3091,19 @@ void SetGroupSectorValue( INT16 sSectorX, INT16 sSectorY, INT16 sSectorZ, UINT8
pGroup->ubOriginalSector = (UINT8)SECTOR( pGroup->ubSectorX, pGroup->ubSectorY );
DeleteStrategicEvent( EVENT_GROUP_ARRIVAL, pGroup->ubGroupID );
// set all of the mercs in the group so that they are in the new sector too.
pPlayer = pGroup->pPlayerList;
while( pPlayer )
if ( pGroup->usGroupTeam == OUR_TEAM )
{
pPlayer->pSoldier->sSectorX = sSectorX;
pPlayer->pSoldier->sSectorY = sSectorY;
pPlayer->pSoldier->bSectorZ = (UINT8)sSectorZ;
pPlayer->pSoldier->flags.fBetweenSectors = FALSE;
pPlayer->pSoldier->flags.uiStatusFlags &= ~SOLDIER_SHOULD_BE_TACTICALLY_VALID;
pPlayer = pPlayer->next;
// set all of the mercs in the group so that they are in the new sector too.
pPlayer = pGroup->pPlayerList;
while( pPlayer )
{
pPlayer->pSoldier->sSectorX = sSectorX;
pPlayer->pSoldier->sSectorY = sSectorY;
pPlayer->pSoldier->bSectorZ = (UINT8)sSectorZ;
pPlayer->pSoldier->flags.fBetweenSectors = FALSE;
pPlayer->pSoldier->flags.uiStatusFlags &= ~SOLDIER_SHOULD_BE_TACTICALLY_VALID;
pPlayer = pPlayer->next;
}
}
CheckAndHandleUnloadingOfCurrentWorld();
+51 -21
View File
@@ -1221,10 +1221,28 @@ INT16 GetLastSectorIdInVehiclePath( INT32 iId )
}
return sLastSector;
}
// get id of last sector in group'S path list
INT16 GetLastSectorIdInMilitiaGroupPath( UINT8 uGroupId )
{
INT16 sLastSector = -1;
INT16 militiapathslot = GetMilitiaPathSlot( uGroupId );
if ( militiapathslot > -1 )
{
PathStPtr pNode = gMilitiaPath[militiapathslot].path;
while ( pNode )
{
sLastSector = (INT16)(pNode->uiSectorId);
pNode = pNode->pNext;
}
}
return sLastSector;
}
PathStPtr CopyPaths( PathStPtr pSourcePath, PathStPtr pDestPath )
@@ -1974,32 +1992,44 @@ void ClearMercPathsAndWaypointsForAllInGroup( GROUP *pGroup )
PLAYERGROUP *pPlayer = NULL;
SOLDIERTYPE *pSoldier = NULL;
pPlayer = pGroup->pPlayerList;
while( pPlayer )
if ( pGroup->usGroupTeam == OUR_TEAM )
{
pSoldier = pPlayer->pSoldier;
if ( pSoldier != NULL )
pPlayer = pGroup->pPlayerList;
while( pPlayer )
{
ClearPathForSoldier( pSoldier );
pSoldier = pPlayer->pSoldier;
if ( pSoldier != NULL )
{
ClearPathForSoldier( pSoldier );
}
pPlayer = pPlayer->next;
}
pPlayer = pPlayer->next;
// if it's a vehicle
if ( pGroup->fVehicle )
{
INT32 iVehicleId = -1;
VEHICLETYPE *pVehicle = NULL;
iVehicleId = GivenMvtGroupIdFindVehicleId( pGroup->ubGroupID );
Assert ( iVehicleId != -1 );
pVehicle = &( pVehicleList[ iVehicleId ] );
// clear the path for that vehicle
pVehicle->pMercPath = ClearStrategicPathList( pVehicle->pMercPath, pVehicle->ubMovementGroup );
}
}
// if it's a vehicle
if ( pGroup->fVehicle )
else if ( pGroup->usGroupTeam == MILITIA_TEAM )
{
INT32 iVehicleId = -1;
VEHICLETYPE *pVehicle = NULL;
INT16 militiapathslot = GetMilitiaPathSlot( pGroup->ubGroupID );
iVehicleId = GivenMvtGroupIdFindVehicleId( pGroup->ubGroupID );
Assert ( iVehicleId != -1 );
pVehicle = &( pVehicleList[ iVehicleId ] );
// clear the path for that vehicle
pVehicle->pMercPath = ClearStrategicPathList( pVehicle->pMercPath, pVehicle->ubMovementGroup );
if ( militiapathslot > -1 )
{
gMilitiaPath[militiapathslot].path = ClearStrategicPathList( gMilitiaPath[militiapathslot].path, pGroup->ubGroupID );
}
}
// clear the waypoints for this group too - no mercpath = no waypoints!
+3
View File
@@ -73,6 +73,9 @@ INT16 GetLastSectorIdInCharactersPath( SOLDIERTYPE *pCharacter );
// get id of last sector in mercs path list
INT16 GetLastSectorIdInVehiclePath( INT32 iId );
// get id of last sector in group'S path list
INT16 GetLastSectorIdInMilitiaGroupPath( UINT8 uGroupId );
// copy paths
PathStPtr CopyPaths( PathStPtr pSourcePath, PathStPtr pDestPath );
+1
View File
@@ -10041,6 +10041,7 @@ STR16 szMilitiaStrategicMovementText[] =
L"ETA",
L"Group %d (new)",
L"Group %d",
L"Final",
};
// WANNE: Some Chinese specific strings that needs to be in unicode!
+1
View File
@@ -10052,6 +10052,7 @@ STR16 szMilitiaStrategicMovementText[] =
L"ETA",
L"Group %d (new)",
L"Group %d",
L"Final",
};
#endif //DUTCH
+1
View File
@@ -10090,6 +10090,7 @@ STR16 szMilitiaStrategicMovementText[] =
L"ETA",
L"Group %d (new)",
L"Group %d",
L"Final",
};
#endif //ENGLISH
+1
View File
@@ -10038,6 +10038,7 @@ STR16 szMilitiaStrategicMovementText[] =
L"ETA",
L"Group %d (new)",
L"Group %d",
L"Final",
};
#endif //FRENCH
+1
View File
@@ -9869,6 +9869,7 @@ STR16 szMilitiaStrategicMovementText[] =
L"ETA",
L"Group %d (new)",
L"Group %d",
L"Final",
};
#endif //GERMAN
+1
View File
@@ -10048,6 +10048,7 @@ STR16 szMilitiaStrategicMovementText[] =
L"ETA",
L"Group %d (new)",
L"Group %d",
L"Final",
};
#endif //ITALIAN
+1
View File
@@ -10063,6 +10063,7 @@ STR16 szMilitiaStrategicMovementText[] =
L"ETA",
L"Group %d (new)",
L"Group %d",
L"Final",
};
#endif //POLISH
+1
View File
@@ -10036,6 +10036,7 @@ STR16 szMilitiaStrategicMovementText[] =
L"ETA",
L"Group %d (new)",
L"Group %d",
L"Final",
};