mirror of
https://github.com/1dot13/source.git
synced 2026-07-22 13:40:22 +02:00
- 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:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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++;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 ];
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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 );
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user