- Made the "Zombie MOD" optional, so we can decide if we like to build an executable with/without the appearance of zombies

o See: builddefines.h: #define ENABLE_ZOMBIES (then you can turn on/off Zombies in the ingame option screen)
o Poison system is still in the code and not combined with the option "Zombie MOD"
o Gamers reported on the Bears Pit, that an executable compiled WITH the Zombies mod enabled makes the game unplayable slow in tactical screen after a few minutes in turn based/realtime



git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@5356 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
Wanne
2012-07-04 10:30:13 +00:00
parent e8027d6663
commit f40e7fb118
42 changed files with 2827 additions and 2479 deletions
+9 -1
View File
@@ -254,7 +254,9 @@ BOOLEAN LoadGameSettings()
gGameSettings.fOptions[TOPTION_AUTO_FAST_FORWARD_MODE] = FALSE;
#endif
#ifdef ENABLE_ZOMBIES
gGameSettings.fOptions[TOPTION_ZOMBIES] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_ZOMBIES" , FALSE );
#endif
gGameSettings.fOptions[NUM_ALL_GAME_OPTIONS] = iniReader.ReadBoolean("JA2 Game Settings","NUM_ALL_GAME_OPTIONS" , FALSE );
@@ -417,7 +419,10 @@ BOOLEAN SaveGameSettings()
settings << "TOPTION_AUTO_FAST_FORWARD_MODE = " << (gGameSettings.fOptions[TOPTION_AUTO_FAST_FORWARD_MODE] ? "TRUE" : "FALSE" ) << endl;
#endif
#ifdef ENABLE_ZOMBIES
settings << "TOPTION_ZOMBIES = " << (gGameSettings.fOptions[TOPTION_ZOMBIES] ? "TRUE" : "FALSE" ) << endl;
#endif
settings << "TOPTION_CHEAT_MODE_OPTIONS_HEADER = " << (gGameSettings.fOptions[TOPTION_CHEAT_MODE_OPTIONS_HEADER] ? "TRUE" : "FALSE" ) << endl;
settings << "TOPTION_FORCE_BOBBY_RAY_SHIPMENTS = " << (gGameSettings.fOptions[TOPTION_FORCE_BOBBY_RAY_SHIPMENTS] ? "TRUE" : "FALSE" ) << endl;
settings << "TOPTION_CHEAT_MODE_OPTIONS_END = " << (gGameSettings.fOptions[TOPTION_CHEAT_MODE_OPTIONS_END] ? "TRUE" : "FALSE" ) << endl;
@@ -549,8 +554,9 @@ void InitGameSettings()
gGameSettings.fOptions[ TOPTION_AUTO_FAST_FORWARD_MODE ] = FALSE;
#endif
#ifdef ENABLE_ZOMBIES
gGameSettings.fOptions[ TOPTION_ZOMBIES ] = FALSE; // Flugente Zombies 1.0
#endif
// arynn: Cheat/Debug Menu
gGameSettings.fOptions[ TOPTION_CHEAT_MODE_OPTIONS_HEADER ] = FALSE;
@@ -1357,6 +1363,7 @@ void LoadGameExternalOptions()
gGameExternalOptions.iCooldownModificatorLonelyBarrel = iniReader.ReadFloat ("Tactical Weapon Overheating Settings","OVERHEATING_COOLDOWN_MODIFICATOR_LONELYBARREL", 1.15f, 1.0f, 10.0f);
gGameExternalOptions.fSetZeroUponNewSector = iniReader.ReadBoolean("Tactical Weapon Overheating Settings","OVERHEATING_SET_ZERO_UPON_NEW_SECTOR",TRUE);
#ifdef ENABLE_ZOMBIES
//################# Tactical Zombie Settings ##################
gGameExternalOptions.sZombieRiseBehaviour = iniReader.ReadInteger("Tactical Zombie Settings", "ZOMBIE_RISE_BEHAVIOUR", 0, 0, 3);
gGameExternalOptions.fZombieSpawnWaves = iniReader.ReadInteger("Tactical Zombie Settings", "ZOMBIE_SPAWN_WAVES", FALSE);
@@ -1368,6 +1375,7 @@ void LoadGameExternalOptions()
gGameExternalOptions.fZombieOnlyHeadshotsWork = iniReader.ReadBoolean("Tactical Zombie Settings", "ZOMBIE_ONLY_HEADSHOTS_WORK", FALSE);
gGameExternalOptions.sZombieDifficultyLevel = iniReader.ReadInteger("Tactical Zombie Settings", "ZOMBIE_DIFFICULTY_LEVEL", 2, 1, 4);
gGameExternalOptions.fZombieRiseWithArmour = iniReader.ReadBoolean("Tactical Zombie Settings", "ZOMBIE_RISE_WITH_ARMOUR", TRUE);
#endif
//################# Tactical Poison Settings ##################
gGameExternalOptions.ubPoisonBaseMedicalSkillToCure = iniReader.ReadInteger("Tactical Poison Settings", "POISON_BASE_MEDICAL_SKILL_TO_CURE", 50, 1, 100);
+4
View File
@@ -95,7 +95,9 @@ enum
TOPTION_AUTO_FAST_FORWARD_MODE, // automatically fast forward through AI turns
#endif
#ifdef ENABLE_ZOMBIES
TOPTION_ZOMBIES, // Flugente Zombies 1.0: allow zombies
#endif
// arynn: Debug/Cheat
TOPTION_CHEAT_MODE_OPTIONS_HEADER,
@@ -369,6 +371,7 @@ typedef struct
//Video settings
BOOLEAN gfVSync;
#ifdef ENABLE_ZOMBIES
// Flugente: zombie settings
INT8 sZombieRiseBehaviour;
BOOLEAN fZombieSpawnWaves;
@@ -380,6 +383,7 @@ typedef struct
BOOLEAN fZombieOnlyHeadshotsWork;
INT8 sZombieDifficultyLevel;
BOOLEAN fZombieRiseWithArmour;
#endif
// Flugente: poison settings
INT32 ubPoisonBaseMedicalSkillToCure;
+13
View File
@@ -4959,7 +4959,12 @@ void DisplayDepartedCharStats(INT32 iId, INT32 iSlot, INT32 iState)
case 14:
// kills
mprintf((INT16)(pPersonnelScreenPoints[20].x+(iSlot*TEXT_BOX_WIDTH)),(pPersonnelScreenPoints[20].y - 12),pPersonnelScreenStrings[PRSNL_TXT_KILLS]);
#ifdef ENABLE_ZOMBIES
swprintf(sString, L"%d",(gMercProfiles[iId].records.usKillsElites + gMercProfiles[iId].records.usKillsRegulars + gMercProfiles[iId].records.usKillsAdmins + gMercProfiles[iId].records.usKillsHostiles + gMercProfiles[iId].records.usKillsCreatures + gMercProfiles[iId].records.usKillsZombies + gMercProfiles[iId].records.usKillsTanks + gMercProfiles[iId].records.usKillsOthers));
#else
swprintf(sString, L"%d",(gMercProfiles[iId].records.usKillsElites + gMercProfiles[iId].records.usKillsRegulars + gMercProfiles[iId].records.usKillsAdmins + gMercProfiles[iId].records.usKillsHostiles + gMercProfiles[iId].records.usKillsCreatures + gMercProfiles[iId].records.usKillsTanks + gMercProfiles[iId].records.usKillsOthers));
#endif
FindFontRightCoordinates((INT16)(pPersonnelScreenPoints[20].x+(iSlot*TEXT_BOX_WIDTH)),0,TEXT_BOX_WIDTH-20,0,sString, PERS_FONT, &sX, &sY);
mprintf(sX,(pPersonnelScreenPoints[20].y - 12),sString);
@@ -6828,7 +6833,12 @@ DEF:3/19/99:
case 14:
// kills
mprintf((INT16)(pPersonnelScreenPoints[20].x+(iSlot*TEXT_BOX_WIDTH)),(pPersonnelScreenPoints[20].y - 12),pPersonnelScreenStrings[PRSNL_TXT_KILLS]);
#ifdef ENABLE_ZOMBIES
swprintf(sString, L"%d",(gMercProfiles[Menptr[iId].ubProfile].records.usKillsElites + gMercProfiles[Menptr[iId].ubProfile].records.usKillsRegulars + gMercProfiles[Menptr[iId].ubProfile].records.usKillsAdmins + gMercProfiles[Menptr[iId].ubProfile].records.usKillsHostiles + gMercProfiles[Menptr[iId].ubProfile].records.usKillsCreatures + gMercProfiles[Menptr[iId].ubProfile].records.usKillsZombies + gMercProfiles[Menptr[iId].ubProfile].records.usKillsTanks + gMercProfiles[Menptr[iId].ubProfile].records.usKillsOthers));
#else
swprintf(sString, L"%d",(gMercProfiles[Menptr[iId].ubProfile].records.usKillsElites + gMercProfiles[Menptr[iId].ubProfile].records.usKillsRegulars + gMercProfiles[Menptr[iId].ubProfile].records.usKillsAdmins + gMercProfiles[Menptr[iId].ubProfile].records.usKillsHostiles + gMercProfiles[Menptr[iId].ubProfile].records.usKillsCreatures + gMercProfiles[Menptr[iId].ubProfile].records.usKillsTanks + gMercProfiles[Menptr[iId].ubProfile].records.usKillsOthers));
#endif
FindFontRightCoordinates((INT16)(pPersonnelScreenPoints[20].x+(iSlot*TEXT_BOX_WIDTH)),0,TEXT_BOX_WIDTH-20,0,sString, PERS_FONT, &sX, &sY);
mprintf(sX,(pPersonnelScreenPoints[20].y - 12),sString);
@@ -8239,6 +8249,8 @@ void AssignPersonnelKillsHelpText( INT32 IMercId )
swprintf(atStr, pPersonnelRecordsHelpTexts[ 6 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usKillsOthers );
wcscat( apStr, atStr );
}
#ifdef ENABLE_ZOMBIES
if (gGameSettings.fOptions[TOPTION_ZOMBIES] )
{
if (gMercProfiles[Menptr[IMercId].ubProfile].records.usKillsZombies > 0 || fShowRecordsIfZero)
@@ -8247,6 +8259,7 @@ void AssignPersonnelKillsHelpText( INT32 IMercId )
wcscat( apStr, atStr );
}
}
#endif
// Set region help text
SetRegionFastHelpText( &(gSkillTraitHelpTextRegion[7]), apStr );
Binary file not shown.
+4
View File
@@ -4598,9 +4598,11 @@ void AttackTarget( SOLDIERCELL *pAttacker, SOLDIERCELL *pTarget )
case SOLDIER_CLASS_CREATURE :
gMercProfiles[ pAttacker->pSoldier->ubProfile ].records.usKillsCreatures++;
break;
#ifdef ENABLE_ZOMBIES
case SOLDIER_CLASS_ZOMBIE :
gMercProfiles[ pAttacker->pSoldier->ubProfile ].records.usKillsZombies++;
break;
#endif
default :
if ( CREATURE_OR_BLOODCAT( pTarget->pSoldier ) )
gMercProfiles[ pAttacker->pSoldier->ubProfile ].records.usKillsCreatures++;
@@ -4789,9 +4791,11 @@ void TargetHitCallback( SOLDIERCELL *pTarget, INT32 index )
case SOLDIER_CLASS_CREATURE :
gMercProfiles[ pKiller->pSoldier->ubProfile ].records.usKillsCreatures++;
break;
#ifdef ENABLE_ZOMBIES
case SOLDIER_CLASS_ZOMBIE :
gMercProfiles[ pKiller->pSoldier->ubProfile ].records.usKillsZombies++;
break;
#endif
default :
if ( CREATURE_OR_BLOODCAT( pTarget->pSoldier ) )
gMercProfiles[ pKiller->pSoldier->ubProfile ].records.usKillsCreatures++;
+3
View File
@@ -820,7 +820,10 @@ void EndMeanwhile( )
{
// We leave this sector open for our POWs to escape!
// Set music mode to enemy present!
#ifdef ENABLE_ZOMBIES
UseCreatureMusic(HostileZombiesPresent());
#endif
SetMusicMode( MUSIC_TACTICAL_ENEMYPRESENT );
// ATE: Restore people to saved positions...
+3
View File
@@ -867,7 +867,10 @@ void InitPreBattleInterface( GROUP *pBattleGroup, BOOLEAN fPersistantPBI )
//Disable the options button when the auto resolve screen comes up
EnableDisAbleMapScreenOptionsButton( FALSE );
#ifdef ENABLE_ZOMBIES
UseCreatureMusic(HostileZombiesPresent());
#endif
SetMusicMode( MUSIC_TACTICAL_ENEMYPRESENT );
#ifdef JA2UB
+3
View File
@@ -959,7 +959,10 @@ void PrepareForPreBattleInterface( GROUP *pPlayerDialogGroup, GROUP *pInitiating
}
//Set music
#ifdef ENABLE_ZOMBIES
UseCreatureMusic(HostileZombiesPresent());
#endif
SetMusicMode( MUSIC_TACTICAL_ENEMYPRESENT );
if( gfTacticalTraversal && pInitiatingBattleGroup == gpTacticalTraversalGroup ||
+2
View File
@@ -1035,9 +1035,11 @@ void StartEnemyTaunt( SOLDIERTYPE *pCiv, INT8 iTauntType )
VIDEO_OVERLAY_DESC VideoOverlayDesc;
CHAR16 gzTauntQuote[ 320 ];
#ifdef ENABLE_ZOMBIES
// Flugente: zombies don't talk
if ( pCiv->IsZombie() )
return;
#endif
// if we have a different quote on, return, this one is not important
if ( gCivQuoteData.bActive )
+30 -25
View File
@@ -1926,13 +1926,8 @@ void InternalInitEDBTooltipRegion( OBJECTTYPE * gpItemDescObject, UINT32 guiCurr
}
}
if ( gGameSettings.fOptions[TOPTION_ZOMBIES] ) // Flugente Zombies
{
//////////////////// POISON PERCENTAGE
{
MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 4 ] );
}
}
//////////////////// POISON PERCENTAGE
MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 4 ] );
}
}
@@ -3864,10 +3859,11 @@ void InternalInitEDBTooltipRegion( OBJECTTYPE * gpItemDescObject, UINT32 guiCurr
}
}
}
//#ifdef ENABLE_ZOMBIES
// Flugente Zombies
if ( gGameSettings.fOptions[TOPTION_ZOMBIES] )
{
//if ( gGameSettings.fOptions[TOPTION_ZOMBIES] )
//{
if(!cnt) cnt += 2;
if (cnt >= sFirstLine && cnt < sLastLine)
@@ -3908,7 +3904,8 @@ void InternalInitEDBTooltipRegion( OBJECTTYPE * gpItemDescObject, UINT32 guiCurr
}
cnt++;
}
}
//}
//#endif
gubDescBoxTotalAdvLines = (UINT8)cnt;
}
@@ -4304,13 +4301,15 @@ void DrawAmmoStats( OBJECTTYPE * gpItemDescObject )
BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAmmoIcon, 16, gItemDescGenRegions[3][0].sLeft+sOffsetX, gItemDescGenRegions[3][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL );
}
}
if ( gGameSettings.fOptions[TOPTION_ZOMBIES] ) // Flugente Zombies
{
//#ifdef ENABLE_ZOMBIES
//if ( gGameSettings.fOptions[TOPTION_ZOMBIES] ) // Flugente Zombies
//{
//////////////// POISON PERCENTAGE
{
//{
BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWH40KIcon, 6, gItemDescGenRegions[4][0].sLeft+sOffsetX, gItemDescGenRegions[4][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL );
}
}
//}
//}
//#endif
DrawSecondaryStats( gpItemDescObject );
}
@@ -5198,9 +5197,10 @@ void DrawAdvancedStats( OBJECTTYPE * gpItemDescObject )
}
}
//#ifdef ENABLE_ZOMBIES
// Flugente Zombies
if ( gGameSettings.fOptions[TOPTION_ZOMBIES] )
{
// if ( gGameSettings.fOptions[TOPTION_ZOMBIES] )
// {
if(!cnt) cnt += 2;
++cnt; // for the new index-line
@@ -5215,7 +5215,8 @@ void DrawAdvancedStats( OBJECTTYPE * gpItemDescObject )
}
cnt++;
}
}
//}
//#endif
}
void DrawMiscStats( OBJECTTYPE * gpItemDescObject )
@@ -7597,8 +7598,9 @@ void DrawAmmoValues( OBJECTTYPE * gpItemDescObject, int shotsLeft )
mprintf( usX, usY, pStr );
}
if ( gGameSettings.fOptions[TOPTION_ZOMBIES] ) // Flugente Zombies
{
//#ifdef ENABLE_ZOMBIES
// if ( gGameSettings.fOptions[TOPTION_ZOMBIES] ) // Flugente Zombies
// {
///////////////////// POISON PERCENTAGE
// Set line to draw into
ubNumLine = 4;
@@ -7648,7 +7650,8 @@ void DrawAmmoValues( OBJECTTYPE * gpItemDescObject, int shotsLeft )
swprintf( pStr, L"%d", finalvalue );
FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY);
mprintf( usX, usY, pStr );
}
// }
//#endif
}
else if (gubDescBoxPage == 2)
{
@@ -11170,8 +11173,9 @@ void DrawAdvancedValues( OBJECTTYPE *gpItemDescObject )
}
// Flugente Zombies
if ( gGameSettings.fOptions[TOPTION_ZOMBIES] )
{
//#ifdef USE_ZOMBIES
// if ( gGameSettings.fOptions[TOPTION_ZOMBIES] )
//{
///////////////////////////////////////////////////// INDEXES
if(!cnt) cnt += 2;
@@ -11252,7 +11256,8 @@ void DrawAdvancedValues( OBJECTTYPE *gpItemDescObject )
}
cnt++;
}
}
//}
//#endif
}
void DrawMiscValues( OBJECTTYPE * gpItemDescObject )
+2
View File
@@ -2211,6 +2211,7 @@ void DrawSelectedUIAboveGuy( UINT16 usSoldierID )
}
}
#ifdef ENABLE_ZOMBIES
if ( pSoldier->IsZombie() )
{
swprintf(NameStr, pSoldier->name);
@@ -2225,6 +2226,7 @@ void DrawSelectedUIAboveGuy( UINT16 usSoldierID )
gprintfdirty( sX, sY, NameStr );
mprintf( sX, sY, NameStr );
}
#endif
//------------
}
}
+8
View File
@@ -847,9 +847,11 @@ void GenerateRandomEquipment( SOLDIERCREATE_STRUCT *pp, INT8 bSoldierClass, INT8
}
break;
#ifdef ENABLE_ZOMBIES
case SOLDIER_CLASS_ZOMBIE:
// zombies get no items at all...
break;
#endif
}
for ( i = 0; i < pp->Inv.size(); i++ )
@@ -1056,8 +1058,11 @@ void ChooseWeaponForSoldierCreateStruct( SOLDIERCREATE_STRUCT *pp, INT8 bWeaponC
bStatus += (INT8)(HighestPlayerProgressPercentage() / 10);
bStatus = (INT8)min( 100, bStatus );
break;
#ifdef ENABLE_ZOMBIES
case SOLDIER_CLASS_ZOMBIE:
bStatus = (INT8)(1); // if a zombie gets anything, it'll be broken
#endif
default:
bStatus = (INT8)(50 + Random( 51 ) );
break;
@@ -2111,8 +2116,11 @@ void ChooseFaceGearForSoldierCreateStruct( SOLDIERCREATE_STRUCT *pp )
break;
case SOLDIER_CLASS_ADMINISTRATOR:
case SOLDIER_CLASS_GREEN_MILITIA:
#ifdef ENABLE_ZOMBIES
case SOLDIER_CLASS_ZOMBIE:
#endif
break;
}
}
+4
View File
@@ -907,8 +907,12 @@ void HandleFirstHeliDropOfGame( )
{
// Say quote.....
SayQuoteFromAnyBodyInSector( QUOTE_ENEMY_PRESENCE );
// Start music
#ifdef ENABLE_ZOMBIES
UseCreatureMusic(HostileZombiesPresent());
#endif
SetMusicMode( MUSIC_TACTICAL_ENEMYPRESENT );
}
else
+50 -32
View File
@@ -6186,7 +6186,10 @@ void ExitCombatMode( )
// unused
//gfForceMusicToTense = TRUE;
#ifdef ENABLE_ZOMBIES
UseCreatureMusic(HostileZombiesPresent());
#endif
SetMusicMode( MUSIC_TACTICAL_ENEMYPRESENT );
BetweenTurnsVisibilityAdjustments();
@@ -6245,7 +6248,11 @@ void SetEnemyPresence( )
#endif
{
#ifdef ENABLE_ZOMBIES
UseCreatureMusic(HostileZombiesPresent());
#endif
SetMusicMode( MUSIC_TACTICAL_ENEMYPRESENT );
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("SetEnemyPresence: warnings = false"));
sniperwarning = FALSE;
@@ -6583,7 +6590,10 @@ BOOLEAN CheckForEndOfCombatMode( BOOLEAN fIncrementTurnsNotSeen )
// Begin tense music....
// unused
//gfForceMusicToTense = TRUE;
#ifdef ENABLE_ZOMBIES
UseCreatureMusic(HostileZombiesPresent());
#endif
SetMusicMode( MUSIC_TACTICAL_ENEMYPRESENT );
return( TRUE );
@@ -6682,8 +6692,10 @@ BOOLEAN CheckForEndOfBattle( BOOLEAN fAnEnemyRetreated )
return( FALSE );
}
#ifdef ENABLE_ZOMBIES
if ( HostileZombiesPresent() ) //Madd: got tired of the victory music playing right after the zombies arose
return FALSE;
#endif
// OK, this is to releave infinate looping...becasue we can kill guys in this function
if ( gfKillingGuysForLosingBattle )
@@ -7267,25 +7279,27 @@ UINT8 NumEnemyInSector( )
}
UINT8 NumZombiesInSector( )
{
SOLDIERTYPE *pTeamSoldier;
INT32 cnt = 0;
UINT8 ubNumZombies = 0;
for ( pTeamSoldier = Menptr, cnt = 0; cnt < TOTAL_SOLDIERS; ++pTeamSoldier, ++cnt )
#ifdef ENABLE_ZOMBIES
UINT8 NumZombiesInSector( )
{
if ( pTeamSoldier->bActive && pTeamSoldier->bInSector && pTeamSoldier->stats.bLife > 0 )
SOLDIERTYPE *pTeamSoldier;
INT32 cnt = 0;
UINT8 ubNumZombies = 0;
for ( pTeamSoldier = Menptr, cnt = 0; cnt < TOTAL_SOLDIERS; ++pTeamSoldier, ++cnt )
{
if ( pTeamSoldier->IsZombie() )
if ( pTeamSoldier->bActive && pTeamSoldier->bInSector && pTeamSoldier->stats.bLife > 0 )
{
++ubNumZombies;
if ( pTeamSoldier->IsZombie() )
{
++ubNumZombies;
}
}
}
}
return( ubNumZombies );
}
return( ubNumZombies );
}
#endif
UINT8 NumEnemyInSectorExceptCreatures()
{
@@ -7799,9 +7813,11 @@ void HandleSuppressionFire( UINT8 ubTargetedMerc, UINT8 ubCausedAttacker )
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("HandleSuppressionFire: loop = %d, numslots = %d ",uiLoop, guiNumMercSlots));
pSoldier = MercSlots[uiLoop];
#ifdef ENABLE_ZOMBIES
// Flugente: zombies do not receive any suppression at all!
if ( pSoldier != NULL && pSoldier->IsZombie() )
continue;
#endif
// Has this character received any Suppression Points since the last attack?
// HEADROCK: Suppression Points accumulate by bullets flying near the character. It includes
@@ -9286,28 +9302,30 @@ BOOLEAN HostileBloodcatsPresent( void )
return( FALSE );
}
BOOLEAN HostileZombiesPresent( void )
{
INT32 iLoop;
SOLDIERTYPE * pSoldier;
if ( gTacticalStatus.Team[ CREATURE_TEAM ].bTeamActive == FALSE )
#ifdef ENABLE_ZOMBIES
BOOLEAN HostileZombiesPresent( void )
{
INT32 iLoop;
SOLDIERTYPE * pSoldier;
if ( gTacticalStatus.Team[ CREATURE_TEAM ].bTeamActive == FALSE )
{
return( FALSE );
}
for ( iLoop = gTacticalStatus.Team[ CREATURE_TEAM ].bFirstID; iLoop <= gTacticalStatus.Team[ CREATURE_TEAM ].bLastID; iLoop++ )
{
pSoldier = MercPtrs[ iLoop ];
if ( pSoldier->bActive && pSoldier->bInSector && pSoldier->stats.bLife > 0 && pSoldier->IsZombie() )
{
return( TRUE );
}
}
return( FALSE );
}
for ( iLoop = gTacticalStatus.Team[ CREATURE_TEAM ].bFirstID; iLoop <= gTacticalStatus.Team[ CREATURE_TEAM ].bLastID; iLoop++ )
{
pSoldier = MercPtrs[ iLoop ];
if ( pSoldier->bActive && pSoldier->bInSector && pSoldier->stats.bLife > 0 && pSoldier->IsZombie() )
{
return( TRUE );
}
}
return( FALSE );
}
#endif
void HandleCreatureTenseQuote( )
{
+9 -3
View File
@@ -362,7 +362,10 @@ void DoPOWPathChecks( void );
BOOLEAN HostileCiviliansWithGunsPresent( void );
BOOLEAN HostileCiviliansPresent( void );
BOOLEAN HostileBloodcatsPresent( void );
BOOLEAN HostileZombiesPresent( void );
#ifdef ENABLE_ZOMBIES
BOOLEAN HostileZombiesPresent( void );
#endif
UINT8 NumPCsInSector( void );
@@ -396,6 +399,9 @@ BOOLEAN WillAirRaidBeStopped( INT16 sSectorX, INT16 sSectorY );
// HEADROCK HAM 3.5: Externalized for First Arrival enemy check
extern UINT8 NumEnemyInSector();
// Flugente
extern UINT8 NumZombiesInSector();
#ifdef ENABLE_ZOMBIES
// Flugente
extern UINT8 NumZombiesInSector();
#endif
#endif
+395 -383
View File
@@ -44,8 +44,7 @@
#include "qarray.h"
#include "Interface.h"
#include "Music Control.h"
#include "Campaign Types.h"
//#include "Queen Command.h"
#include "Campaign Types.h"
#include "text.h" // added by Flugente
#endif
@@ -584,9 +583,11 @@ INT32 AddRottingCorpse( ROTTING_CORPSE_DEFINITION *pCorpseDef )
pCorpse->pAniTile->uiUserData = iIndex;
pCorpse->iID = iIndex;
#ifdef ENABLE_ZOMBIES
// copy name of corpse definition...
memcpy( &(pCorpse->name), &(pCorpseDef->name), sizeof(CHAR16) * 10 );
pCorpse->name[9] = '\0';
#endif
pCorpse->fActivated = TRUE;
@@ -861,6 +862,7 @@ BOOLEAN TurnSoldierIntoCorpse( SOLDIERTYPE *pSoldier, BOOLEAN fRemoveMerc, BOOLE
Corpse.usFlags |= ROTTING_CORPSE_USE_SNOW_CAMO_PALETTE;
}
#ifdef ENABLE_ZOMBIES
// Flugente Zombies: Determine if a zombie can rise from this corpse
switch ( gGameExternalOptions.sZombieRiseBehaviour )
{
@@ -891,6 +893,7 @@ BOOLEAN TurnSoldierIntoCorpse( SOLDIERTYPE *pSoldier, BOOLEAN fRemoveMerc, BOOLE
// Flugente: copy name of soldier...
memcpy( &(Corpse.name), &(pSoldier->name), sizeof(CHAR16) * 10 );
Corpse.name[9] = '\0';
#endif
// Determine corpse type!
ubType = (UINT8)gubAnimSurfaceCorpseID[ pSoldier->ubBodyType][ pSoldier->usAnimState ];
@@ -2085,436 +2088,445 @@ UINT8 GetNearestRottingCorpseAIWarning( INT32 sGridNo )
return( ubHighestWarning );
}
// Flugente Zombies: resurrect zombies
void RaiseZombies( void )
{
if ( gGameSettings.fOptions[TOPTION_ZOMBIES] )
#ifdef ENABLE_ZOMBIES
// Flugente Zombies: resurrect zombies
void RaiseZombies( void )
{
// if gGameExternalOptions.fZombieSpawnWaves is true, zombies will spawn from all corpses (while there is still room for more), creating a wave of zombies. with lots of bodies lying around, this can be a lot.
// if GameExternalOptions.fZombieSpawnWaves is false, each zombie can spawn randomly, you will get zombies on msot turns, but they won't spawn a whole horde at once
if ( ( gGameExternalOptions.fZombieSpawnWaves && (INT8) ( Random( 100 ) ) > 100 - gGameExternalOptions.sZombieRiseWaveFrequency ) || !gGameExternalOptions.fZombieSpawnWaves )
if ( gGameSettings.fOptions[TOPTION_ZOMBIES] )
{
ROTTING_CORPSE * pCorpse;
BOOLEAN zombieshaverisen = FALSE;
SECTORINFO *pSector = &SectorInfo[ SECTOR( gWorldSectorX, gWorldSectorY ) ];
for ( INT32 cnt = giNumRottingCorpse - 1; cnt >= 0; --cnt )
// if gGameExternalOptions.fZombieSpawnWaves is true, zombies will spawn from all corpses (while there is still room for more), creating a wave of zombies. with lots of bodies lying around, this can be a lot.
// if GameExternalOptions.fZombieSpawnWaves is false, each zombie can spawn randomly, you will get zombies on msot turns, but they won't spawn a whole horde at once
if ( ( gGameExternalOptions.fZombieSpawnWaves && (INT8) ( Random( 100 ) ) > 100 - gGameExternalOptions.sZombieRiseWaveFrequency ) || !gGameExternalOptions.fZombieSpawnWaves )
{
if ( pSector->ubNumCreatures < gGameExternalOptions.ubGameMaximumNumberOfCreatures ) // ... if there is still room for more zombies (zombies count as creatures until a separate ZOMBIE_TEAM is implemented)...
ROTTING_CORPSE * pCorpse;
BOOLEAN zombieshaverisen = FALSE;
SECTORINFO *pSector = &SectorInfo[ SECTOR( gWorldSectorX, gWorldSectorY ) ];
for ( INT32 cnt = giNumRottingCorpse - 1; cnt >= 0; --cnt )
{
pCorpse = &(gRottingCorpse[ cnt ] );
// if zombies should spawn individually, roll for every corpse individually
if ( gGameExternalOptions.fZombieSpawnWaves || ( !gGameExternalOptions.fZombieSpawnWaves && (INT8) ( Random( 100 ) ) > 100 - gGameExternalOptions.sZombieRiseWaveFrequency ) )
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 ( pCorpse->fActivated && pCorpse->def.fHeadTaken == FALSE ) // ... if corpse is active, and still has a head ...
pCorpse = &(gRottingCorpse[ cnt ] );
// if zombies should spawn individually, roll for every corpse individually
if ( gGameExternalOptions.fZombieSpawnWaves || ( !gGameExternalOptions.fZombieSpawnWaves && (INT8) ( Random( 100 ) ) > 100 - gGameExternalOptions.sZombieRiseWaveFrequency ) )
{
if ( !(pCorpse->def.usFlags & ROTTING_CORPSE_NEVER_RISE_AGAIN) ) // ... if corpse is already that of a zombie, don't create zombie again ...
if ( pCorpse->fActivated && pCorpse->def.fHeadTaken == FALSE ) // ... if corpse is active, and still has a head ...
{
if ( !TileIsOutOfBounds(pCorpse->def.sGridNo) ) // ... if corpse is on existing coordinates ...
{
if ( WhoIsThere2( pCorpse->def.sGridNo, pCorpse->def.bLevel ) == NOBODY ) // ... if nobody else is on that position ...
{
UINT16 recanimstate = STANDING;
if ( !(pCorpse->def.usFlags & ROTTING_CORPSE_NEVER_RISE_AGAIN) ) // ... if corpse is already that of a zombie, don't create zombie again ...
{
if ( !TileIsOutOfBounds(pCorpse->def.sGridNo) ) // ... if corpse is on existing coordinates ...
{
if ( WhoIsThere2( pCorpse->def.sGridNo, pCorpse->def.bLevel ) == NOBODY ) // ... if nobody else is on that position ...
{
UINT16 recanimstate = STANDING;
if ( CorpseOkToSpawnZombie( pCorpse, &recanimstate ) ) // ... a zombie can be created from this corpse, in the corresponding animstate ...
{
zombieshaverisen = TRUE;
CreateZombiefromCorpse( pCorpse, recanimstate );
if ( CorpseOkToSpawnZombie( pCorpse, &recanimstate ) ) // ... a zombie can be created from this corpse, in the corresponding animstate ...
{
zombieshaverisen = TRUE;
CreateZombiefromCorpse( pCorpse, recanimstate );
//++pSector->ubNumZombies;
//++pSector->ubZombiesInBattle;
//++pSector->ubNumZombies;
//++pSector->ubZombiesInBattle;
RemoveCorpse( cnt );
RemoveCorpse( cnt );
}
}
}
}
}
}
}
else
{
// if there is no more room, we can skip this
break;
}
}
else
if ( zombieshaverisen )
{
// if there is no more room, we can skip this
break;
SetRenderFlags( RENDER_FLAG_FULL );
#ifdef JA2TESTVERSION
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_BETAVERSION, L"A wave of zombies is created");
#endif
// Play sound
PlayJA2SampleFromFile( "Sounds\\zombie1.wav", RATE_11025, HIGHVOLUME, 1, MIDDLEPAN );
UseCreatureMusic(TRUE); // Madd: music when zombies rise
SetMusicMode( MUSIC_TACTICAL_ENEMYPRESENT );
}
}
if ( zombieshaverisen )
{
SetRenderFlags( RENDER_FLAG_FULL );
#ifdef JA2TESTVERSION
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_BETAVERSION, L"A wave of zombies is created");
#endif
// Play sound
PlayJA2SampleFromFile( "Sounds\\zombie1.wav", RATE_11025, HIGHVOLUME, 1, MIDDLEPAN );
UseCreatureMusic(TRUE); // Madd: music when zombies rise
SetMusicMode( MUSIC_TACTICAL_ENEMYPRESENT );
}
}
}
}
// Flugente Zombies 1.0: create a zombie from a corpse
void CreateZombiefromCorpse( ROTTING_CORPSE * pCorpse, UINT16 usAnimState )
{
SOLDIERCREATE_STRUCT MercCreateStruct;
MercCreateStruct.ubProfile = NO_PROFILE;
MercCreateStruct.bTeam = CREATURE_TEAM; // should be ZOMBIE_TEAM, once that is properly implemented
MercCreateStruct.sInsertionGridNo = pCorpse->def.sGridNo;
MercCreateStruct.sSectorX = gWorldSectorX;
MercCreateStruct.sSectorY = gWorldSectorY;
MercCreateStruct.bSectorZ = gbWorldSectorZ;
MercCreateStruct.bBodyType = pCorpse->def.ubBodyType;
MercCreateStruct.ubDirection = pCorpse->def.ubDirection;
MercCreateStruct.fOnRoof = pCorpse->def.bLevel > 0 ? TRUE : FALSE;
// add important stats according to difficulty level
// bLife is actually lower than bLifeMax. Because zombies have poison absorption, they can and will heal themselves over time, thereby gaining more life if they are not put down fast
switch( gGameExternalOptions.sZombieDifficultyLevel )
// Flugente Zombies 1.0: create a zombie from a corpse
void CreateZombiefromCorpse( ROTTING_CORPSE * pCorpse, UINT16 usAnimState )
{
case 4:
MercCreateStruct.bLifeMax = (INT8)( 70 + Random( 30 ) );
MercCreateStruct.bLife = MercCreateStruct.bLifeMax - (INT8)(10 + Random(15));
MercCreateStruct.bAgility = (INT8)( 50 + Random( 10 ) );
MercCreateStruct.bDexterity = (INT8)( 60 + Random( 15 ) );
MercCreateStruct.bStrength = (INT8)( 80 + Random( 20 ) );
break;
SOLDIERCREATE_STRUCT MercCreateStruct;
MercCreateStruct.ubProfile = NO_PROFILE;
MercCreateStruct.bTeam = CREATURE_TEAM; // should be ZOMBIE_TEAM, once that is properly implemented
MercCreateStruct.sInsertionGridNo = pCorpse->def.sGridNo;
MercCreateStruct.sSectorX = gWorldSectorX;
MercCreateStruct.sSectorY = gWorldSectorY;
MercCreateStruct.bSectorZ = gbWorldSectorZ;
MercCreateStruct.bBodyType = pCorpse->def.ubBodyType;
MercCreateStruct.ubDirection = pCorpse->def.ubDirection;
MercCreateStruct.fOnRoof = pCorpse->def.bLevel > 0 ? TRUE : FALSE;
case 3:
MercCreateStruct.bLifeMax = (INT8)( 60 + Random( 20 ) );
MercCreateStruct.bLife = MercCreateStruct.bLifeMax - (INT8)(10 + Random(10));
MercCreateStruct.bAgility = (INT8)( 40 + Random( 10 ) );
MercCreateStruct.bDexterity = (INT8)( 45 + Random( 10 ) );
MercCreateStruct.bStrength = (INT8)( 60 + Random( 20 ) );
break;
case 2:
MercCreateStruct.bLifeMax = (INT8)( 45 + Random( 15 ) );
MercCreateStruct.bLife = MercCreateStruct.bLifeMax - (INT8)(5 + Random(10));
MercCreateStruct.bAgility = (INT8)( 30 + Random( 5 ) );
MercCreateStruct.bDexterity = (INT8)( 30 + Random( 10 ) );
MercCreateStruct.bStrength = (INT8)( 45 + Random( 20 ) );
break;
case 1:
default:
MercCreateStruct.bLifeMax = (INT8)( 35 + Random( 10 ) );
MercCreateStruct.bLife = MercCreateStruct.bLifeMax - (INT8)(5 + Random(5));
MercCreateStruct.bAgility = (INT8)( 15 + Random( 5 ) );
MercCreateStruct.bDexterity = (INT8)( 15 + Random( 5 ) );
MercCreateStruct.bStrength = (INT8)( 30 + Random( 20 ) );
break;
}
// FIX: something's wrong with the FATCIV-bodytype when dying... this is to ensure they die absolutely fast
//if ( MercCreateStruct.bBodyType == FATCIV )
//MercCreateStruct.bLifeMax = OKLIFE;
MercCreateStruct.bExpLevel = 1;
MercCreateStruct.bMarksmanship = 1;
MercCreateStruct.bMedical = 1;
MercCreateStruct.bMechanical = 1;
MercCreateStruct.bExplosive = 1;
MercCreateStruct.bLeadership = 1;
MercCreateStruct.bWisdom = 1;
MercCreateStruct.bMorale = 90;
MercCreateStruct.bAIMorale = MORALE_FEARLESS;
SET_PALETTEREP_ID ( MercCreateStruct.HeadPal, pCorpse->def.HeadPal );
SET_PALETTEREP_ID ( MercCreateStruct.PantsPal, pCorpse->def.PantsPal );
SET_PALETTEREP_ID ( MercCreateStruct.VestPal, pCorpse->def.VestPal );
SET_PALETTEREP_ID ( MercCreateStruct.SkinPal, pCorpse->def.SkinPal );
MercCreateStruct.fVisible = TRUE;
INT8 iNewIndex;
if ( TacticalCreateSoldier( &MercCreateStruct, (UINT8 *)&iNewIndex ) )
{
/* certain values have to be set afterwards - the alternative would be to edit each and every function that gets called from TacticalCreateSoldier() subsequently and
* make an exception for zombies every time...
*/
SOLDIERTYPE* pNewSoldier = MercPtrs[ (UINT8)iNewIndex ];
pNewSoldier->bActionPoints = 60;
pNewSoldier->bInitialActionPoints = 60;
pNewSoldier->sBreathRed = 0;
pNewSoldier->ubInsertionDirection = pCorpse->def.ubDirection;
//pNewSoldier->sHeightAdjustment = pCorpse->def.sHeightAdjustment;
pNewSoldier->sDesiredHeight = 3;
pNewSoldier->ubDesiredHeight = 3; // this forces pNewSoldier to rise up to crouching position
pNewSoldier->ubSoldierClass = SOLDIER_CLASS_ZOMBIE;
pNewSoldier->aiData.bOrders = SEEKENEMY;
pNewSoldier->aiData.bAttitude = AGGRESSIVE;
////////////// stuff for poisoning ///////////////////////////////////
// this is important - by declaring the gap between bLife and bLifeMax as bBleeding, the zombies will bleed (even more if they are damaged)
// all their lifepoints are also poisoned. Thereby all bleeding damage will be poisoned bleeding damage
// as they have bPoisonAbsorption of at least 200%, they will absorp this poison damage
// This leads to them GAINING life through bleeding
// They can thereby regain their health in battle (although not very fast)
pNewSoldier->bBleeding = pNewSoldier->stats.bLifeMax - pNewSoldier->stats.bLife;
pNewSoldier->bPoisonSum = pNewSoldier->stats.bLifeMax;
pNewSoldier->bPoisonLife = pNewSoldier->stats.bLife;
pNewSoldier->bPoisonBleeding = pNewSoldier->bPoisonSum - pNewSoldier->bPoisonLife;
// zombies get 200% poison absorption, but no resistance to it, as it would reduce their healing
pNewSoldier->bPoisonResistance = 0;
pNewSoldier->bPoisonAbsorption = 200 + Random(100);
//////////////////////////////////////////////////////////////////////
if ( !memcmp( pCorpse->name, TacticalStr[ CIV_TEAM_MINER_NAME ], sizeof(pCorpse->name) )
|| !memcmp( pCorpse->name, TacticalStr[ MILITIA_TEAM_MERC_NAME ], sizeof(pCorpse->name) )
|| !memcmp( pCorpse->name, TacticalStr[ CREATURE_TEAM_MERC_NAME ], sizeof(pCorpse->name) )
|| !memcmp( pCorpse->name, TacticalStr[ CIV_TEAM_MERC_NAME ], sizeof(pCorpse->name) )
|| !memcmp( pCorpse->name, TacticalStr[ ZOMBIE_TEAM_MERC_NAME ], sizeof(pCorpse->name) )
|| !memcmp( pCorpse->name, TacticalStr[ ENEMY_TEAM_MERC_NAME ], sizeof(pCorpse->name) ) )
{
swprintf( pNewSoldier->name, TacticalStr[ ZOMBIE_TEAM_MERC_NAME ] );
}
else
{
memcpy( &(pNewSoldier->name), &(pCorpse->name), sizeof(CHAR16) * 10 );
pNewSoldier->name[9] = '\0';
}
// add skills according to difficulty level
// add important stats according to difficulty level
// bLife is actually lower than bLifeMax. Because zombies have poison absorption, they can and will heal themselves over time, thereby gaining more life if they are not put down fast
switch( gGameExternalOptions.sZombieDifficultyLevel )
{
case 4:
if ( gGameOptions.fNewTraitSystem )
{
pNewSoldier->stats.ubSkillTraits[0] = MARTIAL_ARTS_NT;
pNewSoldier->stats.ubSkillTraits[1] = MARTIAL_ARTS_NT;
pNewSoldier->stats.ubSkillTraits[2] = ATHLETICS_NT;
}
else
{
pNewSoldier->stats.ubSkillTraits[0] = HANDTOHAND_OT;
pNewSoldier->stats.ubSkillTraits[1] = MARTIALARTS_OT;
}
MercCreateStruct.bLifeMax = (INT8)( 70 + Random( 30 ) );
MercCreateStruct.bLife = MercCreateStruct.bLifeMax - (INT8)(10 + Random(15));
MercCreateStruct.bAgility = (INT8)( 50 + Random( 10 ) );
MercCreateStruct.bDexterity = (INT8)( 60 + Random( 15 ) );
MercCreateStruct.bStrength = (INT8)( 80 + Random( 20 ) );
break;
case 3:
if ( gGameOptions.fNewTraitSystem )
{
pNewSoldier->stats.ubSkillTraits[0] = MARTIAL_ARTS_NT;
pNewSoldier->stats.ubSkillTraits[1] = ATHLETICS_NT;
pNewSoldier->stats.ubSkillTraits[2] = NO_SKILLTRAIT_NT;
}
else
{
pNewSoldier->stats.ubSkillTraits[0] = HANDTOHAND_OT;
pNewSoldier->stats.ubSkillTraits[1] = NO_SKILLTRAIT_OT;
}
MercCreateStruct.bLifeMax = (INT8)( 60 + Random( 20 ) );
MercCreateStruct.bLife = MercCreateStruct.bLifeMax - (INT8)(10 + Random(10));
MercCreateStruct.bAgility = (INT8)( 40 + Random( 10 ) );
MercCreateStruct.bDexterity = (INT8)( 45 + Random( 10 ) );
MercCreateStruct.bStrength = (INT8)( 60 + Random( 20 ) );
break;
case 2:
if ( gGameOptions.fNewTraitSystem )
{
pNewSoldier->stats.ubSkillTraits[0] = MARTIAL_ARTS_NT;
pNewSoldier->stats.ubSkillTraits[1] = NO_SKILLTRAIT_NT;
pNewSoldier->stats.ubSkillTraits[2] = NO_SKILLTRAIT_NT;
}
else
{
pNewSoldier->stats.ubSkillTraits[0] = NO_SKILLTRAIT_OT;
pNewSoldier->stats.ubSkillTraits[1] = NO_SKILLTRAIT_OT;
}
MercCreateStruct.bLifeMax = (INT8)( 45 + Random( 15 ) );
MercCreateStruct.bLife = MercCreateStruct.bLifeMax - (INT8)(5 + Random(10));
MercCreateStruct.bAgility = (INT8)( 30 + Random( 5 ) );
MercCreateStruct.bDexterity = (INT8)( 30 + Random( 10 ) );
MercCreateStruct.bStrength = (INT8)( 45 + Random( 20 ) );
break;
case 1:
default:
if ( gGameOptions.fNewTraitSystem )
{
pNewSoldier->stats.ubSkillTraits[0] = NO_SKILLTRAIT_NT;
pNewSoldier->stats.ubSkillTraits[1] = NO_SKILLTRAIT_NT;
pNewSoldier->stats.ubSkillTraits[2] = NO_SKILLTRAIT_NT;
}
else
{
pNewSoldier->stats.ubSkillTraits[0] = NO_SKILLTRAIT_OT;
pNewSoldier->stats.ubSkillTraits[1] = NO_SKILLTRAIT_OT;
}
MercCreateStruct.bLifeMax = (INT8)( 35 + Random( 10 ) );
MercCreateStruct.bLife = MercCreateStruct.bLifeMax - (INT8)(5 + Random(5));
MercCreateStruct.bAgility = (INT8)( 15 + Random( 5 ) );
MercCreateStruct.bDexterity = (INT8)( 15 + Random( 5 ) );
MercCreateStruct.bStrength = (INT8)( 30 + Random( 20 ) );
break;
}
AddSoldierToSectorNoCalculateDirectionUseAnimation( iNewIndex, usAnimState, 0 );
// If this corpse has camo, use palette from hvobject
if ( pCorpse->def.ubType == ROTTING_STAGE2 )
{
memcpy( pNewSoldier->p8BPPPalette, gpTileCache[ pCorpse->iCachedTileID ].pImagery->vo->pPaletteEntry, sizeof( pCorpse->p8BPPPalette ) * 256 );
}
else if ( pCorpse->def.usFlags & ROTTING_CORPSE_USE_CAMO_PALETTE )
{
pNewSoldier->bCamo = 60;
pNewSoldier->wornCamo = 60;
}
else if ( pCorpse->def.usFlags & ROTTING_CORPSE_USE_URBAN_CAMO_PALETTE )
{
pNewSoldier->urbanCamo = 60;
pNewSoldier->wornUrbanCamo = 60;
}
else if ( pCorpse->def.usFlags & ROTTING_CORPSE_USE_DESERT_CAMO_PALETTE )
{
pNewSoldier->desertCamo = 60;
pNewSoldier->wornDesertCamo = 60;
}
else if ( pCorpse->def.usFlags & ROTTING_CORPSE_USE_SNOW_CAMO_PALETTE )
{
pNewSoldier->snowCamo = 60;
pNewSoldier->wornSnowCamo = 60;
}
// FIX: something's wrong with the FATCIV-bodytype when dying... this is to ensure they die absolutely fast
//if ( MercCreateStruct.bBodyType == FATCIV )
//MercCreateStruct.bLifeMax = OKLIFE;
MercCreateStruct.bExpLevel = 1;
MercCreateStruct.bMarksmanship = 1;
MercCreateStruct.bMedical = 1;
MercCreateStruct.bMechanical = 1;
MercCreateStruct.bExplosive = 1;
MercCreateStruct.bLeadership = 1;
MercCreateStruct.bWisdom = 1;
MercCreateStruct.bMorale = 90;
MercCreateStruct.bAIMorale = MORALE_FEARLESS;
SET_PALETTEREP_ID ( MercCreateStruct.HeadPal, pCorpse->def.HeadPal );
SET_PALETTEREP_ID ( MercCreateStruct.PantsPal, pCorpse->def.PantsPal );
SET_PALETTEREP_ID ( MercCreateStruct.VestPal, pCorpse->def.VestPal );
SET_PALETTEREP_ID ( MercCreateStruct.SkinPal, pCorpse->def.SkinPal );
MercCreateStruct.fVisible = TRUE;
// Reload palettes....
if ( pNewSoldier->bInSector )
INT8 iNewIndex;
if ( TacticalCreateSoldier( &MercCreateStruct, (UINT8 *)&iNewIndex ) )
{
pNewSoldier->CreateSoldierPalettes( );
}
/* certain values have to be set afterwards - the alternative would be to edit each and every function that gets called from TacticalCreateSoldier() subsequently and
* make an exception for zombies every time...
*/
SOLDIERTYPE* pNewSoldier = MercPtrs[ (UINT8)iNewIndex ];
pNewSoldier->bActionPoints = 60;
pNewSoldier->bInitialActionPoints = 60;
pNewSoldier->sBreathRed = 0;
// Set a pending animation to change stance first...
//SendChangeSoldierStanceEvent( pNewSoldier, ANIM_CROUCH );
pNewSoldier->ubInsertionDirection = pCorpse->def.ubDirection;
// search for armour and equip if found
if ( gGameExternalOptions.fZombieRiseWithArmour )
{
BOOLEAN fHelmetFound = FALSE;
BOOLEAN fVestFound = FALSE;
BOOLEAN fPantsFound = FALSE;
//pNewSoldier->sHeightAdjustment = pCorpse->def.sHeightAdjustment;
pNewSoldier->sDesiredHeight = 3;
ITEM_POOL * pItemPool, * pItemPoolNext;
pNewSoldier->ubDesiredHeight = 3; // this forces pNewSoldier to rise up to crouching position
GetItemPool( pCorpse->def.sGridNo, &pItemPool, pCorpse->def.bLevel );
pNewSoldier->ubSoldierClass = SOLDIER_CLASS_ZOMBIE;
pNewSoldier->aiData.bOrders = SEEKENEMY;
pNewSoldier->aiData.bAttitude = AGGRESSIVE;
while( pItemPool && ( !fHelmetFound || !fVestFound ||!fPantsFound ) )
////////////// stuff for poisoning ///////////////////////////////////
// this is important - by declaring the gap between bLife and bLifeMax as bBleeding, the zombies will bleed (even more if they are damaged)
// all their lifepoints are also poisoned. Thereby all bleeding damage will be poisoned bleeding damage
// as they have bPoisonAbsorption of at least 200%, they will absorp this poison damage
// This leads to them GAINING life through bleeding
// They can thereby regain their health in battle (although not very fast)
pNewSoldier->bBleeding = pNewSoldier->stats.bLifeMax - pNewSoldier->stats.bLife;
pNewSoldier->bPoisonSum = pNewSoldier->stats.bLifeMax;
pNewSoldier->bPoisonLife = pNewSoldier->stats.bLife;
pNewSoldier->bPoisonBleeding = pNewSoldier->bPoisonSum - pNewSoldier->bPoisonLife;
// zombies get 200% poison absorption, but no resistance to it, as it would reduce their healing
pNewSoldier->bPoisonResistance = 0;
pNewSoldier->bPoisonAbsorption = 200 + Random(100);
//////////////////////////////////////////////////////////////////////
#ifdef ENABLE_ZOMBIES
if ( !memcmp( pCorpse->name, TacticalStr[ CIV_TEAM_MINER_NAME ], sizeof(pCorpse->name) )
|| !memcmp( pCorpse->name, TacticalStr[ MILITIA_TEAM_MERC_NAME ], sizeof(pCorpse->name) )
|| !memcmp( pCorpse->name, TacticalStr[ CREATURE_TEAM_MERC_NAME ], sizeof(pCorpse->name) )
|| !memcmp( pCorpse->name, TacticalStr[ CIV_TEAM_MERC_NAME ], sizeof(pCorpse->name) )
|| !memcmp( pCorpse->name, TacticalStr[ ZOMBIE_TEAM_MERC_NAME ], sizeof(pCorpse->name) )
|| !memcmp( pCorpse->name, TacticalStr[ ENEMY_TEAM_MERC_NAME ], sizeof(pCorpse->name) ) )
{
pItemPoolNext = pItemPool->pNext;
OBJECTTYPE* pObj = &(gWorldItems[ pItemPool->iItemIndex ].object);
if ( Item[ pObj->usItem ].usItemClass == IC_ARMOUR )
{
switch (Armour[Item[pObj->usItem].ubClassIndex].ubArmourClass)
{
case ARMOURCLASS_HELMET:
{
if( !fHelmetFound && AutoPlaceObject(pNewSoldier, pObj, FALSE))
{
// remove item from the ground
RemoveItemFromPool( pCorpse->def.sGridNo, pItemPool->iItemIndex, pCorpse->def.bLevel );
fHelmetFound = TRUE;
}
break;
}
case ARMOURCLASS_VEST:
{
if( !fVestFound && AutoPlaceObject(pNewSoldier, pObj, FALSE))
{
// remove item from the ground
RemoveItemFromPool( pCorpse->def.sGridNo, pItemPool->iItemIndex, pCorpse->def.bLevel );
fVestFound = TRUE;
}
break;
}
case ARMOURCLASS_LEGGINGS:
{
if( !fPantsFound && AutoPlaceObject(pNewSoldier, pObj, FALSE))
{
// remove item from the ground
RemoveItemFromPool( pCorpse->def.sGridNo, pItemPool->iItemIndex, pCorpse->def.bLevel );
fPantsFound = TRUE;
}
break;
}
default:
break;
}
}
pItemPool = pItemPoolNext;
swprintf( pNewSoldier->name, TacticalStr[ ZOMBIE_TEAM_MERC_NAME ] );
}
else
{
memcpy( &(pNewSoldier->name), &(pCorpse->name), sizeof(CHAR16) * 10 );
pNewSoldier->name[9] = '\0';
}
#else
memcpy( &(pNewSoldier->name), &(pCorpse->name), sizeof(CHAR16) * 10 );
pNewSoldier->name[9] = '\0';
#endif
// add skills according to difficulty level
switch( gGameExternalOptions.sZombieDifficultyLevel )
{
case 4:
if ( gGameOptions.fNewTraitSystem )
{
pNewSoldier->stats.ubSkillTraits[0] = MARTIAL_ARTS_NT;
pNewSoldier->stats.ubSkillTraits[1] = MARTIAL_ARTS_NT;
pNewSoldier->stats.ubSkillTraits[2] = ATHLETICS_NT;
}
else
{
pNewSoldier->stats.ubSkillTraits[0] = HANDTOHAND_OT;
pNewSoldier->stats.ubSkillTraits[1] = MARTIALARTS_OT;
}
break;
case 3:
if ( gGameOptions.fNewTraitSystem )
{
pNewSoldier->stats.ubSkillTraits[0] = MARTIAL_ARTS_NT;
pNewSoldier->stats.ubSkillTraits[1] = ATHLETICS_NT;
pNewSoldier->stats.ubSkillTraits[2] = NO_SKILLTRAIT_NT;
}
else
{
pNewSoldier->stats.ubSkillTraits[0] = HANDTOHAND_OT;
pNewSoldier->stats.ubSkillTraits[1] = NO_SKILLTRAIT_OT;
}
break;
case 2:
if ( gGameOptions.fNewTraitSystem )
{
pNewSoldier->stats.ubSkillTraits[0] = MARTIAL_ARTS_NT;
pNewSoldier->stats.ubSkillTraits[1] = NO_SKILLTRAIT_NT;
pNewSoldier->stats.ubSkillTraits[2] = NO_SKILLTRAIT_NT;
}
else
{
pNewSoldier->stats.ubSkillTraits[0] = NO_SKILLTRAIT_OT;
pNewSoldier->stats.ubSkillTraits[1] = NO_SKILLTRAIT_OT;
}
break;
case 1:
default:
if ( gGameOptions.fNewTraitSystem )
{
pNewSoldier->stats.ubSkillTraits[0] = NO_SKILLTRAIT_NT;
pNewSoldier->stats.ubSkillTraits[1] = NO_SKILLTRAIT_NT;
pNewSoldier->stats.ubSkillTraits[2] = NO_SKILLTRAIT_NT;
}
else
{
pNewSoldier->stats.ubSkillTraits[0] = NO_SKILLTRAIT_OT;
pNewSoldier->stats.ubSkillTraits[1] = NO_SKILLTRAIT_OT;
}
break;
}
AddSoldierToSectorNoCalculateDirectionUseAnimation( iNewIndex, usAnimState, 0 );
// If this corpse has camo, use palette from hvobject
if ( pCorpse->def.ubType == ROTTING_STAGE2 )
{
memcpy( pNewSoldier->p8BPPPalette, gpTileCache[ pCorpse->iCachedTileID ].pImagery->vo->pPaletteEntry, sizeof( pCorpse->p8BPPPalette ) * 256 );
}
else if ( pCorpse->def.usFlags & ROTTING_CORPSE_USE_CAMO_PALETTE )
{
pNewSoldier->bCamo = 60;
pNewSoldier->wornCamo = 60;
}
else if ( pCorpse->def.usFlags & ROTTING_CORPSE_USE_URBAN_CAMO_PALETTE )
{
pNewSoldier->urbanCamo = 60;
pNewSoldier->wornUrbanCamo = 60;
}
else if ( pCorpse->def.usFlags & ROTTING_CORPSE_USE_DESERT_CAMO_PALETTE )
{
pNewSoldier->desertCamo = 60;
pNewSoldier->wornDesertCamo = 60;
}
else if ( pCorpse->def.usFlags & ROTTING_CORPSE_USE_SNOW_CAMO_PALETTE )
{
pNewSoldier->snowCamo = 60;
pNewSoldier->wornSnowCamo = 60;
}
// Reload palettes....
if ( pNewSoldier->bInSector )
{
pNewSoldier->CreateSoldierPalettes( );
}
// Set a pending animation to change stance first...
//SendChangeSoldierStanceEvent( pNewSoldier, ANIM_CROUCH );
#ifdef ENABLE_ZOMBIES
// search for armour and equip if found
if ( gGameExternalOptions.fZombieRiseWithArmour )
{
BOOLEAN fHelmetFound = FALSE;
BOOLEAN fVestFound = FALSE;
BOOLEAN fPantsFound = FALSE;
ITEM_POOL * pItemPool, * pItemPoolNext;
GetItemPool( pCorpse->def.sGridNo, &pItemPool, pCorpse->def.bLevel );
while( pItemPool && ( !fHelmetFound || !fVestFound ||!fPantsFound ) )
{
pItemPoolNext = pItemPool->pNext;
OBJECTTYPE* pObj = &(gWorldItems[ pItemPool->iItemIndex ].object);
if ( Item[ pObj->usItem ].usItemClass == IC_ARMOUR )
{
switch (Armour[Item[pObj->usItem].ubClassIndex].ubArmourClass)
{
case ARMOURCLASS_HELMET:
{
if( !fHelmetFound && AutoPlaceObject(pNewSoldier, pObj, FALSE))
{
// remove item from the ground
RemoveItemFromPool( pCorpse->def.sGridNo, pItemPool->iItemIndex, pCorpse->def.bLevel );
fHelmetFound = TRUE;
}
break;
}
case ARMOURCLASS_VEST:
{
if( !fVestFound && AutoPlaceObject(pNewSoldier, pObj, FALSE))
{
// remove item from the ground
RemoveItemFromPool( pCorpse->def.sGridNo, pItemPool->iItemIndex, pCorpse->def.bLevel );
fVestFound = TRUE;
}
break;
}
case ARMOURCLASS_LEGGINGS:
{
if( !fPantsFound && AutoPlaceObject(pNewSoldier, pObj, FALSE))
{
// remove item from the ground
RemoveItemFromPool( pCorpse->def.sGridNo, pItemPool->iItemIndex, pCorpse->def.bLevel );
fPantsFound = TRUE;
}
break;
}
default:
break;
}
}
pItemPool = pItemPoolNext;
}
}
#endif
// Change to standing,unless we can getup with an animation
pNewSoldier->EVENT_InitNewSoldierAnim( STANDING, 0, TRUE );
pNewSoldier->BeginSoldierGetup( );
// So we can see them!
AllTeamsLookForAll(ALLOW_INTERRUPTS);
}
}
// Flugente Zombies: returns true if a zombie can be raised from this corpse, and returns the correct pAnimState for the new zombie
BOOLEAN CorpseOkToSpawnZombie( ROTTING_CORPSE * pCorpse, UINT16* pAnimState )
{
BOOLEAN canbezombie = FALSE;
*pAnimState = FALLBACKHIT_STOP;
switch ( pCorpse->def.ubType )
{
case SMERC_BCK:
case SMERC_DHD:
case SMERC_FALL:
case MMERC_BCK:
case MMERC_DHD:
case MMERC_FALL:
case FMERC_BCK:
case FMERC_DHD:
case FMERC_FALL:
case ROTTING_STAGE2:
canbezombie = TRUE;
*pAnimState = FALLBACKHIT_STOP;
break;
case SMERC_FWD:
case SMERC_PRN:
case SMERC_FALLF:
case MMERC_FWD:
case MMERC_PRN:
case MMERC_FALLF:
case FMERC_FWD:
case FMERC_PRN:
case FMERC_FALLF:
canbezombie = TRUE;
*pAnimState = FALLFORWARD_HITDEATH_STOP;
break;
case M_DEAD1:
canbezombie = TRUE;
*pAnimState = GENERIC_HIT_DEATH;
break;
case M_DEAD2:
canbezombie = TRUE;
*pAnimState = CIV_DIE2;
case H_DEAD1:
case K_DEAD1:
case FT_DEAD1:
case S_DEAD1:
case W_DEAD1:
case C_DEAD1:
case H_DEAD2:
case K_DEAD2:
case FT_DEAD2:
case S_DEAD2:
case W_DEAD2:
case C_DEAD2:
canbezombie = TRUE;
*pAnimState = STANDING;
default:
;
}
// Change to standing,unless we can getup with an animation
pNewSoldier->EVENT_InitNewSoldierAnim( STANDING, 0, TRUE );
pNewSoldier->BeginSoldierGetup( );
// So we can see them!
AllTeamsLookForAll(ALLOW_INTERRUPTS);
return( canbezombie );
}
}
// Flugente Zombies: returns true if a zombie can be raised from this corpse, and returns the correct pAnimState for the new zombie
BOOLEAN CorpseOkToSpawnZombie( ROTTING_CORPSE * pCorpse, UINT16* pAnimState )
{
BOOLEAN canbezombie = FALSE;
*pAnimState = FALLBACKHIT_STOP;
switch ( pCorpse->def.ubType )
{
case SMERC_BCK:
case SMERC_DHD:
case SMERC_FALL:
case MMERC_BCK:
case MMERC_DHD:
case MMERC_FALL:
case FMERC_BCK:
case FMERC_DHD:
case FMERC_FALL:
case ROTTING_STAGE2:
canbezombie = TRUE;
*pAnimState = FALLBACKHIT_STOP;
break;
case SMERC_FWD:
case SMERC_PRN:
case SMERC_FALLF:
case MMERC_FWD:
case MMERC_PRN:
case MMERC_FALLF:
case FMERC_FWD:
case FMERC_PRN:
case FMERC_FALLF:
canbezombie = TRUE;
*pAnimState = FALLFORWARD_HITDEATH_STOP;
break;
case M_DEAD1:
canbezombie = TRUE;
*pAnimState = GENERIC_HIT_DEATH;
break;
case M_DEAD2:
canbezombie = TRUE;
*pAnimState = CIV_DIE2;
case H_DEAD1:
case K_DEAD1:
case FT_DEAD1:
case S_DEAD1:
case W_DEAD1:
case C_DEAD1:
case H_DEAD2:
case K_DEAD2:
case FT_DEAD2:
case S_DEAD2:
case W_DEAD2:
case C_DEAD2:
canbezombie = TRUE;
*pAnimState = STANDING;
default:
;
}
return( canbezombie );
}
#endif
+16 -7
View File
@@ -84,7 +84,10 @@ enum RottingCorpseDefines
#define ROTTING_CORPSE_USE_URBAN_CAMO_PALETTE 0x100 //We use urban palette here....
#define ROTTING_CORPSE_USE_DESERT_CAMO_PALETTE 0x200 //We use desert palette here....
#define ROTTING_CORPSE_USE_SNOW_CAMO_PALETTE 0x400 //We use snow palette here....
#define ROTTING_CORPSE_NEVER_RISE_AGAIN 0x800 //a zombie cannot be created from this corpse (if not set, it'll eventually rise again )
#ifdef ENABLE_ZOMBIES
#define ROTTING_CORPSE_NEVER_RISE_AGAIN 0x800 //a zombie cannot be created from this corpse (if not set, it'll eventually rise again )
#endif
typedef struct
@@ -116,8 +119,10 @@ typedef struct
UINT8 ubFiller[ 12 ];
#ifdef ENABLE_ZOMBIES
// Flugente: added name so we can display individual name if corpse gets resurrected...
CHAR16 name[ 10 ];
#endif
} ROTTING_CORPSE_DEFINITION;
@@ -140,8 +145,10 @@ typedef struct
BOOLEAN fAttractCrowsOnlyWhenOnScreen;
INT32 iID;
#ifdef ENABLE_ZOMBIES
// Flugente: added name so we can display individual name if corpse gets resurrected...
CHAR16 name[ 10 ];
#endif
} ROTTING_CORPSE;
@@ -200,13 +207,15 @@ INT32 GetGridNoOfCorpseGivenProfileID( UINT8 ubProfileID );
void DecayRottingCorpseAIWarnings( void );
UINT8 GetNearestRottingCorpseAIWarning( INT32 sGridNo );
// Flugente: Raise zombies
void RaiseZombies( void );
#ifdef ENABLE_ZOMBIES
// Flugente: Raise zombies
void RaiseZombies( void );
// Flugente: create a zombie from a corpse
void CreateZombiefromCorpse( ROTTING_CORPSE * pCorpse, UINT16 usAnimState );
// Flugente: create a zombie from a corpse
void CreateZombiefromCorpse( ROTTING_CORPSE * pCorpse, UINT16 usAnimState );
// Flugente: returns true if a zombie can be raised from this corpse, and returns the correct pAnimState for the new zombie
BOOLEAN CorpseOkToSpawnZombie( ROTTING_CORPSE * pCorpse, UINT16* pAnimState );
// Flugente: returns true if a zombie can be raised from this corpse, and returns the correct pAnimState for the new zombie
BOOLEAN CorpseOkToSpawnZombie( ROTTING_CORPSE * pCorpse, UINT16* pAnimState );
#endif
#endif
+2
View File
@@ -3485,9 +3485,11 @@ BOOLEAN HandleSoldierDeath( SOLDIERTYPE *pSoldier , BOOLEAN *pfMadeCorpse )
case SOLDIER_CLASS_CREATURE :
gMercProfiles[ MercPtrs[ ubAttacker ]->ubProfile ].records.usKillsCreatures++;
break;
#ifdef ENABLE_ZOMBIES
case SOLDIER_CLASS_ZOMBIE :
gMercProfiles[ MercPtrs[ ubAttacker ]->ubProfile ].records.usKillsZombies++;
break;
#endif
default :
if ( CREATURE_OR_BLOODCAT( pSoldier ) )
gMercProfiles[ MercPtrs[ ubAttacker ]->ubProfile ].records.usKillsCreatures++;
+49 -7
View File
@@ -137,8 +137,10 @@ extern INT16 DirIncrementer[8];
#define MIN_SUBSEQUENT_SNDS_DELAY 2000
#include "connect.h"
extern void TeleportSelectedSoldier( void );
extern BOOLEAN AddSoldierToSectorNoCalculateDirectionUseAnimation( UINT8 ubID, UINT16 usAnimState, UINT16 usAnimCode );
#ifdef ENABLE_ZOMBIES
extern void TeleportSelectedSoldier( void );
extern BOOLEAN AddSoldierToSectorNoCalculateDirectionUseAnimation( UINT8 ubID, UINT16 usAnimState, UINT16 usAnimCode );
#endif
// Enumerate extended directions
@@ -1349,7 +1351,11 @@ MERCPROFILESTRUCT& MERCPROFILESTRUCT::operator=(const OLD_MERCPROFILESTRUCT_101&
this->records.usKillsAdmins = (src.usKills/4);
this->records.usKillsHostiles = 0;
this->records.usKillsCreatures = 0;
#ifdef ENABLE_ZOMBIES
this->records.usKillsZombies = 0;
#endif
this->records.usKillsTanks = 0;
this->records.usKillsOthers = 0;
this->records.usAssistsMercs = (src.usAssists*3/4);
@@ -8673,6 +8679,7 @@ void SOLDIERTYPE::BeginSoldierClimbUpRoof( void )
this->ubPendingDirection = bNewDirection;
//this->usPendingAnimation = CLIMBUPROOF;
#ifdef ENABLE_ZOMBIES
// Flugente: In case an animation is missing (zombies with bodytype of civilians), we TELEPORT instead
if ( IsAnimationValidForBodyType( this, CLIMBUPROOF ) == FALSE )
{
@@ -8682,6 +8689,9 @@ void SOLDIERTYPE::BeginSoldierClimbUpRoof( void )
}
else
this->EVENT_InitNewSoldierAnim( CLIMBUPROOF, 0 , FALSE );
#else
this->EVENT_InitNewSoldierAnim( CLIMBUPROOF, 0 , FALSE );
#endif
this->InternalReceivingSoldierCancelServices( FALSE );
this->InternalGivingSoldierCancelServices( FALSE );
@@ -9276,7 +9286,11 @@ UINT8 SOLDIERTYPE::SoldierTakeDamage( INT8 bHeight, INT16 sLifeDeduct, INT16 sPo
// ATE: Put some logic in here to allow enemies to die quicker.....
// Are we an enemy?
// zombies don't die suddenly, as they regenerate health by bloodloss and poison. You have to make sure they die!
#ifdef ENABLE_ZOMBIES
if ( this->bSide != gbPlayerNum && !this->aiData.bNeutral && this->ubProfile == NO_PROFILE && !this->IsZombie() )
#else
if ( this->bSide != gbPlayerNum && !this->aiData.bNeutral && this->ubProfile == NO_PROFILE)
#endif
{
// ATE: Give them a chance to fall down...
if ( this->stats.bLife > 0 && this->stats.bLife < ( OKLIFE - 1 ) )
@@ -9310,12 +9324,15 @@ UINT8 SOLDIERTYPE::SoldierTakeDamage( INT8 bHeight, INT16 sLifeDeduct, INT16 sPo
}
}
}
#ifdef ENABLE_ZOMBIES
else if ( this->IsZombie() && this->stats.bLife > 0 && this->stats.bLife < OKLIFE )
{
// a zombie doesn't automatically die, so he would normally stand up again after being hit.
// We don't want that, because he is dying, so we manually skip that animation
this->usPendingAnimation = NO_PENDING_ANIMATION;
}
#endif
if ( fShowDamage )
{
@@ -9988,6 +10005,7 @@ BOOLEAN SOLDIERTYPE::InternalDoMercBattleSound( UINT8 ubBattleSoundID, INT8 bSpe
}
}
}
#ifdef ENABLE_ZOMBIES
else if ( pSoldier->IsZombie() ) // Madd: add zombie sounds
{
if ( ubSoundID == BATTLE_SOUND_DIE1 )
@@ -10007,6 +10025,7 @@ BOOLEAN SOLDIERTYPE::InternalDoMercBattleSound( UINT8 ubBattleSoundID, INT8 bSpe
}
}
}
#endif
else
{
if ( ubSoundID == BATTLE_SOUND_DIE1 )
@@ -10265,6 +10284,7 @@ void SOLDIERTYPE::BeginSoldierClimbDownRoof( void )
this->ubPendingDirection = bNewDirection;
#ifdef ENABLE_ZOMBIES
// Flugente: In case an animation is missing (zombies with bodytype of civilians), we TELEPORT instead
if ( IsAnimationValidForBodyType( this, JUMPDOWNWALL ) == FALSE )
{
@@ -10274,6 +10294,9 @@ void SOLDIERTYPE::BeginSoldierClimbDownRoof( void )
}
else
this->EVENT_InitNewSoldierAnim( JUMPDOWNWALL, 0 , FALSE );
#else
this->EVENT_InitNewSoldierAnim( JUMPDOWNWALL, 0 , FALSE );
#endif
this->InternalReceivingSoldierCancelServices( FALSE );
this->InternalGivingSoldierCancelServices( FALSE );
@@ -11505,7 +11528,13 @@ void SOLDIERTYPE::EVENT_SoldierBeginPunchAttack( INT32 sGridNo, UINT8 ubDirectio
#if (defined JA2UB || defined JA113NODEMO)
if ( fMartialArtist && !Item[usItem].crowbar && this->ubBodyType == REGMALE)
#else
if ( fMartialArtist && !AreInMeanwhile( ) && !Item[usItem].crowbar && this->ubBodyType == REGMALE && !IsZombie() ) // SANDRO - added check for body type
#ifdef ENABLE_ZOMBIES
if ( fMartialArtist && !AreInMeanwhile( ) && !Item[usItem].crowbar && this->ubBodyType == REGMALE && !IsZombie() ) // SANDRO - added check for body type
#else
if ( fMartialArtist && !AreInMeanwhile( ) && !Item[usItem].crowbar && this->ubBodyType == REGMALE ) // SANDRO - added check for body type
#endif
#endif
{
// Are we in attack mode yet?
@@ -11520,6 +11549,7 @@ void SOLDIERTYPE::EVENT_SoldierBeginPunchAttack( INT32 sGridNo, UINT8 ubDirectio
}
else
{
#ifdef ENABLE_ZOMBIES
// Flugente: civilians can be zombies too, but they do not have a 'punch' animation. Simple fix: They 'attack' without animation...
// CHECK IF WE CAN DO THIS ANIMATION!
if ( this->IsZombie() && IsAnimationValidForBodyType( this, PUNCH ) == FALSE )
@@ -11589,6 +11619,7 @@ void SOLDIERTYPE::EVENT_SoldierBeginPunchAttack( INT32 sGridNo, UINT8 ubDirectio
}
else
{
#endif
// Look at stance of target
switch( gAnimControl[ pTSoldier->usAnimState ].ubEndHeight )
{
@@ -11649,7 +11680,10 @@ void SOLDIERTYPE::EVENT_SoldierBeginPunchAttack( INT32 sGridNo, UINT8 ubDirectio
}
}
break;
#ifdef ENABLE_ZOMBIES
}
#endif
}
}
@@ -13402,6 +13436,8 @@ INT32 SOLDIERTYPE::GetDamageResistance(BOOLEAN fAutoResolve, BOOLEAN fCalcBreath
resistance += gGameExternalOptions.sEnemyRegularDamageResistance;
else if (this->ubSoldierClass == SOLDIER_CLASS_ELITE && gGameExternalOptions.sEnemyEliteDamageResistance != 0)
resistance += gGameExternalOptions.sEnemyEliteDamageResistance;
#ifdef ENABLE_ZOMBIES
else if (IsZombie())
{
if ( fCalcBreathLoss )
@@ -13409,6 +13445,7 @@ INT32 SOLDIERTYPE::GetDamageResistance(BOOLEAN fAutoResolve, BOOLEAN fCalcBreath
else
resistance += gGameExternalOptions.sEnemyZombieDamageResistance;
}
#endif
}
//////////////////////////////////////////////////////////////////////////////////////
@@ -13463,10 +13500,13 @@ INT16 SOLDIERTYPE::GetSoldierCriticalDamageBonus( void )
return val;
}
BOOLEAN SOLDIERTYPE::IsZombie( void )
{
return( ubSoldierClass == SOLDIER_CLASS_ZOMBIE );
}
#ifdef ENABLE_ZOMBIES
BOOLEAN SOLDIERTYPE::IsZombie( void )
{
return( ubSoldierClass == SOLDIER_CLASS_ZOMBIE );
}
#endif
INT16 SOLDIERTYPE::GetPoisonResistance( void )
{
@@ -13497,9 +13537,11 @@ INT16 SOLDIERTYPE::GetPoisonDamagePercentage( void )
// Flugente: this percentage has to be between 0% and 100%
INT16 val = 0;
#ifdef ENABLE_ZOMBIES
// zombies poison damage percentage is externalised
if ( IsZombie() )
val += gGameExternalOptions.sZombiePoisonDamagePercentage;
#endif
if ( this->usAttackingWeapon )
{
+4
View File
@@ -310,7 +310,9 @@ enum
SOLDIER_CLASS_ELITE_MILITIA,
SOLDIER_CLASS_CREATURE,
SOLDIER_CLASS_MINER,
#ifdef ENABLE_ZOMBIES
SOLDIER_CLASS_ZOMBIE,
#endif
};
#define SOLDIER_CLASS_ENEMY( bSoldierClass ) ( ( bSoldierClass >= SOLDIER_CLASS_ADMINISTRATOR ) && ( bSoldierClass <= SOLDIER_CLASS_ARMY ) )
@@ -1358,8 +1360,10 @@ public:
INT16 GetSoldierCriticalDamageBonus( void ); // Flugente: determines critical damage bonus depending on class, skill, etc.
#ifdef ENABLE_ZOMBIES
// Flugente: Zombies
BOOLEAN IsZombie( void );
#endif
// Flugente: poison system
// These functions might one day be modified by traits etc. We'll keep that in these functions and not clutter the rest of the code
+53 -30
View File
@@ -1729,10 +1729,12 @@ BOOLEAN TacticalCopySoldierFromCreateStruct( SOLDIERTYPE *pSoldier, SOLDIERCREAT
{
swprintf( pSoldier->name, gzLateLocalizedString[ 36 ] );
}
#ifdef ENABLE_ZOMBIES
else if ( pSoldier->IsZombie() )
{
swprintf( pSoldier->name, TacticalStr[ ZOMBIE_TEAM_MERC_NAME ] );
}
#endif
else
{
swprintf( pSoldier->name, TacticalStr[ CREATURE_TEAM_MERC_NAME ] ); break;
@@ -2176,7 +2178,9 @@ void CreateDetailedPlacementGivenBasicPlacementInfo( SOLDIERCREATE_STRUCT *pp, B
switch( ubSoldierClass )
{
case SOLDIER_CLASS_ADMINISTRATOR:
#ifdef ENABLE_ZOMBIES
case SOLDIER_CLASS_ZOMBIE:
#endif
pp->bExpLevel = (INT8) 2 + bExpLevelModifier;
break;
case SOLDIER_CLASS_ARMY:
@@ -2294,7 +2298,11 @@ void CreateDetailedPlacementGivenBasicPlacementInfo( SOLDIERCREATE_STRUCT *pp, B
//If it is a detailed placement, don't do this yet, as detailed placements may have their
//own equipment.
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("CreateDetailedPlacementGivenBasicPlacementInfo: generate random equipment"));
#ifdef ENABLE_ZOMBIES
if( !bp->fDetailedPlacement && ubSoldierClass != SOLDIER_CLASS_NONE && ubSoldierClass != SOLDIER_CLASS_CREATURE && ubSoldierClass != SOLDIER_CLASS_MINER && ubSoldierClass != SOLDIER_CLASS_ZOMBIE )
#else
if( !bp->fDetailedPlacement && ubSoldierClass != SOLDIER_CLASS_NONE && ubSoldierClass != SOLDIER_CLASS_CREATURE && ubSoldierClass != SOLDIER_CLASS_MINER )
#endif
GenerateRandomEquipment( pp, ubSoldierClass, bp->bRelativeEquipmentLevel);
DecideToAssignSniperOrders(pp);
@@ -2462,7 +2470,12 @@ void CreateDetailedPlacementGivenStaticDetailedPlacementAndBasicPlacementInfo(
//{
// ReplaceExtendedGuns( pp, bp->ubSoldierClass );
//}
#ifdef ENABLE_ZOMBIES
if( bp->ubSoldierClass != SOLDIER_CLASS_NONE && bp->ubSoldierClass != SOLDIER_CLASS_CREATURE && bp->ubSoldierClass != SOLDIER_CLASS_MINER && bp->ubSoldierClass != SOLDIER_CLASS_ZOMBIE )
#else
if( bp->ubSoldierClass != SOLDIER_CLASS_NONE && bp->ubSoldierClass != SOLDIER_CLASS_CREATURE && bp->ubSoldierClass != SOLDIER_CLASS_MINER )
#endif
{
GenerateRandomEquipment( pp, bp->ubSoldierClass, bp->bRelativeEquipmentLevel);
DecideToAssignSniperOrders(pp);
@@ -2657,7 +2670,11 @@ 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.
#ifdef ENABLE_ZOMBIES
if( ubSoldierClass != SOLDIER_CLASS_CREATURE && ubSoldierClass != SOLDIER_CLASS_ZOMBIE )
#else
if( ubSoldierClass != SOLDIER_CLASS_CREATURE )
#endif
{ //use the enemy team
iStart = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID;
iEnd = gTacticalStatus.Team[ ENEMY_TEAM ].bLastID;
@@ -2799,39 +2816,41 @@ SOLDIERTYPE* TacticalCreateEliteEnemy()
return( pSoldier );
}
//USED BY STRATEGIC AI and AUTORESOLVE
SOLDIERTYPE* TacticalCreateZombie()
{
BASIC_SOLDIERCREATE_STRUCT bp;
SOLDIERCREATE_STRUCT pp;
UINT8 ubID;
SOLDIERTYPE * pSoldier;
if( guiCurrentScreen == AUTORESOLVE_SCREEN && !gfPersistantPBI )
#ifdef ENABLE_ZOMBIES
//USED BY STRATEGIC AI and AUTORESOLVE
SOLDIERTYPE* TacticalCreateZombie()
{
pSoldier = ReserveTacticalSoldierForAutoresolve( SOLDIER_CLASS_ZOMBIE );
if( pSoldier ) return pSoldier;
}
BASIC_SOLDIERCREATE_STRUCT bp;
SOLDIERCREATE_STRUCT pp;
UINT8 ubID;
SOLDIERTYPE * pSoldier;
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.bOrders = SEEKENEMY;
bp.bAttitude = AGGRESSIVE;
bp.bBodyType = -1;
bp.ubSoldierClass = SOLDIER_CLASS_ZOMBIE;
CreateDetailedPlacementGivenBasicPlacementInfo( &pp, &bp );
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 && !gfPersistantPBI )
{
pSoldier = ReserveTacticalSoldierForAutoresolve( SOLDIER_CLASS_ZOMBIE );
if( pSoldier ) return pSoldier;
}
return( pSoldier );
}
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.bOrders = SEEKENEMY;
bp.bAttitude = AGGRESSIVE;
bp.bBodyType = -1;
bp.ubSoldierClass = SOLDIER_CLASS_ZOMBIE;
CreateDetailedPlacementGivenBasicPlacementInfo( &pp, &bp );
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;
}
return( pSoldier );
}
#endif
SOLDIERTYPE* ReserveTacticalMilitiaSoldierForAutoresolve( UINT8 ubSoldierClass )
{
@@ -4236,8 +4255,10 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre
iChance = 10 + ubProgress/4; // 10-35% chance
else if( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA )
iChance = ubProgress/4; // 0-25% chance
#ifdef ENABLE_ZOMBIES
else if (ubSolClass == SOLDIER_CLASS_ZOMBIE )
iChance = 100; // 100% chance
#endif
if( foundHtH ) // if found brass knuckless, increase the chance (doesn't happen often)
iChance += 35;
@@ -4281,8 +4302,10 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre
iChance = 25 + ubProgress*2/5; // 25-65% chance
else if( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA )
iChance = 10 + ubProgress*2/5; // 10-50% chance
#ifdef ENABLE_ZOMBIES
else if (ubSolClass == SOLDIER_CLASS_ZOMBIE )
iChance = 100; // 100% chance
#endif
// modify the chance by preset ini setting
if( gGameExternalOptions.bAssignedTraitsRarity != 0 )
+3 -1
View File
@@ -420,7 +420,9 @@ SOLDIERTYPE* TacticalCreateSoldier( SOLDIERCREATE_STRUCT *pCreateStruct, UINT8 *
SOLDIERTYPE* TacticalCreateAdministrator();
SOLDIERTYPE* TacticalCreateEliteEnemy();
SOLDIERTYPE* TacticalCreateArmyTroop();
SOLDIERTYPE* TacticalCreateZombie(); // Flugente Zombies
#ifdef ENABLE_ZOMBIES
SOLDIERTYPE* TacticalCreateZombie(); // Flugente Zombies
#endif
SOLDIERTYPE* TacticalCreateMilitia( UINT8 ubMilitiaClass );
SOLDIERTYPE* TacticalCreateCreature( INT8 bCreatureBodyType );
+3
View File
@@ -275,11 +275,14 @@ void HandleTacticalEndTurn( )
// Flugente: Cool down all items not in a soldier's inventory
CoolDownWorldItems( FALSE );
#ifdef ENABLE_ZOMBIES
// Flugente: raise zombies if in gamescreen and option set
if ( guiCurrentScreen == GAME_SCREEN )
{
RaiseZombies();
}
#endif
}
+3
View File
@@ -464,11 +464,14 @@ void EndTurnEvents( void )
// Flugente: Cool down all items not in a soldier's inventory
CoolDownWorldItems( FALSE );
#ifdef ENABLE_ZOMBIES
// Flugente: raise zombies if in gamescreen and option set
if ( guiCurrentScreen == GAME_SCREEN )
{
RaiseZombies();
}
#endif
// decay AI warning values from corpses
DecayRottingCorpseAIWarnings();
+2
View File
@@ -8635,12 +8635,14 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, BULLET *pBullet, SOLDIERTYPE * pTarget,
INT8 bStatLoss = 0;
UINT8 ubAmmoType;
#ifdef ENABLE_ZOMBIES
if ( pTarget->IsZombie() && gGameExternalOptions.fZombieOnlyHeadshotsWork )
{
// if bullet does not hits anything other than the head, it doesn't do any damage
if ( ubHitLocation != AIM_SHOT_HEAD )
return 0;
}
#endif
// NOTE: reduction of bullet impact due to range and obstacles is handled
// in MoveBullet.
+4
View File
@@ -4764,7 +4764,11 @@ void DebugSoldierPage4( )
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;
#ifdef ENABLE_ZOMBIES
case SOLDIER_CLASS_ZOMBIE: gprintf( 320, LINE_HEIGHT * ubLine, L"(Zombie)" ); break;
#endif
default: break; //don't care (don't write anything)
}
ubLine++;
+9 -5
View File
@@ -172,12 +172,14 @@ void CreatureCall( SOLDIERTYPE * pCaller );
INT8 CreatureDecideAction( SOLDIERTYPE * pCreature );
void CreatureDecideAlertStatus( SOLDIERTYPE *pCreature );
// Flugente: Zombie AI
INT8 ZombieDecideAction( SOLDIERTYPE * pZombie );
void ZombieDecideAlertStatus( SOLDIERTYPE *pZombie );
#ifdef ENABLE_ZOMBIES
// Flugente: Zombie AI
INT8 ZombieDecideAction( SOLDIERTYPE * pZombie );
void ZombieDecideAlertStatus( SOLDIERTYPE *pZombie );
// a variant of ClosestSeenOpponent(...), that allows zombies
INT32 ClosestSeenOpponentforZombie(SOLDIERTYPE *pSoldier, INT32 * psGridNo, INT8 * pbLevel);
// a variant of ClosestSeenOpponent(...), that allows zombies
INT32 ClosestSeenOpponentforZombie(SOLDIERTYPE *pSoldier, INT32 * psGridNo, INT8 * pbLevel);
#endif
INT8 CrowDecideAction( SOLDIERTYPE * pSoldier );
void DecideAlertStatus( SOLDIERTYPE *pSoldier );
@@ -241,9 +243,11 @@ INT8 FindDirectionForClimbing( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel
// HEADROCK HAM B2.7: Functions to assist group AI
// WANNE: Headrock informed me that I should disable these 3 functions in code, because they need a lot of CPU during AI calculation.
/*
INT16 AssessTacticalSituation( INT8 bSide );
BOOLEAN TeamSeesOpponent( INT8 bSide, SOLDIERTYPE * pOpponent );
INT32 CalcStraightThreatValue( SOLDIERTYPE *pEnemy );
*/
// SANDRO - added following functions
BOOLEAN DoctorIsPresent( SOLDIERTYPE * pPatient, BOOLEAN fOnDoctorAssignmentCheck );
+11
View File
@@ -1616,6 +1616,8 @@ fprintf(NetDebugFile,"\tNPC %d, dtctLvl %d, marking mine at gridno %d, gridCost
void TurnBasedHandleNPCAI(SOLDIERTYPE *pSoldier)
{
#ifdef ENABLE_ZOMBIES
// added by Flugente: static pointers, used to break out of an endless circles (currently only used for zombie AI)
static SOLDIERTYPE* pLastDecisionSoldier = NULL;
static INT16 lastdecisioncount = 0;
@@ -1642,6 +1644,7 @@ void TurnBasedHandleNPCAI(SOLDIERTYPE *pSoldier)
pLastDecisionSoldier = pSoldier;
lastdecisioncount = 0;
}
#endif
/*
if (Status.gamePaused)
@@ -1930,11 +1933,15 @@ void TurnBasedHandleNPCAI(SOLDIERTYPE *pSoldier)
{
if (!(gTacticalStatus.uiFlags & ENGAGED_IN_CONV))
{
#ifdef ENABLE_ZOMBIES
if ( pSoldier->IsZombie() )
{
pSoldier->aiData.bAction = ZombieDecideAction(pSoldier);
}
else if (CREATURE_OR_BLOODCAT( pSoldier ))
#else
if (CREATURE_OR_BLOODCAT( pSoldier ))
#endif
{
pSoldier->aiData.bAction = CreatureDecideAction( pSoldier );
}
@@ -2000,7 +2007,9 @@ void TurnBasedHandleNPCAI(SOLDIERTYPE *pSoldier)
{
// turn based... abort this guy's turn
EndAIGuysTurn( pSoldier );
#ifdef ENABLE_ZOMBIES
lastdecisioncount = 0;
#endif
}
}
else
@@ -2281,8 +2290,10 @@ INT8 ExecuteAction(SOLDIERTYPE *pSoldier)
StartEnemyTaunt( pSoldier, TAUNT_SEEK_NOISE );
else if (pSoldier->aiData.bAction == AI_ACTION_RUN_AWAY )
StartEnemyTaunt( pSoldier, TAUNT_RUN_AWAY );
#ifdef ENABLE_ZOMBIES
else if ( pSoldier->IsZombie() ) // Madd: Zombies randomly moan...
pSoldier->DoMercBattleSound( (INT8)( BATTLE_SOUND_LAUGH1 ) );
#endif
}
}
case AI_ACTION_APPROACH_MERC: // walk up to someone to talk
+83 -79
View File
@@ -1296,98 +1296,100 @@ INT32 ClosestSeenOpponent(SOLDIERTYPE *pSoldier, INT32 * psGridNo, INT8 * pbLeve
// special variant with a minor twist for the zombie AI
INT32 ClosestSeenOpponentforZombie(SOLDIERTYPE *pSoldier, INT32 * psGridNo, INT8 * pbLevel)
{
INT32 sGridNo, sClosestOpponent = NOWHERE;
UINT32 uiLoop;
INT32 iRange, iClosestRange = 1500;
INT8 *pbPersOL;
INT8 bLevel, bClosestLevel;
SOLDIERTYPE * pOpp;
bClosestLevel = -1;
// look through this man's personal & public opplists for opponents known
for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
#ifdef ENABLE_ZOMBIES
INT32 ClosestSeenOpponentforZombie(SOLDIERTYPE *pSoldier, INT32 * psGridNo, INT8 * pbLevel)
{
pOpp = MercSlots[ uiLoop ];
INT32 sGridNo, sClosestOpponent = NOWHERE;
UINT32 uiLoop;
INT32 iRange, iClosestRange = 1500;
INT8 *pbPersOL;
INT8 bLevel, bClosestLevel;
SOLDIERTYPE * pOpp;
// if this merc is inactive, at base, on assignment, or dead
if (!pOpp)
bClosestLevel = -1;
// look through this man's personal & public opplists for opponents known
for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
{
continue; // next merc
pOpp = MercSlots[ uiLoop ];
// if this merc is inactive, at base, on assignment, or dead
if (!pOpp)
{
continue; // next merc
}
// if this merc is neutral/on same side, he's not an opponent
if ( CONSIDERED_NEUTRAL( pSoldier, pOpp ) || (pSoldier->bSide == pOpp->bSide))
{
continue; // next merc
}
// Special stuff for Carmen the bounty hunter
if (pSoldier->aiData.bAttitude == ATTACKSLAYONLY && pOpp->ubProfile != 64)
{
continue; // next opponent
}
pbPersOL = pSoldier->aiData.bOppList + pOpp->ubID;
// if this opponent is not seen personally
if (*pbPersOL != SEEN_CURRENTLY)
{
continue; // next merc
}
// since we're dealing with seen people, use exact gridnos
sGridNo = pOpp->sGridNo;
bLevel = pOpp->pathing.bLevel;
// if we are standing at that gridno(!, obviously our info is old...)
if (sGridNo == pSoldier->sGridNo)
{
continue; // next merc
}
// special: allow zombies to also find opponents on a roof
// otherwise they have will never decide to climb a roof while they are seeing an enemy
// this function is used only for turning towards closest opponent or changing stance
// as such, if they AI is in a building,
// we should ignore people who are on the roof of the same building as the AI
if ( !pSoldier->IsZombie() && (bLevel != pSoldier->pathing.bLevel) && SameBuilding( pSoldier->sGridNo, sGridNo ) )
{
continue;
}
// I hope this will be good enough; otherwise we need a fractional/world-units-based 2D distance function
//sRange = PythSpacesAway( pSoldier->sGridNo, sGridNo);
iRange = GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo, sGridNo );
if (iRange < iClosestRange)
{
iClosestRange = iRange;
sClosestOpponent = sGridNo;
bClosestLevel = bLevel;
}
}
// if this merc is neutral/on same side, he's not an opponent
if ( CONSIDERED_NEUTRAL( pSoldier, pOpp ) || (pSoldier->bSide == pOpp->bSide))
#ifdef DEBUGDECISIONS
if (!TileIsOutOfBounds(sClosestOpponent))
{
continue; // next merc
AINumMessage("CLOSEST OPPONENT is at gridno ",sClosestOpponent);
}
#endif
// Special stuff for Carmen the bounty hunter
if (pSoldier->aiData.bAttitude == ATTACKSLAYONLY && pOpp->ubProfile != 64)
if (psGridNo)
{
continue; // next opponent
*psGridNo = sClosestOpponent;
}
pbPersOL = pSoldier->aiData.bOppList + pOpp->ubID;
// if this opponent is not seen personally
if (*pbPersOL != SEEN_CURRENTLY)
if (pbLevel)
{
continue; // next merc
*pbLevel = bClosestLevel;
}
// since we're dealing with seen people, use exact gridnos
sGridNo = pOpp->sGridNo;
bLevel = pOpp->pathing.bLevel;
// if we are standing at that gridno(!, obviously our info is old...)
if (sGridNo == pSoldier->sGridNo)
{
continue; // next merc
}
// special: allow zombies to also find opponents on a roof
// otherwise they have will never decide to climb a roof while they are seeing an enemy
// this function is used only for turning towards closest opponent or changing stance
// as such, if they AI is in a building,
// we should ignore people who are on the roof of the same building as the AI
if ( !pSoldier->IsZombie() && (bLevel != pSoldier->pathing.bLevel) && SameBuilding( pSoldier->sGridNo, sGridNo ) )
{
continue;
}
// I hope this will be good enough; otherwise we need a fractional/world-units-based 2D distance function
//sRange = PythSpacesAway( pSoldier->sGridNo, sGridNo);
iRange = GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo, sGridNo );
if (iRange < iClosestRange)
{
iClosestRange = iRange;
sClosestOpponent = sGridNo;
bClosestLevel = bLevel;
}
}
#ifdef DEBUGDECISIONS
if (!TileIsOutOfBounds(sClosestOpponent))
{
AINumMessage("CLOSEST OPPONENT is at gridno ",sClosestOpponent);
return( sClosestOpponent );
}
#endif
if (psGridNo)
{
*psGridNo = sClosestOpponent;
}
if (pbLevel)
{
*pbLevel = bClosestLevel;
}
return( sClosestOpponent );
}
INT32 ClosestPC( SOLDIERTYPE *pSoldier, INT32 * psDistance )
{
@@ -2581,9 +2583,11 @@ UINT8 SoldierDifficultyLevel( SOLDIERTYPE * pSoldier )
bDifficulty = 4;
break;
#ifdef ENABLE_ZOMBIES
case SOLDIER_CLASS_ZOMBIE:
bDifficulty = bDifficultyBase;
break;
#endif
default:
if (pSoldier->bTeam == CREATURE_TEAM)
@@ -2733,7 +2737,7 @@ void AINameMessage(SOLDIERTYPE * pSoldier,const STR8 str,INT32 num)
// friendlies. The idea is to return a value called "TacticalSituation" which can tell a combatant
// whether he should try to undertake a smarter course of action.
/////////////////////////////////////////////////////////////////////////////////////////////////
/*
INT16 AssessTacticalSituation( INT8 bTeam )
{
UINT16 ubFriendlyTeamTacticalValue = 0;
@@ -2815,7 +2819,7 @@ INT16 AssessTacticalSituation( INT8 bTeam )
}
*/
// HEADROCK: Function to check whether a team can see the specified soldier.
BOOLEAN TeamSeesOpponent( INT8 bTeam, SOLDIERTYPE * pOpponent )
+1918 -1905
View File
File diff suppressed because it is too large Load Diff
+4
View File
@@ -27,10 +27,12 @@ INT8 RTPlayerDecideAction( SOLDIERTYPE * pSoldier )
{
bAction = DecideAutoBandage( pSoldier );
}
#ifdef ENABLE_ZOMBIES
else if ( pSoldier->IsZombie() )
{
bAction = ZombieDecideAction( pSoldier );
}
#endif
else
{
bAction = DecideAction( pSoldier );
@@ -51,10 +53,12 @@ INT8 RTDecideAction(SOLDIERTYPE *pSoldier)
{
return( CreatureDecideAction( pSoldier ) );
}
#ifdef ENABLE_ZOMBIES
else if ( pSoldier->IsZombie() )
{
return( ZombieDecideAction( pSoldier ) );
}
#endif
else if (pSoldier->ubBodyType == CROW)
{
return( CrowDecideAction( pSoldier ) );
+57
View File
@@ -1582,8 +1582,25 @@ BOOLEAN DamageSoldierFromBlast( UINT8 ubPerson, UINT8 ubOwner, INT32 sBombGridNo
sNewWoundAmt = max( 1, (INT16)(sNewWoundAmt * (100 - gSkillTraitValues.ubBBDamageResistance) / 100));
// Flugente: moved the damage calculation into a separate function
#ifdef ENABLE_ZOMBIES
if ( pSoldier->GetDamageResistance(FALSE, FALSE) > 0 )
sNewWoundAmt -= ((sNewWoundAmt * pSoldier->GetDamageResistance(FALSE, FALSE)) /100);
#else
// Damage resistance for Militia
if (pSoldier->ubSoldierClass == SOLDIER_CLASS_GREEN_MILITIA && gGameExternalOptions.bGreenMilitiaDamageResistance != 0)
sNewWoundAmt -= ((sNewWoundAmt * gGameExternalOptions.bGreenMilitiaDamageResistance) /100);
else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_REG_MILITIA && gGameExternalOptions.bRegularMilitiaDamageResistance != 0)
sNewWoundAmt -= ((sNewWoundAmt * gGameExternalOptions.bRegularMilitiaDamageResistance) /100);
else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA && gGameExternalOptions.bVeteranMilitiaDamageResistance != 0)
sNewWoundAmt -= ((sNewWoundAmt * gGameExternalOptions.bVeteranMilitiaDamageResistance) /100);
// bonus for enemy too
else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ADMINISTRATOR && gGameExternalOptions.sEnemyAdminDamageResistance != 0)
sNewWoundAmt -= ((sNewWoundAmt * gGameExternalOptions.sEnemyAdminDamageResistance) /100);
else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ARMY && gGameExternalOptions.sEnemyRegularDamageResistance != 0)
sNewWoundAmt -= ((sNewWoundAmt * gGameExternalOptions.sEnemyRegularDamageResistance) /100);
else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE && gGameExternalOptions.sEnemyEliteDamageResistance != 0)
sNewWoundAmt -= ((sNewWoundAmt * gGameExternalOptions.sEnemyEliteDamageResistance) /100);
#endif
// we can loose stats due to being hit by the blast
else if ( gGameOptions.fNewTraitSystem && Explosive[Item[usItem].ubClassIndex].ubType == EXPLOSV_NORMAL &&
@@ -1782,6 +1799,38 @@ BOOLEAN DamageSoldierFromBlast( UINT8 ubPerson, UINT8 ubOwner, INT32 sBombGridNo
sNewWoundAmt = max(1, sNewWoundAmt);
}
//////////////////////////////////////////////////////////////////////////////////////
#ifdef ENABLE_ZOMBIES
// Nothing to do here
#else
////////////////////////////////////////////////////////////////////////////////////
// SANDRO - option to make special NPCs stronger - damage resistance
if (gGameExternalOptions.usSpecialNPCStronger > 0)
{
switch( pSoldier->ubProfile )
{
case CARMEN:
case QUEEN:
case JOE:
case ANNIE:
case CHRIS:
case KINGPIN:
case TIFFANY:
case T_REX:
case DRUGGIST:
case GENERAL:
case JACK:
case OLAF:
case RAY:
case OLGA:
case TYRONE:
case MIKE:
sNewWoundAmt -= (sNewWoundAmt * gGameExternalOptions.usSpecialNPCStronger / 200);
sNewWoundAmt = max( 1, sNewWoundAmt);
break;
}
}
#endif
// SANDRO - new merc records - times wounded (blasted by explosion)
if ( ( sNewWoundAmt > 1 || sBreathAmt > 1000 ) && pSoldier->ubProfile != NO_PROFILE )
@@ -1882,7 +1931,11 @@ BOOLEAN DishOutGasDamage( SOLDIERTYPE * pSoldier, EXPLOSIVETYPE * pExplosive, IN
if ( pExplosive->ubType == EXPLOSV_TEARGAS )
{
// zombies and robots are unaffected by tear gas
#ifdef ENABLE_ZOMBIES
if ( AM_A_ROBOT( pSoldier ) || pSoldier->IsZombie() )
#else
if ( AM_A_ROBOT( pSoldier ) )
#endif
{
return( fRecompileMovementCosts );
}
@@ -1896,8 +1949,12 @@ BOOLEAN DishOutGasDamage( SOLDIERTYPE * pSoldier, EXPLOSIVETYPE * pExplosive, IN
}
else if ( pExplosive->ubType == EXPLOSV_MUSTGAS )
{
#ifdef ENABLE_ZOMBIES
// zombies and robots are unaffected by mustard gas
if ( AM_A_ROBOT( pSoldier ) || pSoldier->IsZombie() )
#else
if ( AM_A_ROBOT( pSoldier ) )
#endif
{
return( fRecompileMovementCosts );
}
+6
View File
@@ -5115,7 +5115,10 @@ STR16 zOptionsToggleText[] =
L"自动加速敌军回合", // Automatic fast forward through AI turns
#endif
#ifdef ENABLE_ZOMBIES
L"Allow Zombies", // TODO.Translate
#endif
L"--作弊模式选项--", // TOPTION_CHEAT_MODE_OPTIONS_HEADER,
L"强制 Bobby Ray 送货", // force all pending Bobby Ray shipments
L"-----------------", // TOPTION_CHEAT_MODE_OPTIONS_END
@@ -5228,7 +5231,10 @@ STR16 zOptionsScreenHelpText[] =
L"打开时,敌军回合将被大幅加速。",
#endif
#ifdef ENABLE_ZOMBIES
L"When ON, zombies will span. Be aware!", // allow zombies // TODO.Translate
#endif
L"(text not rendered)TOPTION_CHEAT_MODE_OPTIONS_HEADER",
L"强制 Bobby Ray 出货",
L"(text not rendered)TOPTION_CHEAT_MODE_OPTIONS_END",
+6
View File
@@ -5114,7 +5114,10 @@ STR16 zOptionsToggleText[] =
L"Auto Fast Forward AI Turns", // Automatic fast forward through AI turns // TODO.Translate
#endif
#ifdef ENABLE_ZOMBIES
L"Allow Zombies", // TODO.Translate
#endif
L"--Cheat Mode Options--", // TOPTION_CHEAT_MODE_OPTIONS_HEADER,
L"Force Bobby Ray shipments", // force all pending Bobby Ray shipments
L"-----------------", // TOPTION_CHEAT_MODE_OPTIONS_END
@@ -5227,7 +5230,10 @@ STR16 zOptionsScreenHelpText[] =
L"When ON, AI turns will be much faster.", // TODO.Translate
#endif
#ifdef ENABLE_ZOMBIES
L"When ON, zombies will span. Be aware!", // allow zombies // TODO.Translate
#endif
L"(text not rendered)TOPTION_CHEAT_MODE_OPTIONS_HEADER",
L"Force all pending Bobby Ray shipments",
L"(text not rendered)TOPTION_CHEAT_MODE_OPTIONS_END",
+6
View File
@@ -5113,7 +5113,10 @@ STR16 zOptionsToggleText[] =
L"Auto Fast Forward AI Turns", // Automatic fast forward through AI turns
#endif
#ifdef ENABLE_ZOMBIES
L"Allow Zombies", // Flugente Zombies 1.0
#endif
L"--Cheat Mode Options--", // TOPTION_CHEAT_MODE_OPTIONS_HEADER,
L"Force Bobby Ray shipments", // force all pending Bobby Ray shipments
L"-----------------", // TOPTION_CHEAT_MODE_OPTIONS_END
@@ -5226,7 +5229,10 @@ STR16 zOptionsScreenHelpText[] =
L"When ON, AI turns will be much faster.",
#endif
#ifdef ENABLE_ZOMBIES
L"When ON, zombies will spawn. Be aware!", // allow zombies
#endif
L"(text not rendered)TOPTION_CHEAT_MODE_OPTIONS_HEADER",
L"Force all pending Bobby Ray shipments",
L"(text not rendered)TOPTION_CHEAT_MODE_OPTIONS_END",
+6
View File
@@ -5104,7 +5104,10 @@ STR16 zOptionsToggleText[] =
L"Auto Fast Forward AI Turns", // Automatic fast forward through AI turns // TODO.Translate
#endif
#ifdef ENABLE_ZOMBIES
L"Allow Zombies", // Flugente Zombies 1.0
#endif
L"--Cheat Mode Options--", // TOPTION_CHEAT_MODE_OPTIONS_HEADER,
L"Forcer envois Bobby Ray", // force all pending Bobby Ray shipments
L"-----------------", // TOPTION_CHEAT_MODE_OPTIONS_END
@@ -5217,7 +5220,10 @@ STR16 zOptionsScreenHelpText[] =
L"When ON, AI turns will be much faster.", // TODO.Translate
#endif
#ifdef ENABLE_ZOMBIES
L"When ON, zombies will span. Be aware!", // allow zombies // TODO.Translate
#endif
L"(text not rendered)TOPTION_CHEAT_MODE_OPTIONS_HEADER",
L"Forcer tous les envois en attente de Bobby Ray",
L"(text not rendered)TOPTION_CHEAT_MODE_OPTIONS_END",
+6
View File
@@ -4962,7 +4962,10 @@ STR16 zOptionsToggleText[] =
L"Autom. schnelle Gegner-Züge", // Automatic fast forward through AI turns
#endif
#ifdef ENABLE_ZOMBIES
L"Allow Zombies", // Flugente Zombies 1.0
#endif
L"--Cheat Mode Options--", // TOPTION_CHEAT_MODE_OPTIONS_HEADER,
L"Erzwinge BR Lieferung", // force all pending Bobby Ray shipments
L"-----------------", // TOPTION_CHEAT_MODE_OPTIONS_END
@@ -5075,7 +5078,10 @@ STR16 zOptionsScreenHelpText[] =
L"Wenn diese Funktion aktiviert ist, werden gegnerische Züge schneller durchgeführt.",
#endif
#ifdef ENABLE_ZOMBIES
L"When ON, zombies will span. Be aware!", // allow zombies // TODO.Translate
#endif
L"(text not rendered)TOPTION_CHEAT_MODE_OPTIONS_HEADER",
L"Force all pending Bobby Ray shipments",
L"(text not rendered)TOPTION_CHEAT_MODE_OPTIONS_END",
+6
View File
@@ -5099,7 +5099,10 @@ STR16 zOptionsToggleText[] =
L"Auto Fast Forward AI Turns", // Automatic fast forward through AI turns // TODO.Translate
#endif
#ifdef ENABLE_ZOMBIES
L"Allow Zombies", // Flugente Zombies 1.0
#endif
L"--Cheat Mode Options--", // TOPTION_CHEAT_MODE_OPTIONS_HEADER,
L"Force Bobby Ray shipments", // force all pending Bobby Ray shipments
L"-----------------", // TOPTION_CHEAT_MODE_OPTIONS_END
@@ -5212,7 +5215,10 @@ STR16 zOptionsScreenHelpText[] =
L"When ON, AI turns will be much faster.", // TODO.Translate
#endif
#ifdef ENABLE_ZOMBIES
L"When ON, zombies will span. Be aware!", // allow zombies // TODO.Translate
#endif
L"(text not rendered)TOPTION_CHEAT_MODE_OPTIONS_HEADER",
L"Force all pending Bobby Ray shipments",
L"(text not rendered)TOPTION_CHEAT_MODE_OPTIONS_END",
+6
View File
@@ -5111,7 +5111,10 @@ STR16 zOptionsToggleText[] =
L"Auto Fast Forward AI Turns", // Automatic fast forward through AI turns // TODO.Translate
#endif
#ifdef ENABLE_ZOMBIES
L"Allow Zombies", // Flugente Zombies 1.0
#endif
L"--Cheat Mode Options--", // TOPTION_CHEAT_MODE_OPTIONS_HEADER,
L"Force Bobby Ray shipments", // force all pending Bobby Ray shipments
L"-----------------", // TOPTION_CHEAT_MODE_OPTIONS_END
@@ -5224,7 +5227,10 @@ STR16 zOptionsScreenHelpText[] =
L"When ON, AI turns will be much faster.", // TODO.Translate
#endif
#ifdef ENABLE_ZOMBIES
L"When ON, zombies will span. Be aware!", // allow zombies // TODO.Translate
#endif
L"(text not rendered)TOPTION_CHEAT_MODE_OPTIONS_HEADER",
L"WymuŚ wszystkie oczekiwane dostawy od Bobby Ray's.",
L"(text not rendered)TOPTION_CHEAT_MODE_OPTIONS_END",
+6
View File
@@ -5094,7 +5094,10 @@ STR16 zOptionsToggleText[] =
L"Auto Fast Forward AI Turns", // Automatic fast forward through AI turns // TODO.Translate
#endif
#ifdef ENABLE_ZOMBIES
L"Allow Zombies", // Flugente Zombies 1.0
#endif
L"--Читерские настройки--", // TOPTION_CHEAT_MODE_OPTIONS_HEADER,
L"Ускорить доставку Бобби Рэя", // force all pending Bobby Ray shipments
L"-----------------", // TOPTION_CHEAT_MODE_OPTIONS_END
@@ -5207,7 +5210,10 @@ STR16 zOptionsScreenHelpText[] =
L"When ON, AI turns will be much faster.", // TODO.Translate
#endif
#ifdef ENABLE_ZOMBIES
L"When ON, zombies will span. Be aware!", // allow zombies // TODO.Translate
#endif
L"(text not rendered)TOPTION_CHEAT_MODE_OPTIONS_HEADER",
L"Выберите этот пункт чтобы груз Бобби Рэя прибыл немедленно.",
L"(text not rendered)TOPTION_CHEAT_MODE_OPTIONS_END",
+6
View File
@@ -5115,7 +5115,10 @@ STR16 zOptionsToggleText[] =
L"Auto Fast Forward AI Turns", // Automatic fast forward through AI turns // TODO.Translate
#endif
#ifdef ENABLE_ZOMBIES
L"Allow Zombies", // Flugente Zombies 1.0
#endif
L"--Cheat Mode Options--", // TOPTION_CHEAT_MODE_OPTIONS_HEADER,
L"Force Bobby Ray shipments", // force all pending Bobby Ray shipments
L"-----------------", // TOPTION_CHEAT_MODE_OPTIONS_END
@@ -5228,7 +5231,10 @@ STR16 zOptionsScreenHelpText[] =
L"When ON, AI turns will be much faster.", // TODO.Translate
#endif
#ifdef ENABLE_ZOMBIES
L"When ON, zombies will span. Be aware!", // allow zombies // TODO.Translate
#endif
L"(text not rendered)TOPTION_CHEAT_MODE_OPTIONS_HEADER",
L"Force all pending Bobby Ray shipments",
L"(text not rendered)TOPTION_CHEAT_MODE_OPTIONS_END",
+13 -1
View File
@@ -3,10 +3,22 @@
#include "Language Defines.h"
// -----------------------------
// *****************************
// WANNE: Enable this define, to build an executable where you can enable/disable zombies in tactical (ingame option screen).
// It seems, that executables compiled with this zombie option turned on, causes slowdown in tactical.
//#define ENABLE_ZOMBIES
// -----------------------------
// *****************************
// -----------------------------
// *****************************
// WANNE: Enable this define, to build the gameloop with the highspeed timer. To use the highspeed timer, you also have to set the HIGHSPEED_TIMER = TRUE in ja2.ini
// CAUTION: A lot of games reported, when the exe is compiled with the highspeed timer on, the game runs very slowly in strategy map screen when doing repair, ..
// This is the reason, why I made a compilation define, where we can turn on/off the highspeed timer.
//#define USE_HIGHSPEED_GAMELOOP_TIMER
#define USE_HIGHSPEED_GAMELOOP_TIMER
// -----------------------------
// *****************************
// -----------------------------
// *****************************