New feature: bloodcat/zombie/bandit raids on player-controlled sectors

For more info, see http://thepit.ja-galaxy-forum.com/index.php?t=msg&th=23711&goto=353154&#msg_353154

Requires GameDir >= r2420

git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@8554 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
Flugente
2018-04-15 14:42:01 +00:00
parent 1ea69989ed
commit 80674249cc
52 changed files with 1628 additions and 479 deletions
+18 -1
View File
@@ -2087,7 +2087,24 @@ void LoadGameExternalOptions()
gGameExternalOptions.gEnemyHeliSAMDamage_Var = iniReader.ReadInteger( "Enemy Helicopter Settings", "ENEMYHELI_SAM_DAMAGE_VAR", 30, 10, 100 ); gGameExternalOptions.gEnemyHeliSAMDamage_Var = iniReader.ReadInteger( "Enemy Helicopter Settings", "ENEMYHELI_SAM_DAMAGE_VAR", 30, 10, 100 );
gGameExternalOptions.gEnemyHeliMANPADSDamage_Base = iniReader.ReadInteger( "Enemy Helicopter Settings", "ENEMYHELI_MANPADS_DAMAGE_BASE", 40, 10, 100 ); gGameExternalOptions.gEnemyHeliMANPADSDamage_Base = iniReader.ReadInteger( "Enemy Helicopter Settings", "ENEMYHELI_MANPADS_DAMAGE_BASE", 40, 10, 100 );
gGameExternalOptions.gEnemyHeliMANPADSDamage_Var = iniReader.ReadInteger( "Enemy Helicopter Settings", "ENEMYHELI_MANPADS_DAMAGE_VAR", 80, 10, 100 ); gGameExternalOptions.gEnemyHeliMANPADSDamage_Var = iniReader.ReadInteger( "Enemy Helicopter Settings", "ENEMYHELI_MANPADS_DAMAGE_VAR", 80, 10, 100 );
// Flugente: raids
//################# Raid Settings ##################
gGameExternalOptions.gRaid_Bloodcats = iniReader.ReadBoolean( "Raid Settings", "RAID_BLOODCATS", FALSE );
gGameExternalOptions.gRaid_Zombies = iniReader.ReadBoolean( "Raid Settings", "RAID_ZOMBIES", FALSE );
gGameExternalOptions.gRaid_Bandits = iniReader.ReadBoolean( "Raid Settings", "RAID_BANDITS", FALSE );
gGameExternalOptions.gRaidReplenish_BaseValue = iniReader.ReadInteger( "Raid Settings", "RAID_REPLENISH_BASEVALUE", 3, 1, 100 );
gGameExternalOptions.gRaidMaxSize_Bloodcats = iniReader.ReadInteger( "Raid Settings", "RAID_MAXSIZE_BLOODCATS", 8, 1, 254 );
gGameExternalOptions.gRaidMaxSize_Zombies = iniReader.ReadInteger( "Raid Settings", "RAID_MAXSIZE_ZOMBIES", 15, 1, 254 );
gGameExternalOptions.gRaidMaxSize_Bandits = iniReader.ReadInteger( "Raid Settings", "RAID_MAXSIZE_BANDITS", 6, 1, 254 );
gGameExternalOptions.gRaid_MaxAttackPerNight_Bloodcats = iniReader.ReadInteger( "Raid Settings", "RAID_MAXATTACKSPERNIGHT_BLOODCATS", 3, 0, 100 );
gGameExternalOptions.gRaid_MaxAttackPerNight_Zombies = iniReader.ReadInteger( "Raid Settings", "RAID_MAXATTACKSPERNIGHT_ZOMBIES", 3, 0, 100 );
gGameExternalOptions.gRaid_MaxAttackPerNight_Bandits = iniReader.ReadInteger( "Raid Settings", "RAID_MAXATTACKSPERNIGHT_BANDITS", 3, 0, 100 );
//################# Militia Training Settings ################## //################# Militia Training Settings ##################
gGameExternalOptions.iMaxMilitiaPerSector = iniReader.ReadInteger("Militia Training Settings","MAX_MILITIA_PER_SECTOR",20, 1, CODE_MAXIMUM_NUMBER_OF_REBELS); gGameExternalOptions.iMaxMilitiaPerSector = iniReader.ReadInteger("Militia Training Settings","MAX_MILITIA_PER_SECTOR",20, 1, CODE_MAXIMUM_NUMBER_OF_REBELS);
+15
View File
@@ -689,6 +689,21 @@ typedef struct
UINT16 gEnemyHeliSAMDamage_Var; UINT16 gEnemyHeliSAMDamage_Var;
UINT16 gEnemyHeliMANPADSDamage_Base; UINT16 gEnemyHeliMANPADSDamage_Base;
UINT16 gEnemyHeliMANPADSDamage_Var; UINT16 gEnemyHeliMANPADSDamage_Var;
// Flugente: raids
BOOLEAN gRaid_Bloodcats;
BOOLEAN gRaid_Zombies;
BOOLEAN gRaid_Bandits;
UINT8 gRaidReplenish_BaseValue;
UINT16 gRaidMaxSize_Bloodcats;
UINT16 gRaidMaxSize_Zombies;
UINT16 gRaidMaxSize_Bandits;
UINT8 gRaid_MaxAttackPerNight_Bloodcats;
UINT8 gRaid_MaxAttackPerNight_Zombies;
UINT8 gRaid_MaxAttackPerNight_Bandits;
INT32 ubEnemiesItemDrop; INT32 ubEnemiesItemDrop;
+9 -9
View File
@@ -15,9 +15,9 @@
#ifdef JA2EDITOR #ifdef JA2EDITOR
#ifdef JA2UB #ifdef JA2UB
CHAR16 zVersionLabel[256] = { L"Unfinished Business - Map Editor v1.13.8548 (Development Build)" }; CHAR16 zVersionLabel[256] = { L"Unfinished Business - Map Editor v1.13.8554 (Development Build)" };
#else #else
CHAR16 zVersionLabel[256] = { L"Map Editor v1.13.8548 (Development Build)" }; CHAR16 zVersionLabel[256] = { L"Map Editor v1.13.8554 (Development Build)" };
#endif #endif
// ------------------------------ // ------------------------------
@@ -27,11 +27,11 @@
//DEBUG BUILD VERSION //DEBUG BUILD VERSION
#ifdef JA2UB #ifdef JA2UB
CHAR16 zVersionLabel[256] = { L"Debug: Unfinished Business - v1.13.8548 (Development Build)" }; CHAR16 zVersionLabel[256] = { L"Debug: Unfinished Business - v1.13.8554 (Development Build)" };
#elif defined (JA113DEMO) #elif defined (JA113DEMO)
CHAR16 zVersionLabel[256] = { L"Debug: JA2 Demo - v1.13.8548 (Development Build)" }; CHAR16 zVersionLabel[256] = { L"Debug: JA2 Demo - v1.13.8554 (Development Build)" };
#else #else
CHAR16 zVersionLabel[256] = { L"Debug: v1.13.8548 (Development Build)" }; CHAR16 zVersionLabel[256] = { L"Debug: v1.13.8554 (Development Build)" };
#endif #endif
#elif defined CRIPPLED_VERSION #elif defined CRIPPLED_VERSION
@@ -46,16 +46,16 @@
//RELEASE BUILD VERSION //RELEASE BUILD VERSION
#ifdef JA2UB #ifdef JA2UB
CHAR16 zVersionLabel[256] = { L"Release Unfinished Business - v1.13.8548 (Development Build)" }; CHAR16 zVersionLabel[256] = { L"Release Unfinished Business - v1.13.8554 (Development Build)" };
#elif defined (JA113DEMO) #elif defined (JA113DEMO)
CHAR16 zVersionLabel[256] = { L"Release JA2 Demo - v1.13.8548 (Development Build)" }; CHAR16 zVersionLabel[256] = { L"Release JA2 Demo - v1.13.8554 (Development Build)" };
#else #else
CHAR16 zVersionLabel[256] = { L"Release v1.13.8548 (Development Build)" }; CHAR16 zVersionLabel[256] = { L"Release v1.13.8554 (Development Build)" };
#endif #endif
#endif #endif
CHAR8 czVersionNumber[16] = { "Build 18.03.14" }; //YY.MM.DD CHAR8 czVersionNumber[16] = { "Build 18.04.15" }; //YY.MM.DD
CHAR16 zTrackingNumber[16] = { L"Z" }; CHAR16 zTrackingNumber[16] = { L"Z" };
// SAVE_GAME_VERSION is defined in header, change it there // SAVE_GAME_VERSION is defined in header, change it there
+2 -1
View File
@@ -21,6 +21,7 @@ extern CHAR16 zTrackingNumber[16];
// Keeps track of the saved game version. Increment the saved game version whenever // Keeps track of the saved game version. Increment the saved game version whenever
// you will invalidate the saved game file // you will invalidate the saved game file
#define RAID_EVENTS 178 // Flugente: added bloodcat/zombie/bandit raids
#define INDIVIDUAL_MILITIA_EXP_FLOAT 177 // Flugente: changed the way we store individual militia experience #define INDIVIDUAL_MILITIA_EXP_FLOAT 177 // Flugente: changed the way we store individual militia experience
#define CHAT_TO_DISTRACT 176 // Flugente: internal variable allows us to distract enemies by engrossing them in conversation #define CHAT_TO_DISTRACT 176 // Flugente: internal variable allows us to distract enemies by engrossing them in conversation
#define INDIVIDUAL_MILITIA_RANKFIX 175 // Flugente: internal individual militia change requires variable change #define INDIVIDUAL_MILITIA_RANKFIX 175 // Flugente: internal individual militia change requires variable change
@@ -96,7 +97,7 @@ extern CHAR16 zTrackingNumber[16];
#define AP100_SAVEGAME_DATATYPE_CHANGE 105 // Before this, we didn't have the 100AP structure changes #define AP100_SAVEGAME_DATATYPE_CHANGE 105 // Before this, we didn't have the 100AP structure changes
#define NIV_SAVEGAME_DATATYPE_CHANGE 102 // Before this, we used the old structure system #define NIV_SAVEGAME_DATATYPE_CHANGE 102 // Before this, we used the old structure system
#define SAVE_GAME_VERSION INDIVIDUAL_MILITIA_EXP_FLOAT #define SAVE_GAME_VERSION RAID_EVENTS
//#define RUSSIANGOLD //#define RUSSIANGOLD
#ifdef __cplusplus #ifdef __cplusplus
+2
View File
@@ -168,6 +168,8 @@ Incident_Stats::AddStat( SOLDIERTYPE* pSoldier, UINT8 aType )
case CREATURE_TEAM: case CREATURE_TEAM:
if ( pSoldier->IsZombie() ) if ( pSoldier->IsZombie() )
group = CAMPAIGNHISTORY_SD_ZOMBIE; group = CAMPAIGNHISTORY_SD_ZOMBIE;
else if ( pSoldier->ubSoldierClass == SOLDIER_CLASS_BANDIT )
group = CAMPAIGNHISTORY_SD_ENEMY_ADMIN;
else else
group = CAMPAIGNHISTORY_SD_CREATURE; group = CAMPAIGNHISTORY_SD_CREATURE;
break; break;
+6 -1
View File
@@ -181,7 +181,12 @@ typedef struct
UINT32 usMapIntelFlags; UINT32 usMapIntelFlags;
INT16 sIntelInfoForThisHour[INTELINFO_MAXNUMBER]; INT16 sIntelInfoForThisHour[INTELINFO_MAXNUMBER];
UINT8 bPadding[ 48 ]; // Flugente: raid
INT32 sRaidBloodcats;
INT32 sRaidZombies;
INT32 sRaidBandits;
UINT8 bPadding[ 36 ];
} LaptopSaveInfoStruct; } LaptopSaveInfoStruct;
+6
View File
@@ -6568,6 +6568,12 @@ BOOLEAN LoadSavedGame( int ubSavedGameID )
CalcAproximateAmountPaidToSpeck(); CalcAproximateAmountPaidToSpeck();
} }
// Flugente: if we load an old savegame, this event has to be added
if ( guiCurrentSaveGameVersion < RAID_EVENTS )
{
AddEveryDayStrategicEvent( EVENT_DAILY_RAID_EVENTS, (7*60), 0 );
}
gfLoadedGame = TRUE; gfLoadedGame = TRUE;
uiRelEndPerc = 100; uiRelEndPerc = 100;
+275 -112
View File
@@ -170,6 +170,9 @@ typedef struct AUTORESOLVE_STRUCT
UINT8 ubMercs, ubCivs, ubEnemies; UINT8 ubMercs, ubCivs, ubEnemies;
UINT8 ubAdmins, ubTroops, ubElites, ubTanks, ubJeeps; UINT8 ubAdmins, ubTroops, ubElites, ubTanks, ubJeeps;
UINT8 ubYMCreatures, ubYFCreatures, ubAMCreatures, ubAFCreatures; UINT8 ubYMCreatures, ubYFCreatures, ubAMCreatures, ubAFCreatures;
UINT8 ubBloodcats;
UINT8 ubZombies;
UINT8 ubBandits;
UINT8 ubAliveMercs, ubAliveCivs, ubAliveEnemies; UINT8 ubAliveMercs, ubAliveCivs, ubAliveEnemies;
UINT8 ubMercCols, ubMercRows; UINT8 ubMercCols, ubMercRows;
UINT8 ubEnemyCols, ubEnemyRows; UINT8 ubEnemyCols, ubEnemyRows;
@@ -230,14 +233,18 @@ typedef struct AUTORESOLVE_STRUCT
#define CELL_ROBOT 0x00200000 #define CELL_ROBOT 0x00200000
#define CELL_TANK 0x00400000 #define CELL_TANK 0x00400000
#define CELL_JEEP 0x00800000 #define CELL_JEEP 0x00800000
#define CELL_BLOODCAT 0x01000000
#define CELL_ZOMBIE 0x02000000
#define CELL_BANDIT 0x04000000
//Combined flags //Combined flags
#define CELL_PLAYER ( CELL_MERC | CELL_MILITIA ) #define CELL_PLAYER ( CELL_MERC | CELL_MILITIA )
#define CELL_ENEMY ( CELL_ELITE | CELL_TROOP | CELL_ADMIN | CELL_TANK | CELL_JEEP ) #define CELL_ENEMY ( CELL_ELITE | CELL_TROOP | CELL_ADMIN | CELL_TANK | CELL_JEEP | CELL_BANDIT )
#define CELL_CREATURE ( CELL_AF_CREATURE | CELL_AM_CREATURE | CELL_YF_CREATURE | CELL_YM_CREATURE ) #define CELL_FEMALECREATURE ( CELL_AF_CREATURE | CELL_YF_CREATURE )
#define CELL_FEMALECREATURE ( CELL_AF_CREATURE | CELL_YF_CREATURE ) #define CELL_MALECREATURE ( CELL_AM_CREATURE | CELL_YM_CREATURE )
#define CELL_MALECREATURE ( CELL_AM_CREATURE | CELL_YM_CREATURE ) #define CELL_BUG ( CELL_FEMALECREATURE | CELL_MALECREATURE )
#define CELL_YOUNGCREATURE ( CELL_YF_CREATURE | CELL_YM_CREATURE ) #define CELL_CREATURE ( CELL_BUG | CELL_BLOODCAT | CELL_ZOMBIE )
#define CELL_INVOLVEDINCOMBAT ( CELL_FIREDATTARGET | CELL_DODGEDATTACK | CELL_HITBYATTACKER ) #define CELL_INVOLVEDINCOMBAT ( CELL_FIREDATTARGET | CELL_DODGEDATTACK | CELL_HITBYATTACKER )
enum enum
@@ -303,7 +310,6 @@ void CalculateSoldierCells( BOOLEAN fReset );
void CalculateRowsAndColumns(); void CalculateRowsAndColumns();
void CreateAutoResolveInterface(); void CreateAutoResolveInterface();
void RemoveAutoResolveInterface( BOOLEAN fDeleteForGood ); void RemoveAutoResolveInterface( BOOLEAN fDeleteForGood );
INT32 CalcIndexFromColRowsXY( INT32 iMaxCols, INT32 iMaxRows, INT32 iCol, INT32 iRow );
//Battle system routines //Battle system routines
void DetermineTeamLeader( BOOLEAN fFriendlyTeam ); void DetermineTeamLeader( BOOLEAN fFriendlyTeam );
@@ -484,7 +490,7 @@ void EliminateAllEnemies( UINT8 ubSectorX, UINT8 ubSectorY )
if( gpAR ) if( gpAR )
{ {
for( i = 0; i < gpAR->ubEnemies; i++ ) for( i = 0; i < gpAR->ubEnemies; ++i )
{ {
gpEnemies[ i ].pSoldier->stats.bLife = 0; gpEnemies[ i ].pSoldier->stats.bLife = 0;
} }
@@ -626,6 +632,9 @@ DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"Autoresolve1");
gpAR->ubPlayerDefenceAdvantage = 0; gpAR->ubPlayerDefenceAdvantage = 0;
break; break;
case CREATURE_ATTACK_CODE: case CREATURE_ATTACK_CODE:
case BLOODCAT_ATTACK_CODE:
case ZOMBIE_ATTACK_CODE:
case BANDIT_ATTACK_CODE:
gpAR->ubPlayerDefenceAdvantage = 0; gpAR->ubPlayerDefenceAdvantage = 0;
break; break;
default: default:
@@ -746,7 +755,10 @@ void AssociateEnemiesWithStrategicGroups()
UINT8 ubDirAmount; UINT8 ubDirAmount;
UINT8 ubCurrSI; UINT8 ubCurrSI;
if( GetEnemyEncounterCode() == CREATURE_ATTACK_CODE ) if ( GetEnemyEncounterCode() == CREATURE_ATTACK_CODE ||
GetEnemyEncounterCode() == BLOODCAT_ATTACK_CODE ||
GetEnemyEncounterCode() == ZOMBIE_ATTACK_CODE ||
GetEnemyEncounterCode() == BANDIT_ATTACK_CODE )
return; return;
pSector = &SectorInfo[ SECTOR( gpAR->ubSectorX, gpAR->ubSectorY ) ]; pSector = &SectorInfo[ SECTOR( gpAR->ubSectorX, gpAR->ubSectorY ) ];
@@ -1007,8 +1019,7 @@ void CalculateSoldierCells( BOOLEAN fReset )
// WDS TO BE FIXED -- Why is this 40 here? (18 April 2008) // WDS TO BE FIXED -- Why is this 40 here? (18 April 2008)
//iMaxTeamSize = max( gpAR->ubMercs + gpAR->ubCivs, gpAR->ubEnemies ); //iMaxTeamSize = max( gpAR->ubMercs + gpAR->ubCivs, gpAR->ubEnemies );
iMaxTeamSize = max( min( 40, gpAR->ubMercs + gpAR->ubCivs ), min( 40, gpAR->ubEnemies ) ); iMaxTeamSize = max( min( 40, gpAR->ubMercs + gpAR->ubCivs ), min( 40, gpAR->ubEnemies ) );
if( iMaxTeamSize > 12 ) if( iMaxTeamSize > 12 )
{ {
gpAR->ubTimeModifierPercentage = (UINT8)(118 - iMaxTeamSize*1.5); gpAR->ubTimeModifierPercentage = (UINT8)(118 - iMaxTeamSize*1.5);
@@ -1017,6 +1028,7 @@ void CalculateSoldierCells( BOOLEAN fReset )
{ {
gpAR->ubTimeModifierPercentage = 100; gpAR->ubTimeModifierPercentage = 100;
} }
gpAR->uiTimeSlice = gpAR->uiTimeSlice * gpAR->ubTimeModifierPercentage / 100; gpAR->uiTimeSlice = gpAR->uiTimeSlice * gpAR->ubTimeModifierPercentage / 100;
iTop = iScreenHeightOffset + (240 - gpAR->sHeight/2); iTop = iScreenHeightOffset + (240 - gpAR->sHeight/2);
@@ -1064,6 +1076,7 @@ void CalculateSoldierCells( BOOLEAN fReset )
gpAR->ubAliveMercs--; gpAR->ubAliveMercs--;
} }
} }
if( gpAR->ubCivs ) if( gpAR->ubCivs )
{ {
iStartY = iTop + (gpAR->sHeight - (min(10,gpAR->ubMercRows+gpAR->ubCivRows)*47+7))/2 + gpAR->ubMercRows*47 + 5; iStartY = iTop + (gpAR->sHeight - (min(10,gpAR->ubMercRows+gpAR->ubCivRows)*47+7))/2 + gpAR->ubMercRows*47 + 5;
@@ -1081,6 +1094,7 @@ void CalculateSoldierCells( BOOLEAN fReset )
gpCivs[ index ].uiFlags |= CELL_MILITIA; gpCivs[ index ].uiFlags |= CELL_MILITIA;
} }
} }
if( gpAR->ubEnemies ) if( gpAR->ubEnemies )
{ {
iStartY = iTop + (gpAR->sHeight - (min(10,gpAR->ubEnemyRows)*47+7))/2 + 5; iStartY = iTop + (gpAR->sHeight - (min(10,gpAR->ubEnemyRows)*47+7))/2 + 5;
@@ -1095,21 +1109,8 @@ void CalculateSoldierCells( BOOLEAN fReset )
gpEnemies[ index ].xp = (UINT16)(gpAR->sCenterStartX + 141 + 55*x); gpEnemies[ index ].xp = (UINT16)(gpAR->sCenterStartX + 141 + 55*x);
gpEnemies[ index ].yp = iStartY + y*47; gpEnemies[ index ].yp = iStartY + y*47;
if( GetEnemyEncounterCode() != CREATURE_ATTACK_CODE ) if ( GetEnemyEncounterCode() == CREATURE_ATTACK_CODE )
{
if ( index < gpAR->ubElites )
gpEnemies[ index ].uiFlags = CELL_ELITE;
else if ( index < gpAR->ubElites + gpAR->ubTroops )
gpEnemies[ index ].uiFlags = CELL_TROOP;
else if ( index < gpAR->ubElites + gpAR->ubTroops + gpAR->ubAdmins )
gpEnemies[index].uiFlags = CELL_ADMIN;
else if ( index < gpAR->ubElites + gpAR->ubTroops + gpAR->ubAdmins + gpAR->ubTanks )
gpEnemies[index].uiFlags = CELL_TANK;
else
gpEnemies[index].uiFlags = CELL_JEEP;
}
else
{ {
if( index < gpAR->ubAFCreatures ) if( index < gpAR->ubAFCreatures )
gpEnemies[ index ].uiFlags = CELL_AF_CREATURE; gpEnemies[ index ].uiFlags = CELL_AF_CREATURE;
@@ -1120,6 +1121,30 @@ void CalculateSoldierCells( BOOLEAN fReset )
else else
gpEnemies[ index ].uiFlags = CELL_YM_CREATURE; gpEnemies[ index ].uiFlags = CELL_YM_CREATURE;
} }
else if ( GetEnemyEncounterCode() == BLOODCAT_ATTACK_CODE ||
GetEnemyEncounterCode() == ZOMBIE_ATTACK_CODE ||
GetEnemyEncounterCode() == BANDIT_ATTACK_CODE )
{
if ( index < gpAR->ubBloodcats )
gpEnemies[index].uiFlags = CELL_BLOODCAT;
else if ( index < gpAR->ubBloodcats + gpAR->ubZombies )
gpEnemies[index].uiFlags = CELL_ZOMBIE;
else
gpEnemies[index].uiFlags = CELL_BANDIT;
}
else
{
if ( index < gpAR->ubElites )
gpEnemies[index].uiFlags = CELL_ELITE;
else if ( index < gpAR->ubElites + gpAR->ubTroops )
gpEnemies[index].uiFlags = CELL_TROOP;
else if ( index < gpAR->ubElites + gpAR->ubTroops + gpAR->ubAdmins )
gpEnemies[index].uiFlags = CELL_ADMIN;
else if ( index < gpAR->ubElites + gpAR->ubTroops + gpAR->ubAdmins + gpAR->ubTanks )
gpEnemies[index].uiFlags = CELL_TANK;
else
gpEnemies[index].uiFlags = CELL_JEEP;
}
} }
} }
} }
@@ -1182,8 +1207,10 @@ void RenderSoldierCell( SOLDIERCELL *pCell )
if( !pCell->pSoldier->stats.bLife ) if( !pCell->pSoldier->stats.bLife )
{ {
SetObjectHandleShade( pCell->uiVObjectID, 0 ); SetObjectHandleShade( pCell->uiVObjectID, 0 );
if ( (pCell->uiFlags & CELL_CREATURE) ) if ( ( pCell->uiFlags & CELL_BLOODCAT ) )
BltVideoObjectFromIndex( FRAME_BUFFER, gpAR->iFaces, BLOODCAT_SKULL, pCell->xp + 3 + x, pCell->yp + 3, VO_BLT_SRCTRANSPARENCY, NULL );
else if ( (pCell->uiFlags & CELL_BUG ) )
BltVideoObjectFromIndex( FRAME_BUFFER, gpAR->iFaces, CREATURE_SKULL, pCell->xp + 3 + x, pCell->yp + 3, VO_BLT_SRCTRANSPARENCY, NULL ); BltVideoObjectFromIndex( FRAME_BUFFER, gpAR->iFaces, CREATURE_SKULL, pCell->xp + 3 + x, pCell->yp + 3, VO_BLT_SRCTRANSPARENCY, NULL );
else if ( (pCell->uiFlags & CELL_TANK) ) else if ( (pCell->uiFlags & CELL_TANK) )
BltVideoObjectFromIndex( FRAME_BUFFER, gpAR->iFaces, TANK_WRECK, pCell->xp + 3 + x, pCell->yp + 3, VO_BLT_SRCTRANSPARENCY, NULL ); BltVideoObjectFromIndex( FRAME_BUFFER, gpAR->iFaces, TANK_WRECK, pCell->xp + 3 + x, pCell->yp + 3, VO_BLT_SRCTRANSPARENCY, NULL );
@@ -1677,6 +1704,9 @@ void RenderAutoResolve()
break; break;
case ENEMY_INVASION_CODE: case ENEMY_INVASION_CODE:
case CREATURE_ATTACK_CODE: case CREATURE_ATTACK_CODE:
case BLOODCAT_ATTACK_CODE:
case ZOMBIE_ATTACK_CODE:
case BANDIT_ATTACK_CODE:
swprintf( str, gpStrategicString[STR_AR_DEFEND_HEADER] ); swprintf( str, gpStrategicString[STR_AR_DEFEND_HEADER] );
break; break;
default: default:
@@ -1802,8 +1832,14 @@ void RenderAutoResolve()
break; break;
case BATTLE_DEFEAT: case BATTLE_DEFEAT:
HandleMoraleEvent( NULL, MORALE_HEARD_BATTLE_LOST, gpAR->ubSectorX, gpAR->ubSectorY, 0 ); HandleMoraleEvent( NULL, MORALE_HEARD_BATTLE_LOST, gpAR->ubSectorX, gpAR->ubSectorY, 0 );
if( ProcessLoyalty() )HandleGlobalLoyaltyEvent( GLOBAL_LOYALTY_BATTLE_LOST, gpAR->ubSectorX, gpAR->ubSectorY, 0 );
if( GetEnemyEncounterCode() != CREATURE_ATTACK_CODE ) if( ProcessLoyalty() )
HandleGlobalLoyaltyEvent( GLOBAL_LOYALTY_BATTLE_LOST, gpAR->ubSectorX, gpAR->ubSectorY, 0 );
if ( GetEnemyEncounterCode() != CREATURE_ATTACK_CODE &&
GetEnemyEncounterCode () != BLOODCAT_ATTACK_CODE &&
GetEnemyEncounterCode () != ZOMBIE_ATTACK_CODE &&
GetEnemyEncounterCode () != BANDIT_ATTACK_CODE )
{ {
gsEnemyGainedControlOfSectorID = (INT16)SECTOR( gpAR->ubSectorX, gpAR->ubSectorY ); gsEnemyGainedControlOfSectorID = (INT16)SECTOR( gpAR->ubSectorX, gpAR->ubSectorY );
} }
@@ -1828,8 +1864,13 @@ void RenderAutoResolve()
//Tack on 5 minutes for retreat. //Tack on 5 minutes for retreat.
gpAR->uiTotalElapsedBattleTimeInMilliseconds += 300000; gpAR->uiTotalElapsedBattleTimeInMilliseconds += 300000;
if( ProcessLoyalty() )HandleLoyaltyImplicationsOfMercRetreat( RETREAT_AUTORESOLVE, gpAR->ubSectorX, gpAR->ubSectorY, 0 ); if( ProcessLoyalty() )
if( GetEnemyEncounterCode() != CREATURE_ATTACK_CODE ) HandleLoyaltyImplicationsOfMercRetreat( RETREAT_AUTORESOLVE, gpAR->ubSectorX, gpAR->ubSectorY, 0 );
if ( GetEnemyEncounterCode() != CREATURE_ATTACK_CODE &&
GetEnemyEncounterCode () != BLOODCAT_ATTACK_CODE &&
GetEnemyEncounterCode () != ZOMBIE_ATTACK_CODE &&
GetEnemyEncounterCode () != BANDIT_ATTACK_CODE )
{ {
gsEnemyGainedControlOfSectorID = (INT16)SECTOR( gpAR->ubSectorX, gpAR->ubSectorY ); gsEnemyGainedControlOfSectorID = (INT16)SECTOR( gpAR->ubSectorX, gpAR->ubSectorY );
} }
@@ -2133,7 +2174,7 @@ void CreateAutoResolveInterface()
// Add the militia in the surrounding sectors // Add the militia in the surrounding sectors
// HEADROCK HAM 3.4: Changed argument configuration. // HEADROCK HAM 3.4: Changed argument configuration.
GenerateDirectionInfos( gpAR->ubSectorX, gpAR->ubSectorY, &uiDirNumber, pMoveDir, FALSE, TRUE ); GenerateDirectionInfos( gpAR->ubSectorX, gpAR->ubSectorY, &uiDirNumber, pMoveDir, FALSE, TRUE );
for( i=0; i<uiDirNumber; i++) for( i=0; i<uiDirNumber; ++i)
{ {
INT16 sX = SECTORX( pMoveDir[ i ][0] ); INT16 sX = SECTORX( pMoveDir[ i ][0] );
INT16 sY = SECTORY( pMoveDir[ i ][0] ); INT16 sY = SECTORY( pMoveDir[ i ][0] );
@@ -2144,13 +2185,98 @@ void CreateAutoResolveInterface()
ARCreateMilitiaSquad( &cnt, ubEliteMilitia, ubRegMilitia, ubGreenMilitia, sX, sY ); ARCreateMilitiaSquad( &cnt, ubEliteMilitia, ubRegMilitia, ubGreenMilitia, sX, sY );
} }
if( GetEnemyEncounterCode() != CREATURE_ATTACK_CODE )
index = 0;
if ( GetEnemyEncounterCode() == CREATURE_ATTACK_CODE )
{ {
for( i = 0, index = 0; i < gpAR->ubElites; ++i, ++index ) for ( i = 0; i < gpAR->ubAFCreatures; ++i, ++index )
{
gpEnemies[index].pSoldier = TacticalCreateCreature( ADULTFEMALEMONSTER );
gpEnemies[index].uiVObjectID = gpAR->iFaces;
gpEnemies[index].usIndex = AF_CREATURE_FACE;
gpEnemies[index].pSoldier->sSectorX = gpAR->ubSectorX;
gpEnemies[index].pSoldier->sSectorY = gpAR->ubSectorY;
swprintf( gpEnemies[index].pSoldier->name, gpStrategicString[ STR_AR_CREATURE_NAME ] );
}
for( i = 0; i < gpAR->ubAMCreatures; ++i, ++index )
{
gpEnemies[index].pSoldier = TacticalCreateCreature( AM_MONSTER );
gpEnemies[index].uiVObjectID = gpAR->iFaces;
gpEnemies[index].usIndex = AM_CREATURE_FACE;
gpEnemies[index].pSoldier->sSectorX = gpAR->ubSectorX;
gpEnemies[index].pSoldier->sSectorY = gpAR->ubSectorY;
swprintf( gpEnemies[index].pSoldier->name, gpStrategicString[ STR_AR_CREATURE_NAME ] );
}
for( i = 0; i < gpAR->ubYFCreatures; ++i, ++index )
{
gpEnemies[index].pSoldier = TacticalCreateCreature( YAF_MONSTER );
gpEnemies[index].uiVObjectID = gpAR->iFaces;
gpEnemies[index].usIndex = YF_CREATURE_FACE;
gpEnemies[index].pSoldier->sSectorX = gpAR->ubSectorX;
gpEnemies[index].pSoldier->sSectorY = gpAR->ubSectorY;
swprintf( gpEnemies[index].pSoldier->name, gpStrategicString[ STR_AR_CREATURE_NAME ] );
}
for( i = 0; i < gpAR->ubYMCreatures; ++i, ++index )
{
gpEnemies[index].pSoldier = TacticalCreateCreature( YAM_MONSTER );
gpEnemies[index].uiVObjectID = gpAR->iFaces;
gpEnemies[index].usIndex = YM_CREATURE_FACE;
gpEnemies[index].pSoldier->sSectorX = gpAR->ubSectorX;
gpEnemies[index].pSoldier->sSectorY = gpAR->ubSectorY;
swprintf( gpEnemies[index].pSoldier->name, gpStrategicString[ STR_AR_CREATURE_NAME ] );
}
}
else if ( GetEnemyEncounterCode() == BLOODCAT_ATTACK_CODE ||
GetEnemyEncounterCode() == ZOMBIE_ATTACK_CODE ||
GetEnemyEncounterCode() == BANDIT_ATTACK_CODE )
{
for ( i = 0; i < gpAR->ubBloodcats; ++i, ++index )
{
gpEnemies[index].pSoldier = TacticalCreateCreature( BLOODCAT );
gpEnemies[index].uiVObjectID = gpAR->iFaces;
gpEnemies[index].usIndex = BLOODCAT_FACE;
gpEnemies[index].pSoldier->sSectorX = gpAR->ubSectorX;
gpEnemies[index].pSoldier->sSectorY = gpAR->ubSectorY;
swprintf( gpEnemies[index].pSoldier->name, pDisplayBodyTypeInfoText[27] );
}
for ( i = 0; i < gpAR->ubZombies; ++i, ++index )
{
gpEnemies[index].pSoldier = TacticalCreateZombie();
gpEnemies[index].uiVObjectID = gpAR->iFaces;
gpEnemies[index].usIndex = ZOMBIE_FACE;
gpEnemies[index].pSoldier->sSectorX = gpAR->ubSectorX;
gpEnemies[index].pSoldier->sSectorY = gpAR->ubSectorY;
swprintf( gpEnemies[index].pSoldier->name, gpStrategicString[STR_PB_ZOMBIE] );
}
for ( i = 0; i < gpAR->ubBandits; ++i, ++index )
{
gpEnemies[index].pSoldier = TacticalCreateBandit();
gpEnemies[index].uiVObjectID = gpAR->iFaces;
if ( gpEnemies[index].pSoldier->ubBodyType == REGFEMALE )
{
gpEnemies[index].usIndex = BANDIT1_F_FACE + Random( BLOODCAT_FACE - BANDIT1_F_FACE );
}
else
{
gpEnemies[index].usIndex = BANDIT1_FACE + Random( BANDIT1_F_FACE - BANDIT1_FACE );
}
gpEnemies[index].pSoldier->sSectorX = gpAR->ubSectorX;
gpEnemies[index].pSoldier->sSectorY = gpAR->ubSectorY;
swprintf( gpEnemies[index].pSoldier->name, gpStrategicString[STR_PB_BANDIT] );
}
}
else
{
for ( i = 0; i < gpAR->ubElites; ++i, ++index )
{ {
gpEnemies[index].pSoldier = TacticalCreateEliteEnemy(); gpEnemies[index].pSoldier = TacticalCreateEliteEnemy();
gpEnemies[index].uiVObjectID = gpAR->iFaces; gpEnemies[index].uiVObjectID = gpAR->iFaces;
if( gpEnemies[i].pSoldier->ubBodyType == REGFEMALE ) if ( gpEnemies[index].pSoldier->ubBodyType == REGFEMALE )
{ {
gpEnemies[index].usIndex = ELITEF_FACE; gpEnemies[index].usIndex = ELITEF_FACE;
} }
@@ -2160,39 +2286,39 @@ void CreateAutoResolveInterface()
} }
gpEnemies[index].pSoldier->sSectorX = gpAR->ubSectorX; gpEnemies[index].pSoldier->sSectorX = gpAR->ubSectorX;
gpEnemies[index].pSoldier->sSectorY = gpAR->ubSectorY; gpEnemies[index].pSoldier->sSectorY = gpAR->ubSectorY;
swprintf( gpEnemies[index].pSoldier->name, gpStrategicString[ STR_AR_ELITE_NAME ] ); swprintf( gpEnemies[index].pSoldier->name, gpStrategicString[STR_AR_ELITE_NAME] );
} }
for( i = 0; i < gpAR->ubTroops; ++i, ++index ) for ( i = 0; i < gpAR->ubTroops; ++i, ++index )
{ {
gpEnemies[index].pSoldier = TacticalCreateArmyTroop(); gpEnemies[index].pSoldier = TacticalCreateArmyTroop();
gpEnemies[index].uiVObjectID = gpAR->iFaces; gpEnemies[index].uiVObjectID = gpAR->iFaces;
if ( gpEnemies[i].pSoldier->ubBodyType == REGFEMALE ) if ( gpEnemies[index].pSoldier->ubBodyType == REGFEMALE )
{ {
gpEnemies[index].usIndex = TROOPF_FACE; gpEnemies[index].usIndex = TROOPF_FACE;
} }
else else
{ {
gpEnemies[index].usIndex = TROOP_FACE; gpEnemies[index].usIndex = TROOP_FACE;
} }
gpEnemies[index].pSoldier->sSectorX = gpAR->ubSectorX; gpEnemies[index].pSoldier->sSectorX = gpAR->ubSectorX;
gpEnemies[index].pSoldier->sSectorY = gpAR->ubSectorY; gpEnemies[index].pSoldier->sSectorY = gpAR->ubSectorY;
swprintf( gpEnemies[index].pSoldier->name, gpStrategicString[ STR_AR_TROOP_NAME ] ); swprintf( gpEnemies[index].pSoldier->name, gpStrategicString[STR_AR_TROOP_NAME] );
} }
for ( i = 0; i < gpAR->ubAdmins; ++i, ++index ) for ( i = 0; i < gpAR->ubAdmins; ++i, ++index )
{ {
gpEnemies[index].pSoldier = TacticalCreateAdministrator(); gpEnemies[index].pSoldier = TacticalCreateAdministrator();
gpEnemies[index].uiVObjectID = gpAR->iFaces; gpEnemies[index].uiVObjectID = gpAR->iFaces;
if ( gpEnemies[i].pSoldier->ubBodyType == REGFEMALE ) if ( gpEnemies[index].pSoldier->ubBodyType == REGFEMALE )
{ {
gpEnemies[index].usIndex = ADMINF_FACE; gpEnemies[index].usIndex = ADMINF_FACE;
} }
else else
{ {
gpEnemies[index].usIndex = ADMIN_FACE; gpEnemies[index].usIndex = ADMIN_FACE;
} }
gpEnemies[index].pSoldier->sSectorX = gpAR->ubSectorX; gpEnemies[index].pSoldier->sSectorX = gpAR->ubSectorX;
gpEnemies[index].pSoldier->sSectorY = gpAR->ubSectorY; gpEnemies[index].pSoldier->sSectorY = gpAR->ubSectorY;
swprintf( gpEnemies[index].pSoldier->name, gpStrategicString[ STR_AR_ADMINISTRATOR_NAME ] ); swprintf( gpEnemies[index].pSoldier->name, gpStrategicString[STR_AR_ADMINISTRATOR_NAME] );
} }
for ( i = 0; i < gpAR->ubTanks; ++i, ++index ) for ( i = 0; i < gpAR->ubTanks; ++i, ++index )
@@ -2207,7 +2333,7 @@ void CreateAutoResolveInterface()
for ( i = 0; i < gpAR->ubJeeps; ++i, ++index ) for ( i = 0; i < gpAR->ubJeeps; ++i, ++index )
{ {
gpEnemies[index].pSoldier = TacticalCreateEnemyJeep( ); gpEnemies[index].pSoldier = TacticalCreateEnemyJeep();
gpEnemies[index].uiVObjectID = gpAR->iFaces; gpEnemies[index].uiVObjectID = gpAR->iFaces;
gpEnemies[index].usIndex = JEEP_FACE; gpEnemies[index].usIndex = JEEP_FACE;
gpEnemies[index].pSoldier->sSectorX = gpAR->ubSectorX; gpEnemies[index].pSoldier->sSectorX = gpAR->ubSectorX;
@@ -2217,45 +2343,6 @@ void CreateAutoResolveInterface()
AssociateEnemiesWithStrategicGroups(); AssociateEnemiesWithStrategicGroups();
} }
else
{
for ( i = 0, index = 0; i < gpAR->ubAFCreatures; ++i, ++index )
{
gpEnemies[index].pSoldier = TacticalCreateCreature( ADULTFEMALEMONSTER );
gpEnemies[index].uiVObjectID = gpAR->iFaces;
gpEnemies[index].usIndex = AF_CREATURE_FACE;
gpEnemies[index].pSoldier->sSectorX = gpAR->ubSectorX;
gpEnemies[index].pSoldier->sSectorY = gpAR->ubSectorY;
swprintf( gpEnemies[index].pSoldier->name, gpStrategicString[ STR_AR_CREATURE_NAME ] );
}
for( i = 0; i < gpAR->ubAMCreatures; i++, index++ )
{
gpEnemies[index].pSoldier = TacticalCreateCreature( AM_MONSTER );
gpEnemies[index].uiVObjectID = gpAR->iFaces;
gpEnemies[index].usIndex = AM_CREATURE_FACE;
gpEnemies[index].pSoldier->sSectorX = gpAR->ubSectorX;
gpEnemies[index].pSoldier->sSectorY = gpAR->ubSectorY;
swprintf( gpEnemies[index].pSoldier->name, gpStrategicString[ STR_AR_CREATURE_NAME ] );
}
for( i = 0; i < gpAR->ubYFCreatures; i++, index++ )
{
gpEnemies[index].pSoldier = TacticalCreateCreature( YAF_MONSTER );
gpEnemies[index].uiVObjectID = gpAR->iFaces;
gpEnemies[index].usIndex = YF_CREATURE_FACE;
gpEnemies[index].pSoldier->sSectorX = gpAR->ubSectorX;
gpEnemies[index].pSoldier->sSectorY = gpAR->ubSectorY;
swprintf( gpEnemies[index].pSoldier->name, gpStrategicString[ STR_AR_CREATURE_NAME ] );
}
for( i = 0; i < gpAR->ubYMCreatures; i++, index++ )
{
gpEnemies[index].pSoldier = TacticalCreateCreature( YAM_MONSTER );
gpEnemies[index].uiVObjectID = gpAR->iFaces;
gpEnemies[index].usIndex = YM_CREATURE_FACE;
gpEnemies[index].pSoldier->sSectorX = gpAR->ubSectorX;
gpEnemies[index].pSoldier->sSectorY = gpAR->ubSectorY;
swprintf( gpEnemies[index].pSoldier->name, gpStrategicString[ STR_AR_CREATURE_NAME ] );
}
}
if( gpAR->ubSectorX == gWorldSectorX && gpAR->ubSectorY == gWorldSectorY && !gbWorldSectorZ ) if( gpAR->ubSectorX == gWorldSectorX && gpAR->ubSectorY == gWorldSectorY && !gbWorldSectorZ )
{ {
@@ -2616,7 +2703,10 @@ DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"Autoresolve2");
gpBattleGroup = NULL; gpBattleGroup = NULL;
if( GetEnemyEncounterCode() == CREATURE_ATTACK_CODE ) if ( GetEnemyEncounterCode() == CREATURE_ATTACK_CODE ||
GetEnemyEncounterCode() == BLOODCAT_ATTACK_CODE ||
GetEnemyEncounterCode() == ZOMBIE_ATTACK_CODE ||
GetEnemyEncounterCode() == BANDIT_ATTACK_CODE )
{ {
gubNumCreaturesAttackingTown = 0; gubNumCreaturesAttackingTown = 0;
gubSectorIDOfCreatureAttack = 0; gubSectorIDOfCreatureAttack = 0;
@@ -2915,14 +3005,7 @@ void CalculateAutoResolveInfo()
Assert( gpAR->ubSectorX >= 1 && gpAR->ubSectorX <= 16 ); Assert( gpAR->ubSectorX >= 1 && gpAR->ubSectorX <= 16 );
Assert( gpAR->ubSectorY >= 1 && gpAR->ubSectorY <= 16 ); Assert( gpAR->ubSectorY >= 1 && gpAR->ubSectorY <= 16 );
if( GetEnemyEncounterCode() != CREATURE_ATTACK_CODE ) if ( GetEnemyEncounterCode() == CREATURE_ATTACK_CODE )
{
// GetNumberOfEnemiesInSector( gpAR->ubSectorX, gpAR->ubSectorY,
GetNumberOfEnemiesInFiveSectors( gpAR->ubSectorX, gpAR->ubSectorY,
&gpAR->ubAdmins, &gpAR->ubTroops, &gpAR->ubElites, &gpAR->ubTanks, &gpAR->ubJeeps );
gpAR->ubEnemies = (UINT8)min( gpAR->ubAdmins + gpAR->ubTroops + gpAR->ubElites + gpAR->ubTanks + gpAR->ubJeeps, MAX_AR_TEAM_SIZE );
}
else
{ {
if( gfTransferTacticalOppositionToAutoResolve ) if( gfTransferTacticalOppositionToAutoResolve )
{ {
@@ -2948,8 +3031,35 @@ void CalculateAutoResolveInfo()
gpAR->ubEnemies = (UINT8)min( gpAR->ubYMCreatures + gpAR->ubYFCreatures + gpAR->ubAMCreatures + gpAR->ubAFCreatures, MAX_AR_TEAM_SIZE ); gpAR->ubEnemies = (UINT8)min( gpAR->ubYMCreatures + gpAR->ubYFCreatures + gpAR->ubAMCreatures + gpAR->ubAFCreatures, MAX_AR_TEAM_SIZE );
} }
else if ( GetEnemyEncounterCode() == BLOODCAT_ATTACK_CODE ||
GetEnemyEncounterCode() == ZOMBIE_ATTACK_CODE ||
GetEnemyEncounterCode() == BANDIT_ATTACK_CODE )
{
if ( gfTransferTacticalOppositionToAutoResolve || gubNumCreaturesAttackingTown == 0 )
{
DetermineOtherCreatureTownCompositionBasedOnTacticalInformation( &gubNumCreaturesAttackingTown, &gpAR->ubBloodcats, &gpAR->ubZombies, &gpAR->ubBandits );
}
else
{
if ( GetEnemyEncounterCode() == BLOODCAT_ATTACK_CODE )
gpAR->ubBloodcats = gubNumCreaturesAttackingTown;
else if ( GetEnemyEncounterCode() == ZOMBIE_ATTACK_CODE )
gpAR->ubZombies = gubNumCreaturesAttackingTown;
else if ( GetEnemyEncounterCode() == BANDIT_ATTACK_CODE )
gpAR->ubBandits = gubNumCreaturesAttackingTown;
}
gpAR->ubEnemies = (UINT8)min( gubNumCreaturesAttackingTown, MAX_AR_TEAM_SIZE );
}
else
{
GetNumberOfEnemiesInFiveSectors( gpAR->ubSectorX, gpAR->ubSectorY,
&gpAR->ubAdmins, &gpAR->ubTroops, &gpAR->ubElites, &gpAR->ubTanks, &gpAR->ubJeeps );
gpAR->ubEnemies = (UINT8)min( gpAR->ubAdmins + gpAR->ubTroops + gpAR->ubElites + gpAR->ubTanks + gpAR->ubJeeps, MAX_AR_TEAM_SIZE );
}
gfTransferTacticalOppositionToAutoResolve = FALSE; gfTransferTacticalOppositionToAutoResolve = FALSE;
// gpAR->ubCivs = CountAllMilitiaInSector( gpAR->ubSectorX, gpAR->ubSectorY );
gpAR->ubCivs = CountAllMilitiaInFiveSectors( gpAR->ubSectorX, gpAR->ubSectorY ); gpAR->ubCivs = CountAllMilitiaInFiveSectors( gpAR->ubSectorX, gpAR->ubSectorY );
gpAR->ubMercs = 0; gpAR->ubMercs = 0;
VObjectDesc.fCreateFlags = VOBJECT_CREATE_FROMFILE; VObjectDesc.fCreateFlags = VOBJECT_CREATE_FROMFILE;
@@ -3693,6 +3803,7 @@ FLOAT CalcClassBonusOrPenalty( SOLDIERTYPE *pSoldier )
return 1.0f; return 1.0f;
case SOLDIER_CLASS_ADMINISTRATOR: case SOLDIER_CLASS_ADMINISTRATOR:
case SOLDIER_CLASS_GREEN_MILITIA: case SOLDIER_CLASS_GREEN_MILITIA:
case SOLDIER_CLASS_BANDIT:
return 0.7f; return 0.7f;
} }
@@ -3821,7 +3932,8 @@ void CalculateAttackValues()
gpAR->usPlayerDefence += pCell->usDefence; gpAR->usPlayerDefence += pCell->usDefence;
ResetNextAttackCounter( pCell ); ResetNextAttackCounter( pCell );
if( i > 6 ) if( i > 6 )
{ //Too many militia, delay attack entry of extra mercs. {
//Too many militia, delay attack entry of extra mercs.
pCell->usNextAttack += (UINT32)(( i - 4 ) * 2000 ); pCell->usNextAttack += (UINT32)(( i - 4 ) * 2000 );
} }
@@ -3832,10 +3944,10 @@ void CalculateAttackValues()
pCell->usNextAttack += REINFORCMENT_ATTACK_DELAY_PER_SOLDIER_IN_SECTOR * militiainsector; pCell->usNextAttack += REINFORCMENT_ATTACK_DELAY_PER_SOLDIER_IN_SECTOR * militiainsector;
} }
if( pCell->usNextAttack < usBestAttack ) if( pCell->usNextAttack < usBestAttack )
usBestAttack = pCell->usNextAttack; usBestAttack = pCell->usNextAttack;
} }
//ENEMIES //ENEMIES
gpAR->usEnemyAttack = 0; gpAR->usEnemyAttack = 0;
gpAR->usEnemyDefence = 0; gpAR->usEnemyDefence = 0;
@@ -3847,7 +3959,7 @@ void CalculateAttackValues()
// sOutnumberBonus = (INT16)min( sOutnumberBonus, max( sMaxBonus, 0 ) ); // sOutnumberBonus = (INT16)min( sOutnumberBonus, max( sMaxBonus, 0 ) );
//} //}
for( i = 0; i < gpAR->ubEnemies; i++ ) for( i = 0; i < gpAR->ubEnemies; ++i )
{ {
pCell = &gpEnemies[ i ]; pCell = &gpEnemies[ i ];
pSoldier = pCell->pSoldier; pSoldier = pCell->pSoldier;
@@ -3886,19 +3998,21 @@ void CalculateAttackValues()
ResetNextAttackCounter( pCell ); ResetNextAttackCounter( pCell );
if( i > 4 && !(pCell->uiFlags & CELL_CREATURE) ) if( i > 4 && !(pCell->uiFlags & CELL_CREATURE) )
{ //Too many enemies, delay attack entry of extra mercs. {
//Too many enemies, delay attack entry of extra mercs.
pCell->usNextAttack += (UINT32)( ( i - 4 ) * 1000 ); pCell->usNextAttack += (UINT32)( ( i - 4 ) * 1000 );
} }
if ( i >= NumNonPlayerTeamMembersInSector( gpAR->ubSectorX, gpAR->ubSectorY, ENEMY_TEAM ) && !(pCell->uiFlags & CELL_CREATURE) ) if ( i >= NumNonPlayerTeamMembersInSector( gpAR->ubSectorX, gpAR->ubSectorY, ENEMY_TEAM ) && !(pCell->uiFlags & CELL_CREATURE) )
{ //Extra delay if it's a reinforcement {
//Extra delay if it's a reinforcement
pCell->usNextAttack += REINFORCMENT_ATTACK_DELAY_PER_SOLDIER_IN_SECTOR * NumNonPlayerTeamMembersInSector( gpAR->ubSectorX, gpAR->ubSectorY, ENEMY_TEAM ); pCell->usNextAttack += REINFORCMENT_ATTACK_DELAY_PER_SOLDIER_IN_SECTOR * NumNonPlayerTeamMembersInSector( gpAR->ubSectorX, gpAR->ubSectorY, ENEMY_TEAM );
} }
if( pCell->usNextAttack < usBestAttack ) if( pCell->usNextAttack < usBestAttack )
usBestAttack = pCell->usNextAttack; usBestAttack = pCell->usNextAttack;
} }
//Now, because we are starting a new battle, we want to get the ball rolling a bit earlier. So, //Now, because we are starting a new battle, we want to get the ball rolling a bit earlier. So,
//we will take the usBestAttack value and subtract 60% of it from everybody's next attack. //we will take the usBestAttack value and subtract 60% of it from everybody's next attack.
usBestAttack = usBestAttack * 60 / 100; usBestAttack = usBestAttack * 60 / 100;
@@ -3964,9 +4078,11 @@ SOLDIERCELL* ChooseTarget( SOLDIERCELL *pAttacker )
INT32 iRandom = -1; INT32 iRandom = -1;
SOLDIERCELL *pTarget = NULL; SOLDIERCELL *pTarget = NULL;
UINT32 usSavedDefence; UINT32 usSavedDefence;
//Determine what team we are attacking //Determine what team we are attacking
if( pAttacker->uiFlags & (CELL_ENEMY | CELL_CREATURE) ) if( pAttacker->uiFlags & (CELL_ENEMY | CELL_CREATURE) )
{ //enemy team attacking a player {
//enemy team attacking a player
iAvailableTargets = gpAR->ubMercs + gpAR->ubCivs; iAvailableTargets = gpAR->ubMercs + gpAR->ubCivs;
index = 0; index = 0;
usSavedDefence = gpAR->usPlayerDefence; usSavedDefence = gpAR->usPlayerDefence;
@@ -4302,11 +4418,13 @@ void AttackTarget( SOLDIERCELL *pAttacker, SOLDIERCELL *pTarget )
usDefence = max(0, min(1000, usDefence )); usDefence = max(0, min(1000, usDefence ));
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
if( pAttacker->uiFlags & CELL_FEMALECREATURE ) if( pAttacker->uiFlags & (CELL_FEMALECREATURE | CELL_BLOODCAT | CELL_ZOMBIE) )
{ {
pAttacker->bWeaponSlot = HANDPOS; pAttacker->bWeaponSlot = HANDPOS;
fMelee = TRUE; fMelee = TRUE;
fClaw = TRUE;
if ( pAttacker->uiFlags & ( CELL_FEMALECREATURE | CELL_BLOODCAT ) )
fClaw = TRUE;
} }
// Flugente: if we are a tank, we might fire the main cannon... // Flugente: if we are a tank, we might fire the main cannon...
else if ( FireTankCannon( pAttacker ) ) else if ( FireTankCannon( pAttacker ) )
@@ -4383,13 +4501,27 @@ void AttackTarget( SOLDIERCELL *pAttacker, SOLDIERCELL *pTarget )
PlayAutoResolveSample( MISS_KNIFE, RATE_11025, 50, 1, MIDDLEPAN ); PlayAutoResolveSample( MISS_KNIFE, RATE_11025, 50, 1, MIDDLEPAN );
else if( fClaw ) else if( fClaw )
{ {
if( Chance( 50 ) ) if ( pAttacker->uiFlags & ( CELL_BLOODCAT ) )
{ {
PlayAutoResolveSample( ACR_SWIPE, RATE_11025, 50, 1, MIDDLEPAN ); if ( Chance( 50 ) )
{
PlayAutoResolveSample( BLOODCAT_ATTACK, RATE_11025, 50, 1, MIDDLEPAN );
}
else
{
PlayAutoResolveSample( BLOODCAT_ROAR, RATE_11025, 50, 1, MIDDLEPAN );
}
} }
else else
{ {
PlayAutoResolveSample( ACR_LUNGE, RATE_11025, 50, 1, MIDDLEPAN ); if ( Chance( 50 ) )
{
PlayAutoResolveSample( ACR_SWIPE, RATE_11025, 50, 1, MIDDLEPAN );
}
else
{
PlayAutoResolveSample( ACR_LUNGE, RATE_11025, 50, 1, MIDDLEPAN );
}
} }
} }
else else
@@ -4657,6 +4789,14 @@ void AttackTarget( SOLDIERCELL *pAttacker, SOLDIERCELL *pTarget )
UpdateMilitia( militia ); UpdateMilitia( militia );
} }
// Flugente: for raids, we need to keep track of killed forces
if ( GetEnemyEncounterCode() == BLOODCAT_ATTACK_CODE ||
GetEnemyEncounterCode() == ZOMBIE_ATTACK_CODE ||
GetEnemyEncounterCode() == BANDIT_ATTACK_CODE )
{
AddRaidPersonnel( -( pTarget->pSoldier->ubBodyType == BLOODCAT ), -( pTarget->pSoldier->ubSoldierClass == SOLDIER_CLASS_ZOMBIE ), -( pTarget->pSoldier->ubSoldierClass == SOLDIER_CLASS_BANDIT ) );
}
// Flugente: disease // Flugente: disease
HandleDeathDiseaseImplications( pTarget->pSoldier ); HandleDeathDiseaseImplications( pTarget->pSoldier );
@@ -4681,6 +4821,9 @@ void AttackTarget( SOLDIERCELL *pAttacker, SOLDIERCELL *pTarget )
case SOLDIER_CLASS_ZOMBIE : case SOLDIER_CLASS_ZOMBIE :
gMercProfiles[ pAttacker->pSoldier->ubProfile ].records.usKillsZombies++; gMercProfiles[ pAttacker->pSoldier->ubProfile ].records.usKillsZombies++;
break; break;
case SOLDIER_CLASS_BANDIT:
gMercProfiles[pAttacker->pSoldier->ubProfile].records.usKillsOthers++;
break;
default : default :
if ( CREATURE_OR_BLOODCAT( pTarget->pSoldier ) ) if ( CREATURE_OR_BLOODCAT( pTarget->pSoldier ) )
gMercProfiles[ pAttacker->pSoldier->ubProfile ].records.usKillsCreatures++; gMercProfiles[ pAttacker->pSoldier->ubProfile ].records.usKillsCreatures++;
@@ -4875,6 +5018,14 @@ void TargetHitCallback( SOLDIERCELL *pTarget, INT32 index )
UpdateMilitia( militia ); UpdateMilitia( militia );
} }
// Flugente: for raids, we need to keep track of killed forces
if ( GetEnemyEncounterCode() == BLOODCAT_ATTACK_CODE ||
GetEnemyEncounterCode() == ZOMBIE_ATTACK_CODE ||
GetEnemyEncounterCode() == BANDIT_ATTACK_CODE )
{
AddRaidPersonnel( -( pTarget->pSoldier->ubBodyType == BLOODCAT ), -( pTarget->pSoldier->ubSoldierClass == SOLDIER_CLASS_ZOMBIE ), -( pTarget->pSoldier->ubSoldierClass == SOLDIER_CLASS_BANDIT ) );
}
// Flugente: disease // Flugente: disease
HandleDeathDiseaseImplications( pTarget->pSoldier ); HandleDeathDiseaseImplications( pTarget->pSoldier );
@@ -4915,6 +5066,9 @@ void TargetHitCallback( SOLDIERCELL *pTarget, INT32 index )
case SOLDIER_CLASS_ZOMBIE : case SOLDIER_CLASS_ZOMBIE :
gMercProfiles[ pKiller->pSoldier->ubProfile ].records.usKillsZombies++; gMercProfiles[ pKiller->pSoldier->ubProfile ].records.usKillsZombies++;
break; break;
case SOLDIER_CLASS_BANDIT:
gMercProfiles[pKiller->pSoldier->ubProfile].records.usKillsOthers++;
break;
default : default :
if ( CREATURE_OR_BLOODCAT( pTarget->pSoldier ) ) if ( CREATURE_OR_BLOODCAT( pTarget->pSoldier ) )
gMercProfiles[ pKiller->pSoldier->ubProfile ].records.usKillsCreatures++; gMercProfiles[ pKiller->pSoldier->ubProfile ].records.usKillsCreatures++;
@@ -4993,7 +5147,8 @@ void TargetHitCallback( SOLDIERCELL *pTarget, INT32 index )
PlayAutoResolveSample( (UINT8)DOORCR_1, RATE_11025, HIGHVOLUME, 1, MIDDLEPAN ); PlayAutoResolveSample( (UINT8)DOORCR_1, RATE_11025, HIGHVOLUME, 1, MIDDLEPAN );
PlayAutoResolveSample( (UINT8)HEADCR_1, RATE_11025, HIGHVOLUME, 1, MIDDLEPAN ); PlayAutoResolveSample( (UINT8)HEADCR_1, RATE_11025, HIGHVOLUME, 1, MIDDLEPAN );
} }
if( iNewLife < -60 && !(pTarget->uiFlags & CELL_CREATURE) )
if( iNewLife < -60 && !(pTarget->uiFlags & CELL_BUG ) )
{ //High damage death { //High damage death
if( gpAR->fSound ) if( gpAR->fSound )
{ {
@@ -5186,7 +5341,9 @@ BOOLEAN IsBattleOver()
{ {
if( gpEnemies[ i ].pSoldier->stats.bLife ) if( gpEnemies[ i ].pSoldier->stats.bLife )
{ {
if( GetEnemyEncounterCode() != CREATURE_ATTACK_CODE ) if ( GetEnemyEncounterCode() != CREATURE_ATTACK_CODE &&
GetEnemyEncounterCode() != BLOODCAT_ATTACK_CODE &&
GetEnemyEncounterCode() != ZOMBIE_ATTACK_CODE )
{ {
gpEnemies[ i ].pSoldier->DoMercBattleSound( BATTLE_SOUND_LAUGH1 ); gpEnemies[ i ].pSoldier->DoMercBattleSound( BATTLE_SOUND_LAUGH1 );
} }
@@ -5473,7 +5630,9 @@ void ProcessBattleFrame()
return; return;
} }
CONTINUE_BATTLE: CONTINUE_BATTLE:
if( IsBattleOver() || GetEnemyEncounterCode() != CREATURE_ATTACK_CODE && AttemptPlayerCapture() ) if ( IsBattleOver() ||
(GetEnemyEncounterCode() != CREATURE_ATTACK_CODE && GetEnemyEncounterCode() != BLOODCAT_ATTACK_CODE && GetEnemyEncounterCode() != ZOMBIE_ATTACK_CODE && GetEnemyEncounterCode() != BANDIT_ATTACK_CODE )
&& AttemptPlayerCapture() )
return; return;
iRandom = PreRandom( iTotal ); iRandom = PreRandom( iTotal );
@@ -5558,7 +5717,8 @@ void ProcessBattleFrame()
else else
{ {
if( pAttacker->uiFlags & CELL_RETREATING ) if( pAttacker->uiFlags & CELL_RETREATING )
{ //The merc has successfully retreated. Remove the stats, and continue on. {
//The merc has successfully retreated. Remove the stats, and continue on.
if( pAttacker == gpAR->pRobotCell ) if( pAttacker == gpAR->pRobotCell )
{ {
if( gpAR->pRobotCell->pSoldier->ubRobotRemoteHolderID == NOBODY ) if( gpAR->pRobotCell->pSoldier->ubRobotRemoteHolderID == NOBODY )
@@ -5574,16 +5734,19 @@ void ProcessBattleFrame()
pAttacker->uiFlags |= CELL_RETREATED; pAttacker->uiFlags |= CELL_RETREATED;
continue; continue;
} }
if( pAttacker->usAttack ) if( pAttacker->usAttack )
{ {
pTarget = ChooseTarget( pAttacker ); pTarget = ChooseTarget( pAttacker );
if( pAttacker->uiFlags & CELL_CREATURE && PreRandom( 100 ) < 7 )
if( pAttacker->uiFlags & CELL_BUG && PreRandom( 100 ) < 7 )
PlayAutoResolveSample( ACR_SMELL_THREAT + PreRandom( 2 ), RATE_11025, 50, 1, MIDDLEPAN ); PlayAutoResolveSample( ACR_SMELL_THREAT + PreRandom( 2 ), RATE_11025, 50, 1, MIDDLEPAN );
else else
AttackTarget( pAttacker, pTarget ); AttackTarget( pAttacker, pTarget );
ResetNextAttackCounter( pAttacker ); ResetNextAttackCounter( pAttacker );
pAttacker->usNextAttack += (UINT32)iTime; //tack on the remainder pAttacker->usNextAttack += (UINT32)iTime; //tack on the remainder
iAttacksThisFrame++; ++iAttacksThisFrame;
} }
} }
} }
+5
View File
@@ -28,6 +28,11 @@ enum
MILITIA3F_FACE, MILITIA3F_FACE,
JEEP_FACE, JEEP_FACE,
JEEP_WRECK, JEEP_WRECK,
ZOMBIE_FACE,
BANDIT1_FACE,
BANDIT1_F_FACE = BANDIT1_FACE + 4,
BLOODCAT_FACE = BANDIT1_F_FACE + 4,
BLOODCAT_SKULL,
AUTORESOLVEFACES_MAX AUTORESOLVEFACES_MAX
}; };
+469 -78
View File
@@ -32,6 +32,10 @@
#include "MessageBoxScreen.h" #include "MessageBoxScreen.h"
#include "Map Information.h" #include "Map Information.h"
#include "Queen Command.h" #include "Queen Command.h"
#include "ai.h" // added by Flugente
#include "Isometric Utils.h" // added by Flugente
#include "Soldier Create.h" // added by Flugente
#include "Player Command.h" // added by Flugente
#endif #endif
#include "Strategic Mines.h" #include "Strategic Mines.h"
@@ -148,11 +152,16 @@ UINT8 gubAdultFemalesAttackingTown = 0;
UINT8 gubCreatureBattleCode = CREATURE_BATTLE_CODE_NONE; UINT8 gubCreatureBattleCode = CREATURE_BATTLE_CODE_NONE;
UINT8 gubSectorIDOfCreatureAttack = 0; UINT8 gubSectorIDOfCreatureAttack = 0;
// Flugente: bloodcat raids are mostly similar to creature attacks, so use the same code and differ when necessary with this
UINT8 guCreatureAttackType = CREATURE_ATTACK_TYPE_CREATURE;
extern UNDERGROUND_SECTORINFO* FindUnderGroundSector( INT16 sMapX, INT16 sMapY, UINT8 bMapZ ); extern UNDERGROUND_SECTORINFO* FindUnderGroundSector( INT16 sMapX, INT16 sMapY, UINT8 bMapZ );
extern UNDERGROUND_SECTORINFO* NewUndergroundNode( UINT8 ubSectorX, UINT8 ubSectorY, UINT8 ubSectorZ ); extern UNDERGROUND_SECTORINFO* NewUndergroundNode( UINT8 ubSectorX, UINT8 ubSectorY, UINT8 ubSectorZ );
extern void BuildUndergroundSectorInfoList(); extern void BuildUndergroundSectorInfoList();
void DeleteCreatureDirectives(); void DeleteCreatureDirectives();
extern SECTOR_EXT_DATA SectorExternalData[256][4];
//extern MINE_STATUS_TYPE gMineStatus[ MAX_NUMBER_OF_MINES ]; //extern MINE_STATUS_TYPE gMineStatus[ MAX_NUMBER_OF_MINES ];
@@ -684,10 +693,10 @@ void AddCreaturesToBattle( UINT8 ubNumYoungMales, UINT8 ubNumYoungFemales, UINT8
switch( gsCreatureInsertionCode ) switch( gsCreatureInsertionCode )
{ {
case INSERTION_CODE_NORTH: bDesiredDirection = SOUTHEAST; break; case INSERTION_CODE_NORTH: bDesiredDirection = SOUTHEAST; break;
case INSERTION_CODE_EAST: bDesiredDirection = SOUTHWEST; break; case INSERTION_CODE_EAST: bDesiredDirection = SOUTHWEST; break;
case INSERTION_CODE_SOUTH: bDesiredDirection = NORTHWEST; break; case INSERTION_CODE_SOUTH: bDesiredDirection = NORTHWEST; break;
case INSERTION_CODE_WEST: bDesiredDirection = NORTHEAST; break; case INSERTION_CODE_WEST: bDesiredDirection = NORTHEAST; break;
case INSERTION_CODE_GRIDNO: break; case INSERTION_CODE_GRIDNO: break;
default: AssertMsg( 0, "Illegal direction passed to AddCreaturesToBattle()" ); break; default: AssertMsg( 0, "Illegal direction passed to AddCreaturesToBattle()" ); break;
} }
@@ -772,6 +781,101 @@ void AddCreaturesToBattle( UINT8 ubNumYoungMales, UINT8 ubNumYoungFemales, UINT8
AllTeamsLookForAll( FALSE ); AllTeamsLookForAll( FALSE );
} }
void AddCreaturesToBattle_Other( UINT8 ubNum )
{
INT32 iRandom;
SOLDIERTYPE *pSoldier;
MAPEDGEPOINTINFO MapEdgepointInfo = {};
UINT8 bDesiredDirection = 0;
UINT8 ubCurrSlot = 0;
switch ( gsCreatureInsertionCode )
{
case INSERTION_CODE_NORTH: bDesiredDirection = SOUTHEAST; break;
case INSERTION_CODE_EAST: bDesiredDirection = SOUTHWEST; break;
case INSERTION_CODE_SOUTH: bDesiredDirection = NORTHWEST; break;
case INSERTION_CODE_WEST: bDesiredDirection = NORTHEAST; break;
case INSERTION_CODE_GRIDNO: break;
default: AssertMsg( 0, "Illegal direction passed to AddCreaturesToBattle_Bloodcats()" ); break;
}
#ifdef JA2TESTVERSION
ScreenMsg( FONT_RED, MSG_INTERFACE, L"Creature attackers have arrived!" );
#endif
if ( gsCreatureInsertionCode != INSERTION_CODE_GRIDNO )
{
ChooseMapEdgepoints( &MapEdgepointInfo, (UINT8)gsCreatureInsertionCode, ubNum );
ubCurrSlot = 0;
}
while ( ubNum )
{
--ubNum;
switch ( guCreatureAttackType )
{
// this should not happen!
case CREATURE_ATTACK_TYPE_CREATURE:
pSoldier = TacticalCreateCreature( ADULTFEMALEMONSTER );
break;
case CREATURE_ATTACK_TYPE_ZOMBIE:
pSoldier = TacticalCreateZombie();
break;
case CREATURE_ATTACK_TYPE_BANDIT:
pSoldier = TacticalCreateBandit();
break;
case CREATURE_ATTACK_TYPE_BLOODCAT:
pSoldier = TacticalCreateCreature( BLOODCAT );
break;
}
pSoldier->ubInsertionDirection = bDesiredDirection;
//Setup the position
pSoldier->ubStrategicInsertionCode = INSERTION_CODE_GRIDNO;
pSoldier->aiData.bHunting = TRUE;
if ( gsCreatureInsertionCode != INSERTION_CODE_GRIDNO )
{
if ( ubCurrSlot < MapEdgepointInfo.ubNumPoints )
{
//using an edgepoint
pSoldier->usStrategicInsertionData = MapEdgepointInfo.sGridNo[ubCurrSlot++];
}
else
{
//no edgepoints left, so put him at the entrypoint.
pSoldier->ubStrategicInsertionCode = (UINT8)gsCreatureInsertionCode;
}
}
else
{
pSoldier->usStrategicInsertionData = gsCreatureInsertionGridNo;
}
UpdateMercInSector( pSoldier, gWorldSectorX, gWorldSectorY, 0 );
if ( pSoldier )
{
// send soldier to centre of map, roughly
pSoldier->aiData.sNoiseGridno = ( CENTRAL_GRIDNO + ( Random( CENTRAL_RADIUS * 2 + 1 ) - CENTRAL_RADIUS ) + ( Random( CENTRAL_RADIUS * 2 + 1 ) - CENTRAL_RADIUS ) * WORLD_COLS );
pSoldier->aiData.ubNoiseVolume = MAX_MISC_NOISE_DURATION;
}
}
gsCreatureInsertionCode = 0;
gsCreatureInsertionGridNo = 0;
gubNumCreaturesAttackingTown = 0;
gubYoungMalesAttackingTown = 0;
gubYoungFemalesAttackingTown = 0;
gubAdultMalesAttackingTown = 0;
gubAdultFemalesAttackingTown = 0;
gubCreatureBattleCode = CREATURE_BATTLE_CODE_NONE;
gubSectorIDOfCreatureAttack = 0;
AllTeamsLookForAll( FALSE );
}
void ChooseTownSectorToAttack( UINT8 ubSectorID, BOOLEAN fOverrideTest ) void ChooseTownSectorToAttack( UINT8 ubSectorID, BOOLEAN fOverrideTest )
{ {
INT32 iRandom, i; INT32 iRandom, i;
@@ -1061,6 +1165,7 @@ void CreatureAttackTown( UINT8 ubSectorID, BOOLEAN fOverrideTest )
return; return;
} }
guCreatureAttackType = CREATURE_ATTACK_TYPE_CREATURE;
gubCreatureBattleCode = CREATURE_BATTLE_CODE_NONE; gubCreatureBattleCode = CREATURE_BATTLE_CODE_NONE;
ubSectorX = SECTORX( ubSectorID ); ubSectorX = SECTORX( ubSectorID );
@@ -1098,22 +1203,18 @@ void CreatureAttackTown( UINT8 ubSectorID, BOOLEAN fOverrideTest )
//Now that the sector has been chosen, attack it! //Now that the sector has been chosen, attack it!
if( PlayerGroupsInSector( ubSectorX, ubSectorY, 0 ) ) if( PlayerGroupsInSector( ubSectorX, ubSectorY, 0 ) )
{ //we have players in the sector {
gubCreatureBattleCode = CREATURE_BATTLE_CODE_PREBATTLEINTERFACE;
//we have players in the sector
if( ubSectorX == gWorldSectorX && ubSectorY == gWorldSectorY && !gbWorldSectorZ ) if( ubSectorX == gWorldSectorX && ubSectorY == gWorldSectorY && !gbWorldSectorZ )
{ //This is the currently loaded sector. All we have to do is change the music and insert {
//This is the currently loaded sector. All we have to do is change the music and insert
//the creatures tactically. //the creatures tactically.
if( guiCurrentScreen == GAME_SCREEN ) if( guiCurrentScreen == GAME_SCREEN )
{ {
gubCreatureBattleCode = CREATURE_BATTLE_CODE_TACTICALLYADD; gubCreatureBattleCode = CREATURE_BATTLE_CODE_TACTICALLYADD;
} }
else
{
gubCreatureBattleCode = CREATURE_BATTLE_CODE_PREBATTLEINTERFACE;
}
}
else
{
gubCreatureBattleCode = CREATURE_BATTLE_CODE_PREBATTLEINTERFACE;
} }
} }
else if ( NumNonPlayerTeamMembersInSector( ubSectorX, ubSectorY, MILITIA_TEAM ) ) else if ( NumNonPlayerTeamMembersInSector( ubSectorX, ubSectorY, MILITIA_TEAM ) )
@@ -1123,7 +1224,7 @@ void CreatureAttackTown( UINT8 ubSectorID, BOOLEAN fOverrideTest )
} }
else if( !StrategicMap[ ubSectorX + MAP_WORLD_X * ubSectorY ].fEnemyControlled ) else if( !StrategicMap[ ubSectorX + MAP_WORLD_X * ubSectorY ].fEnemyControlled )
{ //player controlled sector -- eat some civilians { //player controlled sector -- eat some civilians
AdjustLoyaltyForCivsEatenByMonsters( ubSectorX, ubSectorY, gubNumCreaturesAttackingTown ); AdjustLoyaltyForCivsEatenByMonsters( ubSectorX, ubSectorY, gubNumCreaturesAttackingTown, ( guCreatureAttackType == CREATURE_ATTACK_TYPE_BANDIT ) );
SectorInfo[ ubSectorID ].ubDayOfLastCreatureAttack = (UINT8)GetWorldDay(); SectorInfo[ ubSectorID ].ubDayOfLastCreatureAttack = (UINT8)GetWorldDay();
return; return;
} }
@@ -1157,6 +1258,223 @@ void CreatureAttackTown( UINT8 ubSectorID, BOOLEAN fOverrideTest )
LockPauseState( 2 ); LockPauseState( 2 );
} }
void CreatureAttackTown_OtherCreatures( UINT8 ubSectorID, UINT8 ubType )
{
if ( gfWorldLoaded && gTacticalStatus.fEnemyInSector )
{
//Battle currently in progress, repost the event
AddStrategicEvent( ubType, GetWorldTotalMin() + Random( 10 ), ubSectorID );
return;
}
// if this sector is not under player control, nothing to do
if ( StrategicMap[SECTOR_INFO_TO_STRATEGIC_INDEX ( ubSectorID )].fEnemyControlled )
return;
guCreatureAttackType = ubType;
UINT8 ubSectorX = SECTORX( ubSectorID );
UINT8 ubSectorY = SECTORY( ubSectorID );
// test whether the attack is possible in this sector according to xml settings
switch ( guCreatureAttackType )
{
case CREATURE_ATTACK_TYPE_BLOODCAT:
if ( !gGameExternalOptions.gRaid_Bloodcats || !( SectorExternalData[ubSectorID][0].usSectorFlagMask & SECTORFLAG_RAIDPOSSIBLE_BLOODCAT ) )
return;
break;
case CREATURE_ATTACK_TYPE_ZOMBIE:
if ( !gGameExternalOptions.gRaid_Zombies || !( SectorExternalData[ubSectorID][0].usSectorFlagMask & SECTORFLAG_RAIDPOSSIBLE_ZOMBIE ) )
return;
break;
case CREATURE_ATTACK_TYPE_BANDIT:
if ( !gGameExternalOptions.gRaid_Bandits || !( SectorExternalData[ubSectorID][0].usSectorFlagMask & SECTORFLAG_RAIDPOSSIBLE_BANDIT ) )
return;
break;
default:
return;
break;
}
// choose an insertion direction. The intention is to make it seem as if the raids occur from wilderness sectors into the sector
// note that attacks against non-town sectors work, but if no player forces are present, nothing happens (as loyalty won't be affected)
std::vector<INT16> possibleinsertioncodes;
for ( INT16 i = 0; i < THROUGH_STRATEGIC_MOVE; ++i )
{
INT16 loopX = ubSectorX;
INT16 loopY = ubSectorY;
if ( i == NORTH_STRATEGIC_MOVE ) --loopY;
else if ( i == EAST_STRATEGIC_MOVE ) ++loopX;
else if ( i == SOUTH_STRATEGIC_MOVE ) ++loopY;
else if ( i == WEST_STRATEGIC_MOVE ) --loopX;
if ( loopX < 1 || loopX >= MAP_WORLD_X - 1 || loopY < 1 || loopY >= MAP_WORLD_Y - 1 )
continue;
UINT8 townid_B = GetTownIdForSector( loopX, loopY );
if ( townid_B != BLANK_SECTOR )
continue;
UINT8 originsector = SECTOR(loopX, loopY);
// valid entry
if ( SectorInfo[originsector].ubTraversability[i] != GROUNDBARRIER &&
SectorInfo[originsector].ubTraversability[i] != TOWN &&
SectorInfo[originsector].ubTraversability[i] != WATER &&
SectorInfo[originsector].ubTraversability[i] != EDGEOFWORLD )
{
possibleinsertioncodes.push_back( i );
gsCreatureInsertionCode = i;
}
}
if ( possibleinsertioncodes.empty() )
return;
gsCreatureInsertionCode = possibleinsertioncodes[Random( possibleinsertioncodes.size())];
// determine how strong the player presence is, and then determine whether to attack, with how many dudes, or not to attack because the sector is defended to strongly
UINT16 militiapresent = NumNonPlayerTeamMembersInSector( ubSectorX, ubSectorY, MILITIA_TEAM );
UINT16 mercspresent = NumPlayerTeamMembersInSector( ubSectorX, ubSectorY, 0 );
// determine how many troops are available and stop the attack if we don't have enough
INT32 available_bloodcats;
INT32 available_zombies;
INT32 available_bandits;
GetRaidPersonnel( available_bloodcats, available_zombies, available_bandits );
switch ( guCreatureAttackType )
{
case CREATURE_ATTACK_TYPE_BLOODCAT:
gubNumCreaturesAttackingTown = min( gGameExternalOptions.gRaidMaxSize_Bloodcats, available_bloodcats );
// bloodcats won't attack if player forces are too numerous or not enough forces are available
if ( gubNumCreaturesAttackingTown < mercspresent + militiapresent )
return;
break;
case CREATURE_ATTACK_TYPE_ZOMBIE:
gubNumCreaturesAttackingTown = min( gGameExternalOptions.gRaidMaxSize_Zombies, available_zombies );
break;
case CREATURE_ATTACK_TYPE_BANDIT:
gubNumCreaturesAttackingTown = min( gGameExternalOptions.gRaidMaxSize_Bandits, available_bandits );
// bandits won't attack if player forces are too numerous or not enough forces are available
if ( gubNumCreaturesAttackingTown < mercspresent + militiapresent )
return;
break;
default:
return;
break;
}
// safety check - not too small
if ( gubNumCreaturesAttackingTown < 1 )
return;
gubCreatureBattleCode = CREATURE_BATTLE_CODE_NONE;
gubSectorIDOfCreatureAttack = ubSectorID;
//Now that the sector has been chosen, attack it!
if ( mercspresent )
{
gubCreatureBattleCode = CREATURE_BATTLE_CODE_PREBATTLEINTERFACE;
//we have players in the sector
if ( ubSectorX == gWorldSectorX && ubSectorY == gWorldSectorY && !gbWorldSectorZ )
{
//This is the currently loaded sector. All we have to do is change the music and insert
//the creatures tactically.
if ( guiCurrentScreen == GAME_SCREEN )
{
gubCreatureBattleCode = CREATURE_BATTLE_CODE_TACTICALLYADD;
}
}
}
else if ( militiapresent )
{
//we have militia in the sector
gubCreatureBattleCode = CREATURE_BATTLE_CODE_AUTORESOLVE;
}
else
{
// player controlled sector -- eat some civilians
AdjustLoyaltyForCivsEatenByMonsters( ubSectorX, ubSectorY, min(1, gubNumCreaturesAttackingTown / 2), ( guCreatureAttackType == CREATURE_ATTACK_TYPE_BANDIT ) );
// do NOT change sector ownership. This would cause the AI to stop attacking, and we can't have that, no?
//SetThisSectorAsEnemyControlled( ubSectorX, ubSectorY, 0, TRUE );
SectorInfo[ubSectorID].ubDayOfLastCreatureAttack = GetWorldDay();
return;
}
switch ( guCreatureAttackType )
{
case CREATURE_ATTACK_TYPE_BLOODCAT:
SetEnemyEncounterCode( BLOODCAT_ATTACK_CODE );
break;
case CREATURE_ATTACK_TYPE_ZOMBIE:
SetEnemyEncounterCode( ZOMBIE_ATTACK_CODE );
break;
case CREATURE_ATTACK_TYPE_BANDIT:
SetEnemyEncounterCode( BANDIT_ATTACK_CODE );
break;
default:
SetEnemyEncounterCode( CREATURE_ATTACK_CODE );
break;
}
SectorInfo[ubSectorID].ubDayOfLastCreatureAttack = (UINT8)GetWorldDay();
switch ( gubCreatureBattleCode )
{
case CREATURE_BATTLE_CODE_PREBATTLEINTERFACE:
InitPreBattleInterface( NULL, TRUE );
break;
case CREATURE_BATTLE_CODE_AUTORESOLVE:
gfAutomaticallyStartAutoResolve = TRUE;
InitPreBattleInterface( NULL, TRUE );
break;
case CREATURE_BATTLE_CODE_TACTICALLYADD:
if ( is_networked )
{
if ( is_server && gCreatureEnabled == 1 )
PrepareCreaturesForBattle();
}
else
PrepareCreaturesForBattle();
// alert the creatures
HandleInitialRedAlert( CREATURE_TEAM, FALSE );
// we need this so that the battle is properly recognized in strategic
{
//Set up the location as well as turning on the blit flag.
gubPBSectorX = (UINT8)ubSectorX;
gubPBSectorY = (UINT8)ubSectorY;
gubPBSectorZ = (UINT8)0;
gfBlitBattleSectorLocator = TRUE;
}
break;
}
InterruptTime();
PauseGame();
LockPauseState( 2 );
}
//Called by campaign init. //Called by campaign init.
void ChooseCreatureQuestStartDay() void ChooseCreatureQuestStartDay()
{ {
@@ -1376,15 +1694,13 @@ void DetermineCreatureTownComposition( UINT8 ubNumCreatures, UINT8 *pubNumYoungM
void DetermineCreatureTownCompositionBasedOnTacticalInformation( UINT8 *pubNumCreatures, UINT8 *pubNumYoungMales, UINT8 *pubNumYoungFemales, void DetermineCreatureTownCompositionBasedOnTacticalInformation( UINT8 *pubNumCreatures, UINT8 *pubNumYoungMales, UINT8 *pubNumYoungFemales,
UINT8 *pubNumAdultMales, UINT8 *pubNumAdultFemales ) UINT8 *pubNumAdultMales, UINT8 *pubNumAdultFemales )
{ {
SECTORINFO *pSector;
INT32 i;
SOLDIERTYPE *pSoldier; SOLDIERTYPE *pSoldier;
pSector = &SectorInfo[ SECTOR( gWorldSectorX, gWorldSectorY ) ]; SECTORINFO* pSector = &SectorInfo[ SECTOR( gWorldSectorX, gWorldSectorY ) ];
*pubNumCreatures = 0; *pubNumCreatures = 0;
pSector->ubNumCreatures = 0; pSector->ubNumCreatures = 0;
pSector->ubCreaturesInBattle = 0; pSector->ubCreaturesInBattle = 0;
for( i = gTacticalStatus.Team[ CREATURE_TEAM ].bFirstID; i <= gTacticalStatus.Team[ CREATURE_TEAM ].bLastID; i++ ) for( INT32 i = gTacticalStatus.Team[ CREATURE_TEAM ].bFirstID; i <= gTacticalStatus.Team[ CREATURE_TEAM ].bLastID; ++i )
{ {
pSoldier = MercPtrs[ i ]; pSoldier = MercPtrs[ i ];
if( pSoldier->bActive && pSoldier->bInSector && pSoldier->stats.bLife ) if( pSoldier->bActive && pSoldier->bInSector && pSoldier->stats.bLife )
@@ -1412,7 +1728,37 @@ void DetermineCreatureTownCompositionBasedOnTacticalInformation( UINT8 *pubNumCr
} }
} }
void DetermineOtherCreatureTownCompositionBasedOnTacticalInformation( UINT8* pubNumCreatures, UINT8* pubNumBloodcats, UINT8* pubNumZombies, UINT8* pubNumBandits )
{
SOLDIERTYPE *pSoldier;
SECTORINFO* pSector = &SectorInfo[SECTOR( gWorldSectorX, gWorldSectorY )];
*pubNumCreatures = 0;
pSector->ubNumCreatures = 0;
pSector->ubCreaturesInBattle = 0;
for ( INT32 i = gTacticalStatus.Team[CREATURE_TEAM].bFirstID; i <= gTacticalStatus.Team[CREATURE_TEAM].bLastID; ++i )
{
pSoldier = MercPtrs[i];
if ( pSoldier->bActive && pSoldier->bInSector && pSoldier->stats.bLife )
{
if ( pSoldier->IsZombie() )
{
( *pubNumCreatures )++;
( *pubNumZombies )++;
}
else if ( pSoldier->ubBodyType == BLOODCAT )
{
( *pubNumCreatures )++;
( *pubNumBloodcats )++;
}
else
{
( *pubNumCreatures )++;
( *pubNumBandits )++;
}
}
}
}
BOOLEAN PrepareCreaturesForBattle() BOOLEAN PrepareCreaturesForBattle()
{ {
@@ -1481,27 +1827,29 @@ BOOLEAN PrepareCreaturesForBattle()
{ {
return FALSE; return FALSE;
} }
//gfUseCreatureMusic = TRUE; //creatures are here, so play creature music //gfUseCreatureMusic = TRUE; //creatures are here, so play creature music
ubCreatureHabitat = pSector->ubCreatureHabitat; ubCreatureHabitat = pSector->ubCreatureHabitat;
ubNumCreatures = pSector->ubNumCreatures; ubNumCreatures = pSector->ubNumCreatures;
} }
else else
{ //creatures are attacking a town sector {
//creatures are attacking a town sector
//gfUseCreatureMusic = TRUE; //gfUseCreatureMusic = TRUE;
UseCreatureMusic(TRUE); UseCreatureMusic(TRUE);
#ifdef NEWMUSIC #ifdef NEWMUSIC
GlobalSoundID = MusicSoundValues[ SECTOR( gWorldSectorX, gWorldSectorY ) ].SoundTacticalNothing[gbWorldSectorZ]; GlobalSoundID = MusicSoundValues[ SECTOR( gWorldSectorX, gWorldSectorY ) ].SoundTacticalNothing[gbWorldSectorZ];
if ( MusicSoundValues[ SECTOR( gWorldSectorX, gWorldSectorY ) ].SoundTacticalNothing[gbWorldSectorZ] != -1 ) if ( MusicSoundValues[ SECTOR( gWorldSectorX, gWorldSectorY ) ].SoundTacticalNothing[gbWorldSectorZ] != -1 )
SetMusicModeID( MUSIC_TACTICAL_NOTHING, MusicSoundValues[ SECTOR( gWorldSectorX, gWorldSectorY ) ].SoundTacticalNothing[gbWorldSectorZ] ); SetMusicModeID( MUSIC_TACTICAL_NOTHING, MusicSoundValues[ SECTOR( gWorldSectorX, gWorldSectorY ) ].SoundTacticalNothing[gbWorldSectorZ] );
else else
#endif #endif
SetMusicMode( MUSIC_TACTICAL_NOTHING ); SetMusicMode( MUSIC_TACTICAL_NOTHING );
// externalize to xml data // externalize to xml data
//ubCreatureHabitat = MINE_EXIT; //ubCreatureHabitat = MINE_EXIT;
//assign the B1 underground habitat composition to the attacking creatures //assign the B1 underground habitat composition to the attacking creatures
for (UINT8 i = 0; i < MAX_NUMBER_OF_CREATURE_SECTORS; i++) for (UINT8 i = 0; i < MAX_NUMBER_OF_CREATURE_SECTORS; ++i)
{ {
INT16 sX = gCreaturePlacements[ giLairID ].sAttackSourceX; INT16 sX = gCreaturePlacements[ giLairID ].sAttackSourceX;
INT16 sY = gCreaturePlacements[ giLairID ].sAttackSourceY; INT16 sY = gCreaturePlacements[ giLairID ].sAttackSourceY;
@@ -1515,6 +1863,7 @@ BOOLEAN PrepareCreaturesForBattle()
break; break;
} }
} }
ubNumCreatures = gubNumCreaturesAttackingTown; ubNumCreatures = gubNumCreaturesAttackingTown;
} }
@@ -1576,90 +1925,132 @@ BOOLEAN PrepareCreaturesForBattle()
} }
*/ */
//out-of-range habitat if ( guCreatureAttackType == CREATURE_ATTACK_TYPE_CREATURE )
if( ubCreatureHabitat >= NUMBER_OF_CREATURE_COMPOSITIONS )
{ {
AssertMsg( 0, String( "Invalid creature habitat ID of %d for PrepareCreaturesForBattle.", ubCreatureHabitat ) ); //out-of-range habitat
} if ( ubCreatureHabitat >= NUMBER_OF_CREATURE_COMPOSITIONS )
{
//queen sector AssertMsg( 0, String( "Invalid creature habitat ID of %d for PrepareCreaturesForBattle.", ubCreatureHabitat ) );
if( !ubCreatureHabitat ) }
fQueen = TRUE;
else
fQueen = FALSE;
ubLarvaePercentage = gCreatureComposition[ ubCreatureHabitat ].ubLarvaePercent; //queen sector
ubInfantPercentage = gCreatureComposition[ ubCreatureHabitat ].ubInfantPercent; if ( !ubCreatureHabitat )
ubYoungMalePercentage = gCreatureComposition[ ubCreatureHabitat ].ubYoungMalePercent; fQueen = TRUE;
ubYoungFemalePercentage = gCreatureComposition[ ubCreatureHabitat ].ubYoungFemalePercent;
ubAdultMalePercentage = gCreatureComposition[ ubCreatureHabitat ].ubAdultMalePercent;
ubAdultFemalePercentage = gCreatureComposition[ ubCreatureHabitat ].ubAdultFemalePercent;
//First step is to convert the percentages into the numbers we will use.
if( fQueen )
{
ubNumCreatures--;
}
ubInfantPercentage += ubLarvaePercentage;
ubYoungMalePercentage += ubInfantPercentage;
ubYoungFemalePercentage += ubYoungMalePercentage;
ubAdultMalePercentage += ubYoungFemalePercentage;
ubAdultFemalePercentage += ubAdultMalePercentage;
if( ubAdultFemalePercentage != 100 )
{
AssertMsg( 0, "Percentage for adding creatures don't add up to 100." );
}
//Second step is to determine the breakdown of the creatures randomly.
i = ubNumCreatures;
while( i-- )
{
iRandom = Random( 100 );
if( iRandom < ubLarvaePercentage )
ubNumLarvae++;
else if( iRandom < ubInfantPercentage )
ubNumInfants++;
else if( iRandom < ubYoungMalePercentage )
ubNumYoungMales++;
else if( iRandom < ubYoungFemalePercentage )
ubNumYoungFemales++;
else if( iRandom < ubAdultMalePercentage )
ubNumAdultMales++;
else else
ubNumAdultFemales++; fQueen = FALSE;
ubLarvaePercentage = gCreatureComposition[ubCreatureHabitat].ubLarvaePercent;
ubInfantPercentage = gCreatureComposition[ubCreatureHabitat].ubInfantPercent;
ubYoungMalePercentage = gCreatureComposition[ubCreatureHabitat].ubYoungMalePercent;
ubYoungFemalePercentage = gCreatureComposition[ubCreatureHabitat].ubYoungFemalePercent;
ubAdultMalePercentage = gCreatureComposition[ubCreatureHabitat].ubAdultMalePercent;
ubAdultFemalePercentage = gCreatureComposition[ubCreatureHabitat].ubAdultFemalePercent;
//First step is to convert the percentages into the numbers we will use.
if ( fQueen )
{
ubNumCreatures--;
}
ubInfantPercentage += ubLarvaePercentage;
ubYoungMalePercentage += ubInfantPercentage;
ubYoungFemalePercentage += ubYoungMalePercentage;
ubAdultMalePercentage += ubYoungFemalePercentage;
ubAdultFemalePercentage += ubAdultMalePercentage;
if ( ubAdultFemalePercentage != 100 )
{
AssertMsg( 0, "Percentage for adding creatures don't add up to 100." );
}
//Second step is to determine the breakdown of the creatures randomly.
i = ubNumCreatures;
while ( i-- )
{
iRandom = Random( 100 );
if ( iRandom < ubLarvaePercentage )
ubNumLarvae++;
else if ( iRandom < ubInfantPercentage )
ubNumInfants++;
else if ( iRandom < ubYoungMalePercentage )
ubNumYoungMales++;
else if ( iRandom < ubYoungFemalePercentage )
ubNumYoungFemales++;
else if ( iRandom < ubAdultMalePercentage )
ubNumAdultMales++;
else
ubNumAdultFemales++;
}
} }
if( gbWorldSectorZ ) if( gbWorldSectorZ )
{ {
UNDERGROUND_SECTORINFO *pUndergroundSector; UNDERGROUND_SECTORINFO *pUndergroundSector = FindUnderGroundSector( gWorldSectorX, gWorldSectorY, gbWorldSectorZ );
pUndergroundSector = FindUnderGroundSector( gWorldSectorX, gWorldSectorY, gbWorldSectorZ );
if( !pUndergroundSector ) if( !pUndergroundSector )
{ //No info?!!!!! {
//No info?!!!!!
AssertMsg( 0, "Please report underground sector you are in or going to and send save if possible. KM : 0" ); AssertMsg( 0, "Please report underground sector you are in or going to and send save if possible. KM : 0" );
return FALSE; return FALSE;
} }
pUndergroundSector->ubCreaturesInBattle = pUndergroundSector->ubNumCreatures; pUndergroundSector->ubCreaturesInBattle = pUndergroundSector->ubNumCreatures;
} }
else else
{ {
SECTORINFO *pSector; SECTORINFO *pSector;
pSector = &SectorInfo[ SECTOR( gWorldSectorX, gWorldSectorY ) ]; pSector = &SectorInfo[ SECTOR( gWorldSectorX, gWorldSectorY ) ];
pSector->ubNumCreatures = ubNumCreatures;
pSector->ubCreaturesInBattle = ubNumCreatures;
}
switch ( guCreatureAttackType )
{
case CREATURE_ATTACK_TYPE_CREATURE:
case CREATURE_ATTACK_TYPE_ZOMBIE:
case CREATURE_ATTACK_TYPE_BANDIT:
pSector->ubNumCreatures = ubNumCreatures;
pSector->ubCreaturesInBattle = ubNumCreatures;
break;
case CREATURE_ATTACK_TYPE_BLOODCAT:
pSector->bBloodCats = ubNumCreatures;
pSector->ubCreaturesInBattle = ubNumCreatures;
break;
}
}
switch( gubCreatureBattleCode ) switch( gubCreatureBattleCode )
{ {
case CREATURE_BATTLE_CODE_NONE: //in the mines case CREATURE_BATTLE_CODE_NONE: //in the mines
AddSoldierInitListCreatures( fQueen, ubNumLarvae, ubNumInfants, switch ( guCreatureAttackType )
ubNumYoungMales, ubNumYoungFemales, ubNumAdultMales, ubNumAdultFemales ); {
case CREATURE_ATTACK_TYPE_CREATURE:
AddSoldierInitListCreatures( fQueen, ubNumLarvae, ubNumInfants, ubNumYoungMales, ubNumYoungFemales, ubNumAdultMales, ubNumAdultFemales );
break;
case CREATURE_ATTACK_TYPE_ZOMBIE:
case CREATURE_ATTACK_TYPE_BANDIT:
case CREATURE_ATTACK_TYPE_BLOODCAT:
AddSoldierInitListOtherCreatures( ubNumCreatures );
break;
}
break; break;
case CREATURE_BATTLE_CODE_TACTICALLYADD: //creature attacking a town sector case CREATURE_BATTLE_CODE_TACTICALLYADD: //creature attacking a town sector
case CREATURE_BATTLE_CODE_PREBATTLEINTERFACE: case CREATURE_BATTLE_CODE_PREBATTLEINTERFACE:
AddCreaturesToBattle( ubNumYoungMales, ubNumYoungFemales, ubNumAdultMales, ubNumAdultFemales ); switch ( guCreatureAttackType )
{
case CREATURE_ATTACK_TYPE_CREATURE:
AddCreaturesToBattle( ubNumYoungMales, ubNumYoungFemales, ubNumAdultMales, ubNumAdultFemales );
break;
case CREATURE_ATTACK_TYPE_ZOMBIE:
case CREATURE_ATTACK_TYPE_BANDIT:
case CREATURE_ATTACK_TYPE_BLOODCAT:
AddCreaturesToBattle_Other( ubNumCreatures );
break;
}
break; break;
case CREATURE_BATTLE_CODE_AUTORESOLVE: case CREATURE_BATTLE_CODE_AUTORESOLVE:
return FALSE; return FALSE;
} }
return TRUE; return TRUE;
} }
+11
View File
@@ -15,6 +15,7 @@ UINT8 CreaturesInUndergroundSector( UINT8 ubSectorID, UINT8 ubSectorZ );
BOOLEAN PrepareCreaturesForBattle(); BOOLEAN PrepareCreaturesForBattle();
void CreatureNightPlanning(); void CreatureNightPlanning();
void CreatureAttackTown( UINT8 ubSectorID, BOOLEAN fOverrideTest ); void CreatureAttackTown( UINT8 ubSectorID, BOOLEAN fOverrideTest );
void CreatureAttackTown_OtherCreatures( UINT8 ubSectorID, UINT8 ubType );
void CheckConditionsForTriggeringCreatureQuest( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ ); void CheckConditionsForTriggeringCreatureQuest( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ );
@@ -44,6 +45,14 @@ enum{
}; };
extern UINT8 gubCreatureBattleCode; extern UINT8 gubCreatureBattleCode;
enum {
CREATURE_ATTACK_TYPE_CREATURE,
CREATURE_ATTACK_TYPE_BLOODCAT,
CREATURE_ATTACK_TYPE_ZOMBIE,
CREATURE_ATTACK_TYPE_BANDIT,
};
extern UINT8 guCreatureAttackType;
void DetermineCreatureTownComposition( UINT8 ubNumCreatures, void DetermineCreatureTownComposition( UINT8 ubNumCreatures,
UINT8 *pubNumYoungMales, UINT8 *pubNumYoungFemales, UINT8 *pubNumYoungMales, UINT8 *pubNumYoungFemales,
UINT8 *pubNumAdultMales, UINT8 *pubNumAdultFemales ); UINT8 *pubNumAdultMales, UINT8 *pubNumAdultFemales );
@@ -52,6 +61,8 @@ void DetermineCreatureTownCompositionBasedOnTacticalInformation( UINT8 *pubNumCr
UINT8 *pubNumYoungMales, UINT8 *pubNumYoungFemales, UINT8 *pubNumYoungMales, UINT8 *pubNumYoungFemales,
UINT8 *pubNumAdultMales, UINT8 *pubNumAdultFemales ); UINT8 *pubNumAdultMales, UINT8 *pubNumAdultFemales );
void DetermineOtherCreatureTownCompositionBasedOnTacticalInformation( UINT8* pubNumCreatures, UINT8* pubNumBloodcats, UINT8* pubNumZombies, UINT8* pubNumBandits );
BOOLEAN PlayerGroupIsInACreatureInfestedMine(); BOOLEAN PlayerGroupIsInACreatureInfestedMine();
+16
View File
@@ -644,6 +644,22 @@ BOOLEAN ExecuteStrategicEvent( STRATEGICEVENT *pEvent )
case EVENT_INTEL_PHOTOFACT_VERIFY: case EVENT_INTEL_PHOTOFACT_VERIFY:
LuaVerifyPhotoState( (INT16)pEvent->uiParam ); LuaVerifyPhotoState( (INT16)pEvent->uiParam );
break; break;
case EVENT_DAILY_RAID_EVENTS:
HandleRaidEventPlanning();
break;
case EVENT_BLOODCAT_ATTACK:
CreatureAttackTown_OtherCreatures( (UINT8)pEvent->uiParam, CREATURE_ATTACK_TYPE_BLOODCAT );
break;
case EVENT_ZOMBIE_ATTACK:
CreatureAttackTown_OtherCreatures( (UINT8)pEvent->uiParam, CREATURE_ATTACK_TYPE_ZOMBIE );
break;
case EVENT_BANDIT_ATTACK:
CreatureAttackTown_OtherCreatures( (UINT8)pEvent->uiParam, CREATURE_ATTACK_TYPE_BANDIT );
break;
} }
gfPreventDeletionOfAnyEvent = fOrigPreventFlag; gfPreventDeletionOfAnyEvent = fOrigPreventFlag;
return TRUE; return TRUE;
+5
View File
@@ -143,6 +143,11 @@ enum
EVENT_INTEL_ENRICO_EMAIL, // Flugente: Enrico sends us an email introduction to intel EVENT_INTEL_ENRICO_EMAIL, // Flugente: Enrico sends us an email introduction to intel
EVENT_INTEL_PHOTOFACT_VERIFY, // verification of a photo fact EVENT_INTEL_PHOTOFACT_VERIFY, // verification of a photo fact
EVENT_DAILY_RAID_EVENTS, // Flugente: daily planning of raids on player sectors
EVENT_BLOODCAT_ATTACK, // Flugente: like a creature attack, but with cats
EVENT_ZOMBIE_ATTACK, // Flugente: like a creature attack, but with zombies
EVENT_BANDIT_ATTACK, // Flugente: like a creature attack, but with bandits
NUMBER_OF_EVENT_TYPES_PLUS_ONE, NUMBER_OF_EVENT_TYPES_PLUS_ONE,
NUMBER_OF_EVENT_TYPES = NUMBER_OF_EVENT_TYPES_PLUS_ONE - 1 NUMBER_OF_EVENT_TYPES = NUMBER_OF_EVENT_TYPES_PLUS_ONE - 1
}; };
+9 -13
View File
@@ -4051,22 +4051,18 @@ return 0;
// used when monsters attack a town sector without going through tactical and they win // used when monsters attack a town sector without going through tactical and they win
static int l_AdjustLoyaltyForCivsEatenByMonsters(lua_State *L) static int l_AdjustLoyaltyForCivsEatenByMonsters(lua_State *L)
{ {
UINT8 n = lua_gettop(L); UINT8 n = lua_gettop(L);
int i;
INT16 sSectorX; if ( n >= 3 )
INT16 sSectorY;
UINT8 ubHowMany;
for (i= 1; i<=n; i++ )
{ {
if (i == 1 ) sSectorX = lua_tointeger(L,i); INT16 sSectorX = lua_tointeger( L, 1 );
if (i == 2 ) sSectorY = lua_tointeger(L,i); INT16 sSectorY = lua_tointeger( L, 2 );
if (i == 3 ) ubHowMany = lua_tointeger(L,i); UINT8 ubHowMany = lua_tointeger( L, 3 );
AdjustLoyaltyForCivsEatenByMonsters( sSectorX, sSectorY, ubHowMany, ( guCreatureAttackType == CREATURE_ATTACK_TYPE_BANDIT ) );
} }
AdjustLoyaltyForCivsEatenByMonsters( sSectorX, sSectorY, ubHowMany); return 0;
return 0;
} }
static int l_IsTownUnderCompleteControlByPlayer(lua_State *L) static int l_IsTownUnderCompleteControlByPlayer(lua_State *L)
+71 -7
View File
@@ -414,7 +414,7 @@ void InitPreBattleInterface( GROUP *pBattleGroup, BOOLEAN fPersistantPBI )
//There are hostile civilians, so no autoresolve allowed. //There are hostile civilians, so no autoresolve allowed.
SetExplicitEnemyEncounterCode( HOSTILE_CIVILIANS_CODE ); SetExplicitEnemyEncounterCode( HOSTILE_CIVILIANS_CODE );
} }
else if( HostileBloodcatsPresent() ) else if ( GetEnemyEncounterCode() != BLOODCAT_ATTACK_CODE && HostileBloodcatsPresent() )
{ {
//There are bloodcats in the sector, so no autoresolve allowed //There are bloodcats in the sector, so no autoresolve allowed
SetExplicitEnemyEncounterCode( HOSTILE_BLOODCATS_CODE ); SetExplicitEnemyEncounterCode( HOSTILE_BLOODCATS_CODE );
@@ -447,8 +447,12 @@ void InitPreBattleInterface( GROUP *pBattleGroup, BOOLEAN fPersistantPBI )
GetEnemyEncounterCode() == CREATURE_ATTACK_CODE || GetEnemyEncounterCode() == CREATURE_ATTACK_CODE ||
GetEnemyEncounterCode() == ENEMY_AMBUSH_DEPLOYMENT_CODE || GetEnemyEncounterCode() == ENEMY_AMBUSH_DEPLOYMENT_CODE ||
GetEnemyEncounterCode() == ENEMY_INVASION_AIRDROP_CODE || GetEnemyEncounterCode() == ENEMY_INVASION_AIRDROP_CODE ||
GetEnemyEncounterCode() == CONCEALINSERTION_CODE ) GetEnemyEncounterCode() == CONCEALINSERTION_CODE ||
{ //use same code GetEnemyEncounterCode() == BLOODCAT_ATTACK_CODE ||
GetEnemyEncounterCode() == ZOMBIE_ATTACK_CODE ||
GetEnemyEncounterCode() == BANDIT_ATTACK_CODE )
{
//use same code
SetExplicitEnemyEncounterCode( GetEnemyEncounterCode() ); SetExplicitEnemyEncounterCode( GetEnemyEncounterCode() );
} }
else else
@@ -636,7 +640,24 @@ void InitPreBattleInterface( GROUP *pBattleGroup, BOOLEAN fPersistantPBI )
else else
{ {
//creature's attacking! //creature's attacking!
SetEnemyEncounterCode( CREATURE_ATTACK_CODE); switch ( guCreatureAttackType )
{
case CREATURE_ATTACK_TYPE_BLOODCAT:
SetEnemyEncounterCode( BLOODCAT_ATTACK_CODE );
break;
case CREATURE_ATTACK_TYPE_ZOMBIE:
SetEnemyEncounterCode( ZOMBIE_ATTACK_CODE );
break;
case CREATURE_ATTACK_TYPE_BANDIT:
SetEnemyEncounterCode( BANDIT_ATTACK_CODE );
break;
default:
SetEnemyEncounterCode( CREATURE_ATTACK_CODE );
break;
}
} }
} }
else if ( gpBattleGroup->usGroupTeam == OUR_TEAM ) else if ( gpBattleGroup->usGroupTeam == OUR_TEAM )
@@ -901,7 +922,10 @@ void InitPreBattleInterface( GROUP *pBattleGroup, BOOLEAN fPersistantPBI )
GetEnemyEncounterCode() == BLOODCAT_AMBUSH_CODE || GetEnemyEncounterCode() == BLOODCAT_AMBUSH_CODE ||
GetEnemyEncounterCode() == ENEMY_AMBUSH_DEPLOYMENT_CODE || GetEnemyEncounterCode() == ENEMY_AMBUSH_DEPLOYMENT_CODE ||
GetEnemyEncounterCode() == CREATURE_ATTACK_CODE || GetEnemyEncounterCode() == CREATURE_ATTACK_CODE ||
is_client) GetEnemyEncounterCode() == BLOODCAT_ATTACK_CODE ||
GetEnemyEncounterCode() == ZOMBIE_ATTACK_CODE ||
GetEnemyEncounterCode() == BANDIT_ATTACK_CODE ||
is_client)
{ {
DisableButton( iPBButton[ 2 ] ); DisableButton( iPBButton[ 2 ] );
SetButtonFastHelpText( iPBButton[ 2 ], gzNonPersistantPBIText[ 9 ] ); SetButtonFastHelpText( iPBButton[ 2 ], gzNonPersistantPBIText[ 9 ] );
@@ -931,6 +955,9 @@ void InitPreBattleInterface( GROUP *pBattleGroup, BOOLEAN fPersistantPBI )
case ENEMY_ENCOUNTER_CODE: case ENEMY_ENCOUNTER_CODE:
case ENEMY_INVASION_CODE: case ENEMY_INVASION_CODE:
case ENEMY_INVASION_AIRDROP_CODE: case ENEMY_INVASION_AIRDROP_CODE:
case BLOODCAT_ATTACK_CODE:
case ZOMBIE_ATTACK_CODE:
case BANDIT_ATTACK_CODE:
SetButtonFastHelpText( iPBButton[ 0 ], gzNonPersistantPBIText[ 2 ] ); SetButtonFastHelpText( iPBButton[ 0 ], gzNonPersistantPBIText[ 2 ] );
break; break;
case ENTERING_ENEMY_SECTOR_CODE: case ENTERING_ENEMY_SECTOR_CODE:
@@ -1211,6 +1238,18 @@ void RenderPBHeader( INT32 *piX, INT32 *piWidth)
case CONCEALINSERTION_CODE: case CONCEALINSERTION_CODE:
swprintf( str, gpStrategicString[STR_PB_ENEMYENCOUNTER_HEADER] ); swprintf( str, gpStrategicString[STR_PB_ENEMYENCOUNTER_HEADER] );
break; break;
case BLOODCAT_ATTACK_CODE:
swprintf( str, gpStrategicString[STR_PB_BLOODCATRAID_HEADER] );
gfBlinkHeader = TRUE;
break;
case ZOMBIE_ATTACK_CODE:
swprintf( str, gpStrategicString[STR_PB_ZOMBIERAID_HEADER] );
gfBlinkHeader = TRUE;
break;
case BANDIT_ATTACK_CODE:
swprintf( str, gpStrategicString[STR_PB_BANDITRAID_HEADER] );
gfBlinkHeader = TRUE;
break;
} }
width = StringPixLength( str, FONT10ARIALBOLD ); width = StringPixLength( str, FONT10ARIALBOLD );
x = 130 - width / 2; x = 130 - width / 2;
@@ -1307,10 +1346,20 @@ void RenderPreBattleInterface()
{ {
swprintf( str, gpStrategicString[STR_PB_CREATURES ] ); swprintf( str, gpStrategicString[STR_PB_CREATURES ] );
} }
else if( GetEnemyEncounterCode() == BLOODCAT_AMBUSH_CODE || GetEnemyEncounterCode() == ENTERING_BLOODCAT_LAIR_CODE ) else if( GetEnemyEncounterCode() == BLOODCAT_AMBUSH_CODE ||
GetEnemyEncounterCode() == ENTERING_BLOODCAT_LAIR_CODE ||
GetEnemyEncounterCode() == BLOODCAT_ATTACK_CODE )
{ {
swprintf( str, gpStrategicString[ STR_PB_BLOODCATS ] ); swprintf( str, gpStrategicString[ STR_PB_BLOODCATS ] );
} }
else if ( GetEnemyEncounterCode() == ZOMBIE_ATTACK_CODE )
{
swprintf( str, gpStrategicString[STR_PB_ZOMBIES] );
}
else if ( GetEnemyEncounterCode() == BANDIT_ATTACK_CODE )
{
swprintf( str, gpStrategicString[STR_PB_BANDITS] );
}
else else
{ {
swprintf( str, gpStrategicString[ STR_PB_ENEMIES ] ); swprintf( str, gpStrategicString[ STR_PB_ENEMIES ] );
@@ -1371,6 +1420,9 @@ void RenderPreBattleInterface()
if( GetEnemyEncounterCode() == CREATURE_ATTACK_CODE || if( GetEnemyEncounterCode() == CREATURE_ATTACK_CODE ||
GetEnemyEncounterCode() == BLOODCAT_AMBUSH_CODE || GetEnemyEncounterCode() == BLOODCAT_AMBUSH_CODE ||
GetEnemyEncounterCode() == ENTERING_BLOODCAT_LAIR_CODE || GetEnemyEncounterCode() == ENTERING_BLOODCAT_LAIR_CODE ||
GetEnemyEncounterCode() == BLOODCAT_ATTACK_CODE ||
GetEnemyEncounterCode() == ZOMBIE_ATTACK_CODE ||
GetEnemyEncounterCode() == BANDIT_ATTACK_CODE ||
WhatPlayerKnowsAboutEnemiesInSector( gubPBSectorX, gubPBSectorY ) < KNOWS_THEYRE_THERE_AND_HOW_MANY ) // HEADROCK HAM 5: New case above this one... WhatPlayerKnowsAboutEnemiesInSector( gubPBSectorX, gubPBSectorY ) < KNOWS_THEYRE_THERE_AND_HOW_MANY ) // HEADROCK HAM 5: New case above this one...
{ {
// don't know how many // don't know how many
@@ -1600,7 +1652,10 @@ void GoToSectorCallback( GUI_BUTTON *btn, INT32 reason )
GetEnemyEncounterCode() != CREATURE_ATTACK_CODE && GetEnemyEncounterCode() != CREATURE_ATTACK_CODE &&
GetEnemyEncounterCode() != BLOODCAT_AMBUSH_CODE && GetEnemyEncounterCode() != BLOODCAT_AMBUSH_CODE &&
GetEnemyEncounterCode() != ENEMY_INVASION_AIRDROP_CODE && GetEnemyEncounterCode() != ENEMY_INVASION_AIRDROP_CODE &&
GetEnemyEncounterCode() != CONCEALINSERTION_CODE ) GetEnemyEncounterCode() != CONCEALINSERTION_CODE &&
GetEnemyEncounterCode() != BLOODCAT_ATTACK_CODE &&
GetEnemyEncounterCode() != ZOMBIE_ATTACK_CODE &&
GetEnemyEncounterCode() != BANDIT_ATTACK_CODE )
{ {
gfEnterTacticalPlacementGUI = TRUE; gfEnterTacticalPlacementGUI = TRUE;
} }
@@ -2404,6 +2459,7 @@ void LogBattleResults( UINT8 ubVictoryCode)
switch( GetEnemyEncounterCode() ) switch( GetEnemyEncounterCode() )
{ {
case ENEMY_INVASION_CODE: case ENEMY_INVASION_CODE:
case BANDIT_ATTACK_CODE:
AddHistoryToPlayersLog( HISTORY_DEFENDEDTOWNSECTOR, 0, GetWorldTotalMin(), sSectorX, sSectorY ); AddHistoryToPlayersLog( HISTORY_DEFENDEDTOWNSECTOR, 0, GetWorldTotalMin(), sSectorX, sSectorY );
break; break;
case ENEMY_ENCOUNTER_CODE: case ENEMY_ENCOUNTER_CODE:
@@ -2418,10 +2474,12 @@ void LogBattleResults( UINT8 ubVictoryCode)
AddHistoryToPlayersLog( HISTORY_SUCCESSFULATTACK, 0, GetWorldTotalMin(), sSectorX, sSectorY ); AddHistoryToPlayersLog( HISTORY_SUCCESSFULATTACK, 0, GetWorldTotalMin(), sSectorX, sSectorY );
break; break;
case CREATURE_ATTACK_CODE: case CREATURE_ATTACK_CODE:
case ZOMBIE_ATTACK_CODE:
AddHistoryToPlayersLog( HISTORY_CREATURESATTACKED, 0, GetWorldTotalMin(), sSectorX, sSectorY ); AddHistoryToPlayersLog( HISTORY_CREATURESATTACKED, 0, GetWorldTotalMin(), sSectorX, sSectorY );
break; break;
case BLOODCAT_AMBUSH_CODE: case BLOODCAT_AMBUSH_CODE:
case ENTERING_BLOODCAT_LAIR_CODE: case ENTERING_BLOODCAT_LAIR_CODE:
case BLOODCAT_ATTACK_CODE:
AddHistoryToPlayersLog( HISTORY_SLAUGHTEREDBLOODCATS, 0, GetWorldTotalMin(), sSectorX, sSectorY ); AddHistoryToPlayersLog( HISTORY_SLAUGHTEREDBLOODCATS, 0, GetWorldTotalMin(), sSectorX, sSectorY );
break; break;
case CONCEALINSERTION_CODE: case CONCEALINSERTION_CODE:
@@ -2436,6 +2494,7 @@ void LogBattleResults( UINT8 ubVictoryCode)
switch( GetEnemyEncounterCode() ) switch( GetEnemyEncounterCode() )
{ {
case ENEMY_INVASION_CODE: case ENEMY_INVASION_CODE:
case BANDIT_ATTACK_CODE:
AddHistoryToPlayersLog( HISTORY_LOSTTOWNSECTOR, 0, GetWorldTotalMin(), sSectorX, sSectorY ); AddHistoryToPlayersLog( HISTORY_LOSTTOWNSECTOR, 0, GetWorldTotalMin(), sSectorX, sSectorY );
break; break;
case ENEMY_ENCOUNTER_CODE: case ENEMY_ENCOUNTER_CODE:
@@ -2450,10 +2509,12 @@ void LogBattleResults( UINT8 ubVictoryCode)
AddHistoryToPlayersLog( HISTORY_UNSUCCESSFULATTACK, 0, GetWorldTotalMin(), sSectorX, sSectorY ); AddHistoryToPlayersLog( HISTORY_UNSUCCESSFULATTACK, 0, GetWorldTotalMin(), sSectorX, sSectorY );
break; break;
case CREATURE_ATTACK_CODE: case CREATURE_ATTACK_CODE:
case ZOMBIE_ATTACK_CODE:
AddHistoryToPlayersLog( HISTORY_CREATURESATTACKED, 0, GetWorldTotalMin(), sSectorX, sSectorY ); AddHistoryToPlayersLog( HISTORY_CREATURESATTACKED, 0, GetWorldTotalMin(), sSectorX, sSectorY );
break; break;
case BLOODCAT_AMBUSH_CODE: case BLOODCAT_AMBUSH_CODE:
case ENTERING_BLOODCAT_LAIR_CODE: case ENTERING_BLOODCAT_LAIR_CODE:
case BLOODCAT_ATTACK_CODE:
AddHistoryToPlayersLog( HISTORY_KILLEDBYBLOODCATS, 0, GetWorldTotalMin(), sSectorX, sSectorY ); AddHistoryToPlayersLog( HISTORY_KILLEDBYBLOODCATS, 0, GetWorldTotalMin(), sSectorX, sSectorY );
break; break;
case CONCEALINSERTION_CODE: case CONCEALINSERTION_CODE:
@@ -2464,6 +2525,9 @@ void LogBattleResults( UINT8 ubVictoryCode)
switch( GetEnemyEncounterCode() ) switch( GetEnemyEncounterCode() )
{ {
case ENEMY_INVASION_CODE: case ENEMY_INVASION_CODE:
case BLOODCAT_ATTACK_CODE:
case ZOMBIE_ATTACK_CODE:
case BANDIT_ATTACK_CODE:
gCurrentIncident.usIncidentFlags |= INCIDENT_ATTACK_ENEMY; gCurrentIncident.usIncidentFlags |= INCIDENT_ATTACK_ENEMY;
break; break;
case ENEMY_ENCOUNTER_CODE: case ENEMY_ENCOUNTER_CODE:
+4
View File
@@ -43,6 +43,10 @@ enum
ENEMY_AMBUSH_DEPLOYMENT_CODE, // Flugente: an ambush in which we can deploy our mercs (somewhat) ENEMY_AMBUSH_DEPLOYMENT_CODE, // Flugente: an ambush in which we can deploy our mercs (somewhat)
ENEMY_INVASION_AIRDROP_CODE, // Flugente: enemy airdrop ENEMY_INVASION_AIRDROP_CODE, // Flugente: enemy airdrop
CONCEALINSERTION_CODE, // Flugente: a spy is no longer concealed, this causes us to drop into combat CONCEALINSERTION_CODE, // Flugente: a spy is no longer concealed, this causes us to drop into combat
BLOODCAT_ATTACK_CODE, // Flugente: like CREATURE_ATTACK_CODE, but with cats
ZOMBIE_ATTACK_CODE, // Flugente: like CREATURE_ATTACK_CODE, but with zombies
BANDIT_ATTACK_CODE, // Flugente: like CREATURE_ATTACK_CODE, but with bandits
}; };
extern BOOLEAN gfAutoAmbush; extern BOOLEAN gfAutoAmbush;
+32 -23
View File
@@ -738,7 +738,8 @@ BOOLEAN PrepareEnemyForSectorBattle()
{ {
switch( curr->pBasicPlacement->ubSoldierClass ) switch( curr->pBasicPlacement->ubSoldierClass )
{ {
case SOLDIER_CLASS_ADMINISTRATOR: ubTotalAdmins++; break; case SOLDIER_CLASS_ADMINISTRATOR:
case SOLDIER_CLASS_BANDIT: ubTotalAdmins++; break;
case SOLDIER_CLASS_ARMY: ubTotalTroops++; break; case SOLDIER_CLASS_ARMY: ubTotalTroops++; break;
case SOLDIER_CLASS_ELITE: ubTotalElites++; break; case SOLDIER_CLASS_ELITE: ubTotalElites++; break;
case SOLDIER_CLASS_TANK: ubTotalTanks++; break; case SOLDIER_CLASS_TANK: ubTotalTanks++; break;
@@ -1459,14 +1460,15 @@ void ProcessQueenCmdImplicationsOfDeath( SOLDIERTYPE *pSoldier )
} }
break; break;
case SOLDIER_CLASS_CREATURE: case SOLDIER_CLASS_CREATURE:
case SOLDIER_CLASS_BANDIT:
if( pSoldier->ubBodyType != BLOODCAT ) if( pSoldier->ubBodyType != BLOODCAT )
{ {
#ifdef JA2BETAVERSION #ifdef JA2BETAVERSION
if( guiCurrentScreen == GAME_SCREEN ) if( guiCurrentScreen == GAME_SCREEN )
{ {
if( ubTotalEnemies <= (UINT32)iMaxEnemyGroupSize && pSector->ubNumCreatures != pSector->ubCreaturesInBattle || if( ubTotalEnemies <= (UINT32)iMaxEnemyGroupSize && pSector->ubNumCreatures != pSector->ubCreaturesInBattle ||
!pSector->ubNumCreatures || !pSector->ubCreaturesInBattle || !pSector->ubNumCreatures || !pSector->ubCreaturesInBattle ||
pSector->ubNumCreatures > 50 || pSector->ubCreaturesInBattle > 50 ) pSector->ubNumCreatures > 50 || pSector->ubCreaturesInBattle > 50 )
{ {
DoScreenIndependantMessageBox( L"Sector creature counters are bad. What were the last 2-3 things to die, and how? Save game and send to KM with info!!!", MSG_BOX_FLAG_OK, NULL ); DoScreenIndependantMessageBox( L"Sector creature counters are bad. What were the last 2-3 things to die, and how? Save game and send to KM with info!!!", MSG_BOX_FLAG_OK, NULL );
} }
@@ -1563,6 +1565,7 @@ void ProcessQueenCmdImplicationsOfDeath( SOLDIERTYPE *pSoldier )
} }
break; break;
case SOLDIER_CLASS_CREATURE: case SOLDIER_CLASS_CREATURE:
case SOLDIER_CLASS_BANDIT:
if (pSoldier->ubBodyType == BLOODCAT) if (pSoldier->ubBodyType == BLOODCAT)
{ {
if( pSector->ubNumBloodcats > 0 ) if( pSector->ubNumBloodcats > 0 )
@@ -1570,14 +1573,16 @@ void ProcessQueenCmdImplicationsOfDeath( SOLDIERTYPE *pSoldier )
} }
else else
{ {
#ifdef JA2BETAVERSION #ifdef JA2BETAVERSION
if( ubTotalEnemies <= (UINT32)iMaxEnemyGroupSize && pSector->ubNumCreatures != pSector->ubCreaturesInBattle || if( ubTotalEnemies <= (UINT32)iMaxEnemyGroupSize && pSector->ubNumCreatures != pSector->ubCreaturesInBattle ||
!pSector->ubNumCreatures || !pSector->ubCreaturesInBattle || !pSector->ubNumCreatures ||
pSector->ubNumCreatures > gGameExternalOptions.ubGameMaximumNumberOfCreatures || pSector->ubCreaturesInBattle > gGameExternalOptions.ubGameMaximumNumberOfCreatures ) !pSector->ubCreaturesInBattle ||
pSector->ubNumCreatures > gGameExternalOptions.ubGameMaximumNumberOfCreatures ||
pSector->ubCreaturesInBattle > gGameExternalOptions.ubGameMaximumNumberOfCreatures )
{ {
DoScreenIndependantMessageBox( L"Underground sector creature counters are bad. What were the last 2-3 things to die, and how? Save game and send to KM with info!!!", MSG_BOX_FLAG_OK, NULL ); DoScreenIndependantMessageBox( L"Underground sector creature counters are bad. What were the last 2-3 things to die, and how? Save game and send to KM with info!!!", MSG_BOX_FLAG_OK, NULL );
} }
#endif #endif
if( pSector->ubNumCreatures ) if( pSector->ubNumCreatures )
{ {
pSector->ubNumCreatures--; pSector->ubNumCreatures--;
@@ -1587,23 +1592,27 @@ void ProcessQueenCmdImplicationsOfDeath( SOLDIERTYPE *pSoldier )
pSector->ubCreaturesInBattle--; pSector->ubCreaturesInBattle--;
} }
if( !pSector->ubNumCreatures && gWorldSectorX != 9 && gWorldSectorY != 10 ) if ( pSoldier->ubSoldierClass == SOLDIER_CLASS_CREATURE )
{ //If the player has successfully killed all creatures in ANY underground sector except J9
//then cancel any pending creature town attack.
DeleteAllStrategicEventsOfType( EVENT_CREATURE_ATTACK );
}
// a monster has died. Post an event to immediately check whether a mine has been cleared.
AddStrategicEventUsingSeconds( EVENT_CHECK_IF_MINE_CLEARED, GetWorldTotalSeconds() + 15, 0);
if( pSoldier->ubBodyType == QUEENMONSTER )
{ {
//Need to call this, as the queen is really big, and killing her leaves a bunch if ( !pSector->ubNumCreatures && gWorldSectorX != 9 && gWorldSectorY != 10 )
//of bad tiles in behind her. Calling this function cleans it up. {
InvalidateWorldRedundency(); //If the player has successfully killed all creatures in ANY underground sector except J9
//Now that the queen is dead, turn off the creature quest. //then cancel any pending creature town attack.
EndCreatureQuest(); DeleteAllStrategicEventsOfType( EVENT_CREATURE_ATTACK );
EndQuest( QUEST_CREATURES, gWorldSectorX, gWorldSectorY ); }
// a monster has died. Post an event to immediately check whether a mine has been cleared.
AddStrategicEventUsingSeconds( EVENT_CHECK_IF_MINE_CLEARED, GetWorldTotalSeconds() + 15, 0 );
if ( pSoldier->ubBodyType == QUEENMONSTER )
{
//Need to call this, as the queen is really big, and killing her leaves a bunch
//of bad tiles in behind her. Calling this function cleans it up.
InvalidateWorldRedundency();
//Now that the queen is dead, turn off the creature quest.
EndCreatureQuest();
EndQuest( QUEST_CREATURES, gWorldSectorX, gWorldSectorY );
}
} }
} }
break; break;
+85
View File
@@ -27,6 +27,8 @@
#include "strategic.h" #include "strategic.h"
#include "GameSettings.h" #include "GameSettings.h"
#include "history.h" #include "history.h"
#include "Town Militia.h" // added by Flugente
#include "Campaign.h" // added by Flugente
#endif #endif
#include "Luaglobal.h" #include "Luaglobal.h"
@@ -52,6 +54,8 @@ UINT8 gubCambriaMedicalObjects;
extern INT8 NumMercsNear( UINT8 ubProfileID, UINT8 ubMaxDist ); extern INT8 NumMercsNear( UINT8 ubProfileID, UINT8 ubMaxDist );
extern SECTOR_EXT_DATA SectorExternalData[256][4];
// WANNE: No more used for the new airport code // WANNE: No more used for the new airport code
//void DropOffItemsInMeduna( UINT8 ubOrderNum ); //void DropOffItemsInMeduna( UINT8 ubOrderNum );
@@ -1097,6 +1101,87 @@ void HandleEarlyMorningEvents( void )
#endif #endif
} }
// Flugente: creature raids
void HandleRaidEventPlanning()
{
INT32 personnelgain[3];
// the raid order is bloodcats/zombies/bandits
for ( int raidtype = 0; raidtype < 3; ++raidtype )
{
personnelgain[raidtype] = 0;
if ( raidtype == 0 )
{
if ( !gGameExternalOptions.gRaid_Bloodcats )
continue;
// if the lair has been cleared, way less growth
if ( CheckFact(FACT_BLOODCAT_LAIR_CLEANED, NO_PROFILE) )
personnelgain[raidtype] += gGameExternalOptions.gRaidReplenish_BaseValue;
else
personnelgain[raidtype] += 3 * gGameExternalOptions.gRaidReplenish_BaseValue;
}
else if ( raidtype == 1 )
{
if ( !gGameExternalOptions.gRaid_Zombies || !gGameSettings.fOptions[TOPTION_ZOMBIES] )
continue;
// zombies grow very fast
personnelgain[raidtype] += 15 * gGameExternalOptions.gRaidReplenish_BaseValue;
}
else if ( raidtype == 2 )
{
if ( !gGameExternalOptions.gRaid_Bandits )
continue;
// bandit growth depends on progress
personnelgain[raidtype] += gGameExternalOptions.gRaidReplenish_BaseValue * (150 + HighestPlayerProgressPercentage()) / 100;
}
std::vector<INT16> attacksectors;
for ( INT16 sector = 0; sector <= 255; ++sector )
{
if ( !StrategicMap[SECTOR_INFO_TO_STRATEGIC_INDEX( sector )].fEnemyControlled )
{
if ( ( SectorExternalData[sector][0].usSectorFlagMask & (SECTORFLAG_RAIDPOSSIBLE_BLOODCAT << raidtype ) ) )
{
attacksectors.push_back( sector );
}
}
}
if ( attacksectors.empty() )
continue;
int numattacks = gGameExternalOptions.gRaid_MaxAttackPerNight_Bandits;
if ( raidtype == 0 )
numattacks = gGameExternalOptions.gRaid_MaxAttackPerNight_Bloodcats;
else if ( raidtype == 1 )
numattacks = gGameExternalOptions.gRaid_MaxAttackPerNight_Zombies;
for ( int attack = 0; attack < numattacks; ++attack )
{
UINT32 sector = attacksectors[Random(attacksectors.size())];
// attack random sector
if ( raidtype == 0 )
// bloodcats only attack at night (it is 7:00 now)
//AddStrategicEvent( EVENT_BLOODCAT_ATTACK, GetWorldTotalMin() + 14 * 60 + Random(10 * 60), sector );
AddStrategicEvent( EVENT_BLOODCAT_ATTACK, GetWorldTotalMin() + 12 * 60 + 30, sector );
else
// other attacks can happen all the time
//AddStrategicEvent( EVENT_BLOODCAT_ATTACK + raidtype, GetWorldTotalMin() + Random( 24 * 60 ), sector );
AddStrategicEvent( EVENT_BLOODCAT_ATTACK + raidtype, GetWorldTotalMin() + 13 * 60 + 15, sector );
}
}
// every day we refill our available personnel
// this also means that at day 1 we have no personnel for raids, forces have to slowly be built up
AddRaidPersonnel( personnelgain[0], personnelgain[1], personnelgain[2] );
}
void MakeCivGroupHostileOnNextSectorEntrance( UINT8 ubCivGroup ) void MakeCivGroupHostileOnNextSectorEntrance( UINT8 ubCivGroup )
{ {
// if it's the rebels that will become hostile, reduce town loyalties NOW, not later // if it's the rebels that will become hostile, reduce town loyalties NOW, not later
+1
View File
@@ -21,6 +21,7 @@ void AddSecondAirportAttendant( void );
void SetPabloToUnbribed( void ); void SetPabloToUnbribed( void );
void HandleNPCSystemEvent( UINT32 uiEvent ); void HandleNPCSystemEvent( UINT32 uiEvent );
void HandleEarlyMorningEvents( void ); void HandleEarlyMorningEvents( void );
void HandleRaidEventPlanning();
void MakeCivGroupHostileOnNextSectorEntrance( UINT8 ubCivGroup ); void MakeCivGroupHostileOnNextSectorEntrance( UINT8 ubCivGroup );
+2 -5
View File
@@ -396,7 +396,6 @@ void HandleEnricoEmail(void)
gStrategicStatus.ubNumNewSectorsVisitedToday = __min( gStrategicStatus.ubNumNewSectorsVisitedToday, NEW_SECTORS_EQUAL_TO_ACTIVITY ) / 3; gStrategicStatus.ubNumNewSectorsVisitedToday = __min( gStrategicStatus.ubNumNewSectorsVisitedToday, NEW_SECTORS_EQUAL_TO_ACTIVITY ) / 3;
} }
void TrackEnemiesKilled( UINT8 ubKilledHow, UINT8 ubSoldierClass ) void TrackEnemiesKilled( UINT8 ubKilledHow, UINT8 ubSoldierClass )
{ {
INT8 bRankIndex; INT8 bRankIndex;
@@ -418,7 +417,6 @@ void TrackEnemiesKilled( UINT8 ubKilledHow, UINT8 ubSoldierClass )
} }
} }
INT8 SoldierClassToRankIndex( UINT8 ubSoldierClass ) INT8 SoldierClassToRankIndex( UINT8 ubSoldierClass )
{ {
INT8 bRankIndex = -1; INT8 bRankIndex = -1;
@@ -426,7 +424,8 @@ INT8 SoldierClassToRankIndex( UINT8 ubSoldierClass )
// the soldier class defines are not in natural ascending order, elite comes before army! // the soldier class defines are not in natural ascending order, elite comes before army!
switch ( ubSoldierClass ) switch ( ubSoldierClass )
{ {
case SOLDIER_CLASS_ADMINISTRATOR: bRankIndex = 0; break; case SOLDIER_CLASS_ADMINISTRATOR:
case SOLDIER_CLASS_BANDIT: bRankIndex = 0; break;
case SOLDIER_CLASS_ELITE: bRankIndex = 2; break; case SOLDIER_CLASS_ELITE: bRankIndex = 2; break;
case SOLDIER_CLASS_ARMY: bRankIndex = 1; break; case SOLDIER_CLASS_ARMY: bRankIndex = 1; break;
@@ -438,8 +437,6 @@ INT8 SoldierClassToRankIndex( UINT8 ubSoldierClass )
return( bRankIndex ); return( bRankIndex );
} }
UINT8 RankIndexToSoldierClass( UINT8 ubRankIndex ) UINT8 RankIndexToSoldierClass( UINT8 ubRankIndex )
{ {
UINT8 ubSoldierClass = 0; UINT8 ubSoldierClass = 0;
+12 -6
View File
@@ -1592,14 +1592,13 @@ INT32 IsTownUnderCompleteControlByEnemy( INT8 bTownId )
return( FALSE ); return( FALSE );
} }
void AdjustLoyaltyForCivsEatenByMonsters( INT16 sSectorX, INT16 sSectorY, UINT8 ubHowMany) void AdjustLoyaltyForCivsEatenByMonsters( INT16 sSectorX, INT16 sSectorY, UINT8 ubHowMany, BOOLEAN aBandits)
{ {
INT8 bTownId = 0; INT8 bTownId = 0;
UINT32 uiLoyaltyChange = 0; UINT32 uiLoyaltyChange = 0;
CHAR16 str[256]; CHAR16 str[256];
CHAR16 pSectorString[128]; CHAR16 pSectorString[128];
// get town id // get town id
bTownId = GetTownIdForSector( sSectorX, sSectorY ); bTownId = GetTownIdForSector( sSectorX, sSectorY );
@@ -1611,12 +1610,19 @@ void AdjustLoyaltyForCivsEatenByMonsters( INT16 sSectorX, INT16 sSectorY, UINT8
//Report this to player //Report this to player
GetSectorIDString( sSectorX, sSectorY, 0, pSectorString, TRUE ); GetSectorIDString( sSectorX, sSectorY, 0, pSectorString, TRUE );
if ( aBandits )
swprintf( str, gpStrategicString[STR_PB_BANDIT_KILLCIVS_IN_SECTOR], ubHowMany, pSectorString );
else
{
#ifdef CHINESE #ifdef CHINESE
//diffrent order of words in Chinese //diffrent order of words in Chinese
swprintf( str, gpStrategicString[ STR_DIALOG_CREATURES_KILL_CIVILIANS ], pSectorString, ubHowMany); swprintf( str, gpStrategicString[STR_DIALOG_CREATURES_KILL_CIVILIANS], pSectorString, ubHowMany );
#else #else
swprintf( str, gpStrategicString[ STR_DIALOG_CREATURES_KILL_CIVILIANS ], ubHowMany, pSectorString ); swprintf( str, gpStrategicString[STR_DIALOG_CREATURES_KILL_CIVILIANS], ubHowMany, pSectorString );
#endif #endif
}
DoScreenIndependantMessageBox( str, MSG_BOX_FLAG_OK, MapScreenDefaultOkBoxCallback ); DoScreenIndependantMessageBox( str, MSG_BOX_FLAG_OK, MapScreenDefaultOkBoxCallback );
// use same formula as if it were a civilian "murder" in tactical!!! // use same formula as if it were a civilian "murder" in tactical!!!
+1 -1
View File
@@ -175,7 +175,7 @@ INT32 GetNumberOfWholeTownsUnderControl( void );
INT32 IsTownUnderCompleteControlByPlayer( INT8 bTownId ); INT32 IsTownUnderCompleteControlByPlayer( INT8 bTownId );
// used when monsters attack a town sector without going through tactical and they win // used when monsters attack a town sector without going through tactical and they win
void AdjustLoyaltyForCivsEatenByMonsters( INT16 sSectorX, INT16 sSectorY, UINT8 ubHowMany); void AdjustLoyaltyForCivsEatenByMonsters( INT16 sSectorX, INT16 sSectorY, UINT8 ubHowMany, BOOLEAN aBandits );
// these are used to handle global loyalty events (ones that effect EVERY town on the map) // these are used to handle global loyalty events (ones that effect EVERY town on the map)
void IncrementTownLoyaltyEverywhere( UINT32 uiLoyaltyIncrease ); void IncrementTownLoyaltyEverywhere( UINT32 uiLoyaltyIncrease );
+15
View File
@@ -2347,3 +2347,18 @@ FLOAT GetIntel()
{ {
return LaptopSaveInfo.dIntelPool; return LaptopSaveInfo.dIntelPool;
} }
// Flugente: raid 'personnel'
void AddRaidPersonnel( INT32 aBloodcats, INT32 aZombie, INT32 aBandits )
{
LaptopSaveInfo.sRaidBloodcats = max( 0, LaptopSaveInfo.sRaidBloodcats + aBloodcats );
LaptopSaveInfo.sRaidZombies = max( 0, LaptopSaveInfo.sRaidZombies + aZombie );
LaptopSaveInfo.sRaidBandits = max( 0, LaptopSaveInfo.sRaidBandits + aBandits );
}
void GetRaidPersonnel( INT32& arBloodcats, INT32& arZombie, INT32& arBandits )
{
arBloodcats = LaptopSaveInfo.sRaidBloodcats;
arZombie = LaptopSaveInfo.sRaidZombies;
arBandits = LaptopSaveInfo.sRaidBandits;
}
+4
View File
@@ -131,4 +131,8 @@ void DevalueResources(UINT8 aOldProgress, UINT8 aNewProgress);
void AddIntel( FLOAT aValue, BOOLEAN aDoMessage = FALSE ); void AddIntel( FLOAT aValue, BOOLEAN aDoMessage = FALSE );
FLOAT GetIntel(); FLOAT GetIntel();
// Flugente: raid 'personnel'
void AddRaidPersonnel( INT32 aBloodcats, INT32 aZombie, INT32 aBandits );
void GetRaidPersonnel( INT32& arBloodcats, INT32& arZombie, INT32& arBandits );
#endif #endif
+29 -2
View File
@@ -99,7 +99,10 @@ SectorNameStartElementHandle(void *userData, const XML_Char *name, const char **
strcmp(name, "snowchance" ) == 0 || strcmp(name, "snowchance" ) == 0 ||
strcmp(name, "snakechance" ) == 0 || strcmp(name, "snakechance" ) == 0 ||
strcmp(name, "numsnakes" ) == 0 || strcmp(name, "numsnakes" ) == 0 ||
strcmp(name, "maxworkers" ) == 0 )) strcmp(name, "maxworkers" ) == 0 ||
strcmp(name, "bloodcatraidpossible" ) == 0 ||
strcmp(name, "zombieraidpossible" ) == 0 ||
strcmp(name, "banditraidpossible" ) == 0 ))
{ {
pData->curElement = ELEMENT_PROPERTY; pData->curElement = ELEMENT_PROPERTY;
@@ -230,7 +233,12 @@ SectorNameEndElementHandle(void *userData, const XML_Char *name)
SectorExternalData[ubSectorId][1].maxworkers = 0; SectorExternalData[ubSectorId][1].maxworkers = 0;
SectorExternalData[ubSectorId][2].maxworkers = 0; SectorExternalData[ubSectorId][2].maxworkers = 0;
SectorExternalData[ubSectorId][3].maxworkers = 0; SectorExternalData[ubSectorId][3].maxworkers = 0;
SectorExternalData[ubSectorId][0].usSectorFlagMask = pData->sectordata.usSectorFlagMask;
SectorExternalData[ubSectorId][1].usSectorFlagMask = 0;
SectorExternalData[ubSectorId][2].usSectorFlagMask = 0;
SectorExternalData[ubSectorId][3].usSectorFlagMask = 0;
if ( !prisonroomvector.empty( ) ) if ( !prisonroomvector.empty( ) )
{ {
std::vector<UINT16>::iterator itend = prisonroomvector.end( ); std::vector<UINT16>::iterator itend = prisonroomvector.end( );
@@ -255,6 +263,7 @@ SectorNameEndElementHandle(void *userData, const XML_Char *name)
pData->sectordata.snakechance = 0; pData->sectordata.snakechance = 0;
pData->sectordata.numsnakes = 0; pData->sectordata.numsnakes = 0;
pData->sectordata.maxworkers = 0; pData->sectordata.maxworkers = 0;
pData->sectordata.usSectorFlagMask = 0;
} }
else else
{ {
@@ -378,6 +387,24 @@ SectorNameEndElementHandle(void *userData, const XML_Char *name)
pData->curElement = ELEMENT; pData->curElement = ELEMENT;
pData->sectordata.maxworkers = (UINT8)atoi( pData->szCharData ); pData->sectordata.maxworkers = (UINT8)atoi( pData->szCharData );
} }
else if ( strcmp( name, "bloodcatraidpossible" ) == 0 )
{
pData->curElement = ELEMENT;
if ( (UINT8)atoi( pData->szCharData ) )
pData->sectordata.usSectorFlagMask |= SECTORFLAG_RAIDPOSSIBLE_BLOODCAT;
}
else if ( strcmp( name, "zombieraidpossible" ) == 0 )
{
pData->curElement = ELEMENT;
if ( (UINT8)atoi( pData->szCharData ) )
pData->sectordata.usSectorFlagMask |= SECTORFLAG_RAIDPOSSIBLE_ZOMBIE;
}
else if ( strcmp( name, "banditraidpossible" ) == 0 )
{
pData->curElement = ELEMENT;
if ( (UINT8)atoi( pData->szCharData ) )
pData->sectordata.usSectorFlagMask |= SECTORFLAG_RAIDPOSSIBLE_BANDIT;
}
pData->maxReadDepth--; pData->maxReadDepth--;
} }
+3 -3
View File
@@ -15804,9 +15804,9 @@ void HandlePostAutoresolveMessages()
//are "virtually" murdered and loyalty hits will be processed. //are "virtually" murdered and loyalty hits will be processed.
if( gsCiviliansEatenByMonsters >= 1 ) if( gsCiviliansEatenByMonsters >= 1 )
{ {
AdjustLoyaltyForCivsEatenByMonsters( (UINT8)SECTORX( gsEnemyGainedControlOfSectorID ), AdjustLoyaltyForCivsEatenByMonsters( (UINT8)SECTORX( gsEnemyGainedControlOfSectorID ), (UINT8)SECTORY( gsEnemyGainedControlOfSectorID ),
(UINT8)SECTORY( gsEnemyGainedControlOfSectorID ), (UINT8)gsCiviliansEatenByMonsters, ( guCreatureAttackType == CREATURE_ATTACK_TYPE_BANDIT ) );
(UINT8)gsCiviliansEatenByMonsters );
gsCiviliansEatenByMonsters = -2; gsCiviliansEatenByMonsters = -2;
} }
else if( gsCiviliansEatenByMonsters == -2 ) else if( gsCiviliansEatenByMonsters == -2 )
+12 -6
View File
@@ -148,11 +148,11 @@ class SOLDIERTYPE;
//Used by PickGridNoToWalkIn //Used by PickGridNoToWalkIn
#define MAX_ATTEMPTS 200 #define MAX_ATTEMPTS 200
#define QUEST_CHECK_EVENT_TIME ( 8 * 60 ) #define QUEST_CHECK_EVENT_TIME ( 8 * 60 )
#define BOBBYRAY_UPDATE_TIME ( 9 * 60 ) #define BOBBYRAY_UPDATE_TIME ( 9 * 60 )
#define INSURANCE_UPDATE_TIME 0 #define INSURANCE_UPDATE_TIME 0
#define EARLY_MORNING_TIME ( 4 * 60 ) #define EARLY_MORNING_TIME ( 4 * 60 )
#define ENRICO_MAIL_TIME ( 7 * 60 ) #define ENRICO_MAIL_TIME ( 7 * 60 )
enum enum
{ {
@@ -2242,6 +2242,7 @@ BOOLEAN SetCurrentWorldSector( INT16 sMapX, INT16 sMapY, INT8 bMapZ )
PrepareCreaturesForBattle( ); PrepareCreaturesForBattle( );
} }
} }
if ( gfGotoSectorTransition ) if ( gfGotoSectorTransition )
{ {
BeginLoadScreen( ); BeginLoadScreen( );
@@ -5114,6 +5115,8 @@ void SetupNewStrategicGame( )
AddEveryDayStrategicEvent( EVENT_DAILY_UPDATE_BOBBY_RAY_INVENTORY, BOBBYRAY_UPDATE_TIME, 0 ); AddEveryDayStrategicEvent( EVENT_DAILY_UPDATE_BOBBY_RAY_INVENTORY, BOBBYRAY_UPDATE_TIME, 0 );
//Daily Update of the M.E.R.C. site. //Daily Update of the M.E.R.C. site.
AddEveryDayStrategicEvent( EVENT_DAILY_UPDATE_OF_MERC_SITE, 0, 0 ); AddEveryDayStrategicEvent( EVENT_DAILY_UPDATE_OF_MERC_SITE, 0, 0 );
// Flugente: plan when to conduct raids on player sectors
AddEveryDayStrategicEvent( EVENT_DAILY_RAID_EVENTS, ENRICO_MAIL_TIME, 0 );
#ifdef JA2UB #ifdef JA2UB
//Ja25: No insurance for mercs //Ja25: No insurance for mercs
@@ -6528,7 +6531,10 @@ BOOLEAN HandlePotentialBringUpAutoresolveToFinishBattle( int pSectorX, int pSect
gubPBSectorZ = (UINT8)pSectorZ; gubPBSectorZ = (UINT8)pSectorZ;
gfBlitBattleSectorLocator = TRUE; gfBlitBattleSectorLocator = TRUE;
gfTransferTacticalOppositionToAutoResolve = TRUE; gfTransferTacticalOppositionToAutoResolve = TRUE;
if ( GetEnemyEncounterCode() != CREATURE_ATTACK_CODE ) if ( GetEnemyEncounterCode() != CREATURE_ATTACK_CODE &&
GetEnemyEncounterCode() != BLOODCAT_ATTACK_CODE &&
GetEnemyEncounterCode() != ZOMBIE_ATTACK_CODE &&
GetEnemyEncounterCode() != BANDIT_ATTACK_CODE )
{ {
SetEnemyEncounterCode( ENEMY_INVASION_CODE ); //has to be, if militia are here. SetEnemyEncounterCode( ENEMY_INVASION_CODE ); //has to be, if militia are here.
} }
+6
View File
@@ -316,6 +316,11 @@ INT8 GetCivType( SOLDIERTYPE *pCiv )
return( CIV_TYPE_ENEMY ); return( CIV_TYPE_ENEMY );
} }
if ( pCiv->bTeam == CREATURE_TEAM && pCiv->ubSoldierClass == SOLDIER_CLASS_BANDIT )
{
return( CIV_TYPE_ENEMY );
}
if ( pCiv->bTeam != CIV_TEAM && pCiv->bTeam != MILITIA_TEAM ) if ( pCiv->bTeam != CIV_TEAM && pCiv->bTeam != MILITIA_TEAM )
{ {
return( CIV_TYPE_NA ); return( CIV_TYPE_NA );
@@ -1627,6 +1632,7 @@ void StartEnemyTaunt( SOLDIERTYPE *pCiv, TAUNTTYPE iTauntType, SOLDIERTYPE *pTar
switch( pCiv->ubSoldierClass ) switch( pCiv->ubSoldierClass )
{ {
case SOLDIER_CLASS_ADMINISTRATOR: case SOLDIER_CLASS_ADMINISTRATOR:
case SOLDIER_CLASS_BANDIT:
if( !(zTaunt[ i ].uiFlags2 & TAUNT_C_ADMIN) ) if( !(zTaunt[ i ].uiFlags2 & TAUNT_C_ADMIN) )
continue; continue;
if( (zTaunt[ i ].value[TAUNT_PROFILE_ADMIN] != -1 ) && !(zTaunt[ i ].value[TAUNT_PROFILE_ADMIN] == pCiv->usSoldierProfile ) ) if( (zTaunt[ i ].value[TAUNT_PROFILE_ADMIN] != -1 ) && !(zTaunt[ i ].value[TAUNT_PROFILE_ADMIN] == pCiv->usSoldierProfile ) )
+5 -4
View File
@@ -333,10 +333,11 @@ void GenerateRandomEquipment( SOLDIERCREATE_STRUCT *pp, INT8 bSoldierClass, INT8
// handled differently than for enemies. // handled differently than for enemies.
case SOLDIER_CLASS_ADMINISTRATOR: case SOLDIER_CLASS_ADMINISTRATOR:
case SOLDIER_CLASS_GREEN_MILITIA: case SOLDIER_CLASS_GREEN_MILITIA:
case SOLDIER_CLASS_BANDIT:
bRating = BAD_ADMINISTRATOR_EQUIPMENT_RATING + bEquipmentModifier; bRating = BAD_ADMINISTRATOR_EQUIPMENT_RATING + bEquipmentModifier;
// Equipment quality modifier // Equipment quality modifier
if ( bSoldierClass == SOLDIER_CLASS_ADMINISTRATOR ) if ( bSoldierClass == SOLDIER_CLASS_ADMINISTRATOR || bSoldierClass == SOLDIER_CLASS_BANDIT )
{ {
if ( gGameExternalOptions.sEnemyAdminEquipmentQualityModifier != 0 ) if ( gGameExternalOptions.sEnemyAdminEquipmentQualityModifier != 0 )
bRating += gGameExternalOptions.sEnemyAdminEquipmentQualityModifier; bRating += gGameExternalOptions.sEnemyAdminEquipmentQualityModifier;
@@ -360,7 +361,7 @@ void GenerateRandomEquipment( SOLDIERCREATE_STRUCT *pp, INT8 bSoldierClass, INT8
bHelmetClass = bRating; bHelmetClass = bRating;
// no leggings // no leggings
if ( bSoldierClass == SOLDIER_CLASS_ADMINISTRATOR ) if ( bSoldierClass == SOLDIER_CLASS_ADMINISTRATOR || bSoldierClass == SOLDIER_CLASS_BANDIT )
{ {
if ( Chance( 30 ) ) if ( Chance( 30 ) )
bKnifeClass = bRating; bKnifeClass = bRating;
@@ -919,6 +920,7 @@ void ChooseWeaponForSoldierCreateStruct( SOLDIERCREATE_STRUCT *pp, INT8 bWeaponC
case SOLDIER_CLASS_ARMY: case SOLDIER_CLASS_ARMY:
case SOLDIER_CLASS_GREEN_MILITIA: case SOLDIER_CLASS_GREEN_MILITIA:
case SOLDIER_CLASS_REG_MILITIA: case SOLDIER_CLASS_REG_MILITIA:
case SOLDIER_CLASS_BANDIT:
//Admins/Troops: 60-75% + 1% every 4% progress //Admins/Troops: 60-75% + 1% every 4% progress
bStatus = (INT8)(60 + Random( 16 )); bStatus = (INT8)(60 + Random( 16 ));
bStatus += (INT8)(HighestPlayerProgressPercentage() / 4); bStatus += (INT8)(HighestPlayerProgressPercentage() / 4);
@@ -1987,13 +1989,12 @@ void ChooseFaceGearForSoldierCreateStruct( SOLDIERCREATE_STRUCT *pp )
case SOLDIER_CLASS_ADMINISTRATOR: case SOLDIER_CLASS_ADMINISTRATOR:
case SOLDIER_CLASS_GREEN_MILITIA: case SOLDIER_CLASS_GREEN_MILITIA:
case SOLDIER_CLASS_ZOMBIE: case SOLDIER_CLASS_ZOMBIE:
case SOLDIER_CLASS_BANDIT:
break; break;
} }
} }
void ChooseKitsForSoldierCreateStruct( SOLDIERCREATE_STRUCT *pp, INT8 bKitClass ) void ChooseKitsForSoldierCreateStruct( SOLDIERCREATE_STRUCT *pp, INT8 bKitClass )
{ {
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"ChooseKitsForSoldierCreateStruct"); DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"ChooseKitsForSoldierCreateStruct");
+6
View File
@@ -494,6 +494,10 @@ OBJECTTYPE* GetExternalFeedingObject(SOLDIERTYPE* pSoldier, OBJECTTYPE * pObject
BOOLEAN DeductBulletViaExternalFeeding(SOLDIERTYPE* pSoldier, OBJECTTYPE * pObject); BOOLEAN DeductBulletViaExternalFeeding(SOLDIERTYPE* pSoldier, OBJECTTYPE * pObject);
#define SECTORFLAG_RAIDPOSSIBLE_BLOODCAT 0x00000001 // bloodcats can attack this sector
#define SECTORFLAG_RAIDPOSSIBLE_ZOMBIE 0x00000002 // zombies can attack this sector
#define SECTORFLAG_RAIDPOSSIBLE_BANDIT 0x00000004 // bandits can attack this sector
// Flugente: additional xml data for sectors // Flugente: additional xml data for sectors
typedef struct typedef struct
{ {
@@ -515,6 +519,8 @@ typedef struct
UINT8 maxworkers; // maximum number of workers in this sector; UINT8 maxworkers; // maximum number of workers in this sector;
UINT32 usSectorFlagMask; // various flags
} SECTOR_EXT_DATA; } SECTOR_EXT_DATA;
// get dirt increase for object with attachments, fConsiderAmmo: with ammo // get dirt increase for object with attachments, fConsiderAmmo: with ammo
+28 -34
View File
@@ -6856,7 +6856,8 @@ void RemoveCapturedEnemiesFromSectorInfo( INT16 sMapX, INT16 sMapY, INT8 bMapZ )
{ {
switch ( pTeamSoldier->ubSoldierClass ) switch ( pTeamSoldier->ubSoldierClass )
{ {
case SOLDIER_CLASS_ADMINISTRATOR: ++sNumPrisoner[PRISONER_ADMIN]; break; case SOLDIER_CLASS_ADMINISTRATOR:
case SOLDIER_CLASS_BANDIT: ++sNumPrisoner[PRISONER_ADMIN]; break;
case SOLDIER_CLASS_ARMY: ++sNumPrisoner[PRISONER_REGULAR]; break; case SOLDIER_CLASS_ARMY: ++sNumPrisoner[PRISONER_REGULAR]; break;
case SOLDIER_CLASS_ELITE: ++sNumPrisoner[PRISONER_ELITE]; break; case SOLDIER_CLASS_ELITE: ++sNumPrisoner[PRISONER_ELITE]; break;
default: default:
@@ -6865,7 +6866,11 @@ void RemoveCapturedEnemiesFromSectorInfo( INT16 sMapX, INT16 sMapY, INT8 bMapZ )
break; break;
} }
} }
else //if ( pTeamSoldier->bTeam == CIV_TEAM ) else if ( pTeamSoldier->bTeam == CREATURE_TEAM && pTeamSoldier->ubSoldierClass == SOLDIER_CLASS_BANDIT )
{
++sNumPrisoner[PRISONER_ADMIN];
}
else
{ {
++sNumPrisoner[PRISONER_CIVILIAN]; ++sNumPrisoner[PRISONER_CIVILIAN];
} }
@@ -10508,9 +10513,9 @@ void PrisonerSurrenderMessageBoxCallBack( UINT8 ubExitValue )
// We justify this storywise by these soldiers being very determined leaders who don't allow surrender categorically. // We justify this storywise by these soldiers being very determined leaders who don't allow surrender categorically.
BOOLEAN fNoSurrender = FALSE; BOOLEAN fNoSurrender = FALSE;
// enemy team // enemy team and creature team (bandits can be captured)
firstid = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID; firstid = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID;
lastid = gTacticalStatus.Team[ ENEMY_TEAM ].bLastID; lastid = gTacticalStatus.Team[CREATURE_TEAM].bLastID;
for ( uiCnt = firstid, pSoldier = MercPtrs[ uiCnt ]; uiCnt <= lastid; ++uiCnt, ++pSoldier) for ( uiCnt = firstid, pSoldier = MercPtrs[ uiCnt ]; uiCnt <= lastid; ++uiCnt, ++pSoldier)
{ {
if( pSoldier->bActive && ( pSoldier->sSectorX == gWorldSectorX ) && ( pSoldier->sSectorY == gWorldSectorY ) && ( pSoldier->bSectorZ == gbWorldSectorZ) ) if( pSoldier->bActive && ( pSoldier->sSectorX == gWorldSectorX ) && ( pSoldier->sSectorY == gWorldSectorY ) && ( pSoldier->bSectorZ == gbWorldSectorZ) )
@@ -10558,7 +10563,7 @@ void PrisonerSurrenderMessageBoxCallBack( UINT8 ubExitValue )
{ {
// it is enough to simply set all soldiers to captured // it is enough to simply set all soldiers to captured
firstid = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID; firstid = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID;
lastid = gTacticalStatus.Team[ ENEMY_TEAM ].bLastID; lastid = gTacticalStatus.Team[ CIV_TEAM ].bLastID;
for ( uiCnt = firstid, pSoldier = MercPtrs[ uiCnt ]; uiCnt <= lastid; ++uiCnt, ++pSoldier) for ( uiCnt = firstid, pSoldier = MercPtrs[ uiCnt ]; uiCnt <= lastid; ++uiCnt, ++pSoldier)
{ {
if( pSoldier->bActive && ( pSoldier->sSectorX == gWorldSectorX ) && ( pSoldier->sSectorY == gWorldSectorY ) && ( pSoldier->bSectorZ == gbWorldSectorZ) ) if( pSoldier->bActive && ( pSoldier->sSectorX == gWorldSectorX ) && ( pSoldier->sSectorY == gWorldSectorY ) && ( pSoldier->bSectorZ == gbWorldSectorZ) )
@@ -10577,28 +10582,7 @@ void PrisonerSurrenderMessageBoxCallBack( UINT8 ubExitValue )
} }
} }
} }
firstid = gTacticalStatus.Team[CIV_TEAM].bFirstID;
lastid = gTacticalStatus.Team[CIV_TEAM].bLastID;
for ( uiCnt = firstid, pSoldier = MercPtrs[uiCnt]; uiCnt <= lastid; ++uiCnt, ++pSoldier )
{
if ( pSoldier->bActive && (pSoldier->sSectorX == gWorldSectorX) && (pSoldier->sSectorY == gWorldSectorY) && (pSoldier->bSectorZ == gbWorldSectorZ) )
{
// can this guy be captured?
if ( !pSoldier->CanBeCaptured() )
continue;
// only if not dying
if ( pSoldier->stats.bLife >= OKLIFE )
{
pSoldier->usSoldierFlagMask |= SOLDIER_POW;
// Remove as target
RemoveManAsTarget( pSoldier );
}
}
}
// dynamic opinion: a merc caused the remaining enemies to give up // dynamic opinion: a merc caused the remaining enemies to give up
if ( gusSelectedSoldier != NOBODY ) if ( gusSelectedSoldier != NOBODY )
HandleDynamicOpinionChange( MercPtrs[gusSelectedSoldier], OPINIONEVENT_BATTLE_TOOK_PRISONER, TRUE, TRUE ); HandleDynamicOpinionChange( MercPtrs[gusSelectedSoldier], OPINIONEVENT_BATTLE_TOOK_PRISONER, TRUE, TRUE );
@@ -10626,6 +10610,14 @@ void PrisonerSurrenderMessageBoxCallBack( UINT8 ubExitValue )
// we offered to surrender OURSELVES TO the enemy // we offered to surrender OURSELVES TO the enemy
else if ( ubExitValue == 2 ) else if ( ubExitValue == 2 )
{ {
// we cannot surrender to bandits, talk instead
if ( MercPtrs[prisonerdialoguetargetID]->bTeam != CREATURE_TEAM )
{
// normal dialog
StartCivQuote( MercPtrs[prisonerdialoguetargetID] );
return;
}
if ( !gGameExternalOptions.fPlayerCanAsktoSurrender ) if ( !gGameExternalOptions.fPlayerCanAsktoSurrender )
{ {
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szPrisonerTextStr[ SRT_PRISONER_INI_SETTING_OFF ] ); ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szPrisonerTextStr[ SRT_PRISONER_INI_SETTING_OFF ] );
@@ -10763,14 +10755,16 @@ void HandleSurrenderOffer( SOLDIERTYPE* pSoldier )
// open a dialogue box and see wether we really want to offer this, or just talk // open a dialogue box and see wether we really want to offer this, or just talk
wcscpy( gzUserDefinedButton[0], TacticalStr[ PRISONER_DEMAND_SURRENDER_STR ] ); wcscpy( gzUserDefinedButton[0], TacticalStr[ PRISONER_DEMAND_SURRENDER_STR ] );
wcscpy( gzUserDefinedButton[1], TacticalStr[ PRISONER_OFFER_SURRENDER_STR ] );
SOLDIERTYPE* pTargetSoldier = NULL; if ( pSoldier->bTeam != CREATURE_TEAM )
if ( GetSoldier( &pTargetSoldier, prisonerdialoguetargetID ) && wcscpy( gzUserDefinedButton[1], TacticalStr[ PRISONER_OFFER_SURRENDER_STR ] );
pTargetSoldier->bTeam == ENEMY_TEAM && else
pTargetSoldier->ubProfile == NO_PROFILE && wcscpy( gzUserDefinedButton[1], TacticalStr[PRISONER_TALK_STR] );
pTargetSoldier->aiData.bAlertStatus < STATUS_RED &&
!pTargetSoldier->RecognizeAsCombatant( gusSelectedSoldier ) ) if ( pSoldier->bTeam == ENEMY_TEAM &&
pSoldier->ubProfile == NO_PROFILE &&
pSoldier->aiData.bAlertStatus < STATUS_RED &&
!pSoldier->RecognizeAsCombatant( gusSelectedSoldier ) )
{ {
wcscpy( gzUserDefinedButton[2], TacticalStr[PRISONER_DISTRACT_STR] ); wcscpy( gzUserDefinedButton[2], TacticalStr[PRISONER_DISTRACT_STR] );
} }
+26 -5
View File
@@ -47,6 +47,8 @@
#include "Campaign Types.h" #include "Campaign Types.h"
#include "text.h" // added by Flugente #include "text.h" // added by Flugente
#include "Vehicles.h" // added by silversurfer #include "Vehicles.h" // added by silversurfer
#include "ai.h" // added by Flugente
#include "PreBattle Interface.h" // added by Flugente
#endif #endif
#include "Animation Control.h" #include "Animation Control.h"
@@ -2632,7 +2634,7 @@ void RaiseZombies( void )
for ( INT32 cnt = giNumRottingCorpse - 1; cnt >= 0; --cnt ) for ( INT32 cnt = giNumRottingCorpse - 1; cnt >= 0; --cnt )
{ {
if ( pSector->ubNumCreatures < gGameExternalOptions.ubGameMaximumNumberOfCreatures ) // ... if there is still room for more zombies (zombies count as creatures until a separate ZOMBIE_TEAM is implemented)... if ( pSector && pSector->ubNumCreatures < gGameExternalOptions.ubGameMaximumNumberOfCreatures ) // ... if there is still room for more zombies (zombies count as creatures until a separate ZOMBIE_TEAM is implemented)...
{ {
pCorpse = &(gRottingCorpse[ cnt ] ); pCorpse = &(gRottingCorpse[ cnt ] );
@@ -2652,8 +2654,8 @@ void RaiseZombies( void )
zombieshaverisen = TRUE; zombieshaverisen = TRUE;
CreateZombiefromCorpse( pCorpse, recanimstate ); CreateZombiefromCorpse( pCorpse, recanimstate );
//++pSector->ubNumZombies; pSector->ubNumCreatures++;
//++pSector->ubZombiesInBattle; pSector->ubCreaturesInBattle++;
RemoveCorpse( cnt ); RemoveCorpse( cnt );
} }
@@ -2680,13 +2682,32 @@ void RaiseZombies( void )
PlayJA2SampleFromFile( "Sounds\\zombie1.wav", RATE_11025, HIGHVOLUME, 1, MIDDLEPAN ); PlayJA2SampleFromFile( "Sounds\\zombie1.wav", RATE_11025, HIGHVOLUME, 1, MIDDLEPAN );
UseCreatureMusic(TRUE); // Madd: music when zombies rise UseCreatureMusic(TRUE); // Madd: music when zombies rise
#ifdef NEWMUSIC #ifdef NEWMUSIC
GlobalSoundID = MusicSoundValues[ SECTOR( gWorldSectorX, gWorldSectorY ) ].SoundTacticalTensor[gbWorldSectorZ]; GlobalSoundID = MusicSoundValues[ SECTOR( gWorldSectorX, gWorldSectorY ) ].SoundTacticalTensor[gbWorldSectorZ];
if ( MusicSoundValues[ SECTOR( gWorldSectorX, gWorldSectorY ) ].SoundTacticalTensor[gbWorldSectorZ] != -1 ) if ( MusicSoundValues[ SECTOR( gWorldSectorX, gWorldSectorY ) ].SoundTacticalTensor[gbWorldSectorZ] != -1 )
SetMusicModeID( MUSIC_TACTICAL_ENEMYPRESENT, MusicSoundValues[ SECTOR( gWorldSectorX, gWorldSectorY ) ].SoundTacticalTensor[gbWorldSectorZ] ); SetMusicModeID( MUSIC_TACTICAL_ENEMYPRESENT, MusicSoundValues[ SECTOR( gWorldSectorX, gWorldSectorY ) ].SoundTacticalTensor[gbWorldSectorZ] );
else else
#endif #endif
SetMusicMode( MUSIC_TACTICAL_ENEMYPRESENT ); SetMusicMode( MUSIC_TACTICAL_ENEMYPRESENT );
// alert the creatures
HandleInitialRedAlert( CREATURE_TEAM, FALSE );
// we need this so that the battle is properly recognized in strategic
{
//Set up the location as well as turning on the blit flag.
gubPBSectorX = (UINT8)gWorldSectorX;
gubPBSectorY = (UINT8)gWorldSectorY;
gubPBSectorZ = (UINT8)gbWorldSectorZ;
gfBlitBattleSectorLocator = TRUE;
}
if ( GetEnemyEncounterCode() == NO_ENCOUNTER_CODE )
SetEnemyEncounterCode( ZOMBIE_ATTACK_CODE );
// idea... potentially scrap this part and use a simplified form of void CreatureAttackTown_OtherCreatures(...) ?
//gubSectorIDOfCreatureAttack = SECTOR( gWorldSectorX, gWorldSectorY );
} }
} }
} }
+13
View File
@@ -64,6 +64,8 @@
#include "CampaignStats.h" // added by Flugente #include "CampaignStats.h" // added by Flugente
#include "DynamicDialogue.h" // added by Flugente #include "DynamicDialogue.h" // added by Flugente
#include "MilitiaIndividual.h" // added by Flugente #include "MilitiaIndividual.h" // added by Flugente
#include "Town Militia.h" // added by Flugente
#include "PreBattle Interface.h" // added by Flugente
#endif #endif
// anv: for enemy taunts // anv: for enemy taunts
@@ -3945,6 +3947,9 @@ BOOLEAN HandleSoldierDeath( SOLDIERTYPE *pSoldier , BOOLEAN *pfMadeCorpse )
case SOLDIER_CLASS_ZOMBIE : case SOLDIER_CLASS_ZOMBIE :
gMercProfiles[ MercPtrs[ ubAttacker ]->ubProfile ].records.usKillsZombies++; gMercProfiles[ MercPtrs[ ubAttacker ]->ubProfile ].records.usKillsZombies++;
break; break;
case SOLDIER_CLASS_BANDIT:
gMercProfiles[MercPtrs[ubAttacker]->ubProfile].records.usKillsOthers++;
break;
default : default :
if ( CREATURE_OR_BLOODCAT( pSoldier ) ) if ( CREATURE_OR_BLOODCAT( pSoldier ) )
gMercProfiles[ MercPtrs[ ubAttacker ]->ubProfile ].records.usKillsCreatures++; gMercProfiles[ MercPtrs[ ubAttacker ]->ubProfile ].records.usKillsCreatures++;
@@ -4049,6 +4054,14 @@ BOOLEAN HandleSoldierDeath( SOLDIERTYPE *pSoldier , BOOLEAN *pfMadeCorpse )
// Flugente: campaign stats // Flugente: campaign stats
gCurrentIncident.AddStat( pSoldier, CAMPAIGNHISTORY_TYPE_KILL ); gCurrentIncident.AddStat( pSoldier, CAMPAIGNHISTORY_TYPE_KILL );
// Flugente: for raids, we need to keep track of killed forces
if ( GetEnemyEncounterCode() == BLOODCAT_ATTACK_CODE ||
GetEnemyEncounterCode() == ZOMBIE_ATTACK_CODE ||
GetEnemyEncounterCode() == BANDIT_ATTACK_CODE )
{
AddRaidPersonnel( -( pSoldier->ubBodyType == BLOODCAT ), -( pSoldier->ubSoldierClass == SOLDIER_CLASS_ZOMBIE ), -( pSoldier->ubSoldierClass == SOLDIER_CLASS_BANDIT ) );
}
// Flugente: individual militia // Flugente: individual militia
MILITIA militia; MILITIA militia;
if ( GetMilitia( pSoldier->usIndividualMilitiaID, &militia ) && !(militia.flagmask & MILITIAFLAG_DEAD) ) if ( GetMilitia( pSoldier->usIndividualMilitiaID, &militia ) && !(militia.flagmask & MILITIAFLAG_DEAD) )
+6 -2
View File
@@ -14723,7 +14723,7 @@ INT32 SOLDIERTYPE::GetDamageResistance( BOOLEAN fAutoResolve, BOOLEAN fCalcBreat
else if ( this->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA && gGameExternalOptions.bVeteranMilitiaDamageResistance != 0 ) else if ( this->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA && gGameExternalOptions.bVeteranMilitiaDamageResistance != 0 )
resistance += (INT32)(gGameExternalOptions.bVeteranMilitiaDamageResistance / breathmodifiermilitia); resistance += (INT32)(gGameExternalOptions.bVeteranMilitiaDamageResistance / breathmodifiermilitia);
// bonus for enemy too // bonus for enemy too
else if ( this->ubSoldierClass == SOLDIER_CLASS_ADMINISTRATOR && gGameExternalOptions.sEnemyAdminDamageResistance != 0 ) else if ( (this->ubSoldierClass == SOLDIER_CLASS_ADMINISTRATOR || this->ubSoldierClass == SOLDIER_CLASS_BANDIT ) && gGameExternalOptions.sEnemyAdminDamageResistance != 0 )
resistance += gGameExternalOptions.sEnemyAdminDamageResistance; resistance += gGameExternalOptions.sEnemyAdminDamageResistance;
else if ( this->ubSoldierClass == SOLDIER_CLASS_ARMY && gGameExternalOptions.sEnemyRegularDamageResistance != 0 ) else if ( this->ubSoldierClass == SOLDIER_CLASS_ARMY && gGameExternalOptions.sEnemyRegularDamageResistance != 0 )
resistance += gGameExternalOptions.sEnemyRegularDamageResistance; resistance += gGameExternalOptions.sEnemyRegularDamageResistance;
@@ -16211,7 +16211,7 @@ UINT32 SOLDIERTYPE::GetSurrenderStrength( )
// adjust for type of soldier // adjust for type of soldier
if ( this->ubSoldierClass == SOLDIER_CLASS_ELITE || this->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA ) if ( this->ubSoldierClass == SOLDIER_CLASS_ELITE || this->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA )
value *= 1.5f; value *= 1.5f;
else if ( this->ubSoldierClass == SOLDIER_CLASS_ADMINISTRATOR || this->ubSoldierClass == SOLDIER_CLASS_GREEN_MILITIA ) else if ( this->ubSoldierClass == SOLDIER_CLASS_ADMINISTRATOR || this->ubSoldierClass == SOLDIER_CLASS_GREEN_MILITIA || this->ubSoldierClass == SOLDIER_CLASS_BANDIT )
value *= 0.75f; value *= 0.75f;
// tanks won't surrender that easy // tanks won't surrender that easy
@@ -16267,6 +16267,10 @@ BOOLEAN SOLDIERTYPE::CanBeCaptured( )
if ( this->bTeam == ENEMY_TEAM ) if ( this->bTeam == ENEMY_TEAM )
return TRUE; return TRUE;
// bandits can be captured
if ( this->bTeam == CREATURE_TEAM && this->ubSoldierClass == SOLDIER_CLASS_BANDIT )
return TRUE;
// civilians can be captured if their faction can, and if they are hostile // civilians can be captured if their faction can, and if they are hostile
if ( this->bTeam == CIV_TEAM && zCivGroupName[this->ubCivilianGroup].fCanBeCaptured ) if ( this->bTeam == CIV_TEAM && zCivGroupName[this->ubCivilianGroup].fCanBeCaptured )
{ {
+1
View File
@@ -331,6 +331,7 @@ enum
SOLDIER_CLASS_ZOMBIE, SOLDIER_CLASS_ZOMBIE,
SOLDIER_CLASS_TANK, SOLDIER_CLASS_TANK,
SOLDIER_CLASS_JEEP, SOLDIER_CLASS_JEEP,
SOLDIER_CLASS_BANDIT,
SOLDIER_CLASS_MAX, SOLDIER_CLASS_MAX,
}; };
+156 -93
View File
@@ -1799,7 +1799,7 @@ BOOLEAN TacticalCopySoldierFromCreateStruct( SOLDIERTYPE *pSoldier, SOLDIERCREAT
////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////
// Added by SANDRO - the enemy/militia has a decent chance to have some traits // Added by SANDRO - the enemy/militia has a decent chance to have some traits
if ( gGameExternalOptions.fAssignTraitsToEnemy && SOLDIER_CLASS_ENEMY( pSoldier->ubSoldierClass ) ) if ( gGameExternalOptions.fAssignTraitsToEnemy && (SOLDIER_CLASS_ENEMY( pSoldier->ubSoldierClass ) || pSoldier->ubSoldierClass == SOLDIER_CLASS_BANDIT) )
AssignTraitsToSoldier( pSoldier, pCreateStruct ); AssignTraitsToSoldier( pSoldier, pCreateStruct );
if ( gGameExternalOptions.fAssignTraitsToMilitia && SOLDIER_CLASS_MILITIA( pSoldier->ubSoldierClass ) ) if ( gGameExternalOptions.fAssignTraitsToMilitia && SOLDIER_CLASS_MILITIA( pSoldier->ubSoldierClass ) )
AssignTraitsToSoldier( pSoldier, pCreateStruct ); AssignTraitsToSoldier( pSoldier, pCreateStruct );
@@ -2010,7 +2010,7 @@ BOOLEAN TacticalCopySoldierFromCreateStruct( SOLDIERTYPE *pSoldier, SOLDIERCREAT
} }
break; break;
case CREATURE_TEAM: case CREATURE_TEAM:
if( pSoldier->ubBodyType == BLOODCAT ) if ( pSoldier->ubBodyType == BLOODCAT )
{ {
swprintf( pSoldier->name, gzLateLocalizedString[ 36 ] ); swprintf( pSoldier->name, gzLateLocalizedString[ 36 ] );
} }
@@ -2018,9 +2018,13 @@ BOOLEAN TacticalCopySoldierFromCreateStruct( SOLDIERTYPE *pSoldier, SOLDIERCREAT
{ {
swprintf( pSoldier->name, TacticalStr[ ZOMBIE_TEAM_MERC_NAME ] ); swprintf( pSoldier->name, TacticalStr[ ZOMBIE_TEAM_MERC_NAME ] );
} }
else if ( pSoldier->ubBodyType >= ADULTFEMALEMONSTER && pSoldier->ubBodyType <= QUEENMONSTER )
{
swprintf( pSoldier->name, TacticalStr[CREATURE_TEAM_MERC_NAME] ); break;
}
else else
{ {
swprintf( pSoldier->name, TacticalStr[ CREATURE_TEAM_MERC_NAME ] ); break; swprintf( pSoldier->name, gpStrategicString[STR_PB_BANDIT] ); break;
} }
break; break;
} }
@@ -2296,7 +2300,6 @@ INT8 CalcDifficultyModifier( UINT8 ubSoldierClass )
return(bDiffModifier); return(bDiffModifier);
} }
//When the editor modifies the soldier's relative attribute level, //When the editor modifies the soldier's relative attribute level,
//this function is called to update that information. //this function is called to update that information.
//Used to generate a detailed placement from a basic placement. This assumes that the detailed placement //Used to generate a detailed placement from a basic placement. This assumes that the detailed placement
@@ -2397,8 +2400,7 @@ void CreateDetailedPlacementGivenBasicPlacementInfo( SOLDIERCREATE_STRUCT *pp, B
pp->bOrders = bp->bOrders; pp->bOrders = bp->bOrders;
pp->bAttitude = bp->bAttitude; pp->bAttitude = bp->bAttitude;
pp->ubDirection = bp->ubDirection; pp->ubDirection = bp->ubDirection;
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("CreateDetailedPlacementGivenBasicPlacementInfo: determine soldier's class")); DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("CreateDetailedPlacementGivenBasicPlacementInfo: determine soldier's class"));
// determine this soldier's soldier class // determine this soldier's soldier class
if( bp->bTeam == CREATURE_TEAM ) if( bp->bTeam == CREATURE_TEAM )
@@ -2411,8 +2413,7 @@ void CreateDetailedPlacementGivenBasicPlacementInfo( SOLDIERCREATE_STRUCT *pp, B
} }
ubDiffFactor = CalcDifficultyModifier( ubSoldierClass ); ubDiffFactor = CalcDifficultyModifier( ubSoldierClass );
// experience level is modified by game difficulty, player's progress, & proximity to Queen's Palace, etc. // experience level is modified by game difficulty, player's progress, & proximity to Queen's Palace, etc.
// This formula gives the following results: // This formula gives the following results:
// DIFFICULTY FACTOR EXP. LEVEL MODIFIER LEVEL OF AVG REGULAR TROOP // DIFFICULTY FACTOR EXP. LEVEL MODIFIER LEVEL OF AVG REGULAR TROOP
@@ -2457,6 +2458,19 @@ void CreateDetailedPlacementGivenBasicPlacementInfo( SOLDIERCREATE_STRUCT *pp, B
break; break;
} }
UINT8 DiffLevel;
if ( gGameOptions.ubDifficultyLevel == DIF_LEVEL_EASY )
DiffLevel = 1;
else if ( gGameOptions.ubDifficultyLevel == DIF_LEVEL_MEDIUM )
DiffLevel = 2;
else if ( gGameOptions.ubDifficultyLevel == DIF_LEVEL_HARD )
DiffLevel = 3;
else if ( gGameOptions.ubDifficultyLevel == DIF_LEVEL_INSANE )
DiffLevel = 4;
else
{
DiffLevel = 1 + Random ( 4 );
}
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("CreateDetailedPlacementGivenBasicPlacementInfo: set level based on soldier class")); DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("CreateDetailedPlacementGivenBasicPlacementInfo: set level based on soldier class"));
//Set the experience level based on the soldier class and exp level modifier or relative attribute level //Set the experience level based on the soldier class and exp level modifier or relative attribute level
@@ -2464,6 +2478,7 @@ void CreateDetailedPlacementGivenBasicPlacementInfo( SOLDIERCREATE_STRUCT *pp, B
{ {
case SOLDIER_CLASS_ADMINISTRATOR: case SOLDIER_CLASS_ADMINISTRATOR:
case SOLDIER_CLASS_ZOMBIE: case SOLDIER_CLASS_ZOMBIE:
case SOLDIER_CLASS_BANDIT:
pp->bExpLevel = (INT8) 2 + bExpLevelModifier; pp->bExpLevel = (INT8) 2 + bExpLevelModifier;
break; break;
case SOLDIER_CLASS_ARMY: case SOLDIER_CLASS_ARMY:
@@ -2512,23 +2527,7 @@ void CreateDetailedPlacementGivenBasicPlacementInfo( SOLDIERCREATE_STRUCT *pp, B
UINT8 PlacementType = gBloodcatPlacements[ SECTOR(gWorldSectorX, gWorldSectorY) ][0].PlacementType; UINT8 PlacementType = gBloodcatPlacements[ SECTOR(gWorldSectorX, gWorldSectorY) ][0].PlacementType;
if( PlacementType == BLOODCAT_PLACEMENT_LAIR ) if( PlacementType == BLOODCAT_PLACEMENT_LAIR )
{ {
UINT8 DiffLevel;
if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_EASY )
DiffLevel = 1;
else if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_MEDIUM )
DiffLevel = 2;
else if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_HARD )
DiffLevel = 3;
else if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_INSANE )
DiffLevel = 4;
else
{
DiffLevel = Random (4);
if (DiffLevel == 0) DiffLevel = 1;
}
pp->bExpLevel += DiffLevel; pp->bExpLevel += DiffLevel;
//pp->bExpLevel += gGameOptions.ubDifficultyLevel;
} }
break; break;
} }
@@ -2546,8 +2545,8 @@ void CreateDetailedPlacementGivenBasicPlacementInfo( SOLDIERCREATE_STRUCT *pp, B
} }
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("CreateDetailedPlacementGivenBasicPlacementInfo: set exp. level")); DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("CreateDetailedPlacementGivenBasicPlacementInfo: set exp. level"));
pp->bExpLevel = max( gGameOptions.ubDifficultyLevel, pp->bExpLevel ); //minimum exp. level of 1 -- madd->= dif level
pp->bExpLevel = max( DiffLevel, pp->bExpLevel ); //minimum exp. level of 1 -- madd->= dif level
if ( gGameOptions.ubDifficultyLevel == DIF_LEVEL_INSANE ) if ( gGameOptions.ubDifficultyLevel == DIF_LEVEL_INSANE )
pp->bExpLevel = max( 6, pp->bExpLevel ); //minimum exp. level of 6 in insane - madd pp->bExpLevel = max( 6, pp->bExpLevel ); //minimum exp. level of 6 in insane - madd
@@ -2555,23 +2554,7 @@ void CreateDetailedPlacementGivenBasicPlacementInfo( SOLDIERCREATE_STRUCT *pp, B
ubStatsLevel = pp->bExpLevel + bStatsModifier; ubStatsLevel = pp->bExpLevel + bStatsModifier;
UINT8 DiffLevel; ubStatsLevel = max( DiffLevel, ubStatsLevel ); //minimum stats level of 0 -- madd->= dif level
if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_EASY )
DiffLevel = 1;
else if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_MEDIUM )
DiffLevel = 2;
else if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_HARD )
DiffLevel = 3;
else if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_INSANE )
DiffLevel = 4;
else
{
DiffLevel = Random (4);
if (DiffLevel == 0) DiffLevel = 1;
}
ubStatsLevel = max( DiffLevel, ubStatsLevel ); //minimum stats level of 0 -- madd->= dif level
//ubStatsLevel = max( gGameOptions.ubDifficultyLevel, ubStatsLevel ); //minimum stats level of 0 -- madd->= dif level
if ( gGameOptions.ubDifficultyLevel == DIF_LEVEL_INSANE ) if ( gGameOptions.ubDifficultyLevel == DIF_LEVEL_INSANE )
ubStatsLevel = max( 6, ubStatsLevel ); //minimum stats level of 6 in insane ubStatsLevel = max( 6, ubStatsLevel ); //minimum stats level of 6 in insane
@@ -2618,7 +2601,11 @@ void CreateDetailedPlacementGivenBasicPlacementInfo( SOLDIERCREATE_STRUCT *pp, B
//own equipment. //own equipment.
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("CreateDetailedPlacementGivenBasicPlacementInfo: generate random equipment")); DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("CreateDetailedPlacementGivenBasicPlacementInfo: generate random equipment"));
if( !bp->fDetailedPlacement && ubSoldierClass != SOLDIER_CLASS_NONE && ubSoldierClass != SOLDIER_CLASS_CREATURE && ubSoldierClass != SOLDIER_CLASS_MINER && ubSoldierClass != SOLDIER_CLASS_ZOMBIE ) if( !bp->fDetailedPlacement &&
ubSoldierClass != SOLDIER_CLASS_NONE &&
ubSoldierClass != SOLDIER_CLASS_CREATURE &&
ubSoldierClass != SOLDIER_CLASS_MINER &&
ubSoldierClass != SOLDIER_CLASS_ZOMBIE )
{ {
GenerateRandomEquipment( pp, ubSoldierClass, bp->bRelativeEquipmentLevel); GenerateRandomEquipment( pp, ubSoldierClass, bp->bRelativeEquipmentLevel);
@@ -2800,7 +2787,10 @@ void CreateDetailedPlacementGivenStaticDetailedPlacementAndBasicPlacementInfo(
// ReplaceExtendedGuns( pp, bp->ubSoldierClass ); // ReplaceExtendedGuns( pp, bp->ubSoldierClass );
//} //}
if( bp->ubSoldierClass != SOLDIER_CLASS_NONE && bp->ubSoldierClass != SOLDIER_CLASS_CREATURE && bp->ubSoldierClass != SOLDIER_CLASS_MINER && bp->ubSoldierClass != SOLDIER_CLASS_ZOMBIE ) if( bp->ubSoldierClass != SOLDIER_CLASS_NONE &&
bp->ubSoldierClass != SOLDIER_CLASS_CREATURE &&
bp->ubSoldierClass != SOLDIER_CLASS_MINER &&
bp->ubSoldierClass != SOLDIER_CLASS_ZOMBIE )
{ {
GenerateRandomEquipment( pp, bp->ubSoldierClass, bp->bRelativeEquipmentLevel); GenerateRandomEquipment( pp, bp->ubSoldierClass, bp->bRelativeEquipmentLevel);
@@ -2841,6 +2831,7 @@ void UpdateSoldierWithStaticDetailedInformation( SOLDIERTYPE *s, SOLDIERCREATE_S
case SOLDIER_CLASS_ADMINISTRATOR: case SOLDIER_CLASS_ADMINISTRATOR:
case SOLDIER_CLASS_ARMY: case SOLDIER_CLASS_ARMY:
case SOLDIER_CLASS_ELITE: case SOLDIER_CLASS_ELITE:
case SOLDIER_CLASS_BANDIT:
GeneratePaletteForSoldier( s, spp->ubSoldierClass, spp->bTeam ); GeneratePaletteForSoldier( s, spp->ubSoldierClass, spp->bTeam );
break; break;
} }
@@ -3003,7 +2994,7 @@ SOLDIERTYPE* ReserveTacticalSoldierForAutoresolve( UINT8 ubSoldierClass )
//returns the pointer to that soldier. This is used when copying the exact status of //returns the pointer to that soldier. This is used when copying the exact status of
//all remaining enemy troops (or creatures) to finish the battle in autoresolve. To //all remaining enemy troops (or creatures) to finish the battle in autoresolve. To
//signify that the troop has already been reserved, we simply set their gridno to NOWHERE. //signify that the troop has already been reserved, we simply set their gridno to NOWHERE.
if( ubSoldierClass != SOLDIER_CLASS_CREATURE && ubSoldierClass != SOLDIER_CLASS_ZOMBIE ) if( ubSoldierClass != SOLDIER_CLASS_CREATURE && ubSoldierClass != SOLDIER_CLASS_ZOMBIE && ubSoldierClass != SOLDIER_CLASS_BANDIT )
{ {
//use the enemy team //use the enemy team
iStart = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID; iStart = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID;
@@ -3244,12 +3235,16 @@ SOLDIERTYPE* TacticalCreateZombie()
memset( &bp, 0, sizeof( BASIC_SOLDIERCREATE_STRUCT ) ); memset( &bp, 0, sizeof( BASIC_SOLDIERCREATE_STRUCT ) );
RandomizeRelativeLevel( &( bp.bRelativeAttributeLevel ), SOLDIER_CLASS_ZOMBIE ); RandomizeRelativeLevel( &( bp.bRelativeAttributeLevel ), SOLDIER_CLASS_ZOMBIE );
RandomizeRelativeLevel( &( bp.bRelativeEquipmentLevel ), SOLDIER_CLASS_ZOMBIE ); RandomizeRelativeLevel( &( bp.bRelativeEquipmentLevel ), SOLDIER_CLASS_ZOMBIE );
bp.bTeam = CREATURE_TEAM;//ZOMBIE_TEAM; bp.bTeam = CREATURE_TEAM;
bp.bOrders = SEEKENEMY; bp.bOrders = SEEKENEMY;
bp.bAttitude = AGGRESSIVE; bp.bAttitude = AGGRESSIVE;
bp.ubBodyType = -1; bp.ubBodyType = Random( ADULTFEMALEMONSTER );
bp.ubSoldierClass = SOLDIER_CLASS_ZOMBIE; bp.ubSoldierClass = SOLDIER_CLASS_ZOMBIE;
CreateDetailedPlacementGivenBasicPlacementInfo( &pp, &bp ); CreateDetailedPlacementGivenBasicPlacementInfo( &pp, &bp );
// need to properly set this here
pp.ubSoldierClass = SOLDIER_CLASS_ZOMBIE;
pSoldier = TacticalCreateSoldier( &pp, &ubID ); pSoldier = TacticalCreateSoldier( &pp, &ubID );
if ( pSoldier ) if ( pSoldier )
{ {
@@ -3398,10 +3393,13 @@ SOLDIERTYPE* TacticalCreateArmedCivilian( UINT8 usSoldierClass )
pSoldier->aiData.sNoiseGridno = (CENTRAL_GRIDNO + (Random( CENTRAL_RADIUS * 2 + 1 ) - CENTRAL_RADIUS) + (Random( CENTRAL_RADIUS * 2 + 1 ) - CENTRAL_RADIUS) * WORLD_COLS); pSoldier->aiData.sNoiseGridno = (CENTRAL_GRIDNO + (Random( CENTRAL_RADIUS * 2 + 1 ) - CENTRAL_RADIUS) + (Random( CENTRAL_RADIUS * 2 + 1 ) - CENTRAL_RADIUS) * WORLD_COLS);
pSoldier->aiData.ubNoiseVolume = MAX_MISC_NOISE_DURATION; pSoldier->aiData.ubNoiseVolume = MAX_MISC_NOISE_DURATION;
// random clothes if ( guiCurrentScreen != AUTORESOLVE_SCREEN )
SetClothes( pSoldier, Random( NUMSHIRTS ), Random( NUMPANTS ) ); {
// random clothes
SetClothes( pSoldier, Random( NUMSHIRTS ), Random( NUMPANTS ) );
pSoldier->CreateSoldierPalettes( ); pSoldier->CreateSoldierPalettes();
}
} }
return(pSoldier); return(pSoldier);
@@ -3481,25 +3479,28 @@ SOLDIERTYPE* TacticalCreateCivilian( INT32 sGridNo, UINT8 usCivilianGroup, INT8
pSoldier->aiData.bOrders = ONGUARD; pSoldier->aiData.bOrders = ONGUARD;
} }
// make him wear administrator uniform if ( guiCurrentScreen != AUTORESOLVE_SCREEN )
UINT16 usPaletteAnimSurface = LoadSoldierAnimationSurface( pSoldier, pSoldier->usAnimState );
if ( usPaletteAnimSurface != INVALID_ANIMATION_SURFACE )
{ {
SetClothes( pSoldier, aVest, aPants, aHair, aSkin ); // make him wear administrator uniform
UINT16 usPaletteAnimSurface = LoadSoldierAnimationSurface( pSoldier, pSoldier->usAnimState );
// Use palette from HVOBJECT, then use substitution for pants, etc if ( usPaletteAnimSurface != INVALID_ANIMATION_SURFACE )
memcpy( pSoldier->p8BPPPalette, gAnimSurfaceDatabase[usPaletteAnimSurface].hVideoObject->pPaletteEntry, sizeof(pSoldier->p8BPPPalette) * 256 ); {
SetClothes( pSoldier, aVest, aPants, aHair, aSkin );
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->HeadPal ); // Use palette from HVOBJECT, then use substitution for pants, etc
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->VestPal ); memcpy( pSoldier->p8BPPPalette, gAnimSurfaceDatabase[usPaletteAnimSurface].hVideoObject->pPaletteEntry, sizeof( pSoldier->p8BPPPalette ) * 256 );
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->PantsPal );
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->SkinPal );
pSoldier->CreateSoldierPalettes( ); SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->HeadPal );
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->VestPal );
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->PantsPal );
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->SkinPal );
// Dirty pSoldier->CreateSoldierPalettes();
fInterfacePanelDirty = DIRTYLEVEL2;
// Dirty
fInterfacePanelDirty = DIRTYLEVEL2;
}
} }
} }
@@ -3572,6 +3573,65 @@ SOLDIERTYPE* TacticalCreateEnemyAssassin(UINT8 disguisetype)
return( pSoldier ); return( pSoldier );
} }
SOLDIERTYPE* TacticalCreateBandit()
{
BASIC_SOLDIERCREATE_STRUCT bp;
SOLDIERCREATE_STRUCT pp;
UINT8 ubID;
SOLDIERTYPE * pSoldier;
if ( guiCurrentScreen == AUTORESOLVE_SCREEN && !gfPersistantPBI )
{
pSoldier = ReserveTacticalSoldierForAutoresolve( SOLDIER_CLASS_BANDIT );
if ( pSoldier ) return pSoldier;
}
memset( &bp, 0, sizeof( BASIC_SOLDIERCREATE_STRUCT ) );
RandomizeRelativeLevel( &( bp.bRelativeAttributeLevel ), SOLDIER_CLASS_ADMINISTRATOR );
RandomizeRelativeLevel( &( bp.bRelativeEquipmentLevel ), SOLDIER_CLASS_ADMINISTRATOR );
bp.bTeam = ENEMY_TEAM; // set wrong team here, otherwise no bodytype/equipment will be set
bp.bOrders = SEEKENEMY;
bp.bAttitude = (INT8)Random( MAXATTITUDES );
bp.ubBodyType = -1;
bp.ubSoldierClass = SOLDIER_CLASS_ADMINISTRATOR;
CreateDetailedPlacementGivenBasicPlacementInfo( &pp, &bp );
// need to properly set this here
pp.bTeam = CREATURE_TEAM;
pp.ubSoldierClass = SOLDIER_CLASS_BANDIT;
pSoldier = TacticalCreateSoldier( &pp, &ubID );
if ( pSoldier )
{
// send soldier to centre of map, roughly
pSoldier->aiData.sNoiseGridno = ( CENTRAL_GRIDNO + ( Random( CENTRAL_RADIUS * 2 + 1 ) - CENTRAL_RADIUS ) + ( Random( CENTRAL_RADIUS * 2 + 1 ) - CENTRAL_RADIUS ) * WORLD_COLS );
pSoldier->aiData.ubNoiseVolume = MAX_MISC_NOISE_DURATION;
if ( guiCurrentScreen != AUTORESOLVE_SCREEN )
{
UINT16 usPaletteAnimSurface = LoadSoldierAnimationSurface( pSoldier, pSoldier->usAnimState );
if ( usPaletteAnimSurface != INVALID_ANIMATION_SURFACE )
{
// random clothes
SetClothes( pSoldier, Random( NUMSHIRTS ), Random( NUMPANTS ) );
// Use palette from HVOBJECT, then use substitution for pants, etc
memcpy( pSoldier->p8BPPPalette, gAnimSurfaceDatabase[usPaletteAnimSurface].hVideoObject->pPaletteEntry, sizeof( pSoldier->p8BPPPalette ) * 256 );
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->HeadPal );
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->VestPal );
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->PantsPal );
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->SkinPal );
pSoldier->CreateSoldierPalettes();
}
}
}
return( pSoldier );
}
void CreateAssassin(UINT8 disguisetype) void CreateAssassin(UINT8 disguisetype)
{ {
SOLDIERTYPE* pSoldier = TacticalCreateEnemyAssassin( disguisetype ); SOLDIERTYPE* pSoldier = TacticalCreateEnemyAssassin( disguisetype );
@@ -3742,26 +3802,29 @@ void CreatePrisonerOfWar()
swprintf( pSoldier->name, TacticalStr[ POW_TEAM_MERC_NAME ] ); swprintf( pSoldier->name, TacticalStr[ POW_TEAM_MERC_NAME ] );
// make him wear 'prisoner garb' (just what Shank and Dynamo are wearing) if ( guiCurrentScreen != AUTORESOLVE_SCREEN )
UINT16 usPaletteAnimSurface = LoadSoldierAnimationSurface( pSoldier, pSoldier->usAnimState );
if ( usPaletteAnimSurface != INVALID_ANIMATION_SURFACE )
{ {
SET_PALETTEREP_ID( pSoldier->VestPal, "greyVEST" ); // make him wear 'prisoner garb' (just what Shank and Dynamo are wearing)
SET_PALETTEREP_ID( pSoldier->PantsPal, "BLACKPANTS" ); UINT16 usPaletteAnimSurface = LoadSoldierAnimationSurface( pSoldier, pSoldier->usAnimState );
// Use palette from HVOBJECT, then use substitution for pants, etc if ( usPaletteAnimSurface != INVALID_ANIMATION_SURFACE )
memcpy( pSoldier->p8BPPPalette, gAnimSurfaceDatabase[usPaletteAnimSurface].hVideoObject->pPaletteEntry, sizeof(pSoldier->p8BPPPalette) * 256 ); {
SET_PALETTEREP_ID( pSoldier->VestPal, "greyVEST" );
SET_PALETTEREP_ID( pSoldier->PantsPal, "BLACKPANTS" );
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->HeadPal ); // Use palette from HVOBJECT, then use substitution for pants, etc
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->VestPal ); memcpy( pSoldier->p8BPPPalette, gAnimSurfaceDatabase[usPaletteAnimSurface].hVideoObject->pPaletteEntry, sizeof( pSoldier->p8BPPPalette ) * 256 );
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->PantsPal );
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->SkinPal );
pSoldier->CreateSoldierPalettes( ); SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->HeadPal );
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->VestPal );
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->PantsPal );
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->SkinPal );
// Dirty pSoldier->CreateSoldierPalettes();
fInterfacePanelDirty = DIRTYLEVEL2;
// Dirty
fInterfacePanelDirty = DIRTYLEVEL2;
}
} }
// So we can see them! // So we can see them!
@@ -4696,7 +4759,7 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre
// 30-80% // 30-80%
iChance = 30 + ubProgress / 2; iChance = 30 + ubProgress / 2;
} }
else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA || ubSolClass == SOLDIER_CLASS_BANDIT )
{ {
// 15-65% // 15-65%
iChance = 15 + ubProgress / 2; iChance = 15 + ubProgress / 2;
@@ -4757,7 +4820,7 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre
// 30-80% // 30-80%
iChance = 30 + ubProgress / 2; iChance = 30 + ubProgress / 2;
} }
else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA || ubSolClass == SOLDIER_CLASS_BANDIT )
{ {
// 15-65% // 15-65%
iChance = 15 + ubProgress / 2; iChance = 15 + ubProgress / 2;
@@ -4819,7 +4882,7 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre
// 25-75% // 25-75%
iChance = 25 + ubProgress / 2; iChance = 25 + ubProgress / 2;
} }
else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA || ubSolClass == SOLDIER_CLASS_BANDIT )
{ {
// 10-60% // 10-60%
iChance = 10 + ubProgress / 2; iChance = 10 + ubProgress / 2;
@@ -4888,7 +4951,7 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre
// 25-75% // 25-75%
iChance = 25 + ubProgress / 2; iChance = 25 + ubProgress / 2;
} }
else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA || ubSolClass == SOLDIER_CLASS_BANDIT )
{ {
// 10-60% // 10-60%
iChance = 10 + ubProgress / 2; iChance = 10 + ubProgress / 2;
@@ -4993,7 +5056,7 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre
// 25-75% // 25-75%
iChance = 25 + ubProgress / 2; iChance = 25 + ubProgress / 2;
} }
else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA || ubSolClass == SOLDIER_CLASS_BANDIT )
{ {
// 10-60% // 10-60%
iChance = 10 + ubProgress / 2; iChance = 10 + ubProgress / 2;
@@ -5177,7 +5240,7 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre
iChance = 45 + ubProgress / 2; // 45-95% chance iChance = 45 + ubProgress / 2; // 45-95% chance
else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA )
iChance = 30 + ubProgress / 2; // 30-80% chance iChance = 30 + ubProgress / 2; // 30-80% chance
else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA || ubSolClass == SOLDIER_CLASS_BANDIT )
iChance = 15 + ubProgress / 2; // 15-65% chance iChance = 15 + ubProgress / 2; // 15-65% chance
// adust the chance by the type of heavy weapon // adust the chance by the type of heavy weapon
@@ -5239,7 +5302,7 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre
iChance = 20 + ubProgress / 4; // 20-45% chance iChance = 20 + ubProgress / 4; // 20-45% chance
else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA )
iChance = 10 + ubProgress / 4; // 10-35% chance iChance = 10 + ubProgress / 4; // 10-35% chance
else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA || ubSolClass == SOLDIER_CLASS_BANDIT )
iChance = ubProgress / 4; // 0-25% chance iChance = ubProgress / 4; // 0-25% chance
else if ( ubSolClass == SOLDIER_CLASS_ZOMBIE ) else if ( ubSolClass == SOLDIER_CLASS_ZOMBIE )
iChance = 100; // 100% chance iChance = 100; // 100% chance
@@ -5284,7 +5347,7 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre
iChance = 40 + ubProgress * 2 / 5; // 40-80% chance iChance = 40 + ubProgress * 2 / 5; // 40-80% chance
else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA )
iChance = 25 + ubProgress * 2 / 5; // 25-65% chance iChance = 25 + ubProgress * 2 / 5; // 25-65% chance
else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA || ubSolClass == SOLDIER_CLASS_BANDIT )
iChance = 10 + ubProgress * 2 / 5; // 10-50% chance iChance = 10 + ubProgress * 2 / 5; // 10-50% chance
else if ( ubSolClass == SOLDIER_CLASS_ZOMBIE ) else if ( ubSolClass == SOLDIER_CLASS_ZOMBIE )
iChance = 100; // 100% chance iChance = 100; // 100% chance
@@ -5348,7 +5411,7 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre
iChance = 30 + ubProgress / 3 + 30; // 60-92% chance iChance = 30 + ubProgress / 3 + 30; // 60-92% chance
else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA )
iChance = 15 + ubProgress / 3 + 25; // 40-73% chance iChance = 15 + ubProgress / 3 + 25; // 40-73% chance
else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA || ubSolClass == SOLDIER_CLASS_BANDIT )
iChance = ubProgress / 3 + 20; // 20-53% chance iChance = ubProgress / 3 + 20; // 20-53% chance
// modify the chance by preset ini setting // modify the chance by preset ini setting
@@ -5411,7 +5474,7 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre
iChance = 20 + ubProgress / 3; // 20-53% chance iChance = 20 + ubProgress / 3; // 20-53% chance
else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA )
iChance = 10 + ubProgress / 3; // 10-43% chance iChance = 10 + ubProgress / 3; // 10-43% chance
else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA || ubSolClass == SOLDIER_CLASS_BANDIT )
iChance = ubProgress / 3; // 0-33% chance iChance = ubProgress / 3; // 0-33% chance
// modify the chance by preset ini setting // modify the chance by preset ini setting
@@ -5451,7 +5514,7 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre
iChance = 50 + ubProgress * 2 / 5; // 50-90% chance iChance = 50 + ubProgress * 2 / 5; // 50-90% chance
else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA )
iChance = 35 + ubProgress * 2 / 5; // 35-75% chance iChance = 35 + ubProgress * 2 / 5; // 35-75% chance
else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA || ubSolClass == SOLDIER_CLASS_BANDIT )
iChance = 15 + ubProgress * 2 / 5; // 15-55% chance iChance = 15 + ubProgress * 2 / 5; // 15-55% chance
// modify the chance by preset ini setting // modify the chance by preset ini setting
@@ -5514,7 +5577,7 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre
iChance = 40 + ubProgress * 2 / 5; // 40-80% chance iChance = 40 + ubProgress * 2 / 5; // 40-80% chance
else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA )
iChance = 25 + ubProgress * 2 / 5; // 25-65% chance iChance = 25 + ubProgress * 2 / 5; // 25-65% chance
else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA || ubSolClass == SOLDIER_CLASS_BANDIT )
iChance = 10 + ubProgress * 2 / 5; // 10-50% chance iChance = 10 + ubProgress * 2 / 5; // 10-50% chance
// modify the chance by preset ini setting // modify the chance by preset ini setting
@@ -5556,7 +5619,7 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre
iChance = 10 + ubProgress / 4; // 10-35% chance iChance = 10 + ubProgress / 4; // 10-35% chance
else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA )
iChance = ubProgress / 5; // 0-20% chance iChance = ubProgress / 5; // 0-20% chance
else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA || ubSolClass == SOLDIER_CLASS_BANDIT )
iChance = 0; // 0% chance iChance = 0; // 0% chance
// modify the chance by preset ini setting // modify the chance by preset ini setting
@@ -5598,7 +5661,7 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre
iChance = 30 + ubProgress / 2; // 30-90% chance iChance = 30 + ubProgress / 2; // 30-90% chance
else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA )
iChance = 10 + ubProgress / 2; // 10-60% chance iChance = 10 + ubProgress / 2; // 10-60% chance
else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA || ubSolClass == SOLDIER_CLASS_BANDIT )
iChance = ubProgress / 3; // 0-33% chance iChance = ubProgress / 3; // 0-33% chance
// modify the chance by preset ini setting // modify the chance by preset ini setting
+3
View File
@@ -481,6 +481,9 @@ SOLDIERTYPE* TacticalCreateCivilian( INT32 sGridNo, UINT8 usCivilianGroup, INT8
// Flugente: assassins are elite soldiers of the civ team that go hostile on a certain event, otherwise they just blend in // Flugente: assassins are elite soldiers of the civ team that go hostile on a certain event, otherwise they just blend in
SOLDIERTYPE* TacticalCreateEnemyAssassin(UINT8 disguisetype); SOLDIERTYPE* TacticalCreateEnemyAssassin(UINT8 disguisetype);
SOLDIERTYPE* TacticalCreateBandit();
void CreateAssassin(UINT8 disguisetype); void CreateAssassin(UINT8 disguisetype);
// create a prisoner (in a prison cell) in the current sector // create a prisoner (in a prison cell) in the current sector
+130 -2
View File
@@ -59,6 +59,8 @@
#include "PreBattle Interface.h" // added by Flugente #include "PreBattle Interface.h" // added by Flugente
#include "LuaInitNPCs.h" // added by Flugente #include "LuaInitNPCs.h" // added by Flugente
#include "Soldier macros.h" // added by Flugente #include "Soldier macros.h" // added by Flugente
#include "Creature Spreading.h" // added by Flugente
BOOLEAN gfOriginalList = TRUE; BOOLEAN gfOriginalList = TRUE;
@@ -1105,6 +1107,7 @@ void AddSoldierInitListEnemyDefenceSoldiers( UINT8 ubTotalAdmin, UINT8 ubTotalTr
ubEliteBSlots++; ubEliteBSlots++;
break; break;
case SOLDIER_CLASS_ADMINISTRATOR: case SOLDIER_CLASS_ADMINISTRATOR:
case SOLDIER_CLASS_BANDIT:
if( curr->pBasicPlacement->fPriorityExistance && curr->pDetailedPlacement ) if( curr->pBasicPlacement->fPriorityExistance && curr->pDetailedPlacement )
ubAdminPDSlots++; ubAdminPDSlots++;
else if( curr->pBasicPlacement->fPriorityExistance ) else if( curr->pBasicPlacement->fPriorityExistance )
@@ -1163,6 +1166,7 @@ void AddSoldierInitListEnemyDefenceSoldiers( UINT8 ubTotalAdmin, UINT8 ubTotalTr
switch( ubCurrClass ) switch( ubCurrClass )
{ {
case SOLDIER_CLASS_ADMINISTRATOR: case SOLDIER_CLASS_ADMINISTRATOR:
case SOLDIER_CLASS_BANDIT:
pCurrSlots = &ubAdminPDSlots; pCurrSlots = &ubAdminPDSlots;
pCurrTotal = &ubTotalAdmin; pCurrTotal = &ubTotalAdmin;
break; break;
@@ -1229,6 +1233,7 @@ void AddSoldierInitListEnemyDefenceSoldiers( UINT8 ubTotalAdmin, UINT8 ubTotalTr
switch( ubCurrClass ) switch( ubCurrClass )
{ {
case SOLDIER_CLASS_ADMINISTRATOR: case SOLDIER_CLASS_ADMINISTRATOR:
case SOLDIER_CLASS_BANDIT:
pCurrSlots = &ubAdminPSlots; pCurrSlots = &ubAdminPSlots;
pCurrTotal = &ubTotalAdmin; pCurrTotal = &ubTotalAdmin;
break; break;
@@ -1285,6 +1290,7 @@ void AddSoldierInitListEnemyDefenceSoldiers( UINT8 ubTotalAdmin, UINT8 ubTotalTr
switch( ubCurrClass ) switch( ubCurrClass )
{ {
case SOLDIER_CLASS_ADMINISTRATOR: case SOLDIER_CLASS_ADMINISTRATOR:
case SOLDIER_CLASS_BANDIT:
pCurrSlots = &ubAdminDSlots; pCurrSlots = &ubAdminDSlots;
pCurrTotal = &ubTotalAdmin; pCurrTotal = &ubTotalAdmin;
break; break;
@@ -1389,12 +1395,13 @@ void AddSoldierInitListEnemyDefenceSoldiers( UINT8 ubTotalAdmin, UINT8 ubTotalTr
//ADD REMAINING PLACEMENTS WITH BASIC PLACEMENT INFORMATION //ADD REMAINING PLACEMENTS WITH BASIC PLACEMENT INFORMATION
//we now have the numbers of available slots for each soldier class, so loop through three times //we now have the numbers of available slots for each soldier class, so loop through three times
//and randomly choose some (or all) of the matching slots to fill. This is done randomly. //and randomly choose some (or all) of the matching slots to fill. This is done randomly.
for( ubCurrClass = SOLDIER_CLASS_ADMINISTRATOR; ubCurrClass <= SOLDIER_CLASS_ARMY; ubCurrClass++ ) for( ubCurrClass = SOLDIER_CLASS_ADMINISTRATOR; ubCurrClass <= SOLDIER_CLASS_ARMY; ++ubCurrClass )
{ {
//First, prepare the counters. //First, prepare the counters.
switch( ubCurrClass ) switch( ubCurrClass )
{ {
case SOLDIER_CLASS_ADMINISTRATOR: case SOLDIER_CLASS_ADMINISTRATOR:
case SOLDIER_CLASS_BANDIT:
pCurrSlots = &ubAdminBSlots; pCurrSlots = &ubAdminBSlots;
pCurrTotal = &ubTotalAdmin; pCurrTotal = &ubTotalAdmin;
break; break;
@@ -1672,7 +1679,8 @@ void AddSoldierInitListMilitia( UINT8 ubNumGreen, UINT8 ubNumRegs, UINT8 ubNumEl
switch( curr->pBasicPlacement->ubSoldierClass ) switch( curr->pBasicPlacement->ubSoldierClass )
{ {
case SOLDIER_CLASS_ELITE: ubEliteSlots++; break; case SOLDIER_CLASS_ELITE: ubEliteSlots++; break;
case SOLDIER_CLASS_ADMINISTRATOR: ubGreenSlots++; break; case SOLDIER_CLASS_ADMINISTRATOR:
case SOLDIER_CLASS_BANDIT: ubGreenSlots++; break;
case SOLDIER_CLASS_ARMY: ubRegSlots++; break; case SOLDIER_CLASS_ARMY: ubRegSlots++; break;
} }
} }
@@ -1693,6 +1701,7 @@ void AddSoldierInitListMilitia( UINT8 ubNumGreen, UINT8 ubNumRegs, UINT8 ubNumEl
switch( reorder[i] ) switch( reorder[i] )
{ {
case SOLDIER_CLASS_ADMINISTRATOR: case SOLDIER_CLASS_ADMINISTRATOR:
case SOLDIER_CLASS_BANDIT:
pCurrSlots = &ubGreenSlots; pCurrSlots = &ubGreenSlots;
pCurrTotal = &ubNumGreen; pCurrTotal = &ubNumGreen;
break; break;
@@ -1721,6 +1730,7 @@ void AddSoldierInitListMilitia( UINT8 ubNumGreen, UINT8 ubNumRegs, UINT8 ubNumEl
switch( reorder[i] ) switch( reorder[i] )
{ {
case SOLDIER_CLASS_ADMINISTRATOR: case SOLDIER_CLASS_ADMINISTRATOR:
case SOLDIER_CLASS_BANDIT:
curr->pBasicPlacement->ubSoldierClass = SOLDIER_CLASS_GREEN_MILITIA; curr->pBasicPlacement->ubSoldierClass = SOLDIER_CLASS_GREEN_MILITIA;
break; break;
case SOLDIER_CLASS_ARMY: case SOLDIER_CLASS_ARMY:
@@ -2059,7 +2069,125 @@ void AddSoldierInitListCreatures( BOOLEAN fQueen, UINT8 ubNumLarvae, UINT8 ubNum
} }
} }
void AddSoldierInitListOtherCreatures( UINT8 usNum )
{
SOLDIERINITNODE *curr;
INT32 iRandom;
UINT8 ubFreeSlots;
BOOLEAN fDoPlacement;
UINT8 ubNumCreatures = usNum;
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "AddSoldierInitListBloodcats" ) );
SortSoldierInitList();
//First fill up only the priority existance slots (as long as the availability and bodytypes match)
curr = gSoldierInitHead;
while ( curr && curr->pBasicPlacement->fPriorityExistance && ubNumCreatures )
{
fDoPlacement = TRUE;
if ( curr->pBasicPlacement->bTeam == CREATURE_TEAM )
{
//Matching team, now check the soldier class...
switch ( guCreatureAttackType )
{
case CREATURE_ATTACK_TYPE_ZOMBIE:
if ( curr->pBasicPlacement->ubBodyType > REGFEMALE )
fDoPlacement = FALSE;
break;
case CREATURE_ATTACK_TYPE_BANDIT:
if ( curr->pBasicPlacement->ubBodyType > REGFEMALE )
fDoPlacement = FALSE;
break;
case CREATURE_ATTACK_TYPE_BLOODCAT:
if ( curr->pBasicPlacement->ubBodyType != BLOODCAT )
fDoPlacement = FALSE;
break;
}
break;
if ( fDoPlacement )
{
if ( AddPlacementToWorld( curr ) )
{
--ubNumCreatures;
}
else
return;
}
}
curr = curr->next;
}
if ( !ubNumCreatures )
return;
//Count how many free creature slots are left.
curr = gSoldierInitHead;
ubFreeSlots = 0;
while ( curr )
{
if ( !curr->pSoldier && curr->pBasicPlacement->bTeam == CREATURE_TEAM )
++ubFreeSlots;
curr = curr->next;
}
//Now, if we still have creatures to place, do so completely randomly, overriding priority
//placements, etc.
curr = gSoldierInitHead;
while ( curr && ubFreeSlots && ubNumCreatures )
{
if ( !curr->pSoldier && curr->pBasicPlacement->bTeam == CREATURE_TEAM )
{
//Randomly determine if we will use this slot; the more available slots in proportion to
//the number of enemies, the lower the chance of accepting the slot.
if ( ubFreeSlots <= ubNumCreatures || Random( ubFreeSlots ) < ubNumCreatures )
{
switch ( guCreatureAttackType )
{
case CREATURE_ATTACK_TYPE_ZOMBIE:
curr->pBasicPlacement->ubBodyType = Random( ADULTFEMALEMONSTER );
break;
case CREATURE_ATTACK_TYPE_BANDIT:
curr->pBasicPlacement->ubBodyType = Random( ADULTFEMALEMONSTER );
break;
case CREATURE_ATTACK_TYPE_BLOODCAT:
curr->pBasicPlacement->ubBodyType = BLOODCAT;
break;
}
break;
if ( curr->pDetailedPlacement )
{
//delete the detailed placement information.
MemFree( curr->pDetailedPlacement );
curr->pDetailedPlacement = NULL;
curr->pBasicPlacement->fDetailedPlacement = FALSE;
}
if ( AddPlacementToWorld( curr ) )
{
--ubNumCreatures;
}
else
{
return;
}
}
--ubFreeSlots;
//With the decrementing of the slot vars in this manner, the chances increase so that all slots
//will be full by the time the end of the list comes up.
}
curr = curr->next;
}
}
SOLDIERINITNODE* FindSoldierInitNodeWithProfileID( UINT16 usProfile ); SOLDIERINITNODE* FindSoldierInitNodeWithProfileID( UINT16 usProfile );
SOLDIERINITNODE* FindSoldierInitNodeWithProfileID( UINT16 usProfile ) SOLDIERINITNODE* FindSoldierInitNodeWithProfileID( UINT16 usProfile )
+1
View File
@@ -44,6 +44,7 @@ void AddSoldierInitListEnemyDefenceSoldiers( UINT8 ubTotalAdmin, UINT8 ubTotalTr
void AddSoldierInitListCreatures( BOOLEAN fQueen, UINT8 ubNumLarvae, UINT8 ubNumInfants, void AddSoldierInitListCreatures( BOOLEAN fQueen, UINT8 ubNumLarvae, UINT8 ubNumInfants,
UINT8 ubNumYoungMales, UINT8 ubNumYoungFemales, UINT8 ubNumAdultMales, UINT8 ubNumYoungMales, UINT8 ubNumYoungFemales, UINT8 ubNumAdultMales,
UINT8 ubNumAdultFemales ); UINT8 ubNumAdultFemales );
void AddSoldierInitListOtherCreatures( UINT8 usNum );
void AddSoldierInitListMilitia( UINT8 ubNumGreen, UINT8 ubNumReg, UINT8 ubNumElites ); void AddSoldierInitListMilitia( UINT8 ubNumGreen, UINT8 ubNumReg, UINT8 ubNumElites );
void AddSoldierInitListMilitiaOnEdge( UINT8 ubStrategicInsertionCode, UINT8 ubNumGreen, UINT8 ubNumReg, UINT8 ubNumElites ); void AddSoldierInitListMilitiaOnEdge( UINT8 ubStrategicInsertionCode, UINT8 ubNumGreen, UINT8 ubNumReg, UINT8 ubNumElites );
+24 -49
View File
@@ -6477,7 +6477,7 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTime,
else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA && gGameExternalOptions.sVeteranMilitiaCtHBonusPercent != 0) else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA && gGameExternalOptions.sVeteranMilitiaCtHBonusPercent != 0)
iChance += ((iChance * gGameExternalOptions.sVeteranMilitiaCtHBonusPercent) /100); iChance += ((iChance * gGameExternalOptions.sVeteranMilitiaCtHBonusPercent) /100);
// bonus for enemy // bonus for enemy
else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ADMINISTRATOR && gGameExternalOptions.sEnemyAdminCtHBonusPercent != 0) else if ( (pSoldier->ubSoldierClass == SOLDIER_CLASS_ADMINISTRATOR || pSoldier->ubSoldierClass == SOLDIER_CLASS_BANDIT) && gGameExternalOptions.sEnemyAdminCtHBonusPercent != 0)
iChance += ((iChance * gGameExternalOptions.sEnemyAdminCtHBonusPercent) /100); iChance += ((iChance * gGameExternalOptions.sEnemyAdminCtHBonusPercent) /100);
else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ARMY && gGameExternalOptions.sEnemyRegularCtHBonusPercent != 0) else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ARMY && gGameExternalOptions.sEnemyRegularCtHBonusPercent != 0)
iChance += ((iChance * gGameExternalOptions.sEnemyRegularCtHBonusPercent) /100); iChance += ((iChance * gGameExternalOptions.sEnemyRegularCtHBonusPercent) /100);
@@ -9069,6 +9069,8 @@ INT32 HTHImpact( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pTarget, INT32 iHitBy, BO
INT32 iImpact, iFluke, iBonus; INT32 iImpact, iFluke, iBonus;
BOOLEAN autoresolve = IsAutoResolveActive();
// Flugente: check for underbarrel weapons and use that object if necessary (think of bayonets) // Flugente: check for underbarrel weapons and use that object if necessary (think of bayonets)
OBJECTTYPE* pObj = pSoldier->GetUsedWeapon( &(pSoldier->inv[HANDPOS]) ); OBJECTTYPE* pObj = pSoldier->GetUsedWeapon( &(pSoldier->inv[HANDPOS]) );
@@ -9158,9 +9160,10 @@ INT32 HTHImpact( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pTarget, INT32 iHitBy, BO
if ( HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT ) ) if ( HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT ) )
{ {
iBonus += ( gSkillTraitValues.ubMABonusDamageHandToHand * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ) ); iBonus += ( gSkillTraitValues.ubMABonusDamageHandToHand * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ) );
} }
// add bonus for focused punch // add bonus for focused punch
if (pSoldier->usAnimState == NINJA_SPINKICK || pSoldier->usAnimState == FOCUSED_PUNCH || pSoldier->usAnimState == FOCUSED_HTH_KICK ) if ( !autoresolve && (pSoldier->usAnimState == NINJA_SPINKICK || pSoldier->usAnimState == FOCUSED_PUNCH || pSoldier->usAnimState == FOCUSED_HTH_KICK) )
{ {
iBonus += 50; iBonus += 50;
@@ -9180,7 +9183,8 @@ INT32 HTHImpact( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pTarget, INT32 iHitBy, BO
iBonus += ( gSkillTraitValues.ubMABonusDamageHandToHand * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ) ); iBonus += ( gSkillTraitValues.ubMABonusDamageHandToHand * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ) );
// The Spinning kicks or aimed punch bonus - SANDRO // The Spinning kicks or aimed punch bonus - SANDRO
if (pSoldier->usAnimState == NINJA_SPINKICK || (pSoldier->aiData.bAimTime >= (gGameExternalOptions.fEnhancedCloseCombatSystem ? gSkillTraitValues.ubModifierForAPsAddedOnAimedPunches : 6))) if ( !autoresolve &&
(pSoldier->usAnimState == NINJA_SPINKICK || (pSoldier->aiData.bAimTime >= (gGameExternalOptions.fEnhancedCloseCombatSystem ? gSkillTraitValues.ubModifierForAPsAddedOnAimedPunches : 6)) ))
{ {
//iImpact = (INT32)((iImpact * (100 + gSkillTraitValues.usMAAimedPunchDamageBonus * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ) ) / 100) + 0.5); // +75% damage per trait //iImpact = (INT32)((iImpact * (100 + gSkillTraitValues.usMAAimedPunchDamageBonus * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ) ) / 100) + 0.5); // +75% damage per trait
iBonus += ( (gSkillTraitValues.ubMABonusDamageHandToHand + 25 )* NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ) ); iBonus += ( (gSkillTraitValues.ubMABonusDamageHandToHand + 25 )* NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ) );
@@ -9196,28 +9200,31 @@ INT32 HTHImpact( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pTarget, INT32 iHitBy, BO
iBonus += gSkillTraitValues.ubMEDamageBonusBlunt; iBonus += gSkillTraitValues.ubMEDamageBonusBlunt;
// bonus for aimed attack // bonus for aimed attack
if ( pSoldier->aiData.bAimTime >= (gGameExternalOptions.fEnhancedCloseCombatSystem ? gSkillTraitValues.ubModifierForAPsAddedOnAimedBladedAttackes : 6) ) if ( !autoresolve && pSoldier->aiData.bAimTime >= (gGameExternalOptions.fEnhancedCloseCombatSystem ? gSkillTraitValues.ubModifierForAPsAddedOnAimedBladedAttackes : 6) )
{ {
iBonus += gSkillTraitValues.usMEAimedMeleeAttackDamageBonus; // incresed damage if focused melee attack iBonus += gSkillTraitValues.usMEAimedMeleeAttackDamageBonus; // incresed damage if focused melee attack
} }
} }
} }
} }
else // original code else // original code
{ {
if ( gGameExternalOptions.fEnhancedCloseCombatSystem && (pSoldier->usAnimState == NINJA_SPINKICK || pSoldier->usAnimState == FOCUSED_PUNCH || pSoldier->usAnimState == FOCUSED_HTH_KICK )) if ( !autoresolve && gGameExternalOptions.fEnhancedCloseCombatSystem && (pSoldier->usAnimState == NINJA_SPINKICK || pSoldier->usAnimState == FOCUSED_PUNCH || pSoldier->usAnimState == FOCUSED_HTH_KICK ))
{ {
iBonus += 50; iBonus += 50;
} }
// add bonuses for hand-to-hand and martial arts // add bonuses for hand-to-hand and martial arts
if ( HAS_SKILL_TRAIT( pSoldier, MARTIALARTS_OT ) ) if ( HAS_SKILL_TRAIT( pSoldier, MARTIALARTS_OT ) )
{ {
iBonus += gbSkillTraitBonus[MARTIALARTS_OT] * NUM_SKILL_TRAITS( pSoldier, MARTIALARTS_OT ); iBonus += gbSkillTraitBonus[MARTIALARTS_OT] * NUM_SKILL_TRAITS( pSoldier, MARTIALARTS_OT );
if (pSoldier->usAnimState == NINJA_SPINKICK)
if ( !autoresolve && pSoldier->usAnimState == NINJA_SPINKICK)
{ {
iBonus += 100; iBonus += 100;
} }
} }
if ( HAS_SKILL_TRAIT( pSoldier, HANDTOHAND_OT ) ) if ( HAS_SKILL_TRAIT( pSoldier, HANDTOHAND_OT ) )
{ {
// SPECIAL - give TRIPLE bonus for damage for hand-to-hand trait // SPECIAL - give TRIPLE bonus for damage for hand-to-hand trait
@@ -9227,7 +9234,7 @@ INT32 HTHImpact( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pTarget, INT32 iHitBy, BO
} }
// Enhanced Close Combat System - aiming at body parts makes difference // Enhanced Close Combat System - aiming at body parts makes difference
if (gGameExternalOptions.fEnhancedCloseCombatSystem) if ( !autoresolve && gGameExternalOptions.fEnhancedCloseCombatSystem)
{ {
if ( pSoldier->bAimShotLocation == AIM_SHOT_HEAD ) if ( pSoldier->bAimShotLocation == AIM_SHOT_HEAD )
{ {
@@ -9251,22 +9258,6 @@ INT32 HTHImpact( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pTarget, INT32 iHitBy, BO
iBonus += 50; // 50% incresed damage on suprising attacks iBonus += 50; // 50% incresed damage on suprising attacks
} }
} }
// Flugente: power armour reduces damage taken
// SANDRO - huh?!
/*INT8 iSlot = VESTPOS;
switch( pSoldier->bAimShotLocation )
{
case AIM_SHOT_HEAD:
iSlot = HELMETPOS;
break;
case AIM_SHOT_LEGS:
iSlot = LEGPOS;
break;
default:
iSlot = VESTPOS;
break;
}*/
} }
// DAMAGE BONUS TO KNIFE ATTACK WITH MELEE SKILL // DAMAGE BONUS TO KNIFE ATTACK WITH MELEE SKILL
else else
@@ -9277,42 +9268,27 @@ INT32 HTHImpact( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pTarget, INT32 iHitBy, BO
iBonus += gSkillTraitValues.ubMEDamageBonusBlades; // +30% damage iBonus += gSkillTraitValues.ubMEDamageBonusBlades; // +30% damage
// if this attack happens directly after running, the attack is slightly more powerful due to extra force // if this attack happens directly after running, the attack is slightly more powerful due to extra force
if (pSoldier->usSoldierFlagMask2 & SOLDIER_BAYONET_RUNBONUS) if ( !autoresolve && pSoldier->usSoldierFlagMask2 & SOLDIER_BAYONET_RUNBONUS)
iBonus += 20; iBonus += 20;
} }
else if ( HAS_SKILL_TRAIT( pSoldier, MELEE_NT ) && ( gGameOptions.fNewTraitSystem )) else if ( HAS_SKILL_TRAIT( pSoldier, MELEE_NT ) && ( gGameOptions.fNewTraitSystem ))
{ {
iBonus += gSkillTraitValues.ubMEDamageBonusBlades; // +30% damage iBonus += gSkillTraitValues.ubMEDamageBonusBlades; // +30% damage
if (pSoldier->usAnimState == FOCUSED_STAB) if ( !autoresolve && pSoldier->usAnimState == FOCUSED_STAB)
{ {
iBonus += gSkillTraitValues.usMEAimedMeleeAttackDamageBonus; // 50% increased damage if focused melee attack iBonus += gSkillTraitValues.usMEAimedMeleeAttackDamageBonus; // 50% increased damage if focused melee attack
} }
} }
// Enhanced Close Combat System // Enhanced Close Combat System
if (gGameExternalOptions.fEnhancedCloseCombatSystem) if ( !autoresolve && gGameExternalOptions.fEnhancedCloseCombatSystem)
{ {
if (gAnimControl[ pTarget->usAnimState ].ubEndHeight == ANIM_PRONE) if (gAnimControl[ pTarget->usAnimState ].ubEndHeight == ANIM_PRONE)
{ {
iBonus += 30; // incresed damage to lying characters iBonus += 30; // incresed damage to lying characters
} }
} }
// Flugente: power armour reduces damage taken
// SANDRO - huh?!
/*INT8 iSlot = VESTPOS;
switch( pSoldier->bAimShotLocation )
{
case AIM_SHOT_HEAD:
iSlot = HELMETPOS;
break;
case AIM_SHOT_LEGS:
iSlot = LEGPOS;
break;
default:
iSlot = VESTPOS;
break;
}*/
} }
// remove flag, regardless of whether it was used // remove flag, regardless of whether it was used
@@ -9326,7 +9302,7 @@ INT32 HTHImpact( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pTarget, INT32 iHitBy, BO
// Flugente: if we are using a garotte, there is a chance that we score an instakill // Flugente: if we are using a garotte, there is a chance that we score an instakill
// our level in covert ops and wether the target is aware of us has a huge impact // our level in covert ops and wether the target is aware of us has a huge impact
if ( pObj && HasItemFlag(pObj->usItem, GAROTTE) ) if ( !autoresolve && pObj && HasItemFlag(pObj->usItem, GAROTTE) )
{ {
INT32 instakillchance = 0; INT32 instakillchance = 0;
INT32 resistchance = 20; INT32 resistchance = 20;
@@ -9356,7 +9332,6 @@ INT32 HTHImpact( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pTarget, INT32 iHitBy, BO
iImpact = (iImpact * (100 + iBonus) + 50) / 100; // round it properly iImpact = (iImpact * (100 + iBonus) + 50) / 100; // round it properly
// Flugente: moved the damage calculation into a separate function // Flugente: moved the damage calculation into a separate function
BOOLEAN autoresolve = IsAutoResolveActive();
iImpact = max( 1, (INT32)(iImpact * (100 - pTarget->GetDamageResistance(autoresolve, FALSE)) / 100 ) ); iImpact = max( 1, (INT32)(iImpact * (100 - pTarget->GetDamageResistance(autoresolve, FALSE)) / 100 ) );
// Flugente: if the target is a zombie, any melee attack, regardless of hit location, will set the headshot flag. Thus any zombie killed in melee will stay dead (if you play with that option) // Flugente: if the target is a zombie, any melee attack, regardless of hit location, will set the headshot flag. Thus any zombie killed in melee will stay dead (if you play with that option)
@@ -10068,7 +10043,7 @@ UINT32 CalcChanceHTH( SOLDIERTYPE * pAttacker,SOLDIERTYPE *pDefender, INT16 ubAi
else if (pAttacker->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA && gGameExternalOptions.sVeteranMilitiaCtHBonusPercent != 0) else if (pAttacker->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA && gGameExternalOptions.sVeteranMilitiaCtHBonusPercent != 0)
iChance += ((iChance * gGameExternalOptions.sVeteranMilitiaCtHBonusPercent) /100); iChance += ((iChance * gGameExternalOptions.sVeteranMilitiaCtHBonusPercent) /100);
// bonus for enemy // bonus for enemy
else if (pAttacker->ubSoldierClass == SOLDIER_CLASS_ADMINISTRATOR && gGameExternalOptions.sEnemyAdminCtHBonusPercent != 0) else if ( ( pAttacker->ubSoldierClass == SOLDIER_CLASS_ADMINISTRATOR || pAttacker->ubSoldierClass == SOLDIER_CLASS_BANDIT ) && gGameExternalOptions.sEnemyAdminCtHBonusPercent != 0)
iChance += ((iChance * gGameExternalOptions.sEnemyAdminCtHBonusPercent) /100); iChance += ((iChance * gGameExternalOptions.sEnemyAdminCtHBonusPercent) /100);
else if (pAttacker->ubSoldierClass == SOLDIER_CLASS_ARMY && gGameExternalOptions.sEnemyRegularCtHBonusPercent != 0) else if (pAttacker->ubSoldierClass == SOLDIER_CLASS_ARMY && gGameExternalOptions.sEnemyRegularCtHBonusPercent != 0)
iChance += ((iChance * gGameExternalOptions.sEnemyRegularCtHBonusPercent) /100); iChance += ((iChance * gGameExternalOptions.sEnemyRegularCtHBonusPercent) /100);
@@ -10746,7 +10721,7 @@ UINT32 CalcThrownChanceToHit(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTi
else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA && gGameExternalOptions.sVeteranMilitiaCtHBonusPercent != 0) else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA && gGameExternalOptions.sVeteranMilitiaCtHBonusPercent != 0)
iChance += ((iChance * gGameExternalOptions.sVeteranMilitiaCtHBonusPercent) /100); iChance += ((iChance * gGameExternalOptions.sVeteranMilitiaCtHBonusPercent) /100);
// bonus for enemy // bonus for enemy
else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ADMINISTRATOR && gGameExternalOptions.sEnemyAdminCtHBonusPercent != 0) else if ( ( pSoldier->ubSoldierClass == SOLDIER_CLASS_ADMINISTRATOR || pSoldier->ubSoldierClass == SOLDIER_CLASS_BANDIT ) && gGameExternalOptions.sEnemyAdminCtHBonusPercent != 0)
iChance += ((iChance * gGameExternalOptions.sEnemyAdminCtHBonusPercent) /100); iChance += ((iChance * gGameExternalOptions.sEnemyAdminCtHBonusPercent) /100);
else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ARMY && gGameExternalOptions.sEnemyRegularCtHBonusPercent != 0) else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ARMY && gGameExternalOptions.sEnemyRegularCtHBonusPercent != 0)
iChance += ((iChance * gGameExternalOptions.sEnemyRegularCtHBonusPercent) /100); iChance += ((iChance * gGameExternalOptions.sEnemyRegularCtHBonusPercent) /100);
@@ -11801,7 +11776,7 @@ FLOAT CalcNewChanceToHitBaseSpecialBonus(SOLDIERTYPE *pSoldier)
else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA && gGameExternalOptions.sVeteranMilitiaCtHBonusPercent != 0) else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA && gGameExternalOptions.sVeteranMilitiaCtHBonusPercent != 0)
fBaseModifier += gGameExternalOptions.sVeteranMilitiaCtHBonusPercent; fBaseModifier += gGameExternalOptions.sVeteranMilitiaCtHBonusPercent;
// bonus for enemy // bonus for enemy
else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ADMINISTRATOR && gGameExternalOptions.sEnemyAdminCtHBonusPercent != 0) else if ( ( pSoldier->ubSoldierClass == SOLDIER_CLASS_ADMINISTRATOR || pSoldier->ubSoldierClass == SOLDIER_CLASS_BANDIT ) && gGameExternalOptions.sEnemyAdminCtHBonusPercent != 0)
fBaseModifier += gGameExternalOptions.sEnemyAdminCtHBonusPercent; fBaseModifier += gGameExternalOptions.sEnemyAdminCtHBonusPercent;
else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ARMY && gGameExternalOptions.sEnemyRegularCtHBonusPercent != 0) else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ARMY && gGameExternalOptions.sEnemyRegularCtHBonusPercent != 0)
fBaseModifier += gGameExternalOptions.sEnemyRegularCtHBonusPercent; fBaseModifier += gGameExternalOptions.sEnemyRegularCtHBonusPercent;
+15 -14
View File
@@ -4870,18 +4870,19 @@ void DebugSoldierPage4( )
switch( pSoldier->ubSoldierClass ) switch( pSoldier->ubSoldierClass )
{ {
case SOLDIER_CLASS_ADMINISTRATOR: gprintf( 320, LINE_HEIGHT * ubLine, L"(Administrator)" ); break; case SOLDIER_CLASS_ADMINISTRATOR: gprintf( 320, LINE_HEIGHT * ubLine, L"(Administrator)" ); break;
case SOLDIER_CLASS_ELITE: gprintf( 320, LINE_HEIGHT * ubLine, L"(Army Elite)" ); break; case SOLDIER_CLASS_ELITE: gprintf( 320, LINE_HEIGHT * ubLine, L"(Army Elite)" ); break;
case SOLDIER_CLASS_ARMY: gprintf( 320, LINE_HEIGHT * ubLine, L"(Army Troop)" ); break; case SOLDIER_CLASS_ARMY: gprintf( 320, LINE_HEIGHT * ubLine, L"(Army Troop)" ); break;
case SOLDIER_CLASS_CREATURE: gprintf( 320, LINE_HEIGHT * ubLine, L"(Creature)" ); break; case SOLDIER_CLASS_CREATURE: gprintf( 320, LINE_HEIGHT * ubLine, L"(Creature)" ); break;
case SOLDIER_CLASS_GREEN_MILITIA: gprintf( 320, LINE_HEIGHT * ubLine, L"(Green Militia)" ); break; case SOLDIER_CLASS_GREEN_MILITIA: gprintf( 320, LINE_HEIGHT * ubLine, L"(Green Militia)" ); break;
case SOLDIER_CLASS_REG_MILITIA: gprintf( 320, LINE_HEIGHT * ubLine, L"(Reg Militia)" ); break; case SOLDIER_CLASS_REG_MILITIA: gprintf( 320, LINE_HEIGHT * ubLine, L"(Reg Militia)" ); break;
case SOLDIER_CLASS_ELITE_MILITIA: gprintf( 320, LINE_HEIGHT * ubLine, L"(Elite Militia)" ); break; case SOLDIER_CLASS_ELITE_MILITIA: gprintf( 320, LINE_HEIGHT * ubLine, L"(Elite Militia)" ); break;
case SOLDIER_CLASS_MINER: gprintf( 320, LINE_HEIGHT * ubLine, L"(Miner)" ); break; case SOLDIER_CLASS_MINER: gprintf( 320, LINE_HEIGHT * ubLine, L"(Miner)" ); break;
case SOLDIER_CLASS_ZOMBIE: gprintf( 320, LINE_HEIGHT * ubLine, L"(Zombie)" ); break; case SOLDIER_CLASS_ZOMBIE: gprintf( 320, LINE_HEIGHT * ubLine, L"(Zombie)" ); break;
case SOLDIER_CLASS_BANDIT: gprintf( 320, LINE_HEIGHT * ubLine, L"(Bandit)" ); break;
default: break; //don't care (don't write anything) default: break; //don't care (don't write anything)
} }
ubLine++; ++ubLine;
if( pSoldier->bTeam != OUR_TEAM ) if( pSoldier->bTeam != OUR_TEAM )
{ {
@@ -7785,19 +7786,19 @@ void MakeBloodcatsHostile( void )
iLoop = gTacticalStatus.Team[ CREATURE_TEAM ].bFirstID; iLoop = gTacticalStatus.Team[ CREATURE_TEAM ].bFirstID;
for (pSoldier = MercPtrs[iLoop]; iLoop <= gTacticalStatus.Team[ CREATURE_TEAM ].bLastID; iLoop++,pSoldier++ ) for (pSoldier = MercPtrs[iLoop]; iLoop <= gTacticalStatus.Team[ CREATURE_TEAM ].bLastID; ++iLoop, ++pSoldier )
{ {
if ( pSoldier->ubBodyType == BLOODCAT && pSoldier->bActive && pSoldier->bInSector && pSoldier->stats.bLife > 0 ) if ( pSoldier->ubBodyType == BLOODCAT && pSoldier->bActive && pSoldier->bInSector && pSoldier->stats.bLife > 0 )
{ {
SetSoldierNonNeutral( pSoldier ); SetSoldierNonNeutral( pSoldier );
RecalculateOppCntsDueToNoLongerNeutral( pSoldier ); RecalculateOppCntsDueToNoLongerNeutral( pSoldier );
if ( ( gTacticalStatus.uiFlags & INCOMBAT ) )
{ if ( ( gTacticalStatus.uiFlags & INCOMBAT ) )
CheckForPotentialAddToBattleIncrement( pSoldier ); {
} CheckForPotentialAddToBattleIncrement( pSoldier );
}
} }
} }
} }
BOOLEAN SoldierHasLimitedVision(SOLDIERTYPE * pSoldier) BOOLEAN SoldierHasLimitedVision(SOLDIERTYPE * pSoldier)
+7 -7
View File
@@ -2293,12 +2293,11 @@ INT8 CalcMorale(SOLDIERTYPE *pSoldier)
case AGGRESSIVE: bMoraleCategory++; break; case AGGRESSIVE: bMoraleCategory++; break;
} }
// make idiot administrators much more aggressive // make idiot administrators much more aggressive
if ( pSoldier->ubSoldierClass == SOLDIER_CLASS_ADMINISTRATOR ) if ( pSoldier->ubSoldierClass == SOLDIER_CLASS_ADMINISTRATOR || pSoldier->ubSoldierClass == SOLDIER_CLASS_BANDIT )
{ {
bMoraleCategory += 2; bMoraleCategory += 2;
} }
// if still full of energy // if still full of energy
if (pSoldier->bBreath > 75) if (pSoldier->bBreath > 75)
@@ -2737,6 +2736,7 @@ UINT8 SoldierDifficultyLevel( SOLDIERTYPE * pSoldier )
switch( pSoldier->ubSoldierClass ) switch( pSoldier->ubSoldierClass )
{ {
case SOLDIER_CLASS_ADMINISTRATOR: case SOLDIER_CLASS_ADMINISTRATOR:
case SOLDIER_CLASS_BANDIT:
bDifficulty = bDifficultyBase - 1; bDifficulty = bDifficultyBase - 1;
break; break;
@@ -3543,7 +3543,7 @@ INT8 CalcMoraleNew(SOLDIERTYPE *pSoldier)
} }
// make idiot administrators more aggressive // make idiot administrators more aggressive
if ( pSoldier->ubSoldierClass == SOLDIER_CLASS_ADMINISTRATOR ) if ( pSoldier->ubSoldierClass == SOLDIER_CLASS_ADMINISTRATOR || pSoldier->ubSoldierClass == SOLDIER_CLASS_BANDIT )
{ {
bMoraleCategory += 2; bMoraleCategory += 2;
} }
+1 -1
View File
@@ -1409,7 +1409,7 @@ INT8 DecideActionGreen(SOLDIERTYPE *pSoldier)
iChance = 25; iChance = 25;
if ( pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA || pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE ) if ( pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA || pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE )
iChance += 15; iChance += 15;
else if ( pSoldier->ubSoldierClass == SOLDIER_CLASS_GREEN_MILITIA || pSoldier->ubSoldierClass == SOLDIER_CLASS_ADMINISTRATOR ) else if ( pSoldier->ubSoldierClass == SOLDIER_CLASS_GREEN_MILITIA || pSoldier->ubSoldierClass == SOLDIER_CLASS_ADMINISTRATOR || pSoldier->ubSoldierClass == SOLDIER_CLASS_BANDIT )
iChance -= 15; iChance -= 15;
if ( Random(100) < iChance ) if ( Random(100) < iChance )
{ {
+9
View File
@@ -1887,6 +1887,15 @@ enum
STR_BREATH_REGEN_SLEEP, STR_BREATH_REGEN_SLEEP,
STR_PB_ZOMBIES,
STR_PB_BANDITS,
STR_PB_BLOODCATRAID_HEADER,
STR_PB_ZOMBIERAID_HEADER,
STR_PB_BANDITRAID_HEADER,
STR_PB_ZOMBIE,
STR_PB_BANDIT,
STR_PB_BANDIT_KILLCIVS_IN_SECTOR,
TEXT_NUM_STRATEGIC_TEXT TEXT_NUM_STRATEGIC_TEXT
}; };
+9
View File
@@ -3514,6 +3514,15 @@ STR16 gpStrategicString[] =
L"吉普", // L"Jeep", STR_AR_JEEP_NAME L"吉普", // L"Jeep", STR_AR_JEEP_NAME
L"\n睡觉时每小时恢复精力: %d", //L"\nBreath regeneration per hour: %d", // STR_BREATH_REGEN_SLEEP L"\n睡觉时每小时恢复精力: %d", //L"\nBreath regeneration per hour: %d", // STR_BREATH_REGEN_SLEEP
L"Zombies", // TODO.Translate
L"Bandits",
L"BLOODCAT ATTACK",
L"ZOMBIE ATTACK",
L"BANDIT ATTACK",
L"Zombie",
L"Bandit",
L"Bandits attack and kill %d civilians in sector %s.",
}; };
STR16 gpGameClockString[] = STR16 gpGameClockString[] =
+9
View File
@@ -3514,6 +3514,15 @@ STR16 gpStrategicString[] =
L"Jeep", //STR_AR_JEEP_NAME // TODO.Translate L"Jeep", //STR_AR_JEEP_NAME // TODO.Translate
L"\nBreath regeneration per hour: %d", // STR_BREATH_REGEN_SLEEP L"\nBreath regeneration per hour: %d", // STR_BREATH_REGEN_SLEEP
L"Zombies", // TODO.Translate
L"Bandits",
L"BLOODCAT ATTACK",
L"ZOMBIE ATTACK",
L"BANDIT ATTACK",
L"Zombie",
L"Bandit",
L"Bandits attack and kill %d civilians in sector %s.",
}; };
STR16 gpGameClockString[] = STR16 gpGameClockString[] =
+9
View File
@@ -3514,6 +3514,15 @@ STR16 gpStrategicString[] =
L"Jeep", //STR_AR_JEEP_NAME, L"Jeep", //STR_AR_JEEP_NAME,
L"\nBreath regeneration per hour: %d", // STR_BREATH_REGEN_SLEEP L"\nBreath regeneration per hour: %d", // STR_BREATH_REGEN_SLEEP
L"Zombies",
L"Bandits",
L"BLOODCAT ATTACK",
L"ZOMBIE ATTACK",
L"BANDIT ATTACK",
L"Zombie",
L"Bandit",
L"Bandits attack and kill %d civilians in sector %s.",
}; };
STR16 gpGameClockString[] = STR16 gpGameClockString[] =
+9
View File
@@ -3522,6 +3522,15 @@ STR16 gpStrategicString[] =
L"Jeep", //STR_AR_JEEP_NAME // TODO.Translate L"Jeep", //STR_AR_JEEP_NAME // TODO.Translate
L"\nBreath regeneration per hour: %d", // STR_BREATH_REGEN_SLEEP L"\nBreath regeneration per hour: %d", // STR_BREATH_REGEN_SLEEP
L"Zombies", // TODO.Translate
L"Bandits",
L"BLOODCAT ATTACK",
L"ZOMBIE ATTACK",
L"BANDIT ATTACK",
L"Zombie",
L"Bandit",
L"Bandits attack and kill %d civilians in sector %s.",
}; };
STR16 gpGameClockString[] = STR16 gpGameClockString[] =
+9
View File
@@ -3525,6 +3525,15 @@ STR16 gpStrategicString[] =
L"Jeep", //STR_AR_JEEP_NAME // TODO.Translate L"Jeep", //STR_AR_JEEP_NAME // TODO.Translate
L"\nBreath regeneration per hour: %d", // STR_BREATH_REGEN_SLEEP L"\nBreath regeneration per hour: %d", // STR_BREATH_REGEN_SLEEP
L"Zombies", // TODO.Translate
L"Bandits",
L"BLOODCAT ATTACK",
L"ZOMBIE ATTACK",
L"BANDIT ATTACK",
L"Zombie",
L"Bandit",
L"Bandits attack and kill %d civilians in sector %s.",
}; };
STR16 gpGameClockString[] = STR16 gpGameClockString[] =
+9
View File
@@ -3509,6 +3509,15 @@ STR16 gpStrategicString[] =
L"Jeep", //STR_AR_JEEP_NAME // TODO.Translate L"Jeep", //STR_AR_JEEP_NAME // TODO.Translate
L"\nBreath regeneration per hour: %d", // STR_BREATH_REGEN_SLEEP L"\nBreath regeneration per hour: %d", // STR_BREATH_REGEN_SLEEP
L"Zombies", // TODO.Translate
L"Bandits",
L"BLOODCAT ATTACK",
L"ZOMBIE ATTACK",
L"BANDIT ATTACK",
L"Zombie",
L"Bandit",
L"Bandits attack and kill %d civilians in sector %s.",
}; };
STR16 gpGameClockString[] = STR16 gpGameClockString[] =
+9
View File
@@ -3520,6 +3520,15 @@ STR16 gpStrategicString[] =
L"Jeep", //STR_AR_JEEP_NAME // TODO.Translate L"Jeep", //STR_AR_JEEP_NAME // TODO.Translate
L"\nBreath regeneration per hour: %d", // STR_BREATH_REGEN_SLEEP L"\nBreath regeneration per hour: %d", // STR_BREATH_REGEN_SLEEP
L"Zombies", // TODO.Translate
L"Bandits",
L"BLOODCAT ATTACK",
L"ZOMBIE ATTACK",
L"BANDIT ATTACK",
L"Zombie",
L"Bandit",
L"Bandits attack and kill %d civilians in sector %s.",
}; };
STR16 gpGameClockString[] = STR16 gpGameClockString[] =
+9
View File
@@ -3514,6 +3514,15 @@ STR16 gpStrategicString[] =
L"Джип", //STR_AR_JEEP_NAME L"Джип", //STR_AR_JEEP_NAME
L"\nВосстановление дыхания в час: %d", // STR_BREATH_REGEN_SLEEP L"\nВосстановление дыхания в час: %d", // STR_BREATH_REGEN_SLEEP
L"Zombies", // TODO.Translate
L"Bandits",
L"BLOODCAT ATTACK",
L"ZOMBIE ATTACK",
L"BANDIT ATTACK",
L"Zombie",
L"Bandit",
L"Bandits attack and kill %d civilians in sector %s.",
}; };
STR16 gpGameClockString[] = STR16 gpGameClockString[] =