#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 vec_drug = NewDrug[drugused].drug_effects; std::vector::iterator drug_effects_itend = vec_drug.end( ); for ( std::vector::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 vec_disease = NewDrug[drugused].disease_effects; std::vector::iterator disease_effects_itend = vec_disease.end( ); for ( std::vector::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 vec_disability = NewDrug[drugused].disability_effects; std::vector::iterator disability_effects_itend = vec_disability.end( ); for ( std::vector::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 vec_personality = NewDrug[drugused].personality_effects; std::vector::iterator personality_effects_itend = vec_personality.end( ); for ( std::vector::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( 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 ( UINT16 ubID = gTacticalStatus.Team[OUR_TEAM].bFirstID; ubID <= gTacticalStatus.Team[OUR_TEAM].bLastID; ++ubID ) { // every hour, we lower our alcohol counter if ( MercPtrs[ubID]->newdrugs.drinkstaken > 0.0f ) { MercPtrs[ubID]->newdrugs.drinkstaken = max( 0.0, MercPtrs[ubID]->newdrugs.drinkstaken - 0.15f ); if ( MercPtrs[ubID]->newdrugs.drinkstaken <= 0.0f ) { MercPtrs[ubID]->usSoldierFlagMask2 &= ~SOLDIER_HUNGOVER; } } } }