- new ini option ZOMBIE_ONLY_HEADSHOTS_PERMANENTLY_KILL: if a zombie is killed via headshot/melee combat, he can't rise again

- new ini option FOOD_MAX_POISONING: determines the maximum amount of food poisoning eating a singel food item can give
- fixed a bug that caused tooltips to display the wrong traits
- fixed a few zombie-related bugs

git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@5669 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
Flugente
2012-11-05 22:38:52 +00:00
parent 4c232c38c7
commit 8ace761e7f
11 changed files with 92 additions and 19 deletions
+3
View File
@@ -1401,6 +1401,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);
gGameExternalOptions.fZombieOnlyHeadShotsPermanentlyKill = iniReader.ReadBoolean("Tactical Zombie Settings", "ZOMBIE_ONLY_HEADSHOTS_PERMANENTLY_KILL", TRUE);
#endif
//################# Tactical Poison Settings ##################
@@ -1425,6 +1426,8 @@ void LoadGameExternalOptions()
gGameExternalOptions.fFoodDecayInSectors = iniReader.ReadBoolean("Tactical Food Settings", "FOOD_DECAY_IN_SECTORS", TRUE);
gGameExternalOptions.sFoodDecayModificator = iniReader.ReadFloat("Tactical Food Settings", "FOOD_DECAY_MODIFICATOR", 1.0f, 0.1f, 10.0f);
gGameExternalOptions.usFoodMaxPoisoning = iniReader.ReadInteger("Tactical Food Settings", "FOOD_MAX_POISONING", 5, 0, 100);
//################# Strategic Gamestart Settings ##################
//Lalien: Game starting time
+3
View File
@@ -383,6 +383,7 @@ typedef struct
BOOLEAN fZombieOnlyHeadshotsWork;
INT8 sZombieDifficultyLevel;
BOOLEAN fZombieRiseWithArmour;
BOOLEAN fZombieOnlyHeadShotsPermanentlyKill;
#endif
// Flugente: poison settings
@@ -406,6 +407,8 @@ typedef struct
BOOLEAN fFoodDecayInSectors;
FLOAT sFoodDecayModificator;
UINT8 usFoodMaxPoisoning;
//Animation settings
FLOAT giPlayerTurnSpeedUpFactor;
+7
View File
@@ -112,6 +112,13 @@ void ValidateEnemiesHaveWeapons()
{
continue;
}
#ifdef ENABLE_ZOMBIES
// Flugente: zombies are fine with having no weapons...
if ( pSoldier->IsZombie() )
continue;
#endif
if( !pSoldier->inv[ HANDPOS ].usItem )
{
iNumInvalid++;
+3
View File
@@ -142,6 +142,9 @@ BOOLEAN ApplyFood( SOLDIERTYPE *pSoldier, OBJECTTYPE *pObject, BOOLEAN fForce, B
// multiply with 0.25 for more reasonable values
INT8 poisonadd = (INT8)(0.01 * 0.25 * maxpts * (1.0 - foodcondition) );
// added a max threshold to food poisoning
poisonadd = min(poisonadd, gGameExternalOptions.usFoodMaxPoisoning),
pSoldier->AddPoison(poisonadd);
}
+15
View File
@@ -9767,3 +9767,18 @@ void HandleDisplayingOfPlayerLostDialogue( void )
}
}
#endif
// Flugente: the entire new trait to string thingy is a fucked up mess. I've had it. Heres a function that simply handles that crap.
STR16 GetNewTraitStr(UINT8 aTrait)
{
if ( aTrait <= DOCTOR_NT )
;
else if ( aTrait <= SCOUTING_NT )
++aTrait;
else if ( aTrait == COVERT_NT )
aTrait = 10;
else if ( aTrait >= SCOUTING_NT + NUM_MINOR_TRAITS )
aTrait -= NUM_MINOR_TRAITS;
return gzMercSkillTextNew[ aTrait ];
}
+2
View File
@@ -404,4 +404,6 @@ extern UINT8 NumEnemyInSector();
extern UINT8 NumZombiesInSector();
#endif
STR16 GetNewTraitStr(UINT8 aTrait); // Flugente: deal with the insane new trait to string stuff
#endif
+5 -1
View File
@@ -893,6 +893,10 @@ BOOLEAN TurnSoldierIntoCorpse( SOLDIERTYPE *pSoldier, BOOLEAN fRemoveMerc, BOOLE
break;
}
// if zombie and headshots are required, forbid rising if killed by headshot
if ( pSoldier->IsZombie() && gGameExternalOptions.fZombieOnlyHeadShotsPermanentlyKill && (pSoldier->bSoldierFlagMask & SOLDIER_HEADSHOT) )
Corpse.usFlags |= ROTTING_CORPSE_NEVER_RISE_AGAIN;
// Flugente: copy name of soldier...
memcpy( &(Corpse.name), &(pSoldier->name), sizeof(CHAR16) * 10 );
Corpse.name[9] = '\0';
@@ -2730,7 +2734,7 @@ UINT8 GetNearestRottingCorpseAIWarning( INT32 sGridNo )
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);
pNewSoldier->bPoisonAbsorption = 0; // Flugente: Screw this, we use GetPoisonAbsorption() instead... I declare this variable dead until further notice
//////////////////////////////////////////////////////////////////////
#ifdef ENABLE_ZOMBIES
+17 -2
View File
@@ -5861,7 +5861,7 @@ void SOLDIERTYPE::EVENT_SoldierGotHit( UINT16 usWeaponIndex, INT16 sDamage, INT1
return;
}
INT16 poisondamage = (INT16) ( sDamage * MercPtrs[ubAttackerID]->GetPoisonDamagePercentage() / 100 );
INT16 poisondamage = (INT16) ( (sDamage * MercPtrs[ubAttackerID]->GetPoisonDamagePercentage()) / 100 );
// DEDUCT LIFE
ubCombinedLoss = this->SoldierTakeDamage( ANIM_CROUCH, sDamage, poisondamage, sBreathLoss, ubReason, this->ubAttackerID, NOWHERE, FALSE, TRUE );
@@ -10480,6 +10480,10 @@ BOOLEAN SOLDIERTYPE::CheckSoldierHitRoof( void )
fReturnVal = TRUE;
}
// Flugente: some bodytypes can't do these animations, so skip this
if ( IsAnimationValidForBodyType( this, this->usPendingAnimation ) == FALSE )
fReturnVal = FALSE;
}
}
@@ -11838,7 +11842,7 @@ void SOLDIERTYPE::EVENT_SoldierBeginPunchAttack( INT32 sGridNo, UINT8 ubDirectio
if ( pTSoldier->bBreath - breathdamage < 0 )
breathdamage = pTSoldier->bBreath;
INT16 poisondamage = (INT16) ( sDamage * this->GetPoisonDamagePercentage() / 100 );
INT16 poisondamage = (INT16) ( (damage * this->GetPoisonDamagePercentage()) / 100 );
// zombies do ~50% poison damage
pTSoldier->SoldierTakeDamage( 0, damage, poisondamage, breathdamage, TAKE_DAMAGE_HANDTOHAND, this->ubID, pTSoldier->sGridNo, 0, TRUE );
@@ -13956,6 +13960,11 @@ INT16 SOLDIERTYPE::GetPoisonAbsorption( void )
{
// Flugente: absorption can per definition only be >= 0 (at least that's my definition)
INT16 val = bPoisonAbsorption;
#ifdef ENABLE_ZOMBIES
if ( IsZombie() )
val += 200;
#endif
val = max(0, val);
@@ -15018,6 +15027,12 @@ BOOLEAN SOLDIERTYPE::RecognizeAsCombatant(UINT8 ubTargetID)
if ( !pSoldier )
return TRUE;
#ifdef ENABLE_ZOMBIES
// zombies don't care about disguises
if ( IsZombie() )
return TRUE;
#endif
// if neither of the 2 persons is covert, always return true
if ( ( (pSoldier->bSoldierFlagMask & (SOLDIER_COVERT_CIV|SOLDIER_COVERT_SOLDIER)) == 0 ) && ( (this->bSoldierFlagMask & (SOLDIER_COVERT_CIV|SOLDIER_COVERT_SOLDIER)) == 0 ) )
return TRUE;
+2 -2
View File
@@ -354,8 +354,8 @@ enum
#define SOLDIER_NEW_PANTS 0x00000080 //128 // Soldier is wearing new pants
#define SOLDIER_DAMAGED_PANTS 0x00000100 //256 // Soldier's vest is damaged (and thus can't be taken off)
/*#define WH40K_SEAL 0x00000200 //512
#define WH40K_POWER_WEAPON 0x00000400 //1024
#define SOLDIER_HEADSHOT 0x00000200 //512 // last hit received was a headshot (attack to the head, so knifes/punches also work)
/*#define WH40K_POWER_WEAPON 0x00000400 //1024
#define ENEMY_NET_4_LVL_3 0x00000800 //2048
#define ENEMY_NET_1_LVL_4 0x00001000 //4096
+12 -12
View File
@@ -236,33 +236,33 @@ void SoldierTooltip( SOLDIERTYPE* pSoldier )
if (( pSoldier->stats.ubSkillTraits[0] == pSoldier->stats.ubSkillTraits[1] ) && pSoldier->stats.ubSkillTraits[0] != 0 )
{
CHAR16 pStrAux[50];
swprintf( pStrAux, L"(%s)", gzMercSkillTextNew[pSoldier->stats.ubSkillTraits[0]]);
swprintf( pStrAux, L"(%s)", GetNewTraitStr(pSoldier->stats.ubSkillTraits[0]));
swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_1], pStrInfo, pStrAux );
swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_2], pStrInfo, gzMercSkillTextNew[pSoldier->stats.ubSkillTraits[1] + NEWTRAIT_MERCSKILL_EXPERTOFFSET] );
swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_3], pStrInfo, gzMercSkillTextNew[pSoldier->stats.ubSkillTraits[2]] );
swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_2], pStrInfo, GetNewTraitStr(pSoldier->stats.ubSkillTraits[1] + NEWTRAIT_MERCSKILL_EXPERTOFFSET) );
swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_3], pStrInfo, GetNewTraitStr(pSoldier->stats.ubSkillTraits[2]) );
//swprintf( pStrInfo, L"%s\n", pStrInfo );
}
else if (( pSoldier->stats.ubSkillTraits[1] == pSoldier->stats.ubSkillTraits[2] ) && pSoldier->stats.ubSkillTraits[1] != 0 )
{
CHAR16 pStrAux[50];
swprintf( pStrAux, L"(%s)", gzMercSkillTextNew[pSoldier->stats.ubSkillTraits[1]]);
swprintf( pStrAux, L"(%s)", GetNewTraitStr(pSoldier->stats.ubSkillTraits[1]));
swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_1], pStrInfo, pStrAux );
swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_2], pStrInfo, gzMercSkillTextNew[pSoldier->stats.ubSkillTraits[2] + NEWTRAIT_MERCSKILL_EXPERTOFFSET] );
swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_3], pStrInfo, gzMercSkillTextNew[pSoldier->stats.ubSkillTraits[0]] );
swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_2], pStrInfo, GetNewTraitStr(pSoldier->stats.ubSkillTraits[2] + NEWTRAIT_MERCSKILL_EXPERTOFFSET) );
swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_3], pStrInfo, GetNewTraitStr(pSoldier->stats.ubSkillTraits[0]) );
}
else if (( pSoldier->stats.ubSkillTraits[0] == pSoldier->stats.ubSkillTraits[2] ) && pSoldier->stats.ubSkillTraits[0] != 0 )
{
CHAR16 pStrAux[50];
swprintf( pStrAux, L"(%s)", gzMercSkillTextNew[pSoldier->stats.ubSkillTraits[0]]);
swprintf( pStrAux, L"(%s)", GetNewTraitStr(pSoldier->stats.ubSkillTraits[0]));
swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_1], pStrInfo, pStrAux );
swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_2], pStrInfo, gzMercSkillTextNew[pSoldier->stats.ubSkillTraits[2] + NEWTRAIT_MERCSKILL_EXPERTOFFSET] );
swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_3], pStrInfo, gzMercSkillTextNew[pSoldier->stats.ubSkillTraits[1]] );
swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_2], pStrInfo, GetNewTraitStr(pSoldier->stats.ubSkillTraits[2] + NEWTRAIT_MERCSKILL_EXPERTOFFSET) );
swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_3], pStrInfo, GetNewTraitStr(pSoldier->stats.ubSkillTraits[1]) );
}
else
{
swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_1], pStrInfo, gzMercSkillTextNew[pSoldier->stats.ubSkillTraits[0]] );
swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_2], pStrInfo, gzMercSkillTextNew[pSoldier->stats.ubSkillTraits[1]] );
swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_3], pStrInfo, gzMercSkillTextNew[pSoldier->stats.ubSkillTraits[2]] );
swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_1], pStrInfo, GetNewTraitStr(pSoldier->stats.ubSkillTraits[0]) );
swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_2], pStrInfo, GetNewTraitStr(pSoldier->stats.ubSkillTraits[1]) );
swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_3], pStrInfo, GetNewTraitStr(pSoldier->stats.ubSkillTraits[2]) );
}
}
else
+23 -2
View File
@@ -8866,11 +8866,20 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, BULLET *pBullet, SOLDIERTYPE * pTarget,
UINT8 ubAmmoType;
#ifdef ENABLE_ZOMBIES
if ( pTarget->IsZombie() && gGameExternalOptions.fZombieOnlyHeadshotsWork )
if ( pTarget->IsZombie() )
{
// if bullet does not hits anything other than the head, it doesn't do any damage
if ( ubHitLocation != AIM_SHOT_HEAD )
if ( gGameExternalOptions.fZombieOnlyHeadshotsWork && ubHitLocation != AIM_SHOT_HEAD )
return 0;
// set a flag if this was a headshot, unset if it wasn't. Thus we can determine if this was a headshot kill (only if life > 0, ignore if already dead)
if ( gGameExternalOptions.fZombieOnlyHeadShotsPermanentlyKill && pTarget->stats.bLife > 0 )
{
if ( ubHitLocation == AIM_SHOT_HEAD )
pTarget->bSoldierFlagMask |= SOLDIER_HEADSHOT;
else
pTarget->bSoldierFlagMask &= ~SOLDIER_HEADSHOT;
}
}
#endif
@@ -9738,6 +9747,18 @@ INT32 HTHImpact( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pTarget, INT32 iHitBy, BO
BOOLEAN autoresolve = IsAutoResolveActive();
iImpact = max( 1, (INT32)(iImpact * (100 - pTarget->GetDamageResistance(autoresolve, FALSE)) / 100 ) );
#ifdef ENABLE_ZOMBIES
// 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)
if ( pTarget->IsZombie() )
{
// set a flag if this was a headshot, unset if it wasn't. Thus we can determine if this was a headshot kill (only if life > 0, ignore if already dead)
if ( gGameExternalOptions.fZombieOnlyHeadShotsPermanentlyKill && pTarget->stats.bLife > 0 )
{
pTarget->bSoldierFlagMask |= SOLDIER_HEADSHOT;
}
}
#endif
return( iImpact );
}