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.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 );
// 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 ##################
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 gEnemyHeliMANPADSDamage_Base;
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;
+9 -9
View File
@@ -15,9 +15,9 @@
#ifdef JA2EDITOR
#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
CHAR16 zVersionLabel[256] = { L"Map Editor v1.13.8548 (Development Build)" };
CHAR16 zVersionLabel[256] = { L"Map Editor v1.13.8554 (Development Build)" };
#endif
// ------------------------------
@@ -27,11 +27,11 @@
//DEBUG BUILD VERSION
#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)
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
CHAR16 zVersionLabel[256] = { L"Debug: v1.13.8548 (Development Build)" };
CHAR16 zVersionLabel[256] = { L"Debug: v1.13.8554 (Development Build)" };
#endif
#elif defined CRIPPLED_VERSION
@@ -46,16 +46,16 @@
//RELEASE BUILD VERSION
#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)
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
CHAR16 zVersionLabel[256] = { L"Release v1.13.8548 (Development Build)" };
CHAR16 zVersionLabel[256] = { L"Release v1.13.8554 (Development Build)" };
#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" };
// 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
// 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 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
@@ -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 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
#ifdef __cplusplus
+2
View File
@@ -168,6 +168,8 @@ Incident_Stats::AddStat( SOLDIERTYPE* pSoldier, UINT8 aType )
case CREATURE_TEAM:
if ( pSoldier->IsZombie() )
group = CAMPAIGNHISTORY_SD_ZOMBIE;
else if ( pSoldier->ubSoldierClass == SOLDIER_CLASS_BANDIT )
group = CAMPAIGNHISTORY_SD_ENEMY_ADMIN;
else
group = CAMPAIGNHISTORY_SD_CREATURE;
break;
+6 -1
View File
@@ -181,7 +181,12 @@ typedef struct
UINT32 usMapIntelFlags;
INT16 sIntelInfoForThisHour[INTELINFO_MAXNUMBER];
UINT8 bPadding[ 48 ];
// Flugente: raid
INT32 sRaidBloodcats;
INT32 sRaidZombies;
INT32 sRaidBandits;
UINT8 bPadding[ 36 ];
} LaptopSaveInfoStruct;
+6
View File
@@ -6568,6 +6568,12 @@ BOOLEAN LoadSavedGame( int ubSavedGameID )
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;
uiRelEndPerc = 100;
+275 -112
View File
@@ -170,6 +170,9 @@ typedef struct AUTORESOLVE_STRUCT
UINT8 ubMercs, ubCivs, ubEnemies;
UINT8 ubAdmins, ubTroops, ubElites, ubTanks, ubJeeps;
UINT8 ubYMCreatures, ubYFCreatures, ubAMCreatures, ubAFCreatures;
UINT8 ubBloodcats;
UINT8 ubZombies;
UINT8 ubBandits;
UINT8 ubAliveMercs, ubAliveCivs, ubAliveEnemies;
UINT8 ubMercCols, ubMercRows;
UINT8 ubEnemyCols, ubEnemyRows;
@@ -230,14 +233,18 @@ typedef struct AUTORESOLVE_STRUCT
#define CELL_ROBOT 0x00200000
#define CELL_TANK 0x00400000
#define CELL_JEEP 0x00800000
#define CELL_BLOODCAT 0x01000000
#define CELL_ZOMBIE 0x02000000
#define CELL_BANDIT 0x04000000
//Combined flags
#define CELL_PLAYER ( CELL_MERC | CELL_MILITIA )
#define CELL_ENEMY ( CELL_ELITE | CELL_TROOP | CELL_ADMIN | CELL_TANK | CELL_JEEP )
#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_MALECREATURE ( CELL_AM_CREATURE | CELL_YM_CREATURE )
#define CELL_YOUNGCREATURE ( CELL_YF_CREATURE | CELL_YM_CREATURE )
#define CELL_ENEMY ( CELL_ELITE | CELL_TROOP | CELL_ADMIN | CELL_TANK | CELL_JEEP | CELL_BANDIT )
#define CELL_FEMALECREATURE ( CELL_AF_CREATURE | CELL_YF_CREATURE )
#define CELL_MALECREATURE ( CELL_AM_CREATURE | CELL_YM_CREATURE )
#define CELL_BUG ( CELL_FEMALECREATURE | CELL_MALECREATURE )
#define CELL_CREATURE ( CELL_BUG | CELL_BLOODCAT | CELL_ZOMBIE )
#define CELL_INVOLVEDINCOMBAT ( CELL_FIREDATTARGET | CELL_DODGEDATTACK | CELL_HITBYATTACKER )
enum
@@ -303,7 +310,6 @@ void CalculateSoldierCells( BOOLEAN fReset );
void CalculateRowsAndColumns();
void CreateAutoResolveInterface();
void RemoveAutoResolveInterface( BOOLEAN fDeleteForGood );
INT32 CalcIndexFromColRowsXY( INT32 iMaxCols, INT32 iMaxRows, INT32 iCol, INT32 iRow );
//Battle system routines
void DetermineTeamLeader( BOOLEAN fFriendlyTeam );
@@ -484,7 +490,7 @@ void EliminateAllEnemies( UINT8 ubSectorX, UINT8 ubSectorY )
if( gpAR )
{
for( i = 0; i < gpAR->ubEnemies; i++ )
for( i = 0; i < gpAR->ubEnemies; ++i )
{
gpEnemies[ i ].pSoldier->stats.bLife = 0;
}
@@ -626,6 +632,9 @@ DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"Autoresolve1");
gpAR->ubPlayerDefenceAdvantage = 0;
break;
case CREATURE_ATTACK_CODE:
case BLOODCAT_ATTACK_CODE:
case ZOMBIE_ATTACK_CODE:
case BANDIT_ATTACK_CODE:
gpAR->ubPlayerDefenceAdvantage = 0;
break;
default:
@@ -746,7 +755,10 @@ void AssociateEnemiesWithStrategicGroups()
UINT8 ubDirAmount;
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;
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)
//iMaxTeamSize = max( gpAR->ubMercs + gpAR->ubCivs, gpAR->ubEnemies );
iMaxTeamSize = max( min( 40, gpAR->ubMercs + gpAR->ubCivs ), min( 40, gpAR->ubEnemies ) );
if( iMaxTeamSize > 12 )
{
gpAR->ubTimeModifierPercentage = (UINT8)(118 - iMaxTeamSize*1.5);
@@ -1017,6 +1028,7 @@ void CalculateSoldierCells( BOOLEAN fReset )
{
gpAR->ubTimeModifierPercentage = 100;
}
gpAR->uiTimeSlice = gpAR->uiTimeSlice * gpAR->ubTimeModifierPercentage / 100;
iTop = iScreenHeightOffset + (240 - gpAR->sHeight/2);
@@ -1064,6 +1076,7 @@ void CalculateSoldierCells( BOOLEAN fReset )
gpAR->ubAliveMercs--;
}
}
if( gpAR->ubCivs )
{
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;
}
}
if( gpAR->ubEnemies )
{
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 ].yp = iStartY + y*47;
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 ( GetEnemyEncounterCode() == CREATURE_ATTACK_CODE )
{
if( index < gpAR->ubAFCreatures )
gpEnemies[ index ].uiFlags = CELL_AF_CREATURE;
@@ -1120,6 +1121,30 @@ void CalculateSoldierCells( BOOLEAN fReset )
else
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 )
{
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 );
else if ( (pCell->uiFlags & CELL_TANK) )
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;
case ENEMY_INVASION_CODE:
case CREATURE_ATTACK_CODE:
case BLOODCAT_ATTACK_CODE:
case ZOMBIE_ATTACK_CODE:
case BANDIT_ATTACK_CODE:
swprintf( str, gpStrategicString[STR_AR_DEFEND_HEADER] );
break;
default:
@@ -1802,8 +1832,14 @@ void RenderAutoResolve()
break;
case BATTLE_DEFEAT:
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 );
}
@@ -1828,8 +1864,13 @@ void RenderAutoResolve()
//Tack on 5 minutes for retreat.
gpAR->uiTotalElapsedBattleTimeInMilliseconds += 300000;
if( ProcessLoyalty() )HandleLoyaltyImplicationsOfMercRetreat( RETREAT_AUTORESOLVE, gpAR->ubSectorX, gpAR->ubSectorY, 0 );
if( GetEnemyEncounterCode() != CREATURE_ATTACK_CODE )
if( ProcessLoyalty() )
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 );
}
@@ -2133,7 +2174,7 @@ void CreateAutoResolveInterface()
// Add the militia in the surrounding sectors
// HEADROCK HAM 3.4: Changed argument configuration.
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 sY = SECTORY( pMoveDir[ i ][0] );
@@ -2144,13 +2185,98 @@ void CreateAutoResolveInterface()
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].uiVObjectID = gpAR->iFaces;
if( gpEnemies[i].pSoldier->ubBodyType == REGFEMALE )
if ( gpEnemies[index].pSoldier->ubBodyType == REGFEMALE )
{
gpEnemies[index].usIndex = ELITEF_FACE;
}
@@ -2160,39 +2286,39 @@ void CreateAutoResolveInterface()
}
gpEnemies[index].pSoldier->sSectorX = gpAR->ubSectorX;
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].uiVObjectID = gpAR->iFaces;
if ( gpEnemies[i].pSoldier->ubBodyType == REGFEMALE )
if ( gpEnemies[index].pSoldier->ubBodyType == REGFEMALE )
{
gpEnemies[index].usIndex = TROOPF_FACE;
}
else
{
gpEnemies[index].usIndex = TROOP_FACE;
gpEnemies[index].usIndex = TROOP_FACE;
}
gpEnemies[index].pSoldier->sSectorX = gpAR->ubSectorX;
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 )
{
gpEnemies[index].pSoldier = TacticalCreateAdministrator();
gpEnemies[index].uiVObjectID = gpAR->iFaces;
if ( gpEnemies[i].pSoldier->ubBodyType == REGFEMALE )
if ( gpEnemies[index].pSoldier->ubBodyType == REGFEMALE )
{
gpEnemies[index].usIndex = ADMINF_FACE;
}
else
{
gpEnemies[index].usIndex = ADMIN_FACE;
gpEnemies[index].usIndex = ADMIN_FACE;
}
gpEnemies[index].pSoldier->sSectorX = gpAR->ubSectorX;
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 )
@@ -2207,7 +2333,7 @@ void CreateAutoResolveInterface()
for ( i = 0; i < gpAR->ubJeeps; ++i, ++index )
{
gpEnemies[index].pSoldier = TacticalCreateEnemyJeep( );
gpEnemies[index].pSoldier = TacticalCreateEnemyJeep();
gpEnemies[index].uiVObjectID = gpAR->iFaces;
gpEnemies[index].usIndex = JEEP_FACE;
gpEnemies[index].pSoldier->sSectorX = gpAR->ubSectorX;
@@ -2217,45 +2343,6 @@ void CreateAutoResolveInterface()
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 )
{
@@ -2616,7 +2703,10 @@ DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"Autoresolve2");
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;
gubSectorIDOfCreatureAttack = 0;
@@ -2915,14 +3005,7 @@ void CalculateAutoResolveInfo()
Assert( gpAR->ubSectorX >= 1 && gpAR->ubSectorX <= 16 );
Assert( gpAR->ubSectorY >= 1 && gpAR->ubSectorY <= 16 );
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 ( GetEnemyEncounterCode() == CREATURE_ATTACK_CODE )
{
if( gfTransferTacticalOppositionToAutoResolve )
{
@@ -2948,8 +3031,35 @@ void CalculateAutoResolveInfo()
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;
// gpAR->ubCivs = CountAllMilitiaInSector( gpAR->ubSectorX, gpAR->ubSectorY );
gpAR->ubCivs = CountAllMilitiaInFiveSectors( gpAR->ubSectorX, gpAR->ubSectorY );
gpAR->ubMercs = 0;
VObjectDesc.fCreateFlags = VOBJECT_CREATE_FROMFILE;
@@ -3693,6 +3803,7 @@ FLOAT CalcClassBonusOrPenalty( SOLDIERTYPE *pSoldier )
return 1.0f;
case SOLDIER_CLASS_ADMINISTRATOR:
case SOLDIER_CLASS_GREEN_MILITIA:
case SOLDIER_CLASS_BANDIT:
return 0.7f;
}
@@ -3821,7 +3932,8 @@ void CalculateAttackValues()
gpAR->usPlayerDefence += pCell->usDefence;
ResetNextAttackCounter( pCell );
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 );
}
@@ -3832,10 +3944,10 @@ void CalculateAttackValues()
pCell->usNextAttack += REINFORCMENT_ATTACK_DELAY_PER_SOLDIER_IN_SECTOR * militiainsector;
}
if( pCell->usNextAttack < usBestAttack )
usBestAttack = pCell->usNextAttack;
}
//ENEMIES
gpAR->usEnemyAttack = 0;
gpAR->usEnemyDefence = 0;
@@ -3847,7 +3959,7 @@ void CalculateAttackValues()
// sOutnumberBonus = (INT16)min( sOutnumberBonus, max( sMaxBonus, 0 ) );
//}
for( i = 0; i < gpAR->ubEnemies; i++ )
for( i = 0; i < gpAR->ubEnemies; ++i )
{
pCell = &gpEnemies[ i ];
pSoldier = pCell->pSoldier;
@@ -3886,19 +3998,21 @@ void CalculateAttackValues()
ResetNextAttackCounter( pCell );
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 );
}
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 );
}
if( pCell->usNextAttack < usBestAttack )
usBestAttack = pCell->usNextAttack;
}
//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.
usBestAttack = usBestAttack * 60 / 100;
@@ -3964,9 +4078,11 @@ SOLDIERCELL* ChooseTarget( SOLDIERCELL *pAttacker )
INT32 iRandom = -1;
SOLDIERCELL *pTarget = NULL;
UINT32 usSavedDefence;
//Determine what team we are attacking
if( pAttacker->uiFlags & (CELL_ENEMY | CELL_CREATURE) )
{ //enemy team attacking a player
{
//enemy team attacking a player
iAvailableTargets = gpAR->ubMercs + gpAR->ubCivs;
index = 0;
usSavedDefence = gpAR->usPlayerDefence;
@@ -4302,11 +4418,13 @@ void AttackTarget( SOLDIERCELL *pAttacker, SOLDIERCELL *pTarget )
usDefence = max(0, min(1000, usDefence ));
///////////////////////////////////////////////////////////////////////////////////////////
if( pAttacker->uiFlags & CELL_FEMALECREATURE )
if( pAttacker->uiFlags & (CELL_FEMALECREATURE | CELL_BLOODCAT | CELL_ZOMBIE) )
{
pAttacker->bWeaponSlot = HANDPOS;
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...
else if ( FireTankCannon( pAttacker ) )
@@ -4383,13 +4501,27 @@ void AttackTarget( SOLDIERCELL *pAttacker, SOLDIERCELL *pTarget )
PlayAutoResolveSample( MISS_KNIFE, RATE_11025, 50, 1, MIDDLEPAN );
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
{
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
@@ -4657,6 +4789,14 @@ void AttackTarget( SOLDIERCELL *pAttacker, SOLDIERCELL *pTarget )
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
HandleDeathDiseaseImplications( pTarget->pSoldier );
@@ -4681,6 +4821,9 @@ void AttackTarget( SOLDIERCELL *pAttacker, SOLDIERCELL *pTarget )
case SOLDIER_CLASS_ZOMBIE :
gMercProfiles[ pAttacker->pSoldier->ubProfile ].records.usKillsZombies++;
break;
case SOLDIER_CLASS_BANDIT:
gMercProfiles[pAttacker->pSoldier->ubProfile].records.usKillsOthers++;
break;
default :
if ( CREATURE_OR_BLOODCAT( pTarget->pSoldier ) )
gMercProfiles[ pAttacker->pSoldier->ubProfile ].records.usKillsCreatures++;
@@ -4875,6 +5018,14 @@ void TargetHitCallback( SOLDIERCELL *pTarget, INT32 index )
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
HandleDeathDiseaseImplications( pTarget->pSoldier );
@@ -4915,6 +5066,9 @@ void TargetHitCallback( SOLDIERCELL *pTarget, INT32 index )
case SOLDIER_CLASS_ZOMBIE :
gMercProfiles[ pKiller->pSoldier->ubProfile ].records.usKillsZombies++;
break;
case SOLDIER_CLASS_BANDIT:
gMercProfiles[pKiller->pSoldier->ubProfile].records.usKillsOthers++;
break;
default :
if ( CREATURE_OR_BLOODCAT( pTarget->pSoldier ) )
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)HEADCR_1, RATE_11025, HIGHVOLUME, 1, MIDDLEPAN );
}
if( iNewLife < -60 && !(pTarget->uiFlags & CELL_CREATURE) )
if( iNewLife < -60 && !(pTarget->uiFlags & CELL_BUG ) )
{ //High damage death
if( gpAR->fSound )
{
@@ -5186,7 +5341,9 @@ BOOLEAN IsBattleOver()
{
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 );
}
@@ -5473,7 +5630,9 @@ void ProcessBattleFrame()
return;
}
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;
iRandom = PreRandom( iTotal );
@@ -5558,7 +5717,8 @@ void ProcessBattleFrame()
else
{
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( gpAR->pRobotCell->pSoldier->ubRobotRemoteHolderID == NOBODY )
@@ -5574,16 +5734,19 @@ void ProcessBattleFrame()
pAttacker->uiFlags |= CELL_RETREATED;
continue;
}
if( pAttacker->usAttack )
{
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 );
else
AttackTarget( pAttacker, pTarget );
ResetNextAttackCounter( pAttacker );
pAttacker->usNextAttack += (UINT32)iTime; //tack on the remainder
iAttacksThisFrame++;
++iAttacksThisFrame;
}
}
}
+5
View File
@@ -28,6 +28,11 @@ enum
MILITIA3F_FACE,
JEEP_FACE,
JEEP_WRECK,
ZOMBIE_FACE,
BANDIT1_FACE,
BANDIT1_F_FACE = BANDIT1_FACE + 4,
BLOODCAT_FACE = BANDIT1_F_FACE + 4,
BLOODCAT_SKULL,
AUTORESOLVEFACES_MAX
};
+469 -78
View File
@@ -32,6 +32,10 @@
#include "MessageBoxScreen.h"
#include "Map Information.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
#include "Strategic Mines.h"
@@ -148,11 +152,16 @@ UINT8 gubAdultFemalesAttackingTown = 0;
UINT8 gubCreatureBattleCode = CREATURE_BATTLE_CODE_NONE;
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* NewUndergroundNode( UINT8 ubSectorX, UINT8 ubSectorY, UINT8 ubSectorZ );
extern void BuildUndergroundSectorInfoList();
void DeleteCreatureDirectives();
extern SECTOR_EXT_DATA SectorExternalData[256][4];
//extern MINE_STATUS_TYPE gMineStatus[ MAX_NUMBER_OF_MINES ];
@@ -684,10 +693,10 @@ void AddCreaturesToBattle( UINT8 ubNumYoungMales, UINT8 ubNumYoungFemales, UINT8
switch( gsCreatureInsertionCode )
{
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_WEST: bDesiredDirection = NORTHEAST; break;
case INSERTION_CODE_GRIDNO: break;
case INSERTION_CODE_WEST: bDesiredDirection = NORTHEAST; break;
case INSERTION_CODE_GRIDNO: break;
default: AssertMsg( 0, "Illegal direction passed to AddCreaturesToBattle()" ); break;
}
@@ -772,6 +781,101 @@ void AddCreaturesToBattle( UINT8 ubNumYoungMales, UINT8 ubNumYoungFemales, UINT8
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 )
{
INT32 iRandom, i;
@@ -1061,6 +1165,7 @@ void CreatureAttackTown( UINT8 ubSectorID, BOOLEAN fOverrideTest )
return;
}
guCreatureAttackType = CREATURE_ATTACK_TYPE_CREATURE;
gubCreatureBattleCode = CREATURE_BATTLE_CODE_NONE;
ubSectorX = SECTORX( ubSectorID );
@@ -1098,22 +1203,18 @@ void CreatureAttackTown( UINT8 ubSectorID, BOOLEAN fOverrideTest )
//Now that the sector has been chosen, attack it!
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 )
{ //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.
if( guiCurrentScreen == GAME_SCREEN )
{
gubCreatureBattleCode = CREATURE_BATTLE_CODE_TACTICALLYADD;
}
else
{
gubCreatureBattleCode = CREATURE_BATTLE_CODE_PREBATTLEINTERFACE;
}
}
else
{
gubCreatureBattleCode = CREATURE_BATTLE_CODE_PREBATTLEINTERFACE;
}
}
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 )
{ //player controlled sector -- eat some civilians
AdjustLoyaltyForCivsEatenByMonsters( ubSectorX, ubSectorY, gubNumCreaturesAttackingTown );
AdjustLoyaltyForCivsEatenByMonsters( ubSectorX, ubSectorY, gubNumCreaturesAttackingTown, ( guCreatureAttackType == CREATURE_ATTACK_TYPE_BANDIT ) );
SectorInfo[ ubSectorID ].ubDayOfLastCreatureAttack = (UINT8)GetWorldDay();
return;
}
@@ -1157,6 +1258,223 @@ void CreatureAttackTown( UINT8 ubSectorID, BOOLEAN fOverrideTest )
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.
void ChooseCreatureQuestStartDay()
{
@@ -1376,15 +1694,13 @@ void DetermineCreatureTownComposition( UINT8 ubNumCreatures, UINT8 *pubNumYoungM
void DetermineCreatureTownCompositionBasedOnTacticalInformation( UINT8 *pubNumCreatures, UINT8 *pubNumYoungMales, UINT8 *pubNumYoungFemales,
UINT8 *pubNumAdultMales, UINT8 *pubNumAdultFemales )
{
SECTORINFO *pSector;
INT32 i;
SOLDIERTYPE *pSoldier;
pSector = &SectorInfo[ SECTOR( gWorldSectorX, gWorldSectorY ) ];
SECTORINFO* pSector = &SectorInfo[ SECTOR( gWorldSectorX, gWorldSectorY ) ];
*pubNumCreatures = 0;
pSector->ubNumCreatures = 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 ];
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()
{
@@ -1481,27 +1827,29 @@ BOOLEAN PrepareCreaturesForBattle()
{
return FALSE;
}
//gfUseCreatureMusic = TRUE; //creatures are here, so play creature music
ubCreatureHabitat = pSector->ubCreatureHabitat;
ubNumCreatures = pSector->ubNumCreatures;
}
else
{ //creatures are attacking a town sector
{
//creatures are attacking a town sector
//gfUseCreatureMusic = TRUE;
UseCreatureMusic(TRUE);
#ifdef NEWMUSIC
#ifdef NEWMUSIC
GlobalSoundID = MusicSoundValues[ SECTOR( gWorldSectorX, gWorldSectorY ) ].SoundTacticalNothing[gbWorldSectorZ];
if ( MusicSoundValues[ SECTOR( gWorldSectorX, gWorldSectorY ) ].SoundTacticalNothing[gbWorldSectorZ] != -1 )
SetMusicModeID( MUSIC_TACTICAL_NOTHING, MusicSoundValues[ SECTOR( gWorldSectorX, gWorldSectorY ) ].SoundTacticalNothing[gbWorldSectorZ] );
else
#endif
#endif
SetMusicMode( MUSIC_TACTICAL_NOTHING );
// externalize to xml data
//ubCreatureHabitat = MINE_EXIT;
//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 sY = gCreaturePlacements[ giLairID ].sAttackSourceY;
@@ -1515,6 +1863,7 @@ BOOLEAN PrepareCreaturesForBattle()
break;
}
}
ubNumCreatures = gubNumCreaturesAttackingTown;
}
@@ -1576,90 +1925,132 @@ BOOLEAN PrepareCreaturesForBattle()
}
*/
//out-of-range habitat
if( ubCreatureHabitat >= NUMBER_OF_CREATURE_COMPOSITIONS )
if ( guCreatureAttackType == CREATURE_ATTACK_TYPE_CREATURE )
{
AssertMsg( 0, String( "Invalid creature habitat ID of %d for PrepareCreaturesForBattle.", ubCreatureHabitat ) );
}
//queen sector
if( !ubCreatureHabitat )
fQueen = TRUE;
else
fQueen = FALSE;
//out-of-range habitat
if ( ubCreatureHabitat >= NUMBER_OF_CREATURE_COMPOSITIONS )
{
AssertMsg( 0, String( "Invalid creature habitat ID of %d for PrepareCreaturesForBattle.", ubCreatureHabitat ) );
}
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++;
//queen sector
if ( !ubCreatureHabitat )
fQueen = TRUE;
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 )
{
UNDERGROUND_SECTORINFO *pUndergroundSector;
pUndergroundSector = FindUnderGroundSector( gWorldSectorX, gWorldSectorY, gbWorldSectorZ );
UNDERGROUND_SECTORINFO *pUndergroundSector = FindUnderGroundSector( gWorldSectorX, gWorldSectorY, gbWorldSectorZ );
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" );
return FALSE;
}
pUndergroundSector->ubCreaturesInBattle = pUndergroundSector->ubNumCreatures;
}
else
{
SECTORINFO *pSector;
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 )
{
case CREATURE_BATTLE_CODE_NONE: //in the mines
AddSoldierInitListCreatures( fQueen, ubNumLarvae, ubNumInfants,
ubNumYoungMales, ubNumYoungFemales, ubNumAdultMales, ubNumAdultFemales );
switch ( guCreatureAttackType )
{
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;
case CREATURE_BATTLE_CODE_TACTICALLYADD: //creature attacking a town sector
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;
case CREATURE_BATTLE_CODE_AUTORESOLVE:
return FALSE;
}
return TRUE;
}
+11
View File
@@ -15,6 +15,7 @@ UINT8 CreaturesInUndergroundSector( UINT8 ubSectorID, UINT8 ubSectorZ );
BOOLEAN PrepareCreaturesForBattle();
void CreatureNightPlanning();
void CreatureAttackTown( UINT8 ubSectorID, BOOLEAN fOverrideTest );
void CreatureAttackTown_OtherCreatures( UINT8 ubSectorID, UINT8 ubType );
void CheckConditionsForTriggeringCreatureQuest( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ );
@@ -44,6 +45,14 @@ enum{
};
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,
UINT8 *pubNumYoungMales, UINT8 *pubNumYoungFemales,
UINT8 *pubNumAdultMales, UINT8 *pubNumAdultFemales );
@@ -52,6 +61,8 @@ void DetermineCreatureTownCompositionBasedOnTacticalInformation( UINT8 *pubNumCr
UINT8 *pubNumYoungMales, UINT8 *pubNumYoungFemales,
UINT8 *pubNumAdultMales, UINT8 *pubNumAdultFemales );
void DetermineOtherCreatureTownCompositionBasedOnTacticalInformation( UINT8* pubNumCreatures, UINT8* pubNumBloodcats, UINT8* pubNumZombies, UINT8* pubNumBandits );
BOOLEAN PlayerGroupIsInACreatureInfestedMine();
+16
View File
@@ -644,6 +644,22 @@ BOOLEAN ExecuteStrategicEvent( STRATEGICEVENT *pEvent )
case EVENT_INTEL_PHOTOFACT_VERIFY:
LuaVerifyPhotoState( (INT16)pEvent->uiParam );
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;
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_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 = 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
static int l_AdjustLoyaltyForCivsEatenByMonsters(lua_State *L)
{
UINT8 n = lua_gettop(L);
int i;
INT16 sSectorX;
INT16 sSectorY;
UINT8 ubHowMany;
for (i= 1; i<=n; i++ )
UINT8 n = lua_gettop(L);
if ( n >= 3 )
{
if (i == 1 ) sSectorX = lua_tointeger(L,i);
if (i == 2 ) sSectorY = lua_tointeger(L,i);
if (i == 3 ) ubHowMany = lua_tointeger(L,i);
INT16 sSectorX = lua_tointeger( L, 1 );
INT16 sSectorY = lua_tointeger( L, 2 );
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)
+71 -7
View File
@@ -414,7 +414,7 @@ void InitPreBattleInterface( GROUP *pBattleGroup, BOOLEAN fPersistantPBI )
//There are hostile civilians, so no autoresolve allowed.
SetExplicitEnemyEncounterCode( HOSTILE_CIVILIANS_CODE );
}
else if( HostileBloodcatsPresent() )
else if ( GetEnemyEncounterCode() != BLOODCAT_ATTACK_CODE && HostileBloodcatsPresent() )
{
//There are bloodcats in the sector, so no autoresolve allowed
SetExplicitEnemyEncounterCode( HOSTILE_BLOODCATS_CODE );
@@ -447,8 +447,12 @@ void InitPreBattleInterface( GROUP *pBattleGroup, BOOLEAN fPersistantPBI )
GetEnemyEncounterCode() == CREATURE_ATTACK_CODE ||
GetEnemyEncounterCode() == ENEMY_AMBUSH_DEPLOYMENT_CODE ||
GetEnemyEncounterCode() == ENEMY_INVASION_AIRDROP_CODE ||
GetEnemyEncounterCode() == CONCEALINSERTION_CODE )
{ //use same code
GetEnemyEncounterCode() == CONCEALINSERTION_CODE ||
GetEnemyEncounterCode() == BLOODCAT_ATTACK_CODE ||
GetEnemyEncounterCode() == ZOMBIE_ATTACK_CODE ||
GetEnemyEncounterCode() == BANDIT_ATTACK_CODE )
{
//use same code
SetExplicitEnemyEncounterCode( GetEnemyEncounterCode() );
}
else
@@ -636,7 +640,24 @@ void InitPreBattleInterface( GROUP *pBattleGroup, BOOLEAN fPersistantPBI )
else
{
//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 )
@@ -901,7 +922,10 @@ void InitPreBattleInterface( GROUP *pBattleGroup, BOOLEAN fPersistantPBI )
GetEnemyEncounterCode() == BLOODCAT_AMBUSH_CODE ||
GetEnemyEncounterCode() == ENEMY_AMBUSH_DEPLOYMENT_CODE ||
GetEnemyEncounterCode() == CREATURE_ATTACK_CODE ||
is_client)
GetEnemyEncounterCode() == BLOODCAT_ATTACK_CODE ||
GetEnemyEncounterCode() == ZOMBIE_ATTACK_CODE ||
GetEnemyEncounterCode() == BANDIT_ATTACK_CODE ||
is_client)
{
DisableButton( iPBButton[ 2 ] );
SetButtonFastHelpText( iPBButton[ 2 ], gzNonPersistantPBIText[ 9 ] );
@@ -931,6 +955,9 @@ void InitPreBattleInterface( GROUP *pBattleGroup, BOOLEAN fPersistantPBI )
case ENEMY_ENCOUNTER_CODE:
case ENEMY_INVASION_CODE:
case ENEMY_INVASION_AIRDROP_CODE:
case BLOODCAT_ATTACK_CODE:
case ZOMBIE_ATTACK_CODE:
case BANDIT_ATTACK_CODE:
SetButtonFastHelpText( iPBButton[ 0 ], gzNonPersistantPBIText[ 2 ] );
break;
case ENTERING_ENEMY_SECTOR_CODE:
@@ -1211,6 +1238,18 @@ void RenderPBHeader( INT32 *piX, INT32 *piWidth)
case CONCEALINSERTION_CODE:
swprintf( str, gpStrategicString[STR_PB_ENEMYENCOUNTER_HEADER] );
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 );
x = 130 - width / 2;
@@ -1307,10 +1346,20 @@ void RenderPreBattleInterface()
{
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 ] );
}
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
{
swprintf( str, gpStrategicString[ STR_PB_ENEMIES ] );
@@ -1371,6 +1420,9 @@ void RenderPreBattleInterface()
if( GetEnemyEncounterCode() == CREATURE_ATTACK_CODE ||
GetEnemyEncounterCode() == BLOODCAT_AMBUSH_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...
{
// don't know how many
@@ -1600,7 +1652,10 @@ void GoToSectorCallback( GUI_BUTTON *btn, INT32 reason )
GetEnemyEncounterCode() != CREATURE_ATTACK_CODE &&
GetEnemyEncounterCode() != BLOODCAT_AMBUSH_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;
}
@@ -2404,6 +2459,7 @@ void LogBattleResults( UINT8 ubVictoryCode)
switch( GetEnemyEncounterCode() )
{
case ENEMY_INVASION_CODE:
case BANDIT_ATTACK_CODE:
AddHistoryToPlayersLog( HISTORY_DEFENDEDTOWNSECTOR, 0, GetWorldTotalMin(), sSectorX, sSectorY );
break;
case ENEMY_ENCOUNTER_CODE:
@@ -2418,10 +2474,12 @@ void LogBattleResults( UINT8 ubVictoryCode)
AddHistoryToPlayersLog( HISTORY_SUCCESSFULATTACK, 0, GetWorldTotalMin(), sSectorX, sSectorY );
break;
case CREATURE_ATTACK_CODE:
case ZOMBIE_ATTACK_CODE:
AddHistoryToPlayersLog( HISTORY_CREATURESATTACKED, 0, GetWorldTotalMin(), sSectorX, sSectorY );
break;
case BLOODCAT_AMBUSH_CODE:
case ENTERING_BLOODCAT_LAIR_CODE:
case BLOODCAT_ATTACK_CODE:
AddHistoryToPlayersLog( HISTORY_SLAUGHTEREDBLOODCATS, 0, GetWorldTotalMin(), sSectorX, sSectorY );
break;
case CONCEALINSERTION_CODE:
@@ -2436,6 +2494,7 @@ void LogBattleResults( UINT8 ubVictoryCode)
switch( GetEnemyEncounterCode() )
{
case ENEMY_INVASION_CODE:
case BANDIT_ATTACK_CODE:
AddHistoryToPlayersLog( HISTORY_LOSTTOWNSECTOR, 0, GetWorldTotalMin(), sSectorX, sSectorY );
break;
case ENEMY_ENCOUNTER_CODE:
@@ -2450,10 +2509,12 @@ void LogBattleResults( UINT8 ubVictoryCode)
AddHistoryToPlayersLog( HISTORY_UNSUCCESSFULATTACK, 0, GetWorldTotalMin(), sSectorX, sSectorY );
break;
case CREATURE_ATTACK_CODE:
case ZOMBIE_ATTACK_CODE:
AddHistoryToPlayersLog( HISTORY_CREATURESATTACKED, 0, GetWorldTotalMin(), sSectorX, sSectorY );
break;
case BLOODCAT_AMBUSH_CODE:
case ENTERING_BLOODCAT_LAIR_CODE:
case BLOODCAT_ATTACK_CODE:
AddHistoryToPlayersLog( HISTORY_KILLEDBYBLOODCATS, 0, GetWorldTotalMin(), sSectorX, sSectorY );
break;
case CONCEALINSERTION_CODE:
@@ -2464,6 +2525,9 @@ void LogBattleResults( UINT8 ubVictoryCode)
switch( GetEnemyEncounterCode() )
{
case ENEMY_INVASION_CODE:
case BLOODCAT_ATTACK_CODE:
case ZOMBIE_ATTACK_CODE:
case BANDIT_ATTACK_CODE:
gCurrentIncident.usIncidentFlags |= INCIDENT_ATTACK_ENEMY;
break;
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_INVASION_AIRDROP_CODE, // Flugente: enemy airdrop
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;
+32 -23
View File
@@ -738,7 +738,8 @@ BOOLEAN PrepareEnemyForSectorBattle()
{
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_ELITE: ubTotalElites++; break;
case SOLDIER_CLASS_TANK: ubTotalTanks++; break;
@@ -1459,14 +1460,15 @@ void ProcessQueenCmdImplicationsOfDeath( SOLDIERTYPE *pSoldier )
}
break;
case SOLDIER_CLASS_CREATURE:
case SOLDIER_CLASS_BANDIT:
if( pSoldier->ubBodyType != BLOODCAT )
{
#ifdef JA2BETAVERSION
if( guiCurrentScreen == GAME_SCREEN )
{
if( ubTotalEnemies <= (UINT32)iMaxEnemyGroupSize && pSector->ubNumCreatures != pSector->ubCreaturesInBattle ||
!pSector->ubNumCreatures || !pSector->ubCreaturesInBattle ||
pSector->ubNumCreatures > 50 || pSector->ubCreaturesInBattle > 50 )
!pSector->ubNumCreatures || !pSector->ubCreaturesInBattle ||
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 );
}
@@ -1563,6 +1565,7 @@ void ProcessQueenCmdImplicationsOfDeath( SOLDIERTYPE *pSoldier )
}
break;
case SOLDIER_CLASS_CREATURE:
case SOLDIER_CLASS_BANDIT:
if (pSoldier->ubBodyType == BLOODCAT)
{
if( pSector->ubNumBloodcats > 0 )
@@ -1570,14 +1573,16 @@ void ProcessQueenCmdImplicationsOfDeath( SOLDIERTYPE *pSoldier )
}
else
{
#ifdef JA2BETAVERSION
#ifdef JA2BETAVERSION
if( ubTotalEnemies <= (UINT32)iMaxEnemyGroupSize && pSector->ubNumCreatures != pSector->ubCreaturesInBattle ||
!pSector->ubNumCreatures || !pSector->ubCreaturesInBattle ||
pSector->ubNumCreatures > gGameExternalOptions.ubGameMaximumNumberOfCreatures || pSector->ubCreaturesInBattle > gGameExternalOptions.ubGameMaximumNumberOfCreatures )
!pSector->ubNumCreatures ||
!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 );
}
#endif
#endif
if( pSector->ubNumCreatures )
{
pSector->ubNumCreatures--;
@@ -1587,23 +1592,27 @@ void ProcessQueenCmdImplicationsOfDeath( SOLDIERTYPE *pSoldier )
pSector->ubCreaturesInBattle--;
}
if( !pSector->ubNumCreatures && gWorldSectorX != 9 && gWorldSectorY != 10 )
{ //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 )
if ( pSoldier->ubSoldierClass == SOLDIER_CLASS_CREATURE )
{
//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 );
if ( !pSector->ubNumCreatures && gWorldSectorX != 9 && gWorldSectorY != 10 )
{
//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
//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;
+85
View File
@@ -27,6 +27,8 @@
#include "strategic.h"
#include "GameSettings.h"
#include "history.h"
#include "Town Militia.h" // added by Flugente
#include "Campaign.h" // added by Flugente
#endif
#include "Luaglobal.h"
@@ -52,6 +54,8 @@ UINT8 gubCambriaMedicalObjects;
extern INT8 NumMercsNear( UINT8 ubProfileID, UINT8 ubMaxDist );
extern SECTOR_EXT_DATA SectorExternalData[256][4];
// WANNE: No more used for the new airport code
//void DropOffItemsInMeduna( UINT8 ubOrderNum );
@@ -1097,6 +1101,87 @@ void HandleEarlyMorningEvents( void )
#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 )
{
// 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 HandleNPCSystemEvent( UINT32 uiEvent );
void HandleEarlyMorningEvents( void );
void HandleRaidEventPlanning();
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;
}
void TrackEnemiesKilled( UINT8 ubKilledHow, UINT8 ubSoldierClass )
{
INT8 bRankIndex;
@@ -418,7 +417,6 @@ void TrackEnemiesKilled( UINT8 ubKilledHow, UINT8 ubSoldierClass )
}
}
INT8 SoldierClassToRankIndex( UINT8 ubSoldierClass )
{
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!
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_ARMY: bRankIndex = 1; break;
@@ -438,8 +437,6 @@ INT8 SoldierClassToRankIndex( UINT8 ubSoldierClass )
return( bRankIndex );
}
UINT8 RankIndexToSoldierClass( UINT8 ubRankIndex )
{
UINT8 ubSoldierClass = 0;
+12 -6
View File
@@ -1592,14 +1592,13 @@ INT32 IsTownUnderCompleteControlByEnemy( INT8 bTownId )
return( FALSE );
}
void AdjustLoyaltyForCivsEatenByMonsters( INT16 sSectorX, INT16 sSectorY, UINT8 ubHowMany)
void AdjustLoyaltyForCivsEatenByMonsters( INT16 sSectorX, INT16 sSectorY, UINT8 ubHowMany, BOOLEAN aBandits)
{
INT8 bTownId = 0;
UINT32 uiLoyaltyChange = 0;
CHAR16 str[256];
CHAR16 pSectorString[128];
// get town id
bTownId = GetTownIdForSector( sSectorX, sSectorY );
@@ -1611,12 +1610,19 @@ void AdjustLoyaltyForCivsEatenByMonsters( INT16 sSectorX, INT16 sSectorY, UINT8
//Report this to player
GetSectorIDString( sSectorX, sSectorY, 0, pSectorString, TRUE );
if ( aBandits )
swprintf( str, gpStrategicString[STR_PB_BANDIT_KILLCIVS_IN_SECTOR], ubHowMany, pSectorString );
else
{
#ifdef CHINESE
//diffrent order of words in Chinese
swprintf( str, gpStrategicString[ STR_DIALOG_CREATURES_KILL_CIVILIANS ], pSectorString, ubHowMany);
//diffrent order of words in Chinese
swprintf( str, gpStrategicString[STR_DIALOG_CREATURES_KILL_CIVILIANS], pSectorString, ubHowMany );
#else
swprintf( str, gpStrategicString[ STR_DIALOG_CREATURES_KILL_CIVILIANS ], ubHowMany, pSectorString );
swprintf( str, gpStrategicString[STR_DIALOG_CREATURES_KILL_CIVILIANS], ubHowMany, pSectorString );
#endif
}
DoScreenIndependantMessageBox( str, MSG_BOX_FLAG_OK, MapScreenDefaultOkBoxCallback );
// 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 );
// 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)
void IncrementTownLoyaltyEverywhere( UINT32 uiLoyaltyIncrease );
+15
View File
@@ -2347,3 +2347,18 @@ FLOAT GetIntel()
{
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 );
FLOAT GetIntel();
// Flugente: raid 'personnel'
void AddRaidPersonnel( INT32 aBloodcats, INT32 aZombie, INT32 aBandits );
void GetRaidPersonnel( INT32& arBloodcats, INT32& arZombie, INT32& arBandits );
#endif
+29 -2
View File
@@ -99,7 +99,10 @@ SectorNameStartElementHandle(void *userData, const XML_Char *name, const char **
strcmp(name, "snowchance" ) == 0 ||
strcmp(name, "snakechance" ) == 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;
@@ -230,7 +233,12 @@ SectorNameEndElementHandle(void *userData, const XML_Char *name)
SectorExternalData[ubSectorId][1].maxworkers = 0;
SectorExternalData[ubSectorId][2].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( ) )
{
std::vector<UINT16>::iterator itend = prisonroomvector.end( );
@@ -255,6 +263,7 @@ SectorNameEndElementHandle(void *userData, const XML_Char *name)
pData->sectordata.snakechance = 0;
pData->sectordata.numsnakes = 0;
pData->sectordata.maxworkers = 0;
pData->sectordata.usSectorFlagMask = 0;
}
else
{
@@ -378,6 +387,24 @@ SectorNameEndElementHandle(void *userData, const XML_Char *name)
pData->curElement = ELEMENT;
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--;
}
+3 -3
View File
@@ -15804,9 +15804,9 @@ void HandlePostAutoresolveMessages()
//are "virtually" murdered and loyalty hits will be processed.
if( gsCiviliansEatenByMonsters >= 1 )
{
AdjustLoyaltyForCivsEatenByMonsters( (UINT8)SECTORX( gsEnemyGainedControlOfSectorID ),
(UINT8)SECTORY( gsEnemyGainedControlOfSectorID ),
(UINT8)gsCiviliansEatenByMonsters );
AdjustLoyaltyForCivsEatenByMonsters( (UINT8)SECTORX( gsEnemyGainedControlOfSectorID ), (UINT8)SECTORY( gsEnemyGainedControlOfSectorID ),
(UINT8)gsCiviliansEatenByMonsters, ( guCreatureAttackType == CREATURE_ATTACK_TYPE_BANDIT ) );
gsCiviliansEatenByMonsters = -2;
}
else if( gsCiviliansEatenByMonsters == -2 )
+12 -6
View File
@@ -148,11 +148,11 @@ class SOLDIERTYPE;
//Used by PickGridNoToWalkIn
#define MAX_ATTEMPTS 200
#define QUEST_CHECK_EVENT_TIME ( 8 * 60 )
#define BOBBYRAY_UPDATE_TIME ( 9 * 60 )
#define INSURANCE_UPDATE_TIME 0
#define EARLY_MORNING_TIME ( 4 * 60 )
#define ENRICO_MAIL_TIME ( 7 * 60 )
#define QUEST_CHECK_EVENT_TIME ( 8 * 60 )
#define BOBBYRAY_UPDATE_TIME ( 9 * 60 )
#define INSURANCE_UPDATE_TIME 0
#define EARLY_MORNING_TIME ( 4 * 60 )
#define ENRICO_MAIL_TIME ( 7 * 60 )
enum
{
@@ -2242,6 +2242,7 @@ BOOLEAN SetCurrentWorldSector( INT16 sMapX, INT16 sMapY, INT8 bMapZ )
PrepareCreaturesForBattle( );
}
}
if ( gfGotoSectorTransition )
{
BeginLoadScreen( );
@@ -5114,6 +5115,8 @@ void SetupNewStrategicGame( )
AddEveryDayStrategicEvent( EVENT_DAILY_UPDATE_BOBBY_RAY_INVENTORY, BOBBYRAY_UPDATE_TIME, 0 );
//Daily Update of the M.E.R.C. site.
AddEveryDayStrategicEvent( EVENT_DAILY_UPDATE_OF_MERC_SITE, 0, 0 );
// Flugente: plan when to conduct raids on player sectors
AddEveryDayStrategicEvent( EVENT_DAILY_RAID_EVENTS, ENRICO_MAIL_TIME, 0 );
#ifdef JA2UB
//Ja25: No insurance for mercs
@@ -6528,7 +6531,10 @@ BOOLEAN HandlePotentialBringUpAutoresolveToFinishBattle( int pSectorX, int pSect
gubPBSectorZ = (UINT8)pSectorZ;
gfBlitBattleSectorLocator = 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.
}
+6
View File
@@ -316,6 +316,11 @@ INT8 GetCivType( SOLDIERTYPE *pCiv )
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 )
{
return( CIV_TYPE_NA );
@@ -1627,6 +1632,7 @@ void StartEnemyTaunt( SOLDIERTYPE *pCiv, TAUNTTYPE iTauntType, SOLDIERTYPE *pTar
switch( pCiv->ubSoldierClass )
{
case SOLDIER_CLASS_ADMINISTRATOR:
case SOLDIER_CLASS_BANDIT:
if( !(zTaunt[ i ].uiFlags2 & TAUNT_C_ADMIN) )
continue;
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.
case SOLDIER_CLASS_ADMINISTRATOR:
case SOLDIER_CLASS_GREEN_MILITIA:
case SOLDIER_CLASS_BANDIT:
bRating = BAD_ADMINISTRATOR_EQUIPMENT_RATING + bEquipmentModifier;
// Equipment quality modifier
if ( bSoldierClass == SOLDIER_CLASS_ADMINISTRATOR )
if ( bSoldierClass == SOLDIER_CLASS_ADMINISTRATOR || bSoldierClass == SOLDIER_CLASS_BANDIT )
{
if ( gGameExternalOptions.sEnemyAdminEquipmentQualityModifier != 0 )
bRating += gGameExternalOptions.sEnemyAdminEquipmentQualityModifier;
@@ -360,7 +361,7 @@ void GenerateRandomEquipment( SOLDIERCREATE_STRUCT *pp, INT8 bSoldierClass, INT8
bHelmetClass = bRating;
// no leggings
if ( bSoldierClass == SOLDIER_CLASS_ADMINISTRATOR )
if ( bSoldierClass == SOLDIER_CLASS_ADMINISTRATOR || bSoldierClass == SOLDIER_CLASS_BANDIT )
{
if ( Chance( 30 ) )
bKnifeClass = bRating;
@@ -919,6 +920,7 @@ void ChooseWeaponForSoldierCreateStruct( SOLDIERCREATE_STRUCT *pp, INT8 bWeaponC
case SOLDIER_CLASS_ARMY:
case SOLDIER_CLASS_GREEN_MILITIA:
case SOLDIER_CLASS_REG_MILITIA:
case SOLDIER_CLASS_BANDIT:
//Admins/Troops: 60-75% + 1% every 4% progress
bStatus = (INT8)(60 + Random( 16 ));
bStatus += (INT8)(HighestPlayerProgressPercentage() / 4);
@@ -1987,13 +1989,12 @@ void ChooseFaceGearForSoldierCreateStruct( SOLDIERCREATE_STRUCT *pp )
case SOLDIER_CLASS_ADMINISTRATOR:
case SOLDIER_CLASS_GREEN_MILITIA:
case SOLDIER_CLASS_ZOMBIE:
case SOLDIER_CLASS_BANDIT:
break;
}
}
void ChooseKitsForSoldierCreateStruct( SOLDIERCREATE_STRUCT *pp, INT8 bKitClass )
{
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);
#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
typedef struct
{
@@ -515,6 +519,8 @@ typedef struct
UINT8 maxworkers; // maximum number of workers in this sector;
UINT32 usSectorFlagMask; // various flags
} SECTOR_EXT_DATA;
// 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 )
{
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_ELITE: ++sNumPrisoner[PRISONER_ELITE]; break;
default:
@@ -6865,7 +6866,11 @@ void RemoveCapturedEnemiesFromSectorInfo( INT16 sMapX, INT16 sMapY, INT8 bMapZ )
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];
}
@@ -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.
BOOLEAN fNoSurrender = FALSE;
// enemy team
// enemy team and creature team (bandits can be captured)
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)
{
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
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)
{
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
if ( gusSelectedSoldier != NOBODY )
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
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 )
{
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
wcscpy( gzUserDefinedButton[0], TacticalStr[ PRISONER_DEMAND_SURRENDER_STR ] );
wcscpy( gzUserDefinedButton[1], TacticalStr[ PRISONER_OFFER_SURRENDER_STR ] );
SOLDIERTYPE* pTargetSoldier = NULL;
if ( GetSoldier( &pTargetSoldier, prisonerdialoguetargetID ) &&
pTargetSoldier->bTeam == ENEMY_TEAM &&
pTargetSoldier->ubProfile == NO_PROFILE &&
pTargetSoldier->aiData.bAlertStatus < STATUS_RED &&
!pTargetSoldier->RecognizeAsCombatant( gusSelectedSoldier ) )
if ( pSoldier->bTeam != CREATURE_TEAM )
wcscpy( gzUserDefinedButton[1], TacticalStr[ PRISONER_OFFER_SURRENDER_STR ] );
else
wcscpy( gzUserDefinedButton[1], TacticalStr[PRISONER_TALK_STR] );
if ( pSoldier->bTeam == ENEMY_TEAM &&
pSoldier->ubProfile == NO_PROFILE &&
pSoldier->aiData.bAlertStatus < STATUS_RED &&
!pSoldier->RecognizeAsCombatant( gusSelectedSoldier ) )
{
wcscpy( gzUserDefinedButton[2], TacticalStr[PRISONER_DISTRACT_STR] );
}
+26 -5
View File
@@ -47,6 +47,8 @@
#include "Campaign Types.h"
#include "text.h" // added by Flugente
#include "Vehicles.h" // added by silversurfer
#include "ai.h" // added by Flugente
#include "PreBattle Interface.h" // added by Flugente
#endif
#include "Animation Control.h"
@@ -2632,7 +2634,7 @@ void RaiseZombies( void )
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 ] );
@@ -2652,8 +2654,8 @@ void RaiseZombies( void )
zombieshaverisen = TRUE;
CreateZombiefromCorpse( pCorpse, recanimstate );
//++pSector->ubNumZombies;
//++pSector->ubZombiesInBattle;
pSector->ubNumCreatures++;
pSector->ubCreaturesInBattle++;
RemoveCorpse( cnt );
}
@@ -2680,13 +2682,32 @@ void RaiseZombies( void )
PlayJA2SampleFromFile( "Sounds\\zombie1.wav", RATE_11025, HIGHVOLUME, 1, MIDDLEPAN );
UseCreatureMusic(TRUE); // Madd: music when zombies rise
#ifdef NEWMUSIC
#ifdef NEWMUSIC
GlobalSoundID = MusicSoundValues[ SECTOR( gWorldSectorX, gWorldSectorY ) ].SoundTacticalTensor[gbWorldSectorZ];
if ( MusicSoundValues[ SECTOR( gWorldSectorX, gWorldSectorY ) ].SoundTacticalTensor[gbWorldSectorZ] != -1 )
SetMusicModeID( MUSIC_TACTICAL_ENEMYPRESENT, MusicSoundValues[ SECTOR( gWorldSectorX, gWorldSectorY ) ].SoundTacticalTensor[gbWorldSectorZ] );
else
#endif
#endif
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 "DynamicDialogue.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
// anv: for enemy taunts
@@ -3945,6 +3947,9 @@ BOOLEAN HandleSoldierDeath( SOLDIERTYPE *pSoldier , BOOLEAN *pfMadeCorpse )
case SOLDIER_CLASS_ZOMBIE :
gMercProfiles[ MercPtrs[ ubAttacker ]->ubProfile ].records.usKillsZombies++;
break;
case SOLDIER_CLASS_BANDIT:
gMercProfiles[MercPtrs[ubAttacker]->ubProfile].records.usKillsOthers++;
break;
default :
if ( CREATURE_OR_BLOODCAT( pSoldier ) )
gMercProfiles[ MercPtrs[ ubAttacker ]->ubProfile ].records.usKillsCreatures++;
@@ -4049,6 +4054,14 @@ BOOLEAN HandleSoldierDeath( SOLDIERTYPE *pSoldier , BOOLEAN *pfMadeCorpse )
// Flugente: campaign stats
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
MILITIA militia;
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 )
resistance += (INT32)(gGameExternalOptions.bVeteranMilitiaDamageResistance / breathmodifiermilitia);
// 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;
else if ( this->ubSoldierClass == SOLDIER_CLASS_ARMY && gGameExternalOptions.sEnemyRegularDamageResistance != 0 )
resistance += gGameExternalOptions.sEnemyRegularDamageResistance;
@@ -16211,7 +16211,7 @@ UINT32 SOLDIERTYPE::GetSurrenderStrength( )
// adjust for type of soldier
if ( this->ubSoldierClass == SOLDIER_CLASS_ELITE || this->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA )
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;
// tanks won't surrender that easy
@@ -16267,6 +16267,10 @@ BOOLEAN SOLDIERTYPE::CanBeCaptured( )
if ( this->bTeam == ENEMY_TEAM )
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
if ( this->bTeam == CIV_TEAM && zCivGroupName[this->ubCivilianGroup].fCanBeCaptured )
{
+1
View File
@@ -331,6 +331,7 @@ enum
SOLDIER_CLASS_ZOMBIE,
SOLDIER_CLASS_TANK,
SOLDIER_CLASS_JEEP,
SOLDIER_CLASS_BANDIT,
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
if ( gGameExternalOptions.fAssignTraitsToEnemy && SOLDIER_CLASS_ENEMY( pSoldier->ubSoldierClass ) )
if ( gGameExternalOptions.fAssignTraitsToEnemy && (SOLDIER_CLASS_ENEMY( pSoldier->ubSoldierClass ) || pSoldier->ubSoldierClass == SOLDIER_CLASS_BANDIT) )
AssignTraitsToSoldier( pSoldier, pCreateStruct );
if ( gGameExternalOptions.fAssignTraitsToMilitia && SOLDIER_CLASS_MILITIA( pSoldier->ubSoldierClass ) )
AssignTraitsToSoldier( pSoldier, pCreateStruct );
@@ -2010,7 +2010,7 @@ BOOLEAN TacticalCopySoldierFromCreateStruct( SOLDIERTYPE *pSoldier, SOLDIERCREAT
}
break;
case CREATURE_TEAM:
if( pSoldier->ubBodyType == BLOODCAT )
if ( pSoldier->ubBodyType == BLOODCAT )
{
swprintf( pSoldier->name, gzLateLocalizedString[ 36 ] );
}
@@ -2018,9 +2018,13 @@ BOOLEAN TacticalCopySoldierFromCreateStruct( SOLDIERTYPE *pSoldier, SOLDIERCREAT
{
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
{
swprintf( pSoldier->name, TacticalStr[ CREATURE_TEAM_MERC_NAME ] ); break;
swprintf( pSoldier->name, gpStrategicString[STR_PB_BANDIT] ); break;
}
break;
}
@@ -2296,7 +2300,6 @@ INT8 CalcDifficultyModifier( UINT8 ubSoldierClass )
return(bDiffModifier);
}
//When the editor modifies the soldier's relative attribute level,
//this function is called to update that information.
//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->bAttitude = bp->bAttitude;
pp->ubDirection = bp->ubDirection;
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("CreateDetailedPlacementGivenBasicPlacementInfo: determine soldier's class"));
// determine this soldier's soldier class
if( bp->bTeam == CREATURE_TEAM )
@@ -2411,8 +2413,7 @@ void CreateDetailedPlacementGivenBasicPlacementInfo( SOLDIERCREATE_STRUCT *pp, B
}
ubDiffFactor = CalcDifficultyModifier( ubSoldierClass );
// experience level is modified by game difficulty, player's progress, & proximity to Queen's Palace, etc.
// This formula gives the following results:
// DIFFICULTY FACTOR EXP. LEVEL MODIFIER LEVEL OF AVG REGULAR TROOP
@@ -2457,6 +2458,19 @@ void CreateDetailedPlacementGivenBasicPlacementInfo( SOLDIERCREATE_STRUCT *pp, B
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"));
//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_ZOMBIE:
case SOLDIER_CLASS_BANDIT:
pp->bExpLevel = (INT8) 2 + bExpLevelModifier;
break;
case SOLDIER_CLASS_ARMY:
@@ -2512,23 +2527,7 @@ void CreateDetailedPlacementGivenBasicPlacementInfo( SOLDIERCREATE_STRUCT *pp, B
UINT8 PlacementType = gBloodcatPlacements[ SECTOR(gWorldSectorX, gWorldSectorY) ][0].PlacementType;
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 += gGameOptions.ubDifficultyLevel;
}
break;
}
@@ -2546,8 +2545,8 @@ void CreateDetailedPlacementGivenBasicPlacementInfo( SOLDIERCREATE_STRUCT *pp, B
}
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 )
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;
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;
}
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
ubStatsLevel = max( DiffLevel, ubStatsLevel ); //minimum stats level of 0 -- madd->= dif level
if ( gGameOptions.ubDifficultyLevel == DIF_LEVEL_INSANE )
ubStatsLevel = max( 6, ubStatsLevel ); //minimum stats level of 6 in insane
@@ -2618,7 +2601,11 @@ void CreateDetailedPlacementGivenBasicPlacementInfo( SOLDIERCREATE_STRUCT *pp, B
//own 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);
@@ -2800,7 +2787,10 @@ void CreateDetailedPlacementGivenStaticDetailedPlacementAndBasicPlacementInfo(
// 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);
@@ -2841,6 +2831,7 @@ void UpdateSoldierWithStaticDetailedInformation( SOLDIERTYPE *s, SOLDIERCREATE_S
case SOLDIER_CLASS_ADMINISTRATOR:
case SOLDIER_CLASS_ARMY:
case SOLDIER_CLASS_ELITE:
case SOLDIER_CLASS_BANDIT:
GeneratePaletteForSoldier( s, spp->ubSoldierClass, spp->bTeam );
break;
}
@@ -3003,7 +2994,7 @@ SOLDIERTYPE* ReserveTacticalSoldierForAutoresolve( UINT8 ubSoldierClass )
//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
//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
iStart = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID;
@@ -3244,12 +3235,16 @@ SOLDIERTYPE* TacticalCreateZombie()
memset( &bp, 0, sizeof( BASIC_SOLDIERCREATE_STRUCT ) );
RandomizeRelativeLevel( &( bp.bRelativeAttributeLevel ), SOLDIER_CLASS_ZOMBIE );
RandomizeRelativeLevel( &( bp.bRelativeEquipmentLevel ), SOLDIER_CLASS_ZOMBIE );
bp.bTeam = CREATURE_TEAM;//ZOMBIE_TEAM;
bp.bTeam = CREATURE_TEAM;
bp.bOrders = SEEKENEMY;
bp.bAttitude = AGGRESSIVE;
bp.ubBodyType = -1;
bp.ubBodyType = Random( ADULTFEMALEMONSTER );
bp.ubSoldierClass = SOLDIER_CLASS_ZOMBIE;
CreateDetailedPlacementGivenBasicPlacementInfo( &pp, &bp );
// need to properly set this here
pp.ubSoldierClass = SOLDIER_CLASS_ZOMBIE;
pSoldier = TacticalCreateSoldier( &pp, &ubID );
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.ubNoiseVolume = MAX_MISC_NOISE_DURATION;
// random clothes
SetClothes( pSoldier, Random( NUMSHIRTS ), Random( NUMPANTS ) );
if ( guiCurrentScreen != AUTORESOLVE_SCREEN )
{
// random clothes
SetClothes( pSoldier, Random( NUMSHIRTS ), Random( NUMPANTS ) );
pSoldier->CreateSoldierPalettes( );
pSoldier->CreateSoldierPalettes();
}
}
return(pSoldier);
@@ -3481,25 +3479,28 @@ SOLDIERTYPE* TacticalCreateCivilian( INT32 sGridNo, UINT8 usCivilianGroup, INT8
pSoldier->aiData.bOrders = ONGUARD;
}
// make him wear administrator uniform
UINT16 usPaletteAnimSurface = LoadSoldierAnimationSurface( pSoldier, pSoldier->usAnimState );
if ( usPaletteAnimSurface != INVALID_ANIMATION_SURFACE )
if ( guiCurrentScreen != AUTORESOLVE_SCREEN )
{
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
memcpy( pSoldier->p8BPPPalette, gAnimSurfaceDatabase[usPaletteAnimSurface].hVideoObject->pPaletteEntry, sizeof(pSoldier->p8BPPPalette) * 256 );
if ( usPaletteAnimSurface != INVALID_ANIMATION_SURFACE )
{
SetClothes( pSoldier, aVest, aPants, aHair, aSkin );
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->HeadPal );
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->VestPal );
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->PantsPal );
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->SkinPal );
// Use palette from HVOBJECT, then use substitution for pants, etc
memcpy( pSoldier->p8BPPPalette, gAnimSurfaceDatabase[usPaletteAnimSurface].hVideoObject->pPaletteEntry, sizeof( pSoldier->p8BPPPalette ) * 256 );
pSoldier->CreateSoldierPalettes( );
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->HeadPal );
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->VestPal );
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->PantsPal );
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->SkinPal );
// Dirty
fInterfacePanelDirty = DIRTYLEVEL2;
pSoldier->CreateSoldierPalettes();
// Dirty
fInterfacePanelDirty = DIRTYLEVEL2;
}
}
}
@@ -3572,6 +3573,65 @@ SOLDIERTYPE* TacticalCreateEnemyAssassin(UINT8 disguisetype)
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)
{
SOLDIERTYPE* pSoldier = TacticalCreateEnemyAssassin( disguisetype );
@@ -3742,26 +3802,29 @@ void CreatePrisonerOfWar()
swprintf( pSoldier->name, TacticalStr[ POW_TEAM_MERC_NAME ] );
// make him wear 'prisoner garb' (just what Shank and Dynamo are wearing)
UINT16 usPaletteAnimSurface = LoadSoldierAnimationSurface( pSoldier, pSoldier->usAnimState );
if ( usPaletteAnimSurface != INVALID_ANIMATION_SURFACE )
if ( guiCurrentScreen != AUTORESOLVE_SCREEN )
{
SET_PALETTEREP_ID( pSoldier->VestPal, "greyVEST" );
SET_PALETTEREP_ID( pSoldier->PantsPal, "BLACKPANTS" );
// make him wear 'prisoner garb' (just what Shank and Dynamo are wearing)
UINT16 usPaletteAnimSurface = LoadSoldierAnimationSurface( pSoldier, pSoldier->usAnimState );
// Use palette from HVOBJECT, then use substitution for pants, etc
memcpy( pSoldier->p8BPPPalette, gAnimSurfaceDatabase[usPaletteAnimSurface].hVideoObject->pPaletteEntry, sizeof(pSoldier->p8BPPPalette) * 256 );
if ( usPaletteAnimSurface != INVALID_ANIMATION_SURFACE )
{
SET_PALETTEREP_ID( pSoldier->VestPal, "greyVEST" );
SET_PALETTEREP_ID( pSoldier->PantsPal, "BLACKPANTS" );
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->HeadPal );
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->VestPal );
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->PantsPal );
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->SkinPal );
// Use palette from HVOBJECT, then use substitution for pants, etc
memcpy( pSoldier->p8BPPPalette, gAnimSurfaceDatabase[usPaletteAnimSurface].hVideoObject->pPaletteEntry, sizeof( pSoldier->p8BPPPalette ) * 256 );
pSoldier->CreateSoldierPalettes( );
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->HeadPal );
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->VestPal );
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->PantsPal );
SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->SkinPal );
// Dirty
fInterfacePanelDirty = DIRTYLEVEL2;
pSoldier->CreateSoldierPalettes();
// Dirty
fInterfacePanelDirty = DIRTYLEVEL2;
}
}
// So we can see them!
@@ -4696,7 +4759,7 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre
// 30-80%
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%
iChance = 15 + ubProgress / 2;
@@ -4757,7 +4820,7 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre
// 30-80%
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%
iChance = 15 + ubProgress / 2;
@@ -4819,7 +4882,7 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre
// 25-75%
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%
iChance = 10 + ubProgress / 2;
@@ -4888,7 +4951,7 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre
// 25-75%
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%
iChance = 10 + ubProgress / 2;
@@ -4993,7 +5056,7 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre
// 25-75%
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%
iChance = 10 + ubProgress / 2;
@@ -5177,7 +5240,7 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre
iChance = 45 + ubProgress / 2; // 45-95% chance
else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA )
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
// 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
else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA )
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
else if ( ubSolClass == SOLDIER_CLASS_ZOMBIE )
iChance = 100; // 100% chance
@@ -5284,7 +5347,7 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre
iChance = 40 + ubProgress * 2 / 5; // 40-80% chance
else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA )
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
else if ( ubSolClass == SOLDIER_CLASS_ZOMBIE )
iChance = 100; // 100% chance
@@ -5348,7 +5411,7 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre
iChance = 30 + ubProgress / 3 + 30; // 60-92% chance
else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA )
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
// 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
else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA )
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
// 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
else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA )
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
// 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
else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA )
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
// 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
else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA )
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
// 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
else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA )
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
// 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
SOLDIERTYPE* TacticalCreateEnemyAssassin(UINT8 disguisetype);
SOLDIERTYPE* TacticalCreateBandit();
void CreateAssassin(UINT8 disguisetype);
// 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 "LuaInitNPCs.h" // added by Flugente
#include "Soldier macros.h" // added by Flugente
#include "Creature Spreading.h" // added by Flugente
BOOLEAN gfOriginalList = TRUE;
@@ -1105,6 +1107,7 @@ void AddSoldierInitListEnemyDefenceSoldiers( UINT8 ubTotalAdmin, UINT8 ubTotalTr
ubEliteBSlots++;
break;
case SOLDIER_CLASS_ADMINISTRATOR:
case SOLDIER_CLASS_BANDIT:
if( curr->pBasicPlacement->fPriorityExistance && curr->pDetailedPlacement )
ubAdminPDSlots++;
else if( curr->pBasicPlacement->fPriorityExistance )
@@ -1163,6 +1166,7 @@ void AddSoldierInitListEnemyDefenceSoldiers( UINT8 ubTotalAdmin, UINT8 ubTotalTr
switch( ubCurrClass )
{
case SOLDIER_CLASS_ADMINISTRATOR:
case SOLDIER_CLASS_BANDIT:
pCurrSlots = &ubAdminPDSlots;
pCurrTotal = &ubTotalAdmin;
break;
@@ -1229,6 +1233,7 @@ void AddSoldierInitListEnemyDefenceSoldiers( UINT8 ubTotalAdmin, UINT8 ubTotalTr
switch( ubCurrClass )
{
case SOLDIER_CLASS_ADMINISTRATOR:
case SOLDIER_CLASS_BANDIT:
pCurrSlots = &ubAdminPSlots;
pCurrTotal = &ubTotalAdmin;
break;
@@ -1285,6 +1290,7 @@ void AddSoldierInitListEnemyDefenceSoldiers( UINT8 ubTotalAdmin, UINT8 ubTotalTr
switch( ubCurrClass )
{
case SOLDIER_CLASS_ADMINISTRATOR:
case SOLDIER_CLASS_BANDIT:
pCurrSlots = &ubAdminDSlots;
pCurrTotal = &ubTotalAdmin;
break;
@@ -1389,12 +1395,13 @@ void AddSoldierInitListEnemyDefenceSoldiers( UINT8 ubTotalAdmin, UINT8 ubTotalTr
//ADD REMAINING PLACEMENTS WITH BASIC PLACEMENT INFORMATION
//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.
for( ubCurrClass = SOLDIER_CLASS_ADMINISTRATOR; ubCurrClass <= SOLDIER_CLASS_ARMY; ubCurrClass++ )
for( ubCurrClass = SOLDIER_CLASS_ADMINISTRATOR; ubCurrClass <= SOLDIER_CLASS_ARMY; ++ubCurrClass )
{
//First, prepare the counters.
switch( ubCurrClass )
{
case SOLDIER_CLASS_ADMINISTRATOR:
case SOLDIER_CLASS_BANDIT:
pCurrSlots = &ubAdminBSlots;
pCurrTotal = &ubTotalAdmin;
break;
@@ -1672,7 +1679,8 @@ void AddSoldierInitListMilitia( UINT8 ubNumGreen, UINT8 ubNumRegs, UINT8 ubNumEl
switch( curr->pBasicPlacement->ubSoldierClass )
{
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;
}
}
@@ -1693,6 +1701,7 @@ void AddSoldierInitListMilitia( UINT8 ubNumGreen, UINT8 ubNumRegs, UINT8 ubNumEl
switch( reorder[i] )
{
case SOLDIER_CLASS_ADMINISTRATOR:
case SOLDIER_CLASS_BANDIT:
pCurrSlots = &ubGreenSlots;
pCurrTotal = &ubNumGreen;
break;
@@ -1721,6 +1730,7 @@ void AddSoldierInitListMilitia( UINT8 ubNumGreen, UINT8 ubNumRegs, UINT8 ubNumEl
switch( reorder[i] )
{
case SOLDIER_CLASS_ADMINISTRATOR:
case SOLDIER_CLASS_BANDIT:
curr->pBasicPlacement->ubSoldierClass = SOLDIER_CLASS_GREEN_MILITIA;
break;
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 )
+1
View File
@@ -44,6 +44,7 @@ void AddSoldierInitListEnemyDefenceSoldiers( UINT8 ubTotalAdmin, UINT8 ubTotalTr
void AddSoldierInitListCreatures( BOOLEAN fQueen, UINT8 ubNumLarvae, UINT8 ubNumInfants,
UINT8 ubNumYoungMales, UINT8 ubNumYoungFemales, UINT8 ubNumAdultMales,
UINT8 ubNumAdultFemales );
void AddSoldierInitListOtherCreatures( UINT8 usNum );
void AddSoldierInitListMilitia( 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)
iChance += ((iChance * gGameExternalOptions.sVeteranMilitiaCtHBonusPercent) /100);
// 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);
else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ARMY && gGameExternalOptions.sEnemyRegularCtHBonusPercent != 0)
iChance += ((iChance * gGameExternalOptions.sEnemyRegularCtHBonusPercent) /100);
@@ -9069,6 +9069,8 @@ INT32 HTHImpact( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pTarget, INT32 iHitBy, BO
INT32 iImpact, iFluke, iBonus;
BOOLEAN autoresolve = IsAutoResolveActive();
// Flugente: check for underbarrel weapons and use that object if necessary (think of bayonets)
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 ) )
{
iBonus += ( gSkillTraitValues.ubMABonusDamageHandToHand * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ) );
}
}
// 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;
@@ -9180,7 +9183,8 @@ INT32 HTHImpact( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pTarget, INT32 iHitBy, BO
iBonus += ( gSkillTraitValues.ubMABonusDamageHandToHand * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ) );
// 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
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;
// 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
{
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;
}
// add bonuses for hand-to-hand and martial arts
if ( HAS_SKILL_TRAIT( 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;
}
}
if ( HAS_SKILL_TRAIT( pSoldier, HANDTOHAND_OT ) )
{
// 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
if (gGameExternalOptions.fEnhancedCloseCombatSystem)
if ( !autoresolve && gGameExternalOptions.fEnhancedCloseCombatSystem)
{
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
}
}
// 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
else
@@ -9277,42 +9268,27 @@ INT32 HTHImpact( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pTarget, INT32 iHitBy, BO
iBonus += gSkillTraitValues.ubMEDamageBonusBlades; // +30% damage
// 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;
}
else if ( HAS_SKILL_TRAIT( pSoldier, MELEE_NT ) && ( gGameOptions.fNewTraitSystem ))
{
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
}
}
// Enhanced Close Combat System
if (gGameExternalOptions.fEnhancedCloseCombatSystem)
if ( !autoresolve && gGameExternalOptions.fEnhancedCloseCombatSystem)
{
if (gAnimControl[ pTarget->usAnimState ].ubEndHeight == ANIM_PRONE)
{
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
@@ -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
// 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 resistchance = 20;
@@ -9356,7 +9332,6 @@ INT32 HTHImpact( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pTarget, INT32 iHitBy, BO
iImpact = (iImpact * (100 + iBonus) + 50) / 100; // round it properly
// Flugente: moved the damage calculation into a separate function
BOOLEAN autoresolve = IsAutoResolveActive();
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)
@@ -10068,7 +10043,7 @@ UINT32 CalcChanceHTH( SOLDIERTYPE * pAttacker,SOLDIERTYPE *pDefender, INT16 ubAi
else if (pAttacker->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA && gGameExternalOptions.sVeteranMilitiaCtHBonusPercent != 0)
iChance += ((iChance * gGameExternalOptions.sVeteranMilitiaCtHBonusPercent) /100);
// 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);
else if (pAttacker->ubSoldierClass == SOLDIER_CLASS_ARMY && gGameExternalOptions.sEnemyRegularCtHBonusPercent != 0)
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)
iChance += ((iChance * gGameExternalOptions.sVeteranMilitiaCtHBonusPercent) /100);
// 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);
else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ARMY && gGameExternalOptions.sEnemyRegularCtHBonusPercent != 0)
iChance += ((iChance * gGameExternalOptions.sEnemyRegularCtHBonusPercent) /100);
@@ -11801,7 +11776,7 @@ FLOAT CalcNewChanceToHitBaseSpecialBonus(SOLDIERTYPE *pSoldier)
else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA && gGameExternalOptions.sVeteranMilitiaCtHBonusPercent != 0)
fBaseModifier += gGameExternalOptions.sVeteranMilitiaCtHBonusPercent;
// 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;
else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ARMY && gGameExternalOptions.sEnemyRegularCtHBonusPercent != 0)
fBaseModifier += gGameExternalOptions.sEnemyRegularCtHBonusPercent;
+15 -14
View File
@@ -4870,18 +4870,19 @@ void DebugSoldierPage4( )
switch( pSoldier->ubSoldierClass )
{
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_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_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_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_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_MINER: gprintf( 320, LINE_HEIGHT * ubLine, L"(Miner)" ); break;
case SOLDIER_CLASS_ZOMBIE: gprintf( 320, LINE_HEIGHT * ubLine, L"(Zombie)" ); 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_BANDIT: gprintf( 320, LINE_HEIGHT * ubLine, L"(Bandit)" ); break;
default: break; //don't care (don't write anything)
}
ubLine++;
++ubLine;
if( pSoldier->bTeam != OUR_TEAM )
{
@@ -7785,19 +7786,19 @@ void MakeBloodcatsHostile( void )
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 )
{
SetSoldierNonNeutral( pSoldier );
RecalculateOppCntsDueToNoLongerNeutral( pSoldier );
if ( ( gTacticalStatus.uiFlags & INCOMBAT ) )
{
CheckForPotentialAddToBattleIncrement( pSoldier );
}
SetSoldierNonNeutral( pSoldier );
RecalculateOppCntsDueToNoLongerNeutral( pSoldier );
if ( ( gTacticalStatus.uiFlags & INCOMBAT ) )
{
CheckForPotentialAddToBattleIncrement( pSoldier );
}
}
}
}
BOOLEAN SoldierHasLimitedVision(SOLDIERTYPE * pSoldier)
+7 -7
View File
@@ -2293,12 +2293,11 @@ INT8 CalcMorale(SOLDIERTYPE *pSoldier)
case AGGRESSIVE: bMoraleCategory++; break;
}
// make idiot administrators much more aggressive
if ( pSoldier->ubSoldierClass == SOLDIER_CLASS_ADMINISTRATOR )
{
bMoraleCategory += 2;
}
// make idiot administrators much more aggressive
if ( pSoldier->ubSoldierClass == SOLDIER_CLASS_ADMINISTRATOR || pSoldier->ubSoldierClass == SOLDIER_CLASS_BANDIT )
{
bMoraleCategory += 2;
}
// if still full of energy
if (pSoldier->bBreath > 75)
@@ -2737,6 +2736,7 @@ UINT8 SoldierDifficultyLevel( SOLDIERTYPE * pSoldier )
switch( pSoldier->ubSoldierClass )
{
case SOLDIER_CLASS_ADMINISTRATOR:
case SOLDIER_CLASS_BANDIT:
bDifficulty = bDifficultyBase - 1;
break;
@@ -3543,7 +3543,7 @@ INT8 CalcMoraleNew(SOLDIERTYPE *pSoldier)
}
// make idiot administrators more aggressive
if ( pSoldier->ubSoldierClass == SOLDIER_CLASS_ADMINISTRATOR )
if ( pSoldier->ubSoldierClass == SOLDIER_CLASS_ADMINISTRATOR || pSoldier->ubSoldierClass == SOLDIER_CLASS_BANDIT )
{
bMoraleCategory += 2;
}
+1 -1
View File
@@ -1409,7 +1409,7 @@ INT8 DecideActionGreen(SOLDIERTYPE *pSoldier)
iChance = 25;
if ( pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA || pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE )
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;
if ( Random(100) < iChance )
{
+9
View File
@@ -1887,6 +1887,15 @@ enum
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
};
+9
View File
@@ -3514,6 +3514,15 @@ STR16 gpStrategicString[] =
L"吉普", // L"Jeep", STR_AR_JEEP_NAME
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[] =
+9
View File
@@ -3514,6 +3514,15 @@ STR16 gpStrategicString[] =
L"Jeep", //STR_AR_JEEP_NAME // TODO.Translate
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[] =
+9
View File
@@ -3514,6 +3514,15 @@ STR16 gpStrategicString[] =
L"Jeep", //STR_AR_JEEP_NAME,
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[] =
+9
View File
@@ -3522,6 +3522,15 @@ STR16 gpStrategicString[] =
L"Jeep", //STR_AR_JEEP_NAME // TODO.Translate
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[] =
+9
View File
@@ -3525,6 +3525,15 @@ STR16 gpStrategicString[] =
L"Jeep", //STR_AR_JEEP_NAME // TODO.Translate
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[] =
+9
View File
@@ -3509,6 +3509,15 @@ STR16 gpStrategicString[] =
L"Jeep", //STR_AR_JEEP_NAME // TODO.Translate
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[] =
+9
View File
@@ -3520,6 +3520,15 @@ STR16 gpStrategicString[] =
L"Jeep", //STR_AR_JEEP_NAME // TODO.Translate
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[] =
+9
View File
@@ -3514,6 +3514,15 @@ STR16 gpStrategicString[] =
L"Джип", //STR_AR_JEEP_NAME
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[] =