Files
source/Tactical/Drugs And Alcohol.cpp

424 lines
13 KiB
C++

#include "sgp.h"
#include "Soldier Control.h"
#include "Soldier Profile.h"
#include "Drugs And Alcohol.h"
#include "Items.h"
#include "Morale.h"
#include "Points.h"
#include "message.h"
#include "GameSettings.h" // SANDRO - had to add this, dammit!
#include "random.h"
#include "Text.h"
#include "Interface.h"
#include "Food.h" // added by Flugente
#include "Animation Data.h" // added by Flugente for SoldierBodyTypes
#include "CampaignStats.h" // added by Flugente
#include "DynamicDialogue.h"// added by Flugente
//forward declarations of common classes to eliminate includes
class OBJECTTYPE;
INT32 giDrunkModifier[] =
{
100, // Sober
75, // Feeling good,
65, // Bporderline
50, // Drunk
100, // HungOver
};
#define HANGOVER_AP_REDUCE 5
#define HANGOVER_BP_REDUCE 200
BOOLEAN ApplyDrugs_New( SOLDIERTYPE *pSoldier, UINT16 usItem, UINT16 uStatusUsed )
{
// If not a drug, return
if ( !Item[usItem].drugtype || !uStatusUsed || !pSoldier )
return(FALSE);
UINT32 drugused = Item[usItem].drugtype;
// to stop Larry from getting stoned via unsanitary bandages etc., note whether this is a 'real' drug
BOOL complainworthyeffects = FALSE;
// we might not use up the entire item, so reduce effects accordingly
FLOAT effectivepercentage = uStatusUsed / 100.0;
// if this alcohol, alcohol resistance can lower the effects
if ( Item[usItem].alcohol > 0.0f )
{
effectivepercentage = effectivepercentage * ((100.0 - pSoldier->GetBackgroundValue( BG_RESI_ALCOHOL )) / 100.0);
FLOAT weight = pSoldier->GetBodyWeight( );
// the alcohol amounts in the xml are intended for a person with weight 80. We thus have to alter the effective value
if ( weight > 0.0f )
{
effectivepercentage *= 80.0f / weight;
}
}
// we now add drug, disease, personality and disability effects
// every effect has a chance of happening (not entering a chance, so 0, always results in a effect for xml editing simplicity reasons)
// add effects
std::vector<DRUG_EFFECT> vec_drug = NewDrug[drugused].drug_effects;
std::vector<DRUG_EFFECT>::iterator drug_effects_itend = vec_drug.end( );
for ( std::vector<DRUG_EFFECT>::iterator drug_effects_it = vec_drug.begin( ); drug_effects_it != drug_effects_itend; ++drug_effects_it )
{
if ( !(*drug_effects_it).chance || Chance( (*drug_effects_it).chance ) )
{
// if we are already under influence of this effect, merge them, otherwise just add effect
if ( pSoldier->newdrugs.duration[(*drug_effects_it).effect] )
{
INT32 effectsum_existing = pSoldier->newdrugs.duration[(*drug_effects_it).effect] * pSoldier->newdrugs.size[(*drug_effects_it).effect];
INT32 effectsum_new = (*drug_effects_it).duration * (*drug_effects_it).size;
INT32 effectsum_total = effectsum_existing + effectsum_new * effectivepercentage;
UINT16 newduration = (pSoldier->newdrugs.duration[(*drug_effects_it).effect] + (*drug_effects_it).duration) / 2;
if ( newduration )
{
INT32 newsize = effectsum_total / newduration;
pSoldier->newdrugs.duration[(*drug_effects_it).effect] = newduration;
pSoldier->newdrugs.size[(*drug_effects_it).effect] = newsize;
}
}
else
{
pSoldier->newdrugs.duration[(*drug_effects_it).effect] = (*drug_effects_it).duration;
pSoldier->newdrugs.size[(*drug_effects_it).effect] = (*drug_effects_it).size * effectivepercentage;
}
complainworthyeffects = TRUE;
}
}
// add diseases
std::vector<DISEASE_EFFECT> vec_disease = NewDrug[drugused].disease_effects;
std::vector<DISEASE_EFFECT>::iterator disease_effects_itend = vec_disease.end( );
for ( std::vector<DISEASE_EFFECT>::iterator disease_effects_it = vec_disease.begin( ); disease_effects_it != disease_effects_itend; ++disease_effects_it )
{
if ( !(*disease_effects_it).chance || Chance( (*disease_effects_it).chance ) )
{
pSoldier->AddDiseasePoints( (*disease_effects_it).disease, (*disease_effects_it).size * effectivepercentage );
}
}
// add disability
std::vector<DISABILITY_EFFECT> vec_disability = NewDrug[drugused].disability_effects;
std::vector<DISABILITY_EFFECT>::iterator disability_effects_itend = vec_disability.end( );
for ( std::vector<DISABILITY_EFFECT>::iterator disability_effects_it = vec_disability.begin( ); disability_effects_it != disability_effects_itend; ++disability_effects_it )
{
if ( !(*disability_effects_it).chance || Chance( (*disability_effects_it).chance ) )
{
if ( pSoldier->newdrugs.drugdisability == (*disability_effects_it).disability )
{
pSoldier->newdrugs.drugdisability_duration += (*disability_effects_it).duration * effectivepercentage;
}
else
{
pSoldier->newdrugs.drugdisability = (*disability_effects_it).disability;
pSoldier->newdrugs.drugdisability_duration = (*disability_effects_it).duration * effectivepercentage;
}
}
}
// add personality
std::vector<PERSONALITY_EFFECT> vec_personality = NewDrug[drugused].personality_effects;
std::vector<PERSONALITY_EFFECT>::iterator personality_effects_itend = vec_personality.end( );
for ( std::vector<PERSONALITY_EFFECT>::iterator personality_effects_it = vec_personality.begin( ); personality_effects_it != personality_effects_itend; ++personality_effects_it )
{
if ( !(*personality_effects_it).chance || Chance( (*personality_effects_it).chance ) )
{
if ( pSoldier->newdrugs.drugpersonality == (*personality_effects_it).personality )
{
pSoldier->newdrugs.drugpersonality_duration += (*personality_effects_it).duration * effectivepercentage;
}
else
{
pSoldier->newdrugs.drugpersonality = (*personality_effects_it).personality;
pSoldier->newdrugs.drugpersonality_duration = (*personality_effects_it).duration * effectivepercentage;
}
}
}
if ( complainworthyeffects )
{
// do switch for Larry!!
if ( pSoldier->ubProfile == LARRY_NORMAL )
{
SwapToProfile( pSoldier, LARRY_DRUNK );
gMercProfiles[LARRY_NORMAL].bNPCData = LARRY_FALLS_OFF_WAGON;
}
else if ( pSoldier->ubProfile == LARRY_DRUNK )
{
// NB store all drunkenness info in LARRY_NORMAL profile (to use same values)
// so long as he keeps consuming, keep number above level at which he cracked
gMercProfiles[LARRY_NORMAL].bNPCData += (INT8)Random( 5 );
// allow value to keep going up to 24 (about 2 days since we subtract Random( 2 ) when he has no access )
gMercProfiles[LARRY_NORMAL].bNPCData = __min( gMercProfiles[LARRY_NORMAL].bNPCData, 24 );
gMercProfiles[LARRY_NORMAL].bNPCData = __max( gMercProfiles[LARRY_NORMAL].bNPCData, LARRY_FALLS_OFF_WAGON );
}
if (gGameExternalOptions.fDynamicOpinions && NewDrug[drugused].opinionevent )
{
HandleDynamicOpinionChange( pSoldier, OPINIONEVENT_ADDICT, TRUE, TRUE );
}
}
if ( Item[usItem].alcohol > 0.0f )
{
FLOAT weight = pSoldier->GetBodyWeight( );
// the alcohol amounts in the xml are intended for a person with weight 80. We thus have to alter the effective value
if ( weight > 0.0f )
{
// added promille = alcohol added (g) / (weight of person (kg) * 0.7)
FLOAT addedpromille = (Item[usItem].alcohol * effectivepercentage) / (weight * 0.7);
pSoldier->newdrugs.drinkstaken += addedpromille;
}
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, pMessageStrings[MSG_DRANK_SOME], pSoldier->GetName( ), ShortItemNames[usItem] );
if (gGameExternalOptions.fDynamicOpinions)
{
HandleDynamicOpinionTeamDrinking(pSoldier);
}
}
else
{
// set flag: we are on non-alcoholic drugs
pSoldier->usSoldierFlagMask |= SOLDIER_DRUGGED;
if ( complainworthyeffects && gMercProfiles[pSoldier->ubProfile].ubNumTimesDrugUseInLifetime != 255 )
{
gMercProfiles[pSoldier->ubProfile].ubNumTimesDrugUseInLifetime++;
}
if (ItemIsCigarette(usItem))
{
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, pMessageStrings[MSG_MERC_TOOK_CIGARETTE], pSoldier->GetName( ), ShortItemNames[usItem] );
}
else
{
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, pMessageStrings[MSG_MERC_TOOK_DRUG], pSoldier->GetName( ), ShortItemNames[usItem] );
}
}
// Dirty panel
fInterfacePanelDirty = DIRTYLEVEL2;
fCharacterInfoPanelDirty = TRUE;
return TRUE;
}
void HandleEndTurnDrugAdjustments_New( SOLDIERTYPE *pSoldier )
{
// some effects are handled here
if ( pSoldier->newdrugs.size[DRUG_EFFECT_HP] )
{
// note the current hp
INT8 oldlife = pSoldier->stats.bLife;
// increase life
pSoldier->stats.bLife = __min( pSoldier->stats.bLife + pSoldier->newdrugs.size[DRUG_EFFECT_HP], pSoldier->stats.bLifeMax );
//SANDRO - Insta-healable injury reduction
if ( pSoldier->newdrugs.size[DRUG_EFFECT_HP] > 0 )
{
pSoldier->iHealableInjury = max( 0, (pSoldier->iHealableInjury - (100 * pSoldier->newdrugs.size[DRUG_EFFECT_HP])) );
}
if ( pSoldier->stats.bLife == pSoldier->stats.bLifeMax )
{
pSoldier->bBleeding = 0;
pSoldier->iHealableInjury = 0;
}
else if ( pSoldier->bBleeding + pSoldier->stats.bLife > pSoldier->stats.bLifeMax )
{
// got to reduce amount of bleeding
pSoldier->bBleeding = (pSoldier->stats.bLifeMax - pSoldier->stats.bLife);
}
// display health change next time we are in tactical
pSoldier->flags.fDisplayDamage = TRUE;
pSoldier->sDamage -= pSoldier->stats.bLife - oldlife;
}
pSoldier->bExtraStrength += pSoldier->newdrugs.size[DRUG_EFFECT_STR];
pSoldier->bExtraDexterity += pSoldier->newdrugs.size[DRUG_EFFECT_DEX];
pSoldier->bExtraAgility += pSoldier->newdrugs.size[DRUG_EFFECT_AGI];
pSoldier->bExtraWisdom += pSoldier->newdrugs.size[DRUG_EFFECT_WIS];
BOOLEAN fStillDrugged = FALSE;
// as time progresses, effects wear off
for ( UINT8 i = 0; i < DRUG_EFFECT_MAX; ++i )
{
pSoldier->newdrugs.duration[i] = max( 0, pSoldier->newdrugs.duration[i] - 1 );
if ( !pSoldier->newdrugs.duration[i] )
pSoldier->newdrugs.size[i] = 0;
else
fStillDrugged = TRUE;
}
pSoldier->newdrugs.drugpersonality_duration = max( 0, pSoldier->newdrugs.drugpersonality_duration - 1 );
if ( !pSoldier->newdrugs.drugpersonality_duration )
pSoldier->newdrugs.drugpersonality = 0;
else
fStillDrugged = TRUE;
pSoldier->newdrugs.drugdisability_duration = max( 0, pSoldier->newdrugs.drugdisability_duration - 1 );
if ( !pSoldier->newdrugs.drugdisability_duration )
pSoldier->newdrugs.drugdisability = 0;
else
fStillDrugged = TRUE;
if ( !fStillDrugged )
{
pSoldier->usSoldierFlagMask &= ~SOLDIER_DRUGGED;
fInterfacePanelDirty = DIRTYLEVEL1;
}
}
INT8 GetDrunkLevel( SOLDIERTYPE *pSoldier )
{
if ( pSoldier->usSoldierFlagMask2 & SOLDIER_HUNGOVER )
{
return HUNGOVER;
}
if ( pSoldier->newdrugs.drinkstaken <= 0.01 )
{
return SOBER;
}
else if ( pSoldier->newdrugs.drinkstaken <= 0.7 )
{
return FEELING_GOOD;
}
else if ( pSoldier->newdrugs.drinkstaken <= 2.0 )
{
return BORDERLINE;
}
return DRUNK;
}
// does a merc have a disability/personality, or is he under drugs that simulate this?
BOOLEAN DoesMercHaveDisability( const SOLDIERTYPE *pSoldier, UINT8 aVal )
{
if ( pSoldier->ubProfile != NO_PROFILE )
{
if ( gMercProfiles[pSoldier->ubProfile].bDisability == aVal )
return TRUE;
if ( pSoldier->newdrugs.drugdisability == aVal )
return TRUE;
// Flugente: if disease with severe limitations is active, we can have multiple disabilities
if ( gGameExternalOptions.fDisease
&& gGameExternalOptions.fDiseaseSevereLimitations
&& pSoldier->usDisabilityFlagMask & ( 1 << (aVal - 1) ) )
return TRUE;
}
return FALSE;
}
BOOLEAN DoesMercHavePersonality( SOLDIERTYPE *pSoldier, UINT8 aVal )
{
// personalities are new trait system only!
if ( !gGameOptions.fNewTraitSystem )
return FALSE;
if ( pSoldier->ubProfile != NO_PROFILE )
{
if ( gMercProfiles[pSoldier->ubProfile].bCharacterTrait == aVal )
return TRUE;
if ( pSoldier->newdrugs.drugpersonality == aVal )
return TRUE;
}
return FALSE;
}
void HandleAPEffectDueToDrugs( SOLDIERTYPE *pSoldier, INT16 *pubPoints )
{
*pubPoints += pSoldier->newdrugs.size[DRUG_EFFECT_AP];
if ( GetDrunkLevel( pSoldier ) == HUNGOVER )
{
// Reduce....
*pubPoints -= HANGOVER_AP_REDUCE;
if ( *pubPoints < APBPConstants[AP_MINIMUM] )
{
*pubPoints = APBPConstants[AP_MINIMUM];
}
}
}
void HandleBPEffectDueToDrugs( SOLDIERTYPE *pSoldier, INT16 *psPointReduction )
{
*psPointReduction -= pSoldier->newdrugs.size[DRUG_EFFECT_BP];
if ( GetDrunkLevel( pSoldier ) == HUNGOVER )
{
// Reduce....
(*psPointReduction) += HANGOVER_BP_REDUCE;
}
}
INT32 EffectStatForBeingDrunk( SOLDIERTYPE *pSoldier, INT32 iStat )
{
return( ( iStat * giDrunkModifier[ GetDrunkLevel( pSoldier ) ] / 100 ) );
}
BOOLEAN MercDruggedOrDrunk( SOLDIERTYPE *pSoldier )
{
if ( pSoldier->newdrugs.drinkstaken )
return TRUE;
if ( pSoldier->usSoldierFlagMask & SOLDIER_DRUGGED )
return TRUE;
return FALSE;
}
BOOLEAN MercDrugged( SOLDIERTYPE *pSoldier )
{
return (pSoldier->usSoldierFlagMask & SOLDIER_DRUGGED);
}
void HourlyDrugUpdate( )
{
for ( SoldierID ubID = gTacticalStatus.Team[OUR_TEAM].bFirstID; ubID <= gTacticalStatus.Team[OUR_TEAM].bLastID; ++ubID )
{
// every hour, we lower our alcohol counter
if ( ubID->newdrugs.drinkstaken > 0.0f )
{
ubID->newdrugs.drinkstaken = max( 0.0, ubID->newdrugs.drinkstaken - 0.15f );
if ( ubID->newdrugs.drinkstaken <= 0.0f )
{
ubID->usSoldierFlagMask2 &= ~SOLDIER_HUNGOVER;
}
}
}
}