Advertisement
Guest User

Untitled

a guest
Jan 17th, 2018
426
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 143.20 KB | None | 0 0
  1. Scriptname Hardcore:HC_ManagerScript extends Quest conditional
  2.  
  3. ;**************************************************************************************************
  4. ;************************************** INITIALIZATION ***************************************
  5. ;**************************************************************************************************
  6.  
  7. Event OnInit()
  8. trace(self, "OnInit()")
  9.  
  10. ; We may need this later...
  11. PlayerRef = Game.GetPlayer()
  12. RegisterForRemoteEvent(PlayerRef, "OnDifficultyChanged") ;for turning it all off...
  13.  
  14. ; If we're playing Hardcore lets get everything turned on... Otherwise lets remove all effects.
  15. if (Game.GetDifficulty() == 6)
  16. trace(self, "OnInit() - Difficulty is set to Survival. Starting up...")
  17. StartupHardcore()
  18. else
  19. trace(self, "OnInit() - Difficulty is not set to Survival. Sleeping for now...")
  20. endif
  21.  
  22. EndEvent
  23.  
  24. ;**************************************************************************************************
  25. ;*********************************** STARTUP & SHUTDOWN ***********************************
  26. ;**************************************************************************************************
  27.  
  28. ; It rubs the lotion on its skin...
  29. Function StartupHardcore()
  30. trace(self, "StartupHardcore()")
  31.  
  32. if !bHardcoreIsRunning
  33.  
  34. FoodItems = new form[0]
  35.  
  36. ; Set our max adrenaline as defined by these other two values...
  37. MaxAdrenaline = KillsForAdrenalinePerkLevel * MaxAdrenalinePerkLevel
  38.  
  39. HC_HoursToRespawnCellMult.SetValue(HoursToRespawnCellMult)
  40. HC_HoursToRespawnCellClearedMult.SetValue(HoursToRespawnCellClearedMult)
  41.  
  42. RegisterForRemoteEvent(PlayerRef, "OnPlayerLoadGame") ;for not disabling the sleep message.
  43.  
  44. RegisterForRemoteEvent(PlayerRef, "OnKill") ;for awarding Adrenaline
  45.  
  46. RegisterForPlayerSleep() ; for resetting adrenaline
  47. RegisterForPlayerWait()
  48.  
  49. RegisterForRemoteEvent(PlayerRef, "OnCombatStateChanged") ;for hunger effects
  50. RegisterForRemoteEvent(PlayerRef, "OnItemEquipped") ;for hunger effects
  51.  
  52. RegisterForHitEvent(PlayerRef, DiseaseRiskCombatantFactions) ; for getting diseased when hit by these combatants
  53. RegisterForRemoteEvent(PlayerRef, "OnPlayerSwimming") ;for disease
  54.  
  55. RegisterForCustomEvent(Followers, "CompanionChange") ;DONT UNREGISTER - for toggling companion no bleedout recovery
  56. RegisterForRemoteEvent(Companion, "OnEnterBleedout") ;for dismissing if player gets too far away while bleeding out
  57. RegisterForRemoteEvent(DogmeatCompanion, "OnEnterBleedout") ;for dismissing if player gets too far away while bleeding out
  58. RegisterForRemoteEvent(PlayerRef, "OnPlayerHealTeammate") ;DONT UNREGISTER - for toggling off variable that means player should heal companion
  59.  
  60. RegisterForMenuOpenCloseEvent("PipboyMenu") ;for toggling off the fast travel tutorial
  61.  
  62. RegisterForRemoteEvent(PlayerRef, "OnLocationChange") ;for toggling map marker fast travel allowances while in the institute
  63.  
  64. playerRef.addPerk(HC_SustenanceEffectsTurnOffFood)
  65. playerRef.addPerk(HC_FillWaterBottlePerk)
  66.  
  67. ;we don't need to remove these because the condition itself is conditioned, and we don't know how to find them again if they aren't currently a companion
  68. AddReduceCarryWeightAbility(Companion.GetActorReference())
  69. AddReduceCarryWeightAbility(DogmeatCompanion.GetActorReference())
  70. AddReduceCarryWeightAbility(PlayerRef)
  71.  
  72. HC_Vendor_Antiboitic_ChanceNone.setvalue(0) ;turns on vendors selling antiboitics
  73. HC_Medkit_Antiboitic_ChanceNone.setvalue(0) ;turns on finding antiboitics
  74.  
  75. ; HACK! The game clock gets adjusted early game to set lighting and such.
  76. ; This will fix out clocks from getting out of alignment on new game start.
  77. bTimersInitialized = false
  78. StartTimer(1.0, RealTimerID_HackClockSyncer)
  79.  
  80. trace(self, " StartupHardcore(): Hardcore is now running.")
  81. else
  82. trace(self, " StartupHardcore(): Hardcore was already running.")
  83. endif
  84.  
  85. bHardcoreIsRunning = true
  86.  
  87. CompanionSetNoBleedoutRecovery(Companion.GetActorReference(), true)
  88. CompanionSetNoBleedoutRecovery(DogmeatCompanion.GetActorReference(), true)
  89.  
  90. EndFunction
  91.  
  92. ; I WANT IT SHUT DOWN... ALL OF IT!
  93. Function ShutdownHardcore()
  94. trace(self, "ShutdownHardcore()")
  95.  
  96. Tutorial.RegisterForTutorialEvent("OnEnterPipBoyMapPage")
  97.  
  98. FoodItems = none
  99.  
  100. HC_HoursToRespawnCellMult.SetValue(1.0)
  101. HC_HoursToRespawnCellClearedMult.SetValue(1.0)
  102.  
  103. UnRegisterForRemoteEvent(PlayerRef, "OnPlayerLoadGame") ;for not disabling the sleep message.
  104.  
  105. UnRegisterForRemoteEvent(PlayerRef, "OnKill") ;for awarding Adrenaline
  106.  
  107. UnRegisterForPlayerSleep() ; for resetting adrenaline
  108. UnRegisterForPlayerWait()
  109.  
  110. UnRegisterForRemoteEvent(PlayerRef, "OnCombatStateChanged") ;for hunger effects
  111. UnRegisterForRemoteEvent(PlayerRef, "OnItemEquipped") ;for hunger effects
  112.  
  113. UnRegisterForHitEvent(PlayerRef, DiseaseRiskCombatantFactions) ; for getting diseased when hit by these combatants
  114. UnRegisterForRemoteEvent(PlayerRef, "OnPlayerSwimming") ;for disease
  115.  
  116. UnRegisterForRemoteEvent(Companion, "OnEnterBleedout") ;for dismissing if player gets too far away while bleeding out
  117. UnRegisterForRemoteEvent(DogmeatCompanion, "OnEnterBleedout") ;for dismissing if player gets too far away while bleeding out
  118.  
  119. CancelTimer(RealTimerID_HackClockSyncer)
  120. CancelTimerGameTime(GameTimerID_SleepDeprivation)
  121. CancelTimerGameTime(GameTimerID_Sustenance)
  122. CancelTimerGameTime(GameTimerID_Disease)
  123. CancelTimerGameTime(GameTimerID_Encumbrance)
  124.  
  125. ; remove diseases
  126. ClearDisease()
  127. HC_Vendor_Antiboitic_ChanceNone.setvalue(100) ;turns off vendors selling antiboitics
  128. HC_Medkit_Antiboitic_ChanceNone.setvalue(100) ;turns off finding antiboitics
  129.  
  130. ; remove sleep and sustenance effects
  131. FoodPool = 0
  132. PlayerRef.SetValue(HC_HungerEffect, HC_HE_Fed.GetValue())
  133. ApplyEffect(HC_Rule_SustenanceEffects, HungerEffects, HC_HungerEffect, bBypassGlobalCheck = true)
  134.  
  135. playerRef.removePerk(HC_SustenanceEffectsTurnOffFood)
  136.  
  137. ;turn off cannibal effect ravenous hunger
  138. CureRavenousHunger()
  139.  
  140. DrinkPool = 0
  141. PlayerRef.SetValue(HC_ThirstEffect, HC_TE_Hydrated.GetValue())
  142. ApplyEffect(HC_Rule_SustenanceEffects, ThirstEffects, HC_ThirstEffect, bBypassGlobalCheck = true)
  143.  
  144. PlayerRef.SetValue(HC_SleepEffect, HC_SE_Rested.GetValue())
  145. ApplyEffect(HC_Rule_SleepEffects, SleepEffects, HC_SleepEffect, bBypassGlobalCheck = true)
  146. playerRef.removePerk(HC_AdrenalinePerk)
  147.  
  148. playerRef.removePerk(HC_WellRestedPerk)
  149. playerRef.removePerk(HC_LoversEmbracePerk)
  150.  
  151. ClearFatigue()
  152.  
  153. ; remove encumbrance effect
  154. PlayerRef.UnEquipItem(HC_EncumbranceEffect_OverEncumbered, abSilent = true)
  155.  
  156. CompanionSetNoBleedoutRecovery(Companion.GetActorReference(), false)
  157. CompanionSetNoBleedoutRecovery(DogmeatCompanion.GetActorReference(), false)
  158.  
  159. bHardcoreIsRunning = false
  160. trace(self, " ShutdownHardcore(): Hardcore is no longer running.")
  161.  
  162. EndFunction
  163.  
  164. Event Actor.OnDifficultyChanged(actor aSender, int aOldDifficulty, int aNewDifficulty)
  165. trace(self, "OnDifficultyChanged() aOldDifficulty, aNewDifficulty: " + aOldDifficulty + ", " + aNewDifficulty)
  166.  
  167. if (aOldDifficulty != 6) && (aNewDifficulty == 6)
  168. trace(self, " Player wants hardcore mode...")
  169. StartupHardcore()
  170. elseif (aOldDifficulty == 6) && (aNewDifficulty != 6)
  171. trace(self, " Player no longer wants hardcore mode...")
  172. ShutdownHardcore()
  173. endif
  174.  
  175. EndEvent
  176.  
  177. ;FOR DEBUG PRIOR TO CODE SWITCH (can come out later)
  178. Function SetHardcoreMode(bool HardcoreModeOn = true)
  179.  
  180. RegisterForRemoteEvent(Game.GetPlayer(), "OnDifficultyChanged") ;for turning it all off...
  181.  
  182. int i = 0
  183. while (i < HC_Rules.GetSize())
  184. SetGlobal(HC_Rules.GetAt(i) as GlobalVariable, HardcoreModeOn)
  185. i += 1
  186. endwhile
  187.  
  188. if HardcoreModeOn
  189. trace(self, " Player wants hardcore mode...")
  190. StartupHardcore()
  191. elseif !HardcoreModeOn
  192. trace(self, " Player no longer wants hardcore mode...")
  193. ShutdownHardcore()
  194. endif
  195.  
  196. EndFunction
  197.  
  198. ;**************************************************************************************************
  199. ;************************************** COMMON ***************************************
  200. ;**************************************************************************************************
  201.  
  202. Group CommonProperties
  203. Formlist Property HC_Rules const auto mandatory
  204. ActorValue property Fatigue auto const mandatory; FatigueAV
  205.  
  206. FollowersScript Property Followers const auto mandatory
  207. {Autofill; needed for reimplementing lover's embrace and turning off bleedout recovery}
  208.  
  209. keyword[] Property NonFoodKeywords auto const mandatory
  210.  
  211. ; Globals for altering the world reset times.
  212. float Property HoursToRespawnCellMult = 5.0 const auto
  213. float Property HoursToRespawnCellClearedMult = 4.0 const auto
  214. globalvariable Property HC_HoursToRespawnCellMult const auto
  215. globalvariable Property HC_HoursToRespawnCellClearedMult const auto
  216.  
  217. EndGroup
  218.  
  219. ; TUTORIALS
  220. ;;;;;;;;;;;;;;;;;;
  221. Struct HC_Tutorial
  222. message MessageToDisplay
  223. int TimesToDisplay = 1
  224. int TimesDisplayed hidden
  225. float GameDaysBetweenDisplays = 0.01
  226. float LastTimeDisplayed hidden
  227. EndStruct
  228.  
  229. ; Checks to see if we should display the current tutorial and displays it.
  230. bool Function TryTutorial(HC_Tutorial t, string EventName)
  231. float DaysUntilNextDisplay = 0
  232. trace(self, "TryTutorial() - Tutorial: " + EventName + ", TimesDisplayed: " + t.TimesDisplayed)
  233. trace(self, " TryTutorial() - Tutorial: " + EventName + ", TimesToDisplay: " + t.TimesToDisplay)
  234. if t.TimesDisplayed < t.TimesToDisplay
  235. float currentGameTime = Utility.GetCurrentGameTime()
  236. float nextDisplayTime = t.LastTimeDisplayed + t.GameDaysBetweenDisplays
  237. if currentGameTime > nextDisplayTime
  238. t.MessageToDisplay.ShowAsHelpMessage(EventName, 8, 0, 1, "")
  239. t.TimesDisplayed += 1
  240. t.LastTimeDisplayed = currentGameTime
  241. trace(self, " TryTutorial() - Show Tutorial: " + EventName + ", TimesDisplayed: " + t.TimesDisplayed)
  242. return true
  243. endif
  244. DaysUntilNextDisplay = nextDisplayTime - currentGameTime
  245. trace(self, " TryTutorial() - Tutorial: " + EventName + ", DaysUntilNextDisplay: " + DaysUntilNextDisplay)
  246. endif
  247. trace(self, " TryTutorial() - Hide Tutorial: " + EventName + ", TimesDisplayed: " + t.TimesDisplayed + ", DaysUntilNextDisplay: " + DaysUntilNextDisplay)
  248. return false
  249. EndFunction
  250. ;;;;;;;;;;;;;;;;;;
  251.  
  252. Group Tutorials
  253. HC_Tutorial Property ImmunodeficiencyTutorial Auto
  254. HC_Tutorial Property TirednessTutorial Auto
  255. HC_Tutorial Property HungerTutorial Auto
  256. HC_Tutorial Property ThirstTutorial Auto
  257. HC_Tutorial Property HighRiskEventTutorial Auto
  258. HC_Tutorial Property DiseasedTutorial Auto
  259. HC_Tutorial Property AdrenalineTutorial Auto
  260. HC_Tutorial Property NonBedSleepTutorial Auto
  261. HC_Tutorial Property CompanionDownedTutorial Auto
  262. HC_Tutorial Property SleepToSaveTutorial Auto
  263. EndGroup
  264.  
  265. Actor PlayerRef ;pointwe to player, set in OnInit()
  266.  
  267. ; Keep track of whether we are or are not playing Hardcore
  268. bool bHardcoreIsRunning = false
  269.  
  270. ;Global "enum" values, used by IsGlobalTrue, SetGlobal
  271. int iGlobalTrue = 1 const
  272. int iGlobalFalse = 0 const
  273.  
  274. ; This is the absolute cap on fatigue...
  275. float fMaxFatigue = 1000.00 const
  276. ; This is the selfimposed cap on fatigue...
  277. float fCapFatigue = 950.00 const
  278. ; This is the lowest value Fatigue can be if not 0. This helps visually with the hud.
  279. float fLowestNonZeroFatigue = 20.0 const
  280.  
  281. ; Our epsilon value for safe floating...
  282. float fEpsilon = 0.0001 const
  283.  
  284. ;************************************ TIMERS *********************************************
  285. int GameTimerID_SleepDeprivation = 1 const
  286. int GameTimerID_Encumbrance = 2 const
  287. int GameTimerID_Sustenance = 3 const
  288. int GameTimerID_Disease = 4 const
  289. int RealTimerID_HackClockSyncer = 5 const
  290. int GameTimerID_DisplaySleepMessage = 6 const
  291. int GameTimerID_IgnoreNonWeaponHits = 7 const
  292.  
  293. Group Timers
  294.  
  295. float Property GameTimerInterval_SleepDeprivation = 14.0 auto const ;hours
  296.  
  297. float Property GameTimerInterval_Encumbrance = 24.0 auto const ;hours
  298.  
  299. float Property GameTimerInterval_Sustenance = 0.1 auto const ;hours -- THIS NEEDS TO BE LESS THAN TickHoursCostPerCombat
  300. {THIS NEEDS TO BE LESS THAN TickHoursCostPerCombat }
  301.  
  302. float Property GameTimerInterval_Disease = 0.333333 auto const ;hours
  303. float Property GameTimerInterval_DiseasePostRiskEvent = 0.033 auto const ;hours - Used as alternate to the standard disease interval.
  304.  
  305. float Property GameTimerInterval_DisplaySleepMessage = 0.033 auto const ; hours
  306.  
  307. float Property GameTimerInterval_IgnoreNonWeaponHits = 0.16666667 auto const ; 30 real seconds.
  308.  
  309. EndGroup
  310. ; (seconds) Setup our Clock Resync Timer values.
  311. float RealTimerInterval_HackClockSyncer = 30.0 const
  312. ; The game is setup so that on game start the time moves around. Need to track that to properly start our timers.
  313. float LowestGameTimeResetTime;
  314. ; Flag to track clock initialization. False in StartupHardcore; True on first initialization.
  315. bool bTimersInitialized = false
  316.  
  317.  
  318. Event Actor.OnPlayerLoadGame(actor aSender)
  319.  
  320. ;<NEW STUFF> - SUPPORTING EXISTING SAVES DURING DEVELOPMENT - can come out before shipping
  321. if false == PlayerRef.HasPerk(HC_FillWaterBottlePerk)
  322. PlayerRef.AddPerk(HC_FillWaterBottlePerk)
  323. endif
  324.  
  325. if HC_Medkit_Antiboitic_ChanceNone.GetValue() == 100
  326. HC_Medkit_Antiboitic_ChanceNone.setvalue(0) ;turns on finding antiboitics
  327. endif
  328.  
  329. ; Fixup New Food Values
  330. if FoodReqs < 0
  331. FoodReqs = FoodPool
  332. endif
  333. if DrinkReqs < 0
  334. DrinkReqs = DrinkPool
  335. endif
  336.  
  337. RegisterForRemoteEvent(PlayerRef, "OnPlayerHealTeammate") ;for toggling off variable that means player should heal companion
  338.  
  339. ;</NEW STUFF>
  340.  
  341.  
  342. float currentGameTime = Utility.GetCurrentGameTime()
  343. trace(self, "OnPlayerLoadGame() @ " + currentGameTime)
  344.  
  345. CancelTimerGameTime(GameTimerID_DisplaySleepMessage)
  346.  
  347. ; Use the current game time to possibly update our "LastSleepUpdateDay". This is primarily an old save fix. Delete for ship?
  348. if currentGameTime - LastSleepUpdateDay > 1.0 || LastSleepUpdateDay > currentGameTime
  349. trace(self, " OnPlayerLoadGame() Old LastSleepUpdateDay: " + LastSleepUpdateDay + ", New LastSleepUpdateDay: " + currentGameTime)
  350. LastSleepUpdateDay = currentGameTime
  351. else
  352. trace(self, " OnPlayerLoadGame() LastSleepUpdateDay: " + LastSleepUpdateDay)
  353. endif
  354.  
  355. ; If NextSleepUpdateDay is out of whack, correct it and restart our clock to finalize the correction. This is primarily an old save fix. Delete for ship?
  356. if NextSleepUpdateDay < (currentGameTime - 0.05)
  357. float temp = NextSleepUpdateDay
  358. NextSleepUpdateDay = currentGameTime + (currentGameTime - LastSleepUpdateDay)
  359. ; This just takes the time we think we should have left and adjusts it based on disease.
  360. StartSleepDeprivationTimer(GetHoursUntilCurrentSleepCycleEnds())
  361. trace(self, " OnPlayerLoadGame() Old NextSleepUpdateDay: " + temp + ", New NextSleepUpdateDay: " + NextSleepUpdateDay)
  362. else
  363. trace(self, " OnPlayerLoadGame() NextSleepUpdateDay: " + NextSleepUpdateDay)
  364. endif
  365.  
  366. ; Make sure carry weight can be updated as needed.
  367. RemoveReduceCarryWeightAbility(Companion.GetActorReference())
  368. RemoveReduceCarryWeightAbility(DogmeatCompanion.GetActorReference())
  369. RemoveReduceCarryWeightAbility(PlayerRef)
  370. AddReduceCarryWeightAbility(Companion.GetActorReference())
  371. AddReduceCarryWeightAbility(DogmeatCompanion.GetActorReference())
  372. AddReduceCarryWeightAbility(PlayerRef)
  373.  
  374. EndEvent
  375.  
  376.  
  377. Event OnTimer(int aiTimerID)
  378.  
  379. float currentGameTime = Utility.GetCurrentGameTime()
  380.  
  381. ; HACK! The game clock gets adjusted early game to set lighting and such.
  382. ; This will fix out clocks from getting out of alignment on new game start.
  383. if aiTimerID == RealTimerID_HackClockSyncer
  384.  
  385. ; Initial Timer setup. This should work regardless of how you start a new game.
  386. if !bTimersInitialized
  387. ; Start our timers...
  388. InitializeHardcoreTimers(currentGameTime)
  389. trace(self, "HackClockSyncer: Setup @ " + currentGameTime + " - CLOCKS ARE SET!")
  390. bTimersInitialized = true
  391.  
  392. ; If we have traveled back in time, someone get Hewy Lewis on the phone and lets resync our clocks!
  393. elseif bHardcoreIsRunning && currentGameTime < LowestGameTimeResetTime
  394. ; Restart our timers...
  395. InitializeHardcoreTimers(currentGameTime)
  396. trace(self, " HackClockSyncer: Resyncing Survival Clocks To The Game Clock! LowestGameTimeResetTime: " + currentGameTime)
  397. endif
  398.  
  399. ; Let's keep verifying we dont need travel back any further until we are out of the woods, er... Vault.
  400. if bHardcoreIsRunning && currentGameTime <= LowestGameTimeResetTime + 0.05
  401. StartTimer(RealTimerInterval_HackClockSyncer, RealTimerID_HackClockSyncer)
  402. trace(self, " HackClockSyncer: Restarting Clock Sync Timer @ " + currentGameTime)
  403. elseif bHardcoreIsRunning
  404. ; Hey look, we're out of the vault now...
  405. ; Tutorial Call - Sleep To Save.
  406. TryTutorial(SleepToSaveTutorial, "SleepToSaveTutorial")
  407. endif
  408.  
  409. endif
  410.  
  411. EndEvent
  412.  
  413. Function InitializeHardcoreTimers(float CurrentGameTime)
  414.  
  415. CancelTimerGameTime(GameTimerID_SleepDeprivation)
  416. CancelTimerGameTime(GameTimerID_Sustenance)
  417. CancelTimerGameTime(GameTimerID_Disease)
  418. CancelTimerGameTime(GameTimerID_Encumbrance)
  419.  
  420. StartSleepDeprivationTimer(2.0, true)
  421. bFirstSleep = true
  422. StartTimerGameTime(GameTimerInterval_Sustenance, GameTimerID_Sustenance)
  423. StartTimerGameTime(GameTimerInterval_Disease, GameTimerID_Disease)
  424. StartTimerGameTime(0.033, GameTimerID_Encumbrance)
  425.  
  426. ; The Sustenance Timer is short enough to trip mid vault. Reseting the tick day when we reset the clock.
  427. NextSustenanceTickDay= 0
  428.  
  429. ; Store this update time for handling no effect clearing sleeps.
  430. LastSleepUpdateDay= CurrentGameTime
  431.  
  432. ; Store this update time for handling pushing off diseases for the first 24 hours.
  433. LastDiseasedDay= CurrentGameTime
  434.  
  435. ; Store our new low!
  436. LowestGameTimeResetTime= CurrentGameTime
  437.  
  438. EndFunction
  439.  
  440. Event OnTimerGameTime(int aiTimerID)
  441.  
  442. float currentGameTime = Utility.GetCurrentGameTime()
  443.  
  444. if aiTimerID == GameTimerID_SleepDeprivation
  445. trace(self, "OnTimerGameTime() aiTimerID: = GameTimerID_SleepDeprivation @ " + currentGameTime)
  446.  
  447. if IsGlobalTrue(HC_Rule_SleepEffects) && ProcessingSleep == false
  448. HandleSleepDeprivationTimer()
  449. endif
  450. ;this needs to live outside the if check, in case we allow turning on option during play
  451. if iCaffeinated > 0
  452. StartSleepDeprivationTimer(fCaffeinatedTimeTracker)
  453. else
  454. StartSleepDeprivationTimer()
  455. endif
  456.  
  457. ; The Caffeine has worn off.
  458. ; When we get Caffeinated we set ourselfs on a short clock and this thing clears when the time is up.
  459. HC_CaffeinatedEffect.Dispel()
  460. HC_CaffeinatedEffect = none
  461. iCaffeinated = 0
  462. CaffeinatedCount = 0
  463. ExtraCaffeinatedCount = 0
  464.  
  465. elseif aiTimerID == GameTimerID_Encumbrance
  466. trace(self, "OnTimerGameTime() aiTimerID: = GameTimerID_Encumbrance @ " + currentGameTime)
  467. if IsGlobalTrue(HC_Rule_DamageWhenEncumbered) && ProcessingSleep == false
  468. HandleEncumbranceTimer()
  469. endif
  470. ;this needs to live outside the if check, in case we allow turning on option during play
  471. StartTimerGameTime(GameTimerInterval_Encumbrance, GameTimerID_Encumbrance)
  472.  
  473. elseif aiTimerID == GameTimerID_Sustenance
  474. trace(self, "OnTimerGameTime() aiTimerID: = GameTimerID_Sustenance @ " + currentGameTime)
  475. if IsGlobalTrue(HC_Rule_SustenanceEffects) && ProcessingSleep == false
  476. HandleSustenanceTimer()
  477. endif
  478. ;this needs to live outside the if check, in case we allow turning on option during play
  479. StartTimerGameTime(GameTimerInterval_Sustenance, GameTimerID_Sustenance)
  480.  
  481. elseif aiTimerID == GameTimerID_Disease
  482. trace(self, "OnTimerGameTime() aiTimerID: = GameTimerID_Disease @ " + currentGameTime)
  483. if IsGlobalTrue(HC_Rule_DiseaseEffects) && ProcessingSleep == false
  484. HandleDiseaseTimer()
  485. endif
  486. ;this needs to live outside the if check, in case we allow turning on option during play
  487. StartTimerGameTime(GameTimerInterval_Disease, GameTimerID_Disease)
  488.  
  489. elseif aiTimerID == GameTimerID_DisplaySleepMessage
  490. trace(self, "OnTimerGameTime() aiTimerID: = GameTimerID_DisplaySleepMessage @ " + currentGameTime)
  491. ; explain why he woke up early... If you didnt get what you asked for, that is.
  492. if EarlyWakeMessageToShow
  493. EarlyWakeMessageToShow.show()
  494. EarlyWakeMessageToShow = none
  495. endif
  496.  
  497. elseif aiTimerID == GameTimerID_IgnoreNonWeaponHits
  498. trace(self, "OnTimerGameTime() aiTimerID: = GameTimerID_IgnoreNonWeaponHits @ " + currentGameTime)
  499. bIgnoreNonWeaponHits = false
  500.  
  501. else
  502. trace(self, "OnTimerGameTime() NO MATCH! - aiTimerID: " + aiTimerID )
  503.  
  504. endif
  505.  
  506. EndEvent
  507.  
  508. bool Function Trace(ScriptObject CallingObject, string asTextToPrint, int aiSeverity = 0) debugOnly
  509. ;we are sending callingObject so we can in the future route traces to different logs based on who is calling the function
  510. string logName = "Hardcore"
  511. debug.OpenUserLog(logName)
  512. RETURN debug.TraceUser(logName, CallingObject + ": " + asTextToPrint, aiSeverity)
  513.  
  514. EndFunction
  515.  
  516. ;convenience function, also helps enforce the values
  517. bool function IsGlobalTrue(globalvariable GlobalToCheck)
  518.  
  519. bool val = GlobalToCheck.GetValue()
  520.  
  521. if val == iGlobalTrue
  522. RETURN true
  523. elseif val == iGlobalFalse
  524. RETURN false
  525. else
  526. ;ERROR
  527. Game.Warning(self + "IsGlobalTrue() found unrecognized value in " + GlobalToCheck + ": " + GlobalToCheck.GetValue())
  528. RETURN false
  529. endif
  530.  
  531. EndFunction
  532.  
  533. ;convenience function, also helps enforce the values
  534. Function SetGlobal(globalvariable GlobalToSet, bool ValueToSet)
  535. if ValueToSet
  536. GlobalToSet.SetValue(iGlobalTrue)
  537. else
  538. GlobalToSet.SetValue(iGlobalFalse)
  539. endif
  540. EndFunction
  541.  
  542.  
  543. ;**************************************************************************************************
  544. ;************************************** FAST TRAVEL *************************************
  545. ;**************************************************************************************************
  546.  
  547. Group FastTravel
  548.  
  549. GlobalVariable Property HC_Rule_NoFastTravel const auto Mandatory
  550. {autofill}
  551.  
  552. TutorialScript Property Tutorial const auto Mandatory
  553. {autofill; used to toggle on/off tutorial message for pipboy map}
  554.  
  555. Location Property InstituteLocation Auto Const Mandatory
  556. {Autofill}
  557.  
  558. formlist Property HC_FastTravelAllowedList Auto Const Mandatory
  559. {autofill}
  560.  
  561. ObjectReference[] Property FastTravelAllowedWhileInInstituteMapMarkers Auto Const Mandatory
  562. {CITRuinsMapMarker, others?}
  563.  
  564. message Property HC_TutorialFastTravelInstitute Auto Const Mandatory
  565. {Autofill}
  566.  
  567. message Property HC_FastTravelInstitute_Out Auto Const Mandatory
  568. {Autofill}
  569.  
  570. message Property HC_FastTravelInstitute_To Auto Const Mandatory
  571. {Autofill}
  572.  
  573. Quest Property MQ207 Auto Const Mandatory
  574. {autofill}
  575.  
  576. EndGroup
  577.  
  578. Event OnMenuOpenCloseEvent(string asMenuName, bool abOpening)
  579. if asMenuName == "PipboyMenu" && IsGlobalTrue(HC_Rule_NoFastTravel)
  580. Tutorial.UnregisterForTutorialEvent("OnEnterPipBoyMapPage")
  581. endif
  582. EndEvent
  583.  
  584.  
  585. bool MsgInsideInstitute = false
  586. Event Actor.OnLocationChange(Actor akSender, Location akOldLoc, Location akNewLoc)
  587. ;akSender ASSUMED to be player, as that's the only thing we've registered for
  588.  
  589. if IsGlobalTrue(HC_Rule_NoFastTravel)
  590.  
  591. int i = 0
  592. While (i < FastTravelAllowedWhileInInstituteMapMarkers.length)
  593. ObjectReference currentRef = FastTravelAllowedWhileInInstituteMapMarkers[i]
  594.  
  595. if PlayerRef.IsInLocation(InstituteLocation)
  596. trace(self, "Actor.OnLocationChange ADDING ref to HC_FastTravelAllowedList: " + currentRef)
  597. HC_FastTravelAllowedList.addform(currentRef)
  598.  
  599. if false == MsgInsideInstitute
  600. MsgInsideInstitute = true
  601.  
  602. if Game.IsFastTravelEnabled()
  603. utility.wait(3)
  604. HC_FastTravelInstitute_Out.show()
  605. endif
  606. endif
  607.  
  608. else
  609. trace(self, "Actor.OnLocationChange REMOVING ref from HC_FastTravelAllowedList: " + currentRef)
  610. HC_FastTravelAllowedList.RemoveAddedForm(currentRef)
  611.  
  612. if MsgInsideInstitute
  613. MsgInsideInstitute = false
  614.  
  615. if Game.IsFastTravelEnabled()
  616. utility.wait(3)
  617. HC_FastTravelInstitute_To.show()
  618. endif
  619. endif
  620.  
  621. endif
  622.  
  623. i += 1
  624. EndWhile
  625.  
  626. endif
  627.  
  628. EndEvent
  629.  
  630. Function ShowInstituteFastTravelTutorial(string asEvent, float afDuration, float afInterval, int aiMaxTimes, string asContext="", int aiPriority=0)
  631. HC_TutorialFastTravelInstitute.ShowAsHelpMessage(asEvent, afDuration, afInterval, aiMaxTimes, asContext, aiPriority)
  632. EndFunction
  633.  
  634.  
  635. ;**************************************************************************************************
  636. ;************************************** BALANCE CHANGES *************************************
  637. ;**************************************************************************************************
  638.  
  639. Group Balance
  640. globalvariable Property HC_Rule_ScaleDamage const auto mandatory ;used by perk on Player scale damage based on actor valies
  641. EndGroup
  642.  
  643. ;**************************************************************************************************
  644. ;************************************** ADRENALINE ***************************************
  645. ;**************************************************************************************************
  646.  
  647. Group Adrenaline
  648. globalvariable Property HC_Rule_AdrenalineOn const auto mandatory
  649. ActorValue Property HC_Adrenaline const auto mandatory
  650. perk Property HC_AdrenalinePerk const auto mandatory
  651. int Property KillsForAdrenalinePerkLevel = 5 const auto ;how many kills before you gain an adrenaline perk level
  652. {***IMPORTANT*** if we ever change KillsForAdrenalinePerkLevel, we must change the conditions in HC_AdrenalineEffect potion}
  653. int Property MaxAdrenalinePerkLevel = 10 const auto
  654. potion Property HC_AdrenalineEffect Auto Const Mandatory
  655. {autofill; potion with effects to show player has adrenaline}
  656. EndGroup
  657.  
  658. int MaxAdrenaline ;This will never change once we are all setup, so why should we recompute it every time?
  659.  
  660. int AdrenalineKills ;Keeps track of the number of kills we have gotten recently (to better compute your adrenaline with).
  661. bool bProcessingAdrenalineKills = false ;Flag used to keep us from processing more than once at the same time.
  662.  
  663.  
  664. ;Registered for in OnInit()
  665. Event Actor.OnKill(Actor akSender, Actor akVictim)
  666. if akSender == PlayerRef ;registered only for player, but doesn't hurt to check
  667. AdrenalineKills += 1
  668. trace(self, "Actor.OnKill() player killed: " + akVictim + ". Adding Kill! Now at " + AdrenalineKills + " Total Kills...")
  669. CallFunctionNoWait("ProcessAdrenalineKills", new var[0])
  670. endif
  671.  
  672. EndEvent
  673.  
  674. ; NO RENAMING! THIS FUNCTION IS CALLED BY "CallFunctionNoWait" FROM Actor.OnKill() WHICH RELIES ON THE NAME. NO RENAMING!
  675. Function ProcessAdrenalineKills()
  676.  
  677. ; Check to see if we're already running this.
  678. if bProcessingAdrenalineKills
  679. return
  680. endif
  681. trace(self, " ProcessAdrenalineKills() Processing " + AdrenalineKills + " Adrenaline Kills...")
  682.  
  683. ; Set our flag and start processing these kills. Feel the Adrenaline flow through you...
  684. bProcessingAdrenalineKills = true
  685.  
  686. ; Grab our current value and then immediately reset it.
  687. int currentAdrenalineKillTotal = AdrenalineKills
  688. AdrenalineKills = 0
  689.  
  690. ; Update our Adrenaline totals with this new information.
  691. ModAdrenaline(currentAdrenalineKillTotal)
  692.  
  693. ; We out. Peace!
  694. bProcessingAdrenalineKills = false
  695. trace(self, " ProcessAdrenalineKills() Processing complete.")
  696.  
  697. EndFunction
  698.  
  699. Function ModAdrenaline(int amountToMod)
  700.  
  701. ; Get our current values and compute an updated one.
  702. int currentAdrenaline = playerRef.GetValue(HC_Adrenaline) as int
  703. int updatedAdrenaline = currentAdrenaline + amountToMod
  704. trace(self, " ModAdrenaline() currentAdrenaline: " + currentAdrenaline + " + amountToMod: " + amountToMod + " = updatedAdrenaline: " + updatedAdrenaline)
  705.  
  706. ; Jethro Clamp-It.
  707. if updatedAdrenaline < 0
  708. trace(self, " ModAdrenaline() clamping updatedAdrenaline to 0")
  709. updatedAdrenaline = 0
  710. elseif updatedAdrenaline > MaxAdrenaline
  711. trace(self, " ModAdrenaline() clamping updatedAdrenaline to maxAdrenaline: " + MaxAdrenaline)
  712. updatedAdrenaline = MaxAdrenaline
  713. endif
  714.  
  715. ; Store our value for the future. Think of the children!
  716. playerRef.SetValue(HC_Adrenaline, updatedAdrenaline)
  717.  
  718. ; Check to see if we need to make updates to our perk rank, and then make them if need be...
  719. int perkLevelHasBeen = currentAdrenaline / KillsForAdrenalinePerkLevel
  720. int perkLevelShouldBe = updatedAdrenaline / KillsForAdrenalinePerkLevel
  721.  
  722. if perkLevelShouldBe == perkLevelHasBeen
  723.  
  724. ; No reason to continue...
  725. trace(self, " ModAdrenaline() Adrenaline Rank remains the same at: " + perkLevelShouldBe)
  726. return
  727.  
  728. else
  729.  
  730. ;equip the effect potion in case it's duration has expired
  731. playerRef.EquipItem(HC_AdrenalineEffect, abSilent = true)
  732.  
  733. ; Setup
  734. int i = 0
  735.  
  736. if perkLevelShouldBe > perkLevelHasBeen
  737.  
  738. ; Clamp our perk level since we will be increasing it.
  739. if perkLevelShouldBe > MaxAdrenalinePerkLevel
  740. perkLevelShouldBe = MaxAdrenalinePerkLevel
  741. endif
  742.  
  743. ; Setup the number of ranks we will be due...
  744. i = perkLevelShouldBe - perkLevelHasBeen
  745. trace(self, " ModAdrenaline() Adrenaline Rank increases from " + perkLevelHasBeen + " to " + perkLevelShouldBe)
  746.  
  747. ; Tutorial Call - Adrenaline.
  748. TryTutorial(AdrenalineTutorial, "AdrenalineTutorial")
  749.  
  750. elseif perkLevelShouldBe < perkLevelHasBeen
  751.  
  752. ; Remove all ranks (because we have too?) and setup the number of ranks we will be due...
  753. playerRef.removePerk(HC_AdrenalinePerk)
  754. i = perkLevelShouldBe
  755. trace(self, " ModAdrenaline() Adrenaline Rank decreases from " + perkLevelHasBeen + " to " + perkLevelShouldBe)
  756.  
  757. endif
  758.  
  759. ; Now we add what we are due...
  760. while (i > 0)
  761. playerRef.AddPerk(HC_AdrenalinePerk)
  762. i -= 1
  763. endwhile
  764.  
  765. endif
  766.  
  767. EndFunction
  768.  
  769.  
  770. ;**************************************************************************************************
  771. ;************************************** COMMON EFFECTS ********************************
  772. ;**************************************************************************************************
  773.  
  774. Struct Effect
  775.  
  776. Potion EffectPotion
  777. {What potion to apply when gaining this effect - for all negative effects so they show up in stats effects list in pipboy}
  778. MagicEffect MagicEffectToApply
  779. {The Magic Effect this effect applies, if any. This lets us to test whether or not it's active (Disease Symptoms).}
  780. GlobalVariable GlobalEnum
  781. {this global's value is the enum for this effect}
  782. Message MessageToDisplay
  783. {What message do we display when gaining this effect}
  784. Message MessageToRedisplay
  785. {What message do we display when regaining this effect while it's already active}
  786. Message MessageToDisplayAfterAwaking
  787. {What message do we display when awaking with this effect}
  788. float DiseaseChanceFloor = 0.05
  789. {The lowest chance of getting diseased the player has with this effect}
  790. float DiseaseChanceCeiling = 0.9
  791. {The highest chance of getting diseased the player has with this effect}
  792. float DiseaseChanceDrainMult = 1.0
  793. {The multiplier on that rate at which the disease chance drains to the floor value}
  794. float FatigueMult = 0.01
  795. {The percentage of fatigue that this effect adds}
  796. MagicEffect HerbalRemedyEffect
  797. {This Herbal Remedy, if applied, can counter disease if RNGesus shows grace.}
  798. float HerbalRemedyBoostedImmunityThreshold = 0.20
  799. {The disease die roll needs to be <= Risk Pool && >= BoostedImmunityThreshold to get this disease.
  800. This number acts as both a minimum Risk Pool threshold to even get this disease and
  801. once the Risk Pool is high enough, adds some randomness to whether you would get this disease with each risky action.
  802. IMPORTANT: to prevent total imminuty this value should be below 1.}
  803.  
  804. EndStruct
  805.  
  806. message EffectMessageToShow
  807.  
  808. ; IncrementEffectBy is assumed to be a positive value as negative values will be discarded like the trash they are.
  809. Function ApplyEffect(GlobalVariable RuleGlobal, Effect[] EffectsArray, ActorValue EffectActorValue, bool DispellRestedSpells = false, int IncrementEffectBy = 0, bool DisplayAfterAwakingMessage = false, bool bDisplayMessage = true, bool bDamageFatigue = true, bool bAnnounceFatigue = false, bool bBypassGlobalCheck = false)
  810. trace(self, " ApplyEffect()")
  811. if IsGlobalTrue(RuleGlobal) == false && bBypassGlobalCheck == false
  812. ;** This ASSUMES we don't toggle off and on in the same play through... if so, this could cause you to permamently be in the effected state)
  813. ;BAIL OUT, not in hardcore mode
  814. RETURN
  815. endif
  816.  
  817. ;just incase there's base game spells running:
  818. if DispellRestedSpells
  819. playerRef.dispelSpell(WellRested)
  820. playerRef.dispelSpell(LoversEmbracePerkSpell)
  821. endif
  822.  
  823. ;give the player all the effects
  824. ;they are potions he needs to equip, which will restart their duration
  825. ;the effects on each potion are conditioned on the EffectActorValue actorvalue
  826. ;I tried having each one dispel the effects on the other, similar to MS19MoleRatPoison and Cure... but that didn't work for some reason. Perhaps it'd only work on checking in?
  827.  
  828. ;restart all the effects by equipping their potions on the player.
  829. int i = 0
  830. int EffectsLength = EffectsArray.length
  831. while (i < EffectsLength)
  832. potion potionToApply = EffectsArray[i].EffectPotion
  833.  
  834. if potionToApply ;detrimental effects are potions
  835. PlayerRef.EquipItem(potionToApply, abSilent = true)
  836. endif
  837.  
  838. i += 1
  839. endwhile
  840.  
  841.  
  842. ; Increment the effect actor value
  843. int newVal = PlayerRef.GetValue(EffectActorValue) as int
  844. int oldVal = newVal
  845. trace(self, " ApplyEffect() Current Value: " + newVal)
  846. if IncrementEffectBy > 0
  847. newVal += IncrementEffectBy
  848. trace(self, " ApplyEffect() Updated Value: " + newVal)
  849.  
  850. ;don't exceed the array of effects
  851. if newVal < EffectsLength
  852. PlayerRef.SetValue(EffectActorValue, newVal)
  853. endif
  854. endif
  855.  
  856. ; Display appropriate message
  857. message PreviousEffectMessageToShow = EffectMessageToShow
  858. if DisplayAfterAwakingMessage
  859. PreviousEffectMessageToShow = None ;always show messages upon waking
  860. EffectMessageToShow = EffectsArray[newVal].MessageToDisplayAfterAwaking
  861. else
  862. EffectMessageToShow = EffectsArray[newVal].MessageToDisplay
  863. endif
  864.  
  865. ; There has been no change... nothing to see here.
  866. if IncrementEffectBy > 0 && newVal == oldVal
  867. EffectMessageToShow = none
  868. endif
  869.  
  870. if bDisplayMessage && EffectMessageToShow != PreviousEffectMessageToShow
  871. EffectMessageToShow.show()
  872. endif
  873.  
  874. ; Update Fatigue.
  875. if bDamageFatigue
  876. DamageFatigue(bAnnounceFatigue)
  877. endif
  878.  
  879. EndFunction
  880.  
  881. Function DamageFatigue(bool bAnnounceFatigue = false)
  882. trace(self, " DamageFatigue() bAnnounceFatigue: " + bAnnounceFatigue)
  883.  
  884. ; Grab our current values
  885. float HungerFatigueMult = HungerEffects[PlayerRef.GetValue(HC_HungerEffect) as int].FatigueMult
  886. float ThirstFatigueMult = ThirstEffects[PlayerRef.GetValue(HC_ThirstEffect) as int].FatigueMult
  887. float SleepFatigueMult = SleepEffects[PlayerRef.GetValue( HC_SleepEffect ) as int].FatigueMult
  888. trace(self, " DamageFatigue() HungerFatigueMult (2x): " + HungerFatigueMult)
  889. trace(self, " DamageFatigue() ThirstFatigueMult (2x): " + ThirstFatigueMult)
  890. trace(self, " DamageFatigue() SleepFatigueMult (3x): " + SleepFatigueMult)
  891.  
  892. ; Average them up...
  893. float AverageFatigueMult = ((HungerFatigueMult * 2.0) + (ThirstFatigueMult * 2.0) + (SleepFatigueMult * 3.0)) / 7.0
  894. trace(self, " DamageFatigue() AverageFatigueMult: " + AverageFatigueMult)
  895.  
  896. ; Let's store our average fatigue.
  897. float currentFatigue = AverageFatigueMult * fMaxFatigue
  898.  
  899. ; Captastic.
  900. if currentFatigue > fCapFatigue
  901. currentFatigue = fCapFatigue
  902. elseif currentFatigue > 0 && currentFatigue < fLowestNonZeroFatigue
  903. currentFatigue = fLowestNonZeroFatigue
  904. elseif currentFatigue < 0
  905. currentFatigue = 0
  906. endif
  907.  
  908. ; Only worry about touching this AV if the value is actually changing...
  909. float previousFatigue = PlayerRef.GetValue(Fatigue)
  910. if previousFatigue != currentFatigue
  911. ; First, we set it back to 0...
  912. ClearFatigue()
  913.  
  914. ; Then, we set it to the desired value.
  915. PlayerRef.DamageValue(Fatigue, currentFatigue)
  916. trace(self, " DamageFatigue() Updated currentFatigue: " + currentFatigue)
  917.  
  918. ; Display the Fatigue Warning?
  919. if bAnnounceFatigue && currentFatigue > previousFatigue
  920. Game.ShowFatigueWarningOnHUD()
  921. trace(self, " DamageFatigue() - Announcing Fatigue!")
  922. endif
  923.  
  924. endif
  925.  
  926. Endfunction
  927.  
  928. Function ClearFatigue()
  929. PlayerRef.RestoreValue(Fatigue, fMaxFatigue)
  930. EndFunction
  931.  
  932. ;**************************************************************************************************
  933. ;************************************** SUSTENANCE EFFECTS *******************************
  934. ;**************************************************************************************************
  935.  
  936. Group SustenanceEffects
  937. globalvariable Property HC_Rule_SustenanceEffects const auto mandatory
  938.  
  939. ActorValue Property HC_HungerEffect const auto mandatory
  940.  
  941. Effect[] Property HungerEffects const auto mandatory
  942. {The order in this array, is the order they devolution after time passes since eating.}
  943.  
  944. keyword[] Property IncreasesHungerKeywords const auto mandatory
  945. {keywords in here, removes points from Food pool, making the player more hungry}
  946.  
  947. float Property IncreasesHungerCostMult = 0.65 const auto
  948. {Multiplier on things that increase hunger's caps value}
  949.  
  950. keyword Property ObjectTypeFood const auto mandatory
  951. {autofill}
  952.  
  953. ActorValue Property HC_ThirstEffect const auto mandatory
  954.  
  955. Effect[] Property ThirstEffects const auto mandatory
  956. {The order in this array, is the order they devolution after time passes since eating.}
  957.  
  958. keyword[] Property IncreasesThirstKeywords const auto mandatory
  959. {keywords in here, removes points from Drink pool, making the player more thirsty}
  960.  
  961. float Property IncreasesThirstCostMult = 0.5 const auto
  962. {Default: 0.5; Multiplier on things that increase thirst's caps value}
  963.  
  964. keyword[] Property QuenchesThirstKeywords const auto mandatory
  965. {keywords in here, removes points from Drink pool, making the player more thirsty}
  966.  
  967. keyword Property ObjectTypeNukaCola const auto mandatory
  968. {autofill}
  969.  
  970. float Property NukaThirstCostMult = 0.4 const auto
  971. {Cost * this = Thirst Value}
  972.  
  973. float Property NukaFoodCostMult = 0.2 const auto
  974. {-Cost * this = Food Value}
  975.  
  976. keyword Property ObjectTypeCaffeinated const auto mandatory
  977. {autofill}
  978. keyword Property ObjectTypeExtraCaffeinated const auto mandatory
  979. {autofill}
  980.  
  981. MagicEffect Property HC_Disease_NeedMoreFood_Effect const auto mandatory
  982. {Autofill, if player has this effect, he requires more food -- eating restores less food}
  983.  
  984. float Property DiseaseNeedMoreFoodMult = 0.5 const auto
  985. {multiplyer on the value of food when player have the need more food disease effect}
  986.  
  987. perk Property HC_SustenanceEffectsTurnOffFood const auto mandatory
  988.  
  989.  
  990. int Property CannibalTicksToGoRavenous = 12 const auto
  991. {How many sustenance ticks as a cannibal it takes to go Ravenous}
  992.  
  993. ActorValue Property HC_CannibalEffect const auto mandatory
  994. {Autofill; 0 = normal, 1 = has ravenous hunger (recently ate a corpse)}
  995.  
  996. Potion Property HC_Cannibal_RavenousHunger const auto mandatory
  997. {Autofill; potion that has the Ravenous Hunger effect - conditioned on AV HC_CannibalRavenousHunger being 1}
  998.  
  999. Message Property HC_Cannibal_Msg_RavenousHunger_EatFood const auto mandatory
  1000. {autofill; message to display when eating normal food while suffering from Cannibal Effect Ravenous Hunger}
  1001.  
  1002. Message Property HC_Cannibal_Msg_RavenousHunger_EatCorpse const auto mandatory
  1003. {autofill; message to display when eating a corpse and gaiing the Ravenous Hunger}
  1004.  
  1005. Message Property HC_Cannibal_Msg_RavenousHunger_DropToRavenousLevel const auto mandatory
  1006. {autofill; message to display when dropping to ravenous hunger level while suffering from Cannibal Effect Ravenous Hunger}
  1007.  
  1008. potion Property HC_SippableWater const auto mandatory
  1009. {autofill; Water we force you to drink when you drink from a fountain or pool to run it through the correct processes}
  1010.  
  1011. potion Property HC_SippableDirtyWater const auto mandatory
  1012. {autofill; Dirty water we force you to drink when you drink from a dirty fountain or pool to run it through the correct processes}
  1013.  
  1014. perk Property HC_FillWaterBottlePerk Auto Const Mandatory
  1015. {autofill; this perk let's you fill empty bottles at water sources}
  1016.  
  1017. EndGroup
  1018.  
  1019. Group SustenanceTiers
  1020. float Property GamesHoursPerTick = 1.0 const auto
  1021. {How many game hours for a standard hunger/thirst check tick}
  1022. float Property BonusDigestionHours = 1.0 Auto Const
  1023. {How many hours you get after clearing a hunger or thirst tier before the next sustenance tick}
  1024. float Property SustenanceTickWhileSleepingMult = 0.25 const auto
  1025. {This is a cut on the amount of time being passed as percieved by sustenance, to prevent massive changes while sleeping.}
  1026. float Property TickHoursCostPerCombat = 0.25 const auto
  1027. {in terms of game hours, how much does each combat shave off the next tick time}
  1028.  
  1029. ; Food
  1030. int Property FoodCostPerTick = 4 const auto
  1031. {in terms of caps value, how much food per tick is required to remain normal}
  1032. int Property iFoodPoolPeckishAmount = -24 const auto ; 6 hours
  1033. int Property iFoodPoolHungryAmount = -48 const auto ; 12 hours
  1034. int Property iFoodPoolFamishedAmount = -96 const auto ; 24 hours
  1035. int Property iFoodPoolRavenousAmount = -144 const auto ; 36 hours
  1036. int Property iFoodPoolStarvingAmount = -256 const auto ; 64 hours
  1037. int Property MinFoodValueFed = 12 const auto
  1038. int Property MinFoodValuePeckish = 12 const auto ; Maximum of 2 Food to Fed
  1039. int Property MinFoodValueHungry = 12 const auto ; Maximum of 4 Food to Fed
  1040. int Property MinFoodValueFamished = 24 const auto ; Maximum of 6 Food to Fed
  1041. int Property MinFoodValueRavenous = 24 const auto ; Maximum of 8 Food to Fed
  1042. int Property MinFoodValueStarving = 56 const auto ; Maximum of 10 Food to Fed
  1043. int Property MaxFoodValue = 231 const auto ; The most food points we will ever take.
  1044.  
  1045. ; Drink
  1046. int Property DrinkCostPerTick = 4 const auto
  1047. {in terms of caps value, how much drink per tick is required to remain normal}
  1048. int Property iDrinkPoolParchedAmount = -16 const auto ; 4 hours
  1049. int Property iDrinkPoolThirstyAmount = -36 const auto ; 9 hours
  1050. int Property iDrinkPoolMildlyDehydratedAmount = -72 const auto ; 18 hours
  1051. int Property iDrinkPoolDehydratedAmount = -120 const auto ; 30 hours
  1052. int Property iDrinkPoolSeverelyDehydratedAmount = -180 const auto ; 45 hours
  1053. int Property MinDrinkValueHydrated = 8 const auto
  1054. int Property MinDrinkValueParched = 8 const auto ; Maximum of 2 Drink to Hydrated
  1055. int Property MinDrinkValueThirsty = 10 const auto ; Maximum of 4 Drink to Hydrated
  1056. int Property MinDrinkValueMildlyDehydrated = 18 const auto ; Maximum of 6 Drink to Hydrated
  1057. int Property MinDrinkValueDehydrated = 24 const auto ; Maximum of 8 Drink to Hydrated
  1058. int Property MinDrinkValueSeverelyDehydrated = 30 const auto ; Maximum of 10 Drink to Hydrated
  1059. int Property MaxDrinkValue = 167 const auto ; The most drink points we will ever take.
  1060.  
  1061. EndGroup
  1062.  
  1063. Group SustenanceEffectsGlobalEnums
  1064. globalvariable Property HC_HE_Fed const auto
  1065. {autofill; global whose value represents this level}
  1066.  
  1067. globalvariable Property HC_HE_Peckish const auto
  1068. {autofill; global whose value represents this level}
  1069.  
  1070. globalvariable Property HC_HE_Hungry const auto
  1071. {autofill; global whose value represents this level}
  1072.  
  1073. globalvariable Property HC_HE_Famished const auto
  1074. {autofill; global whose value represents this level}
  1075.  
  1076. globalvariable Property HC_HE_Ravenous const auto
  1077. {autofill; global whose value represents this level}
  1078.  
  1079. globalvariable Property HC_HE_Starving const auto
  1080. {autofill; global whose value represents this level}
  1081.  
  1082.  
  1083. globalvariable Property HC_TE_Hydrated const auto
  1084. {autofill; global whose value represents this level}
  1085.  
  1086. globalvariable Property HC_TE_Parched const auto
  1087. {autofill; global whose value represents this level}
  1088.  
  1089. globalvariable Property HC_TE_Thirsty const auto
  1090. {autofill; global whose value represents this level}
  1091.  
  1092. globalvariable Property HC_TE_MildlyDehydrated const auto
  1093. {autofill; global whose value represents this level}
  1094.  
  1095. globalvariable Property HC_TE_Dehydrated const auto
  1096. {autofill; global whose value represents this level}
  1097.  
  1098. globalvariable Property HC_TE_SeverelyDehyrdated const auto
  1099. {autofill; global whose value represents this level}
  1100.  
  1101.  
  1102. globalvariable Property HC_SE_WellRestedORLoversEmbrace const auto
  1103. {autofill; global whose value represents this level}
  1104.  
  1105. globalvariable Property HC_SE_Rested const auto
  1106. {autofill; global whose value represents this level}
  1107.  
  1108. globalvariable Property HC_SE_Tired const auto
  1109. {autofill; global whose value represents this level}
  1110.  
  1111. globalvariable Property HC_SE_Weary const auto
  1112. {autofill; global whose value represents this level}
  1113.  
  1114. globalvariable Property HC_SE_Fatigued const auto
  1115. {autofill; global whose value represents this level}
  1116.  
  1117. globalvariable Property HC_SE_Exhausted const auto
  1118. {autofill; global whose value represents this level}
  1119.  
  1120. globalvariable Property HC_SE_Incapacitated const auto
  1121. {autofill; global whose value represents this level}
  1122.  
  1123. EndGroup
  1124.  
  1125. int iCaffeinated = 0 ; 0 = None, 1 = Caffeinated, 2 = Well Rested + Caffeinated
  1126. int CaffeinatedCount = 0 ; Track the number of times we've been extra caffeinated.
  1127. int ExtraCaffeinatedCount = 0 ; Track the number of times we've been caffeinated.
  1128. float fCaffeinatedTimeTracker ; Store off the time remaining when we got caffeinated.
  1129. float DEBUGCaffeinatedTimeRemaining ; (DEBUG) Store off the time we will be caffeinated if it's allowed to expire.
  1130.  
  1131. int CannibalTicks = 0 ; How many sustenance ticks have passed while you've been a cannibal?
  1132.  
  1133. int FoodPool = 0 ; negative means a debt that needs to be paid or suffer effect
  1134. int FoodReqs = -1 ; This is how much you actually have to eat in order to remove the effects.
  1135. int DrinkPool = 0 ; negative means a debt that needs to be paid or suffer effect
  1136. int DrinkReqs = -1 ; This is how much you actually have to drink in order to remove the effects.
  1137. ;int DeadPool ; negative needs to be paid for effects suffered...
  1138.  
  1139.  
  1140.  
  1141. float LastCombatDay ;store the last combat time in terms of game days passed
  1142. float MinDaysPerCombat = 0.1 ;how many gamedayspassed need to occur before we count a new combat
  1143.  
  1144. float NextSustenanceTickDay ;expressed in GameDaysPassed, when is the next game day that a tick occurs - player getting in combats can shorten this.
  1145.  
  1146. form[] FoodItems ; Holds our food for later processing.
  1147. bool bProcessingFood = false ; Flag used to keep us from processing more than once at the same time.
  1148.  
  1149. Event Actor.OnCombatStateChanged(Actor akSender, Actor akTarget, int aeCombatState)
  1150. trace(self, "OnCombatStateChanged()")
  1151.  
  1152. float GameDaysPassed = Utility.GetCurrentGameTime()
  1153.  
  1154. if aeCombatState == 1 && GameDaysPassed < (LastCombatDay + MinDaysPerCombat)
  1155.  
  1156. trace(self, " OnCombatStateChanged() shaving time off NextSustenanceTickDay. Was: " + NextSustenanceTickDay)
  1157.  
  1158. ;shave off time from tick day because player is exerting himself in combat
  1159. NextSustenanceTickDay -= (TickHoursCostPerCombat/24)
  1160.  
  1161. trace(self, " OnCombatStateChanged() shaving time off NextSustenanceTickDay. Now: " + NextSustenanceTickDay)
  1162.  
  1163. LastCombatDay = GameDaysPassed
  1164. endif
  1165. EndEvent
  1166.  
  1167. Event Actor.OnItemEquipped(Actor akSender, Form akBaseObject, ObjectReference akReference)
  1168. ; As long as your actually food and not one of our many tasty potions, lets add you to the food array.
  1169. if akBaseObject == HC_Antibiotics || (akReference == none || false == akReference.IsQuestItem()) && false == CommonArrayFunctions.CheckFormAgainstKeywordArray(akBaseObject, NonFoodKeywords)
  1170. AddFoodItem(akBaseObject)
  1171. endif
  1172.  
  1173. EndEvent
  1174.  
  1175. Function AddFoodItem(Form akBaseObject)
  1176. FoodItems.add(akBaseObject)
  1177. trace(self, "Adding Food Item " + akBaseObject + " To Array With " + FoodItems.length + " Total Food Items...")
  1178. CallFunctionNoWait("ProcessFoodItems", new var[0])
  1179. EndFunction
  1180.  
  1181.  
  1182. ; NO RENAMING! THIS FUNCTION IS CALLED BY "CallFunctionNoWait" FROM Actor.OnItemEquipped() WHICH RELIES ON THE NAME. NO RENAMING!
  1183. Function ProcessFoodItems()
  1184. trace(self, "Processing " + FoodItems.length + " Food Items...")
  1185.  
  1186. ; Check to see if we're already running this. Additional items will just be added to the array.
  1187. if bProcessingFood
  1188. return
  1189. endif
  1190.  
  1191. ; Set our flag and start eating all this delicous food product.
  1192. bProcessingFood = true
  1193. while FoodItems.length > 0
  1194. ProcessSingleFoodItem(FoodItems[0])
  1195. FoodItems.remove(0)
  1196. trace(self, " Food Item Processed! " + FoodItems.length + " remaining...")
  1197. utility.WaitMenuMode(0.1)
  1198. endwhile
  1199.  
  1200. ; We out. Peace.
  1201. bProcessingFood = false
  1202.  
  1203. EndFunction
  1204.  
  1205. ; Process each item one at a time.
  1206. Function ProcessSingleFoodItem(Form akBaseObject)
  1207. int baseCost = akBaseObject.GetGoldValue()
  1208. trace(self, " ProcessSingleFoodItem(): " + akBaseObject + ", Base Cost: " + baseCost)
  1209.  
  1210. if akBaseObject == HC_Antibiotics
  1211. bPlayerTookAntibiotics = true
  1212. HandleDiseaseRiskEvent(0)
  1213. endif
  1214.  
  1215. ; Caffeine makes me feel alright... for a time.
  1216. if akBaseObject.HasKeyword(ObjectTypeCaffeinated)
  1217. ; Time until sleep cycle ends / length of Caffeination.
  1218. float timeToCaffeinate = 0
  1219.  
  1220. if iCaffeinated > 0
  1221. timeToCaffeinate = GetHoursUntilCurrentSleepCycleEnds()
  1222. endif
  1223.  
  1224. ; To prevent staving off sleep forever by caffeinating, we increase it by the standard value scaled by the number of times caffeinated (typed).
  1225. if akBaseObject.HasKeyword(ObjectTypeExtraCaffeinated)
  1226. ExtraCaffeinatedCount += 1
  1227. timeToCaffeinate += ExtraCaffeineInducedSleepDelay / ExtraCaffeinatedCount
  1228. else
  1229. CaffeinatedCount += 1
  1230. timeToCaffeinate += CaffeineInducedSleepDelay / CaffeinatedCount
  1231. endif
  1232.  
  1233. ; Get Caffeinated
  1234. PlayerRef.EquipItem(HC_Effect_Caffeinated, abSilent = true)
  1235.  
  1236. ; Get our current value - 1.
  1237. int newVal = (PlayerRef.GetValue(HC_SleepEffect) as int) - 1
  1238.  
  1239. if iCaffeinated == 0 && newVal >= 0
  1240. iCaffeinated = 1
  1241. PlayerRef.SetValue(HC_SleepEffect, newVal)
  1242. fCaffeinatedTimeTracker = GetHoursUntilCurrentSleepCycleEnds()
  1243. elseif iCaffeinated == 0
  1244. iCaffeinated = 2
  1245. endif
  1246. trace(self, " ProcessSingleFoodItem(): CAFFEINATED!!! iCaffeinated: " + iCaffeinated + ", SleepEffect[" + newVal + "]")
  1247.  
  1248. ; Show our message (Using Redisplay exlusively for this.)
  1249. HC_SE_Msg_Caffeinated.show()
  1250.  
  1251. ; Restart the sleep timer with the Caffeine delay.
  1252. StartSleepDeprivationTimer(timeToCaffeinate)
  1253.  
  1254. ; For logging.
  1255. DEBUGCaffeinatedTimeRemaining = timeToCaffeinate
  1256.  
  1257. endif
  1258.  
  1259. ; FOOD!
  1260. if akBaseObject.HasKeyword(ObjectTypeFood)
  1261. trace(self, " ProcessSingleFoodItem() player eating food: " + akBaseObject + ", Base Cost: " + baseCost)
  1262. ;based on food pool deficit, set hunger effect
  1263. ModFoodPoolAndUpdateHungerEffects(basecost)
  1264. ; Increase the chance for the disease without immediately forcing a roll.
  1265. FillDiseaseRiskPool(DiseaseRiskIncreaser_Food)
  1266. elseif IsHungerIncreasing(akBaseObject)
  1267. trace(self, " ProcessSingleFoodItem() player increasing hunger: " + akBaseObject + ", cost: -" + basecost)
  1268. ModFoodPoolAndUpdateHungerEffects(math.floor(-basecost * IncreasesHungerCostMult))
  1269. endif
  1270.  
  1271. ;DRINK - This is not ifelse'd, because some food also cures thirst.
  1272. if IsThirstQuenching(akBaseObject)
  1273. trace(self, " ProcessSingleFoodItem() player quenching thirst: " + akBaseObject + ", cost: " + basecost)
  1274. ModDrinkPoolAndUpdateThirstEffects(basecost)
  1275. ; Increase the chance for the disease without immediately forcing a roll.
  1276. FillDiseaseRiskPool(DiseaseRiskIncreaser_Drink)
  1277. elseif IsThirstIncreasing(akBaseObject)
  1278. trace(self, " ProcessSingleFoodItem() player increasing thirst: " + akBaseObject + ", cost: -" + basecost)
  1279. ModDrinkPoolAndUpdateThirstEffects(math.floor(-basecost * IncreasesThirstCostMult))
  1280. endif
  1281.  
  1282. ; NUKA COLA, GET YOURSELF REFRESHED!!!
  1283. if akBaseObject.HasKeyword(ObjectTypeNukaCola)
  1284. trace(self, " ProcessSingleFoodItem() Player is drinking cola (" + akBaseObject + "): Thirst +" + (basecost * NukaThirstCostMult) + ", Hunger -" + (basecost * NukaFoodCostMult))
  1285. ModFoodPoolAndUpdateHungerEffects( math.floor(-basecost * NukaFoodCostMult))
  1286. ModDrinkPoolAndUpdateThirstEffects(math.floor( basecost * NukaThirstCostMult))
  1287. ; Increase the chance for the disease without immediately forcing a roll.
  1288. FillDiseaseRiskPool(DiseaseRiskIncreaser_Cola)
  1289. endif
  1290.  
  1291. ; Handle Disease Risks (with rolls!)
  1292. if CommonArrayFunctions.CheckFormAgainstKeywordArray(akBaseObject, DiseaseRiskFoodStandardKeywords)
  1293. trace(self, " ProcessSingleFoodItem() player eating food with standard disease risk: " + akBaseObject )
  1294. HandleDiseaseRiskEvent(DiseaseRiskFoodStandardAmount)
  1295.  
  1296. elseif CommonArrayFunctions.CheckFormAgainstKeywordArray(akBaseObject, DiseaseRiskFoodHighKeywords)
  1297. trace(self, " ProcessSingleFoodItem() player eating food with high disease risk: " + akBaseObject )
  1298. HandleDiseaseRiskEvent(DiseaseRiskFoodHighAmount)
  1299.  
  1300. elseif CommonArrayFunctions.CheckFormAgainstKeywordArray(akBaseObject, DiseaseRiskChemsKeywords)
  1301. trace(self, " ProcessSingleFoodItem() player taking chem with disease risk: " + akBaseObject )
  1302. HandleDiseaseRiskEvent(DiseaseRiskChemsAmount)
  1303.  
  1304. endif
  1305.  
  1306. ; Handle Radaway and other similar Rad treatments.
  1307. if IsGlobalTrue(HC_Rule_DiseaseEffects) && akBaseObject.HasKeyword(HC_CausesImmunodeficiency)
  1308. trace(self, " ProcessSingleFoodItem() player is using Rad Treatment and must be punished!")
  1309. PlayerRef.EquipItem(HC_Effect_Immunodeficiency, abSilent = true)
  1310. ; Increase the chance for the disease without immediately forcing a roll.
  1311. FillDiseaseRiskPool(DiseaseRiskIncreaser_Immunodeficiency)
  1312. endif
  1313.  
  1314. Endfunction
  1315.  
  1316. bool Function IsThirstQuenching(form akBaseObject)
  1317. bool returnVal = false
  1318. if akBaseObject
  1319. int i = 0
  1320. while (returnVal == false && i < QuenchesThirstKeywords.length)
  1321. returnVal = akBaseObject.HasKeyword(QuenchesThirstKeywords[i])
  1322. i += 1
  1323. endwhile
  1324. endif
  1325. return returnVal
  1326. EndFunction
  1327.  
  1328. bool Function IsThirstIncreasing(form akBaseObject)
  1329. bool returnVal = false
  1330. if akBaseObject
  1331. int i = 0
  1332. while (returnVal == false && i < IncreasesThirstKeywords.length)
  1333. returnVal = akBaseObject.HasKeyword(IncreasesThirstKeywords[i])
  1334. i += 1
  1335. endwhile
  1336. endif
  1337. return returnVal
  1338. EndFunction
  1339.  
  1340. bool Function IsHungerIncreasing(form akBaseObject)
  1341. bool returnVal = false
  1342. if akBaseObject
  1343. int i = 0
  1344. while (returnVal == false && i < IncreasesHungerKeywords.length)
  1345. returnVal = akBaseObject.HasKeyword(IncreasesHungerKeywords[i])
  1346. i += 1
  1347. endwhile
  1348. endif
  1349. return returnVal
  1350. EndFunction
  1351.  
  1352. function HandleSustenanceTimer(bool bWasSleeping = false, bool bCanceledSleepPreHour = false)
  1353. trace(self, " HandleSustenanceTimer()")
  1354.  
  1355. float GameDaysPassed = Utility.GetCurrentGameTime()
  1356. trace(self, " HandleSustenanceTimer() GameDaysPassed: " + GameDaysPassed)
  1357. trace(self, " HandleSustenanceTimer() NextSustenanceTickDay: " + NextSustenanceTickDay)
  1358.  
  1359. ; Store this off and use it a couple of times...
  1360. float GameDaysPerTick = GamesHoursPerTick / 24.0
  1361.  
  1362. ; If we've been sleeping we are conserving energy.
  1363. if bWasSleeping
  1364. trace(self, " HandleSustenanceTimer() Look at this sleepyhead! You just woke up! I'll take that into account!")
  1365. GameDaysPerTick *= 1/SustenanceTickWhileSleepingMult
  1366. if bCanceledSleepPreHour
  1367. NextSustenanceTickDay -= 1.0 / 24.0
  1368. trace(self, " HandleSustenanceTimer() Sleep Canceled! Updated NextSustenanceTickDay: " + NextSustenanceTickDay)
  1369. endif
  1370. EndIf
  1371.  
  1372. ; "If this is your first time..., you have to fight." - Tyler Durden
  1373. ; Translation: If this is 0, then it has never been run before, so we correctly increment it from out incoming starting time.
  1374. if false == NextSustenanceTickDay
  1375. NextSustenanceTickDay = GameDaysPassed + GameDaysPerTick
  1376. trace(self, " HandleSustenanceTimer() FIRST CALL - GameDaysPassed: " + GameDaysPassed + ", NextSustenanceTickDay: " + NextSustenanceTickDay)
  1377. return
  1378. endif
  1379.  
  1380. trace(self, " HandleSustenanceTimer() GamesHoursPerTick: " + GamesHoursPerTick)
  1381. trace(self, " HandleSustenanceTimer() GameDaysPerTick: " + GameDaysPerTick)
  1382.  
  1383. ; Is this a tick threshold?
  1384. if GameDaysPassed >= NextSustenanceTickDay
  1385.  
  1386. trace(self, " HandleSustenanceTimer() GameDaysPassed >= NextSustenanceTickDay >>> PROCESSING HUNGER >>>")
  1387. trace(self, " HandleSustenanceTimer() (NextSustenanceTickDay - GameDaysPerTick): " + (NextSustenanceTickDay - GameDaysPerTick))
  1388. trace(self, " HandleSustenanceTimer() GameDaysPassed - ABOVE: " + (GameDaysPassed - (NextSustenanceTickDay - GameDaysPerTick)))
  1389. trace(self, " HandleSustenanceTimer() ABOVE / GameDaysPerTick): " + ((GameDaysPassed - (NextSustenanceTickDay - GameDaysPerTick)) / GameDaysPerTick))
  1390. trace(self, " HandleSustenanceTimer() math.floor(ABOVE): " + math.floor( ((GameDaysPassed - (NextSustenanceTickDay - GameDaysPerTick)) / GameDaysPerTick) ))
  1391.  
  1392. ;get # of ticks since last time we handled the timer (in case player waits for a long time for example)
  1393. int ticks = math.floor( ((GameDaysPassed - (NextSustenanceTickDay - GameDaysPerTick)) / GameDaysPerTick) )
  1394.  
  1395. int ModFoodPool = 0
  1396.  
  1397. ;IF SUFFERING RAVENOUS HUNGER Cannibal Effect
  1398. ;set the hunger ticks to trigger ravenous hunger effect
  1399. if PlayerRef.GetValue(HC_CannibalEffect) <= 0
  1400. trace(self, " HandleSustenanceTimer() You're not a cannibal! TICKS: " + ticks)
  1401. ;normal amount
  1402. ModFoodPool = -FoodCostPerTick * ticks
  1403. else
  1404. CannibalTicks += 1 * ticks
  1405. trace(self, " HandleSustenanceTimer() You're a cannibal! WHY!? CANNABIL TICKS: " + CannibalTicks)
  1406. ; Every X ticks we are going to go ravenous until we eat a corpse.
  1407. if CannibalTicks >= CannibalTicksToGoRavenous
  1408. ;specific amount because player is suffering from ravenous hunger
  1409. ModFoodPool = iFoodPoolRavenousAmount
  1410. ;pop a message explaining what happened
  1411. HC_Cannibal_Msg_RavenousHunger_DropToRavenousLevel.show()
  1412. ; reset our counter and be prepaird to do this again.
  1413. CannibalTicks = 0
  1414. endif
  1415. endif
  1416.  
  1417. ModFoodPoolAndUpdateHungerEffects(ModFoodPool)
  1418. ModDrinkPoolAndUpdateThirstEffects(-DrinkCostPerTick * ticks)
  1419.  
  1420. ;set up for the next tick
  1421. NextSustenanceTickDay = GameDaysPassed + GameDaysPerTick
  1422.  
  1423. else
  1424. trace(self, " HandleSustenanceTimer() GameDaysPassed < NextSustenanceTickDay. Try again later.")
  1425. endif
  1426.  
  1427. endfunction
  1428.  
  1429. float Function CapFoodAndDrinkPoolMinValue(float afModPoolAmount, int aiMinTierValue)
  1430. if afModPoolAmount < aiMinTierValue
  1431. return aiMinTierValue
  1432. endif
  1433. ; Otherwise return what we had.
  1434. return afModPoolAmount
  1435. EndFunction
  1436.  
  1437. int Function SetOrCapReqsToTiersSustenanceValueOnDeterioration(int aiReqs, int aiCurrentEffectTier, int aiNewEffectTier, int aiFoodPoolValueForTier)
  1438. ; We've gotten worse. Bump up the Food Requirements needed to clear states.
  1439. if (aiCurrentEffectTier != aiNewEffectTier)
  1440. trace(self, " SetOrCapReqsToTiersSustenanceValueOnDeterioration(): Updated Reqs: " + aiFoodPoolValueForTier)
  1441. return aiFoodPoolValueForTier
  1442. ; Make sure Food Requirements remains atleast as high as the current cap.
  1443. elseif aiReqs < aiFoodPoolValueForTier
  1444. trace(self, " SetOrCapReqsToTiersSustenanceValueOnDeterioration(): Capped Reqs: " + aiFoodPoolValueForTier)
  1445. return aiFoodPoolValueForTier
  1446. endif
  1447. ; Otherwise return what we had.
  1448. trace(self, " SetOrCapReqsToTiersSustenanceValueOnDeterioration(): Unchanged Reqs: " + aiReqs)
  1449. return aiReqs
  1450. EndFunction
  1451.  
  1452. int Function SetPoolToTiersSustenanceValueOnRecovery(int aiPool, int aiCurrentEffectTier, int aiNewEffectTier, int aiFoodPoolValueForTier)
  1453. ; We've gotten better. Roll back out food pool to the new value.
  1454. if (aiCurrentEffectTier != aiNewEffectTier)
  1455. if aiPool < aiFoodPoolValueForTier
  1456. trace(self, " SetPoolToTiersSustenanceValueOnRecovery(): Updated Pool: " + aiFoodPoolValueForTier)
  1457. return aiFoodPoolValueForTier
  1458. endif
  1459. endif
  1460. ; Otherwise return what we had.
  1461. trace(self, " SetPoolToTiersSustenanceValueOnRecovery(): Unchanged Pool: " + aiPool)
  1462. return aiPool
  1463. EndFunction
  1464.  
  1465. bool Function ShowSustenance(bool abStateChanged)
  1466. ; Is this a state change? If so, let's add some fatigue and show our message.
  1467. if abStateChanged
  1468. return true
  1469. endif
  1470. return false
  1471. EndFunction
  1472.  
  1473. bool Function AnnounceFatigue(bool abStateChanged, int aiModPoolAmount)
  1474. ; We're transitioning to a worse effect.
  1475. if abStateChanged && aiModPoolAmount < 0
  1476. ; Tutorial Call - Thirst.
  1477. TryTutorial(ThirstTutorial, "ThirstTutorial")
  1478. return true
  1479. endif
  1480. return false
  1481. EndFunction
  1482.  
  1483. Function UpdateNextSustenanceTickDay(bool abStateChanged, int aiModPoolAmount)
  1484. ; We're transitioning to a better effect
  1485. if abStateChanged && aiModPoolAmount > 0
  1486. ; Reset out time.
  1487. NextSustenanceTickDay = Utility.GetCurrentGameTime() + (BonusDigestionHours / 24.0)
  1488. endif
  1489. EndFunction
  1490.  
  1491. Function ModFoodPoolAndUpdateHungerEffects(float ModPoolAmount, bool IsEatingCorpse = false)
  1492. trace(self, " ModFoodPoolAndUpdateHungerEffects() ModPoolAmount: " + ModPoolAmount)
  1493.  
  1494. ; Store our current effect to test for a change...
  1495. int currentHE = PlayerRef.GetValue(HC_HungerEffect) as int
  1496.  
  1497. if ModPoolAmount >= 0
  1498. ; FIND OUR CORRECT MOD VALUE BASED ON YOU CURRENT TIER AND/OR EFFECTS
  1499. ;if player has Cannibal effect Ravenous Hunger, he gets no value from normal food.
  1500. if (false == IsEatingCorpse) && PlayerRef.GetValue(HC_CannibalEffect) > 0
  1501. ;suffering Ravenous Hunger
  1502. ModPoolAmount = 0 ;gains no benefit from food.
  1503. HC_Cannibal_Msg_RavenousHunger_EatFood.Show()
  1504. trace(self, " ModFoodPoolAndUpdateHungerEffects(): Player is suffering Cannibal's Hunger! Food is worthless!")
  1505.  
  1506. ; Check our max value first
  1507. elseif ModPoolAmount > MaxFoodValue && (false == IsEatingCorpse) ;no cap for corpses!
  1508. ModPoolAmount = MaxFoodValue
  1509. trace(self, " ModFoodPoolAndUpdateHungerEffects(): Capped @ MaxFoodValue: " + ModPoolAmount)
  1510.  
  1511. ; Adjust our ModPoolAmount for current hunger state:
  1512. elseif HC_HE_Fed.GetValue() == currentHE
  1513. ModPoolAmount = CapFoodAndDrinkPoolMinValue(ModPoolAmount, MinFoodValueFed)
  1514. trace(self, " ModFoodPoolAndUpdateHungerEffects(): Player is Fed! Updated ModPoolAmount: " + ModPoolAmount)
  1515.  
  1516. elseif HC_HE_Peckish.GetValue() == currentHE
  1517. ModPoolAmount = CapFoodAndDrinkPoolMinValue(ModPoolAmount, MinFoodValuePeckish)
  1518. trace(self, " ModFoodPoolAndUpdateHungerEffects(): Player is Peckish! Updated ModPoolAmount: " + ModPoolAmount)
  1519.  
  1520. elseif HC_HE_Hungry.GetValue() == currentHE
  1521. ModPoolAmount = CapFoodAndDrinkPoolMinValue(ModPoolAmount, MinFoodValueHungry)
  1522. trace(self, " ModFoodPoolAndUpdateHungerEffects(): Player is Hungry! Updated ModPoolAmount: " + ModPoolAmount)
  1523.  
  1524. elseif HC_HE_Famished.GetValue() == currentHE
  1525. ModPoolAmount = CapFoodAndDrinkPoolMinValue(ModPoolAmount, MinFoodValueFamished)
  1526. trace(self, " ModFoodPoolAndUpdateHungerEffects(): Player is Famished! Updated ModPoolAmount: " + ModPoolAmount)
  1527.  
  1528. elseif HC_HE_Ravenous.GetValue() == currentHE
  1529. ModPoolAmount = CapFoodAndDrinkPoolMinValue(ModPoolAmount, MinFoodValueRavenous)
  1530. trace(self, " ModFoodPoolAndUpdateHungerEffects(): Player is Ravenous! Updated ModPoolAmount: " + ModPoolAmount)
  1531.  
  1532. elseif HC_HE_Starving.GetValue() == currentHE
  1533. ModPoolAmount = CapFoodAndDrinkPoolMinValue(ModPoolAmount, MinFoodValueStarving)
  1534. trace(self, " ModFoodPoolAndUpdateHungerEffects(): Player is Starving! Updated ModPoolAmount: " + ModPoolAmount)
  1535.  
  1536. endif
  1537.  
  1538. ;reduce it if it's positive change and the player is suffering disease effect that requires more food
  1539. if PlayerRef.HasMagicEffect(HC_Disease_NeedMoreFood_Effect)
  1540. ModPoolAmount *= DiseaseNeedMoreFoodMult
  1541. trace(self, " ModFoodPoolAndUpdateHungerEffects(): Player has Disease Effect requiring more food, scaling ModPoolAmount to: " + ModPoolAmount)
  1542. endif
  1543.  
  1544. EndIf
  1545.  
  1546. ; Uupdate our new pool and required food values.
  1547. trace(self, " ModFoodPoolAndUpdateHungerEffects() Old FoodPool: " + FoodPool)
  1548. trace(self, " ModFoodPoolAndUpdateHungerEffects() Old FoodReqs: " + FoodReqs)
  1549. trace(self, " ModFoodPoolAndUpdateHungerEffects() + ModPoolAmount: " + ModPoolAmount)
  1550. FoodPool += ModPoolAmount as int
  1551. FoodReqs += ModPoolAmount as int
  1552. trace(self, " ModFoodPoolAndUpdateHungerEffects() New FoodPool: " + FoodPool)
  1553. trace(self, " ModFoodPoolAndUpdateHungerEffects() New FoodReqs: " + FoodReqs)
  1554.  
  1555. ; Based on Food pool deficit, set effect...
  1556. ; We're transitioning to a worse effect:
  1557. if ModPoolAmount < 0
  1558. if FoodPool <= iFoodPoolStarvingAmount && currentHE <= HC_HE_Starving.GetValue()
  1559. trace(self, " ModFoodPoolAndUpdateHungerEffects(): Player is Starving")
  1560. PlayerRef.SetValue(HC_HungerEffect, HC_HE_Starving.GetValue())
  1561.  
  1562. ; We've gotten worse. Bump up the Food Requirements needed to clear states.
  1563. FoodReqs = SetOrCapReqsToTiersSustenanceValueOnDeterioration(FoodReqs, currentHE, HC_HE_Starving.GetValue() as int, iFoodPoolStarvingAmount)
  1564.  
  1565. ;cap it
  1566. FoodPool = iFoodPoolStarvingAmount
  1567.  
  1568. elseif FoodPool <= iFoodPoolRavenousAmount && currentHE <= HC_HE_Ravenous.GetValue()
  1569. trace(self, " ModFoodPoolAndUpdateHungerEffects(): Player is Ravenous")
  1570. PlayerRef.SetValue(HC_HungerEffect, HC_HE_Ravenous.GetValue())
  1571.  
  1572. ; We've gotten worse. Bump up the Food Requirements needed to clear states.
  1573. FoodReqs = SetOrCapReqsToTiersSustenanceValueOnDeterioration(FoodReqs, currentHE, HC_HE_Ravenous.GetValue() as int, iFoodPoolRavenousAmount)
  1574.  
  1575. elseif FoodPool <= iFoodPoolFamishedAmount && currentHE <= HC_HE_Famished.GetValue()
  1576. trace(self, " ModFoodPoolAndUpdateHungerEffects(): Player is Famished")
  1577. PlayerRef.SetValue(HC_HungerEffect, HC_HE_Famished.GetValue())
  1578.  
  1579. ; We've gotten worse. Bump up the Food Requirements needed to clear states.
  1580. FoodReqs = SetOrCapReqsToTiersSustenanceValueOnDeterioration(FoodReqs, currentHE, HC_HE_Famished.GetValue() as int, iFoodPoolFamishedAmount)
  1581.  
  1582. elseif FoodPool <= iFoodPoolHungryAmount && currentHE <= HC_HE_Hungry.GetValue()
  1583. trace(self, " ModFoodPoolAndUpdateHungerEffects(): Player is Hungry")
  1584. PlayerRef.SetValue(HC_HungerEffect, HC_HE_Hungry.GetValue())
  1585.  
  1586. ; We've gotten worse. Bump up the Food Requirements needed to clear states.
  1587. FoodReqs = SetOrCapReqsToTiersSustenanceValueOnDeterioration(FoodReqs, currentHE, HC_HE_Hungry.GetValue() as int, iFoodPoolHungryAmount)
  1588.  
  1589. elseif FoodPool <= iFoodPoolPeckishAmount && currentHE <= HC_HE_Peckish.GetValue()
  1590. trace(self, " ModFoodPoolAndUpdateHungerEffects(): Player is Peckish")
  1591. PlayerRef.SetValue(HC_HungerEffect, HC_HE_Peckish.GetValue())
  1592.  
  1593. ; We've gotten worse. Bump up the Food Requirements needed to clear states.
  1594. FoodReqs = SetOrCapReqsToTiersSustenanceValueOnDeterioration(FoodReqs, currentHE, HC_HE_Peckish.GetValue() as int, iFoodPoolPeckishAmount)
  1595.  
  1596. elseif currentHE <= HC_HE_Fed.GetValue()
  1597. trace(self, " ModFoodPoolAndUpdateHungerEffects(): Player is Fed")
  1598. PlayerRef.SetValue(HC_HungerEffect, HC_HE_Fed.GetValue())
  1599.  
  1600. ; Make sure Food Requirements remains atleast as high as the current cap.
  1601. if FoodReqs < 0
  1602. FoodReqs = 0
  1603. endif
  1604.  
  1605. ;cap it, if we are over the limit.
  1606. if FoodPool > 0
  1607. FoodPool = 0
  1608. endif
  1609.  
  1610. else
  1611. trace(self, " ModFoodPoolAndUpdateHungerEffects(): GETTING WORSE - NO MATCH!")
  1612. trace(self, " ModFoodPoolAndUpdateHungerEffects(): Player is: " + PlayerRef.GetValue(HC_HungerEffect))
  1613. trace(self, " ModFoodPoolAndUpdateHungerEffects(): Foodpool: " + FoodPool)
  1614. trace(self, " ModFoodPoolAndUpdateHungerEffects(): FoodReqs: " + FoodReqs)
  1615. endif
  1616.  
  1617. ; We're transitioning to a better effect:
  1618. elseif ModPoolAmount > 0
  1619.  
  1620. if FoodReqs >= 0 && currentHE >= HC_HE_Fed.GetValue()
  1621. ;fed
  1622. trace(self, " ModFoodPoolAndUpdateHungerEffects(): Player is Fed")
  1623. PlayerRef.SetValue(HC_HungerEffect, HC_HE_Fed.GetValue())
  1624.  
  1625. ; We've gotten better. Roll back out food pool to the new value.
  1626. FoodPool = SetPoolToTiersSustenanceValueOnRecovery(FoodPool, currentHE, HC_HE_Fed.GetValue() as int, 0)
  1627.  
  1628. ;cap it, if we are over the limit.
  1629. FoodReqs = 0
  1630. if FoodPool > 0
  1631. FoodPool = 0
  1632. endif
  1633.  
  1634. elseif FoodReqs >= iFoodPoolPeckishAmount && currentHE >= HC_HE_Peckish.GetValue()
  1635. trace(self, " ModFoodPoolAndUpdateHungerEffects(): Player is Peckish")
  1636. PlayerRef.SetValue(HC_HungerEffect, HC_HE_Peckish.GetValue())
  1637.  
  1638. ; We've gotten better. Roll back out food pool to the new value.
  1639. FoodPool = SetPoolToTiersSustenanceValueOnRecovery(FoodPool, currentHE, HC_HE_Peckish.GetValue() as int, iFoodPoolPeckishAmount)
  1640.  
  1641. elseif FoodReqs >= iFoodPoolHungryAmount && currentHE >= HC_HE_Hungry.GetValue()
  1642. trace(self, " ModFoodPoolAndUpdateHungerEffects(): Player is Hungry")
  1643. PlayerRef.SetValue(HC_HungerEffect, HC_HE_Hungry.GetValue())
  1644.  
  1645. ; We've gotten better. Roll back out food pool to the new value.
  1646. FoodPool = SetPoolToTiersSustenanceValueOnRecovery(FoodPool, currentHE, HC_HE_Hungry.GetValue() as int, iFoodPoolHungryAmount)
  1647.  
  1648. elseif FoodReqs >= iFoodPoolFamishedAmount && currentHE >= HC_HE_Famished.GetValue()
  1649. trace(self, " ModFoodPoolAndUpdateHungerEffects(): Player is Famished")
  1650. PlayerRef.SetValue(HC_HungerEffect, HC_HE_Famished.GetValue())
  1651.  
  1652. ; We've gotten better. Roll back out food pool to the new value.
  1653. FoodPool = SetPoolToTiersSustenanceValueOnRecovery(FoodPool, currentHE, HC_HE_Famished.GetValue() as int, iFoodPoolFamishedAmount)
  1654.  
  1655. elseif FoodReqs >= iFoodPoolRavenousAmount && currentHE >= HC_HE_Ravenous.GetValue()
  1656. trace(self, " ModFoodPoolAndUpdateHungerEffects(): Player is Ravenous")
  1657. PlayerRef.SetValue(HC_HungerEffect, HC_HE_Ravenous.GetValue())
  1658.  
  1659. ; We've gotten better. Roll back out food pool to the new value.
  1660. FoodPool = SetPoolToTiersSustenanceValueOnRecovery(FoodPool, currentHE, HC_HE_Ravenous.GetValue() as int, iFoodPoolRavenousAmount)
  1661.  
  1662. elseif currentHE >= HC_HE_Starving.GetValue()
  1663. trace(self, " ModFoodPoolAndUpdateHungerEffects(): Player is Starving")
  1664. PlayerRef.SetValue(HC_HungerEffect, HC_HE_Starving.GetValue())
  1665.  
  1666. ;cap it
  1667. if foodPool < iFoodPoolStarvingAmount
  1668. foodPool = iFoodPoolStarvingAmount
  1669. endif
  1670. if FoodReqs < iFoodPoolStarvingAmount
  1671. FoodReqs = iFoodPoolStarvingAmount
  1672. endif
  1673.  
  1674. else
  1675. trace(self, " ModFoodPoolAndUpdateHungerEffects(): GETTING BETTER - NO MATCH!")
  1676. trace(self, " ModFoodPoolAndUpdateHungerEffects(): Player is " + PlayerRef.GetValue(HC_HungerEffect))
  1677. trace(self, " ModFoodPoolAndUpdateHungerEffects(): Foodpool: " + FoodPool)
  1678. trace(self, " ModFoodPoolAndUpdateHungerEffects(): FoodReqs: " + FoodReqs)
  1679.  
  1680. endif
  1681. endif
  1682.  
  1683. ; If we've changed tiers, let's add some fatigue and show our message.
  1684. bool bstateChanged = currentHE != PlayerRef.GetValue(HC_HungerEffect) as int
  1685. bool showSustenanceMessage = ShowSustenance(bstateChanged)
  1686. bool announceFatigue = AnnounceFatigue(bstateChanged, ModPoolAmount as int)
  1687. UpdateNextSustenanceTickDay(bstateChanged, ModPoolAmount as int)
  1688.  
  1689. trace(self, " ModFoodPoolAndUpdateHungerEffects() Final FoodPool: " + FoodPool)
  1690. trace(self, " ModFoodPoolAndUpdateHungerEffects() Final FoodReqs: " + FoodReqs)
  1691. ApplyEffect(HC_Rule_SustenanceEffects, HungerEffects, HC_HungerEffect, DispellRestedSpells = false, DisplayAfterAwakingMessage= !announceFatigue, bDisplayMessage = showSustenanceMessage, bAnnounceFatigue = announceFatigue)
  1692.  
  1693. EndFunction
  1694.  
  1695. Function ModDrinkPoolAndUpdateThirstEffects(int ModPoolAmount)
  1696. trace(self, " ModDrinkPoolAndUpdateThirstEffects(): ModPoolAmount: " + ModPoolAmount)
  1697.  
  1698. ; Store our current effect to test for a change...
  1699. int currentTE = PlayerRef.GetValue(HC_ThirstEffect) as int
  1700.  
  1701. if ModPoolAmount >= 0
  1702. ; FIND OUR CORRECT MOD VALUE BASED ON YOU CURRENT TIER AND/OR EFFECTS
  1703. ; We cap this value because our high value beverages are really high value...
  1704. if ModPoolAmount > MaxDrinkValue
  1705. ModPoolAmount = MaxDrinkValue
  1706. trace(self, " ModDrinkPoolAndUpdateThirstEffects(): Capped @ MaxDrinkValue: " + ModPoolAmount)
  1707.  
  1708. ; Adjust our ModPoolAmount for current thirst state:
  1709. elseif HC_TE_Hydrated.GetValue() == currentTE
  1710. ModPoolAmount = CapFoodAndDrinkPoolMinValue(ModPoolAmount as float, MinDrinkValueHydrated) as int
  1711. trace(self, " ModDrinkPoolAndUpdateThirstEffects(): Player is Hydrated! Updated ModPoolAmount: " + ModPoolAmount)
  1712.  
  1713. elseif HC_TE_Parched.GetValue() == currentTE
  1714. ModPoolAmount = CapFoodAndDrinkPoolMinValue(ModPoolAmount as float, MinDrinkValueParched) as int
  1715. trace(self, " ModDrinkPoolAndUpdateThirstEffects(): Player is Parched! Updated ModPoolAmount: " + ModPoolAmount)
  1716.  
  1717. elseif HC_TE_Thirsty.GetValue() == currentTE
  1718. ModPoolAmount = CapFoodAndDrinkPoolMinValue(ModPoolAmount as float, MinDrinkValueThirsty) as int
  1719. trace(self, " ModDrinkPoolAndUpdateThirstEffects(): Player is Thirsty! Updated ModPoolAmount: " + ModPoolAmount)
  1720.  
  1721. elseif HC_TE_MildlyDehydrated.GetValue() == currentTE
  1722. ModPoolAmount = CapFoodAndDrinkPoolMinValue(ModPoolAmount as float, MinDrinkValueMildlyDehydrated) as int
  1723. trace(self, " ModDrinkPoolAndUpdateThirstEffects(): Player is Mildly Dehydrated! Updated ModPoolAmount: " + ModPoolAmount)
  1724.  
  1725. elseif HC_TE_Dehydrated.GetValue() == currentTE
  1726. ModPoolAmount = CapFoodAndDrinkPoolMinValue(ModPoolAmount as float, MinDrinkValueDehydrated) as int
  1727. trace(self, " ModDrinkPoolAndUpdateThirstEffects(): Player is Dehydrated! Updated ModPoolAmount: " + ModPoolAmount)
  1728.  
  1729. elseif HC_TE_SeverelyDehyrdated.GetValue() == currentTE
  1730. ModPoolAmount = CapFoodAndDrinkPoolMinValue(ModPoolAmount as float, MinDrinkValueSeverelyDehydrated) as int
  1731. trace(self, " ModDrinkPoolAndUpdateThirstEffects(): Player is Severely Dehydrated! Updated ModPoolAmount: " + ModPoolAmount)
  1732.  
  1733. endif
  1734.  
  1735. endif
  1736.  
  1737. ; Update our new pool and required food values.
  1738. trace(self, " ModDrinkPoolAndUpdateThirstEffects(): Old DrinkPool: " + DrinkPool)
  1739. trace(self, " ModDrinkPoolAndUpdateThirstEffects(): Old DrinkReqs: " + DrinkReqs)
  1740. trace(self, " ModDrinkPoolAndUpdateThirstEffects(): + ModPoolAmount: " + ModPoolAmount)
  1741. DrinkPool += ModPoolAmount
  1742. DrinkReqs += ModPoolAmount
  1743. trace(self, " ModDrinkPoolAndUpdateThirstEffects(): New DrinkPool: " + DrinkPool)
  1744. trace(self, " ModDrinkPoolAndUpdateThirstEffects(): New DrinkReqs: " + DrinkReqs)
  1745.  
  1746. ; Based on Drink pool deficit, set effect...
  1747. ; We're transitioning to a worse effect:
  1748. if ModPoolAmount < 0
  1749. if DrinkPool <= iDrinkPoolSeverelyDehydratedAmount && currentTE <= HC_TE_SeverelyDehyrdated.GetValue()
  1750. trace(self, " ModDrinkPoolAndUpdateThirstEffects(): Player is Severely Dehydrated")
  1751. PlayerRef.SetValue(HC_ThirstEffect, HC_TE_SeverelyDehyrdated.GetValue())
  1752.  
  1753. ; We've gotten worse. Bump up the Food Requirements needed to clear states.
  1754. DrinkReqs = SetOrCapReqsToTiersSustenanceValueOnDeterioration(DrinkReqs, currentTE, HC_TE_SeverelyDehyrdated.GetValue() as int, iDrinkPoolSeverelyDehydratedAmount)
  1755.  
  1756. ;cap it
  1757. DrinkPool = iDrinkPoolSeverelyDehydratedAmount
  1758.  
  1759. elseif DrinkPool <= iDrinkPoolDehydratedAmount && currentTE <= HC_TE_Dehydrated.GetValue()
  1760. trace(self, " ModDrinkPoolAndUpdateThirstEffects(): Player is Dehydrated")
  1761. PlayerRef.SetValue(HC_ThirstEffect, HC_TE_Dehydrated.GetValue())
  1762.  
  1763. ; We've gotten worse. Bump up the Food Requirements needed to clear states.
  1764. DrinkReqs = SetOrCapReqsToTiersSustenanceValueOnDeterioration(DrinkReqs, currentTE, HC_TE_Dehydrated.GetValue() as int, iDrinkPoolDehydratedAmount)
  1765.  
  1766. elseif DrinkPool <= iDrinkPoolMildlyDehydratedAmount && currentTE <= HC_TE_MildlyDehydrated.GetValue()
  1767. trace(self, " ModDrinkPoolAndUpdateThirstEffects(): Player is Mildly Dehyrdated")
  1768. PlayerRef.SetValue(HC_ThirstEffect, HC_TE_MildlyDehydrated.GetValue())
  1769.  
  1770. ; We've gotten worse. Bump up the Food Requirements needed to clear states.
  1771. DrinkReqs = SetOrCapReqsToTiersSustenanceValueOnDeterioration(DrinkReqs, currentTE, HC_TE_MildlyDehydrated.GetValue() as int, iDrinkPoolMildlyDehydratedAmount)
  1772.  
  1773. elseif DrinkPool <= iDrinkPoolThirstyAmount && currentTE <= HC_TE_Thirsty.GetValue()
  1774. trace(self, " ModDrinkPoolAndUpdateThirstEffects(): Player is Thirsty")
  1775. PlayerRef.SetValue(HC_ThirstEffect, HC_TE_Thirsty.GetValue())
  1776.  
  1777. ; We've gotten worse. Bump up the Food Requirements needed to clear states.
  1778. DrinkReqs = SetOrCapReqsToTiersSustenanceValueOnDeterioration(DrinkReqs, currentTE, HC_TE_Thirsty.GetValue() as int, iDrinkPoolThirstyAmount)
  1779.  
  1780. elseif DrinkPool <= iDrinkPoolParchedAmount && currentTE <= HC_TE_Parched.GetValue()
  1781. trace(self, " ModDrinkPoolAndUpdateThirstEffects(): Player is Parched")
  1782. PlayerRef.SetValue(HC_ThirstEffect, HC_TE_Parched.GetValue())
  1783.  
  1784. ; We've gotten worse. Bump up the Food Requirements needed to clear states.
  1785. DrinkReqs = SetOrCapReqsToTiersSustenanceValueOnDeterioration(DrinkReqs, currentTE, HC_TE_Parched.GetValue() as int, iDrinkPoolParchedAmount)
  1786.  
  1787. elseif currentTE <= HC_TE_Hydrated.GetValue()
  1788. trace(self, " ModDrinkPoolAndUpdateThirstEffects(): Player is Hydrated")
  1789. PlayerRef.SetValue(HC_ThirstEffect, HC_TE_Hydrated.GetValue())
  1790.  
  1791. ; Make sure Drink Requirements remains atleast as high as the current cap.
  1792. if DrinkReqs < 0
  1793. DrinkReqs = 0
  1794. endif
  1795.  
  1796. ;cap it, if we are over the limit.
  1797. if DrinkPool > 0
  1798. DrinkPool = 0
  1799. endif
  1800.  
  1801. else
  1802. trace(self, " ModDrinkPoolAndUpdateThirstEffects(): GETTING WORSE - NO MATCH!")
  1803. trace(self, " ModDrinkPoolAndUpdateThirstEffects(): Player is: " + PlayerRef.GetValue(HC_ThirstEffect))
  1804. trace(self, " ModDrinkPoolAndUpdateThirstEffects(): Drinkpool: " + Drinkpool)
  1805. trace(self, " ModDrinkPoolAndUpdateThirstEffects(): DrinkReqs: " + DrinkReqs)
  1806. endif
  1807.  
  1808. ; We're transitioning to a better effect:
  1809. elseif ModPoolAmount > 0
  1810. if DrinkReqs >= 0 && currentTE >= HC_TE_Hydrated.GetValue()
  1811. trace(self, " ModDrinkPoolAndUpdateThirstEffects(): Player is Hydrated")
  1812. PlayerRef.SetValue(HC_ThirstEffect, HC_TE_Hydrated.GetValue())
  1813.  
  1814. ; We've gotten better. Roll back out drink pool to the new value.
  1815. DrinkPool = SetPoolToTiersSustenanceValueOnRecovery(DrinkPool, currentTE, HC_TE_Hydrated.GetValue() as int, 0)
  1816.  
  1817. ;cap it, if we are over the limit.
  1818. DrinkReqs = 0
  1819. if DrinkPool > 0
  1820. DrinkPool = 0
  1821. endif
  1822.  
  1823. elseif DrinkReqs >= iDrinkPoolParchedAmount && currentTE >= HC_TE_Parched.GetValue()
  1824. trace(self, " ModDrinkPoolAndUpdateThirstEffects(): Player is Parched")
  1825. PlayerRef.SetValue(HC_ThirstEffect, HC_TE_Parched.GetValue())
  1826.  
  1827. ; We've gotten better. Roll back out drink pool to the new value.
  1828. DrinkPool = SetPoolToTiersSustenanceValueOnRecovery(DrinkPool, currentTE, HC_TE_Parched.GetValue() as int, iDrinkPoolParchedAmount)
  1829.  
  1830. elseif DrinkReqs >= iDrinkPoolThirstyAmount && currentTE >= HC_TE_Thirsty.GetValue()
  1831. trace(self, " ModDrinkPoolAndUpdateThirstEffects(): Player is Thirsty")
  1832. PlayerRef.SetValue(HC_ThirstEffect, HC_TE_Thirsty.GetValue())
  1833.  
  1834. ; We've gotten better. Roll back out drink pool to the new value.
  1835. DrinkPool = SetPoolToTiersSustenanceValueOnRecovery(DrinkPool, currentTE, HC_TE_Thirsty.GetValue() as int, iDrinkPoolThirstyAmount)
  1836.  
  1837. elseif DrinkReqs >= iDrinkPoolMildlyDehydratedAmount && currentTE >= HC_TE_MildlyDehydrated.GetValue()
  1838. trace(self, " ModDrinkPoolAndUpdateThirstEffects(): Player is Mildly Dehyrdated")
  1839. PlayerRef.SetValue(HC_ThirstEffect, HC_TE_MildlyDehydrated.GetValue())
  1840.  
  1841. ; We've gotten better. Roll back out drink pool to the new value.
  1842. DrinkPool = SetPoolToTiersSustenanceValueOnRecovery(DrinkPool, currentTE, HC_TE_MildlyDehydrated.GetValue() as int, iDrinkPoolMildlyDehydratedAmount)
  1843.  
  1844. elseif DrinkReqs >= iDrinkPoolDehydratedAmount && currentTE >= HC_TE_Dehydrated.GetValue()
  1845. trace(self, " ModDrinkPoolAndUpdateThirstEffects(): Player is Dehydrated")
  1846. PlayerRef.SetValue(HC_ThirstEffect, HC_TE_Dehydrated.GetValue())
  1847.  
  1848. ; We've gotten better. Roll back out drink pool to the new value.
  1849. DrinkPool = SetPoolToTiersSustenanceValueOnRecovery(DrinkPool, currentTE, HC_TE_Dehydrated.GetValue() as int, iDrinkPoolDehydratedAmount)
  1850.  
  1851. elseif currentTE >= HC_TE_SeverelyDehyrdated.GetValue()
  1852. trace(self, " ModDrinkPoolAndUpdateThirstEffects(): Player is Severely Dehydrated")
  1853. PlayerRef.SetValue(HC_ThirstEffect, HC_TE_SeverelyDehyrdated.GetValue())
  1854.  
  1855. ;cap it
  1856. if DrinkPool < iDrinkPoolSeverelyDehydratedAmount
  1857. DrinkPool = iDrinkPoolSeverelyDehydratedAmount
  1858. endif
  1859. if DrinkReqs < iDrinkPoolSeverelyDehydratedAmount
  1860. DrinkReqs = iDrinkPoolSeverelyDehydratedAmount
  1861. endif
  1862.  
  1863. else
  1864. trace(self, " ModDrinkPoolAndUpdateThirstEffects(): GETTING BETTER - NO MATCH!")
  1865. trace(self, " ModDrinkPoolAndUpdateThirstEffects(): Player is " + PlayerRef.GetValue(HC_ThirstEffect))
  1866. trace(self, " ModDrinkPoolAndUpdateThirstEffects(): Drinkpool: " + Drinkpool)
  1867. trace(self, " ModDrinkPoolAndUpdateThirstEffects(): DrinkReqs: " + DrinkReqs)
  1868. endif
  1869. endif
  1870.  
  1871. ; Is this a state change? If so, let's add some fatigue and show our message.
  1872. bool bstateChanged = currentTE != PlayerRef.GetValue(HC_ThirstEffect) as int
  1873. bool showSustenanceMessage = ShowSustenance(bstateChanged)
  1874. bool announceFatigue = AnnounceFatigue(bstateChanged, ModPoolAmount)
  1875. UpdateNextSustenanceTickDay(bstateChanged, ModPoolAmount)
  1876.  
  1877. trace(self, " ModDrinkPoolAndUpdateThirstEffects(): Final DrinkPool: " + DrinkPool)
  1878. trace(self, " ModDrinkPoolAndUpdateThirstEffects(): Final DrinkReqs: " + DrinkReqs)
  1879. ApplyEffect(HC_Rule_SustenanceEffects, ThirstEffects, HC_ThirstEffect, DispellRestedSpells = false, DisplayAfterAwakingMessage= !announceFatigue, bDisplayMessage = showSustenanceMessage, bAnnounceFatigue = announceFatigue)
  1880.  
  1881. EndFunction
  1882.  
  1883. Function DrinkSippableWater(bool bDirtyWater)
  1884. if bDirtyWater
  1885. PlayerRef.EquipItem(HC_SippableDirtyWater, abSilent = true)
  1886. else
  1887. PlayerRef.EquipItem(HC_SippableWater, abSilent = true)
  1888. endif
  1889. EndFunction
  1890.  
  1891. Function FillWaterBottle(ObjectReference TargetRef)
  1892. ((self as quest) as HC_WaterBottleScript).FillWaterBottle(TargetRef)
  1893. EndFunction
  1894.  
  1895. ; Called from ShutdownHardcore() and from HC_CureRavenousHunger.
  1896. Function CureRavenousHunger()
  1897. ; Turn off our value.
  1898. trace(self, "CureRavenouseHunger(): Setting HC_CannibalEffect actor value to 0")
  1899. playerRef.SetValue(HC_CannibalEffect, 0)
  1900. ; Reset our cannibal ticks count.
  1901. CannibalTicks = 0
  1902. EndFunction
  1903.  
  1904.  
  1905.  
  1906. ;**************************************************************************************************
  1907. ;*********************************** DISEASE EFFECTS *****************************
  1908. ;**************************************************************************************************
  1909.  
  1910. Group Disease
  1911. float Property DiseaseRiskRollThreshold = 0.25 const auto
  1912. {When we have this much disease chance built up, as scaled by the currect wellness rating, we need to roll for disease}
  1913.  
  1914. float Property DiseaseRiskDrainPerCycle= -0.01 const auto
  1915. {Each disease update we drain this much out of the DiseaseRiskPool}
  1916.  
  1917. float Property CurrentDiseasePoolValueMult = 1.75 const auto
  1918. {If NOT 0, scales the current Disease Risk Pool to multiply against the current Disease Pool Drain Rate}
  1919.  
  1920. float Property DiseaseGracePeriod = 1.0 const auto
  1921. {You're not allowed to roll a disease unless you have been playing for longer than this many game days after getting diseased.}
  1922.  
  1923. globalvariable Property HC_Rule_DiseaseEffects const auto mandatory
  1924.  
  1925. Effect[] Property DiseaseEffects const auto mandatory
  1926. {Array of the various Disease Effects.}
  1927. ;IMPORTANT NOTE: disease effects work a different than the others. They are simply effects we give the player that eventually time out.
  1928.  
  1929. keyword[] Property DiseaseRiskFoodStandardKeywords const auto mandatory
  1930. {keywords in here represent things that are disease risks for the player}
  1931.  
  1932. float Property DiseaseRiskFoodStandardAmount = 0.07 const auto
  1933. {how much % chance does this event add tot he DiseaseRiskPool}
  1934.  
  1935. keyword[] Property DiseaseRiskFoodHighKeywords const auto mandatory
  1936. {keywords in here represent things that are disease risks for the player}
  1937.  
  1938. float Property DiseaseRiskFoodHighAmount = 0.12 const auto
  1939. {how much % chance does this event add to the DiseaseRiskPool}
  1940.  
  1941. keyword[] Property DiseaseRiskChemsKeywords const auto mandatory
  1942. {keywords in here represent things that are disease risks for the player}
  1943.  
  1944. float Property DiseaseRiskChemsAmount = 0.07 const auto
  1945. {how much % chance does this event add to the DiseaseRiskPool}
  1946.  
  1947. formlist Property DiseaseRiskCombatantFactions const auto mandatory
  1948. {if hit by these factions, player might get a disease. It's a formlist so we can use it as a filter for the onhit event as well}
  1949.  
  1950. float Property DiseaseRiskCombatantAmount = 0.05 const auto
  1951. {how much % chance does this event add to the DiseaseRiskPool}
  1952.  
  1953. float Property DiseaseRiskCannibalAmount = 0.05 const auto
  1954. {how much % chance does this event add to the DiseaseRiskPool}
  1955.  
  1956. float Property GameDaysPerSwimmingEvent = 0.1 const auto
  1957. {in terms of game dayspassed, how long until we allow subsequent swimming events}
  1958.  
  1959. float Property DiseaseRiskSwimmingAmount = 0.03 const auto
  1960. {how much % chance does this event add to the DiseaseRiskPool}
  1961.  
  1962. float Property GameDaysPerRainEvent = 0.5 const auto
  1963. {in terms of game dayspassed, how long until we allow subsequent swimming events}
  1964.  
  1965. float Property DiseaseRiskRainAmount = 0.03 const auto
  1966. {how much % chance does this event add to the DiseaseRiskPool}
  1967.  
  1968. Potion Property HC_Antibiotics const auto mandatory
  1969. {Antibiotics for catching it to process as food.}
  1970.  
  1971. Potion Property HC_Antibiotics_SILENT_SCRIPT_ONLY const auto mandatory
  1972. {doesn't have audio effect. Used only for clearing on doctors healing and lowering diffiuclt}
  1973.  
  1974. GlobalVariable Property HC_Vendor_Antiboitic_ChanceNone const auto mandatory
  1975. {autofill}
  1976.  
  1977. GlobalVariable Property HC_Medkit_Antiboitic_ChanceNone const auto mandatory
  1978. {autofill}
  1979.  
  1980. keyword Property HC_CausesImmunodeficiency const auto mandatory
  1981. {autofill; Checked to see if an item causes Immunodeficiency}
  1982.  
  1983. Potion Property HC_Effect_Immunodeficiency const auto mandatory
  1984. {Drink this potion when you drink something that causes Immunodeficiency. This will weaken your immunity for some time, raising the chance for disease}
  1985.  
  1986. float Property ImmunodeficiencyDiseaseChanceMult = 1.2 const auto
  1987. {Immunodeficiency increases your chance for disease by this much.}
  1988.  
  1989. float Property DiseaseRiskIncreaser_Food = 0.01 const auto
  1990. {Food increases your disease chance this much every time you eat. DOES NOT FORCE A ROLL!}
  1991.  
  1992. float Property DiseaseRiskIncreaser_Drink = 0.00 const auto
  1993. {Drink increases your disease chance this much every time you drink. DOES NOT FORCE A ROLL!}
  1994.  
  1995. float Property DiseaseRiskIncreaser_Cola = 0.02 const auto
  1996. {Cola increases your disease chance this much every time you drink. DOES NOT FORCE A ROLL!}
  1997.  
  1998. float Property DiseaseRiskIncreaser_Immunodeficiency = 0.05 const auto
  1999. {Immunodeficiency increases your disease chance this much every time you get it. DOES NOT FORCE A ROLL!}
  2000.  
  2001. EndGroup
  2002.  
  2003. ActiveMagicEffect HC_CaffeinatedEffect ; This is the active magic effect for Caffeinated.
  2004.  
  2005. float DiseaseRiskPool ;The value of our "bucket". This is the chance of the player getting sick.
  2006.  
  2007. int lastDiseaseDieRoll = -1
  2008.  
  2009. float NextSwimEventAllowed ;in terms of gamedayspassed, when do we next want to send a disease risk event for swimming
  2010.  
  2011. float NextRainEventAllowed conditional ;in terms of gamedayspassed, when do we next want to send a disease risk event for Rain event
  2012.  
  2013. float LastDiseaseCycle = 0.0 ; Store off the last time we started the disease timer.
  2014.  
  2015. bool bIgnoreNonWeaponHits = false
  2016.  
  2017. bool bHandleDiseaseRiskEvent = false
  2018.  
  2019. float ImmunodeficiencyMult = 1.0 ; Used in the disease roll. Get's set in ImmunodeficiencyEffectToggle()
  2020.  
  2021. bool bPlayerTookAntibiotics = false; Used to keep track of a player taken antibiotics so we can consume with HandleDiseaseRiskEvent()
  2022.  
  2023. float LastDiseasedDay ; Used to give a grace period between diseases.
  2024.  
  2025. ;called here and from GenericDoctorScript
  2026. Function ClearDisease()
  2027. DiseaseRiskPool = 0
  2028. PlayerRef.EquipItem(HC_Antibiotics_SILENT_SCRIPT_ONLY, abSilent = true)
  2029. EndFunction
  2030.  
  2031.  
  2032. Function PlayerEatsCorpse()
  2033. trace(self, "PlayerEatsCorpse()")
  2034.  
  2035. if IsGlobalTrue(HC_Rule_SustenanceEffects) == false
  2036. ;BAIL OUT, not in hardcore mode
  2037. RETURN
  2038. endif
  2039.  
  2040. ;Remove all food debt, eating corpses should always sate you fully (for a time)
  2041. ModFoodPoolAndUpdateHungerEffects(9999, IsEatingCorpse = true)
  2042.  
  2043. ;Give you "Ravenous Hunger" potion effect which scales all food points that aren’t from bodies down to 0 for the next 24 game hours.
  2044. playerRef.EquipItem(HC_Cannibal_RavenousHunger, abSilent = true) ;re-up this, it's effects last fo 9999 days but conditioned on actor value
  2045.  
  2046. ;set actor value to 1
  2047. PlayerRef.SetValue(HC_CannibalEffect, 1)
  2048.  
  2049. ;subtract 1 from our ticks to remove an hour per body once we've started Craving.
  2050. CannibalTicks -= 1
  2051. if CannibalTicks < 0
  2052. CannibalTicks = 0
  2053. endif
  2054.  
  2055. ;Reset the Sustenenance Tick clock - to prevent you from getting hungry again right away - note this also resets the drink timer... lucky you.
  2056. StartTimerGameTime(GameTimerInterval_Sustenance, GameTimerID_Sustenance)
  2057.  
  2058. ;Future sustenance ticks will drop you down to Ravenous
  2059. ;handled in HandleSustenanceTimer
  2060.  
  2061. ;show message
  2062. HC_Cannibal_Msg_RavenousHunger_EatCorpse.show()
  2063.  
  2064. ;start risk event
  2065. HandleDiseaseRiskEvent(DiseaseRiskCannibalAmount)
  2066. EndFunction
  2067.  
  2068.  
  2069. Event OnHit(ObjectReference akTarget, ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked, string apMaterial)
  2070.  
  2071. bool bhandleDisease = true
  2072.  
  2073. ; If this is something other than a weapon, we need to see if we're allowed to handle it at this time.
  2074. ; ...Looking at you GLOWING ONES RADIATION CLOAK!
  2075. if !(akSource as Weapon) && bIgnoreNonWeaponHits
  2076. trace(self, " OnHit() BAILING OUT! NON Weapon Hit from DiseaseRiskCombatantFactions. Currently ignored.")
  2077. bhandleDisease = false
  2078. elseif !(akSource as Weapon) && !bIgnoreNonWeaponHits
  2079. trace(self, " OnHit() HANDLING DISEASE! NON Weapon Hit from DiseaseRiskCombatantFactions. Currently allowed.")
  2080. StartTimerGameTime(GameTimerInterval_IgnoreNonWeaponHits, GameTimerID_IgnoreNonWeaponHits)
  2081. bIgnoreNonWeaponHits = true
  2082. else
  2083. trace(self, " OnHit() HANDLING DISEASE! Weapon Hit from DiseaseRiskCombatantFactions.")
  2084. endif
  2085.  
  2086. ; Each hit is a chance for getting disease:
  2087. if bhandleDisease
  2088. HandleDiseaseRiskEvent(DiseaseRiskCombatantAmount)
  2089. endif
  2090.  
  2091. ;filtered by DiseaseRiskCombatantFactions
  2092. RegisterForHitEvent(PlayerRef, DiseaseRiskCombatantFactions)
  2093.  
  2094. EndEvent
  2095.  
  2096.  
  2097. Event Perk.OnEntryRun(Perk akSender, int auiEntryID, ObjectReference akTarget, Actor akOwner)
  2098. trace(self, "Perk.OnEntryRun() for Cannibal perks. Will call HandleDiseaseRiskEvent()")
  2099.  
  2100. ;only Cannibal perks are registered so we can assume it was one of those
  2101.  
  2102. HandleDiseaseRiskEvent(DiseaseRiskCannibalAmount)
  2103.  
  2104. EndEvent
  2105.  
  2106.  
  2107. Event Actor.OnPlayerSwimming(Actor akSender)
  2108. float GameDaysPassed = Utility.GetCurrentGameTime()
  2109.  
  2110. if NextSwimEventAllowed <= GameDaysPassed
  2111. trace(self, "Actor.OnPlayerSwimming() and NextSwimEventAllowed <= GameDaysPassed. Will call HandleDiseaseRiskEvent()")
  2112. HandleDiseaseRiskEvent(DiseaseRiskSwimmingAmount)
  2113. NextSwimEventAllowed = GameDaysPassed + GameDaysPerSwimmingEvent
  2114. endif
  2115.  
  2116. EndEvent
  2117.  
  2118.  
  2119. Function SetNextRainEventAllowed()
  2120. float GameDaysPassed = Utility.GetCurrentGameTime()
  2121. NextRainEventAllowed = GameDaysPassed + GameDaysPerRainEvent
  2122. EndFunction
  2123.  
  2124. ; ALL HAIL THE DANGER TACO!!!
  2125. Function HandleDiseaseRiskEvent(float RiskyEventPoints)
  2126. trace(self, "HandleDiseaseRiskEvent() RiskyEventPoints: " + RiskyEventPoints)
  2127.  
  2128. if IsGlobalTrue(HC_Rule_DiseaseEffects) == false
  2129. ;BAIL OUT, not in hardcore mode
  2130. RETURN
  2131. endif
  2132.  
  2133. ; Tutorial Call - High Risk Event.
  2134. TryTutorial(HighRiskEventTutorial, "HighRiskEventTutorial")
  2135.  
  2136. ; If our risk pool is greater than the Wellness ceiling it's not allowed to go higher,
  2137. ; but it must drain out from there. Otherwise, we add the risk and cap it out to the ceiling.
  2138. float wellnessCeiling= GetWellnessCeiling()
  2139. trace(self, " HandleDiseaseRiskEvent() Old DiseaseRiskPool " + DiseaseRiskPool)
  2140. if DiseaseRiskPool < wellnessCeiling
  2141. DiseaseRiskPool += RiskyEventPoints
  2142. if DiseaseRiskPool > wellnessCeiling
  2143. DiseaseRiskPool = wellnessCeiling
  2144. endif
  2145. endif
  2146. trace(self, " HandleDiseaseRiskEvent() Updated DiseaseRiskPool " + DiseaseRiskPool)
  2147.  
  2148. ; Set our flag.
  2149. bHandleDiseaseRiskEvent = true
  2150.  
  2151. ; Restart the timer... You're buying youself time but it's gonna catch up with you.
  2152. StartTimerGameTime(GameTimerInterval_DiseasePostRiskEvent, GameTimerID_Disease)
  2153.  
  2154. EndFunction
  2155.  
  2156.  
  2157. Function HandleDiseaseTimer()
  2158. trace(self, " HandleDiseaseTimer() bHandleDiseaseRiskEvent: " + bHandleDiseaseRiskEvent + ", DiseaseRiskPool: " + DiseaseRiskPool + ", DiseaseRiskRollThreshold" + DiseaseRiskRollThreshold)
  2159.  
  2160. ; If the risk pool is greater than the roll threshold, let's roll for disease! NO WHAMMY!
  2161. if bHandleDiseaseRiskEvent && DiseaseRiskPool > DiseaseRiskRollThreshold
  2162. ; Check for disease. If you get one (true), we empty the pool entirely. If not (false), we should drain some out.
  2163. if !CheckAndPossiblyApplyDisease(bShouldClearDiseaseRiskPoolOnDisease = true, bShouldClearDiseaseRiskPool = false)
  2164. DrainDiseaseRiskPool()
  2165. endif
  2166. else
  2167. ; We still need to drain this every tick.
  2168. DrainDiseaseRiskPool()
  2169. endif
  2170.  
  2171. ; Events handled. Unflagging.
  2172. bHandleDiseaseRiskEvent = false
  2173.  
  2174. EndFunction
  2175.  
  2176.  
  2177. Function CheckForDiseaseAndRestart()
  2178. trace(self, " CheckForDiseaseAndRestart()")
  2179. DrainDiseaseRiskPool()
  2180. CheckAndPossiblyApplyDisease(bShouldClearDiseaseRiskPoolOnDisease = true, bShouldClearDiseaseRiskPool = true)
  2181. StartTimerGameTime(GameTimerInterval_Disease, GameTimerID_Disease)
  2182. EndFunction
  2183.  
  2184. Function FillDiseaseRiskPool(float PoolIncrease = 0.01)
  2185.  
  2186. trace(self, " FillDiseaseRiskPool() - Old DiseaseRiskPool: " + DiseaseRiskPool)
  2187. float wellnessCeiling= GetWellnessCeiling()
  2188. if DiseaseRiskPool < wellnessCeiling
  2189. DiseaseRiskPool += PoolIncrease
  2190. if DiseaseRiskPool > wellnessCeiling
  2191. DiseaseRiskPool = wellnessCeiling
  2192. endif
  2193. endif
  2194. trace(self, " FillDiseaseRiskPool() - New DiseaseRiskPool: " + DiseaseRiskPool)
  2195.  
  2196. EndFunction
  2197.  
  2198. Function DrainDiseaseRiskPool()
  2199. ; Grab out current time in hours...
  2200. float currentGameTime= Utility.GetCurrentGameTime() * 24.0
  2201.  
  2202. ; How long have we been unresponsive?
  2203. float cyclesPassed= (currentGameTime - LastDiseaseCycle) / GameTimerInterval_Disease
  2204.  
  2205. ; Show me...
  2206. trace(self, " DrainDiseaseRiskPool() currentGameTime: " + currentGameTime)
  2207. trace(self, " DrainDiseaseRiskPool() LastDiseaseCycle: " + LastDiseaseCycle)
  2208. trace(self, " DrainDiseaseRiskPool() cyclesPassed: " + cyclesPassed)
  2209.  
  2210. ; Grab our needed values.
  2211. float wellnessCeiling = GetWellnessCeiling()
  2212. float wellnessFloor = GetWellnessFloor()
  2213. float diseaseToDrain = 0.0
  2214.  
  2215. ; Drain it, but only down to your current tiers ceiling.
  2216. ; Yes, the ceiling, this is intended to get you back down to...
  2217. ; your current tier not drain what's in your current tier.
  2218. if DiseaseRiskPool > wellnessCeiling
  2219. ; Calculate how much we need to drain from the pool.
  2220. diseaseToDrain= DiseaseRiskDrainPerCycle * cyclesPassed * GetWellnessDrainMult() * GetWellnessPoolDrainMult(wellnessFloor)
  2221. trace(self, " DrainDiseaseRiskPool() OLD DiseaseRiskPool: " + DiseaseRiskPool)
  2222. trace(self, " DrainDiseaseRiskPool() diseaseToDrain: " + diseaseToDrain)
  2223. DiseaseRiskPool += diseaseToDrain
  2224. trace(self, " DrainDiseaseRiskPool() UPDATED DiseaseRiskPool: " + DiseaseRiskPool)
  2225. if DiseaseRiskPool < wellnessCeiling
  2226. DiseaseRiskPool = wellnessCeiling
  2227. trace(self, " DrainDiseaseRiskPool() CAPPING DiseaseRiskPool: " + DiseaseRiskPool)
  2228. endif
  2229. elseif DiseaseRiskPool < wellnessFloor
  2230. DiseaseRiskPool = wellnessFloor
  2231. trace(self, " DrainDiseaseRiskPool() Old DiseaseRiskPool: " + DiseaseRiskPool)
  2232. trace(self, " DrainDiseaseRiskPool() diseaseToDrain: " + diseaseToDrain)
  2233. trace(self, " DrainDiseaseRiskPool() FLOORED DiseaseRiskPool: " + DiseaseRiskPool)
  2234. else
  2235. trace(self, " DrainDiseaseRiskPool() HELD DiseaseRiskPool @: " + DiseaseRiskPool)
  2236. endif
  2237.  
  2238. ; Note our current time.
  2239. LastDiseaseCycle = currentGameTime
  2240.  
  2241. EndFunction
  2242.  
  2243.  
  2244. ; returns true if diseased.
  2245. bool Function CheckAndPossiblyApplyDisease(bool bShouldClearDiseaseRiskPoolOnDisease = true, bool bShouldClearDiseaseRiskPool = false)
  2246. trace(self, " CheckAndPossiblyApplyDisease() bShouldClearDiseaseRiskPoolOnDisease, bShouldClearDiseaseRiskPool: " + bShouldClearDiseaseRiskPoolOnDisease + ", " + bShouldClearDiseaseRiskPool )
  2247.  
  2248. if IsGlobalTrue(HC_Rule_DiseaseEffects) == false
  2249. ;BAIL OUT, not in hardcore mode
  2250. RETURN false
  2251. endif
  2252.  
  2253. float diseaseDieRoll = RollForDisease() ;returns positive if disease roll was successful, negative if not diseased
  2254. bool diseased = diseaseDieRoll > 0
  2255.  
  2256. trace(self, " CheckAndPossiblyApplyDisease() bPlayerTookAntibiotics: " + bPlayerTookAntibiotics)
  2257. if bPlayerTookAntibiotics
  2258. diseased = false
  2259. bPlayerTookAntibiotics = false
  2260. trace(self, " CheckAndPossiblyApplyDisease() PLAYER TOOK ANTIBIOTICS RECENTLY! NO DISEASES WILL BE APPLIED!!")
  2261. endif
  2262.  
  2263. if diseased
  2264. trace(self, " CheckAndPossiblyApplyDisease() Player will be diseased if he doesnt have a remedy...")
  2265.  
  2266. ;Randomly pick a disease and apply it
  2267. int arrayLen = DiseaseEffects.length
  2268. int dieRoll = utility.RandomInt(0, arrayLen - 1)
  2269.  
  2270. ;if same as last time, pick the higher one (they are arranged in array so that this increased chance these come in pairs will maybe make some thematic sense)
  2271. if dieRoll == lastDiseaseDieRoll
  2272. dieRoll += 1
  2273. endif
  2274.  
  2275. if dieRoll > arrayLen - 1
  2276. dieRoll = 0
  2277. endif
  2278.  
  2279. lastDiseaseDieRoll = dieRoll
  2280. effect effectToApply = DiseaseEffects[dieRoll]
  2281.  
  2282. ;*** CHECK FOR HERBAL MEDICATION PROTECTION
  2283. if PlayerRef.HasMagicEffect(effectToApply.HerbalRemedyEffect)
  2284. trace(self, " CheckAndPossiblyApplyDisease() Player has Remedy (" + effectToApply.HerbalRemedyEffect + ") for " + effectToApply.EffectPotion)
  2285. trace(self, " CheckAndPossiblyApplyDisease() diseaseDieRoll: " + diseaseDieRoll)
  2286. trace(self, " CheckAndPossiblyApplyDisease() ImmunityThreshold: " + effectToApply.HerbalRemedyBoostedImmunityThreshold)
  2287. ; diseaseDieRoll needs to be <= Risk Pool (check!) && >= BoostedImmunityThreshold to get this disease.
  2288. diseased = diseaseDieRoll >= effectToApply.HerbalRemedyBoostedImmunityThreshold
  2289. trace(self, " CheckAndPossiblyApplyDisease() PROTECTED AGAINST DISEASE: " + !diseased)
  2290. endif
  2291.  
  2292.  
  2293. if diseased
  2294.  
  2295. LastDiseasedDay = Utility.GetCurrentGameTime()
  2296. trace(self, " CheckAndPossiblyApplyDisease() **DISEASED** - INFECTED @: " + LastDiseasedDay)
  2297.  
  2298. message diseaseMessageToDisplay
  2299. ; If you already have this effect lets tweak our announce.
  2300. if PlayerRef.HasMagicEffect(effectToApply.MagicEffectToApply)
  2301. diseaseMessageToDisplay = effectToApply.MessageToRedisplay
  2302. else
  2303. diseaseMessageToDisplay = effectToApply.MessageToDisplay
  2304. endif
  2305.  
  2306. ; Apply the effect and show our chosen message.
  2307. playerRef.EquipItem(effectToApply.EffectPotion, abSilent = true)
  2308. diseaseMessageToDisplay.Show()
  2309. ; Tutorial Call - Diseased.
  2310. TryTutorial(DiseasedTutorial, "DiseasedTutorial")
  2311.  
  2312. ; Did you request to clear the pool if diseased?
  2313. if bShouldClearDiseaseRiskPoolOnDisease
  2314. DiseaseRiskPool = GetWellnessFloor()
  2315. endif
  2316.  
  2317. endif
  2318. endif
  2319.  
  2320. ; Did you request to clear the pool after the roll?
  2321. if bShouldClearDiseaseRiskPool
  2322. DiseaseRiskPool = GetWellnessFloor()
  2323. endif
  2324. trace(self, " CheckAndPossiblyApplyDisease() Updated DiseaseRiskPool " + DiseaseRiskPool)
  2325.  
  2326. return diseased
  2327.  
  2328. EndFunction
  2329.  
  2330. ;returns > dieroll amount if roll was successful (ie should gain a disease)
  2331. ;return < 0 if roll was unsuccessful
  2332. float Function RollForDisease()
  2333. trace(self, " RollForDisease()")
  2334.  
  2335. float currentGameTime = utility.GetCurrentGameTime()
  2336.  
  2337. if currentGameTime < LastDiseasedDay + DiseaseGracePeriod
  2338. trace(self, " Too Soon! Failing roll due to being within the Grace Period!")
  2339. return -1.0
  2340. endif
  2341.  
  2342. float dieRoll = utility.Randomfloat(0.01, 1.0)
  2343.  
  2344. trace(self, " RollForDisease() DiseaseRiskPool: " + DiseaseRiskPool)
  2345. trace(self, " RollForDisease() dieRoll: " + dieRoll)
  2346.  
  2347. float diseaseChance = DiseaseRiskPool * ImmunodeficiencyMult
  2348.  
  2349. if dieRoll <= diseaseChance
  2350. trace(self, " RollForDisease() dieRoll: " + dieRoll + " <= chance: " + diseaseChance + ", returning: true")
  2351. return dieRoll
  2352. else
  2353. trace(self, " RollForDisease() dieRoll: " + dieRoll + " > chance: " + diseaseChance + ", returning: false")
  2354. return -1.0
  2355. endif
  2356.  
  2357. EndFunction
  2358.  
  2359. ; Returns this Wellness tiers Disease Chance ceiling
  2360. float Function GetWellnessCeiling()
  2361. trace(self, " GetWellnessCeiling()")
  2362.  
  2363. ; Figure out which effects by consulting player's current actor values
  2364. effect HungerEffect = GetCurrentEffect(HC_HungerEffect, HungerEffects)
  2365. effect ThirstEffect = GetCurrentEffect(HC_ThirstEffect, ThirstEffects)
  2366. effect SleepEffect = GetCurrentEffect(HC_SleepEffect, SleepEffects )
  2367.  
  2368. ; Average the Wellness based Ceiling
  2369. float HungerCeiling = HungerEffect.DiseaseChanceCeiling
  2370. float ThirstCeiling = ThirstEffect.DiseaseChanceCeiling
  2371. float SleepCeiling = SleepEffect.DiseaseChanceCeiling
  2372. float WellnessCeiling = ((HungerCeiling + ThirstCeiling + SleepCeiling) * 0.3333333)
  2373.  
  2374. ; Debuggerific
  2375. trace(self, " GetWellnessCeiling() HungerCeiling: " + HungerCeiling )
  2376. trace(self, " GetWellnessCeiling() ThirstCeiling: " + ThirstCeiling )
  2377. trace(self, " GetWellnessCeiling() SleepCeiling: " + SleepCeiling )
  2378. trace(self, " GetWellnessCeiling() returning: " + WellnessCeiling)
  2379.  
  2380. ; Return the averaged Ceiling
  2381. return WellnessCeiling
  2382.  
  2383. EndFunction
  2384.  
  2385. ; Returns this Wellness tiers Disease Chance floor
  2386. float Function GetWellnessFloor()
  2387. trace(self, " GetWellnessFloor()")
  2388.  
  2389. ; Figure out which effects by consulting player's current actor values
  2390. effect HungerEffect = GetCurrentEffect(HC_HungerEffect, HungerEffects)
  2391. effect ThirstEffect = GetCurrentEffect(HC_ThirstEffect, ThirstEffects)
  2392. effect SleepEffect = GetCurrentEffect(HC_SleepEffect, SleepEffects )
  2393.  
  2394. ; Average the Wellness based Floor
  2395. float HungerFloor = HungerEffect.DiseaseChanceFloor
  2396. float ThirstFloor = ThirstEffect.DiseaseChanceFloor
  2397. float SleepFloor = SleepEffect.DiseaseChanceFloor
  2398. float WellnessFloor = ((HungerFloor + ThirstFloor + SleepFloor) * 0.3333333)
  2399.  
  2400. ; Debuggerific
  2401. trace(self, " GetWellnessFloor() HungerFloor: " + HungerFloor )
  2402. trace(self, " GetWellnessFloor() ThirstFloor: " + ThirstFloor )
  2403. trace(self, " GetWellnessFloor() SleepFloor: " + SleepFloor )
  2404. trace(self, " GetWellnessFloor() returning: " + WellnessFloor)
  2405.  
  2406. ; Return the averaged Floor
  2407. return WellnessFloor
  2408.  
  2409. EndFunction
  2410.  
  2411. ; Returns this Wellness tiers Disease Chance Drain Multiplier
  2412. float Function GetWellnessDrainMult()
  2413. trace(self, " GetWellnessDrainMult()")
  2414.  
  2415. ; Figure out which effects by consulting player's current actor values
  2416. effect HungerEffect = GetCurrentEffect(HC_HungerEffect, HungerEffects)
  2417. effect ThirstEffect = GetCurrentEffect(HC_ThirstEffect, ThirstEffects)
  2418. effect SleepEffect = GetCurrentEffect(HC_SleepEffect, SleepEffects )
  2419.  
  2420. ; Average the Wellness based Drain Mult
  2421. float HungerDrainMult = HungerEffect.DiseaseChanceDrainMult
  2422. float ThirstDrainMult = ThirstEffect.DiseaseChanceDrainMult
  2423. float SleepDrainMult = SleepEffect.DiseaseChanceDrainMult
  2424. float WellnessDrainMult = ((HungerDrainMult + ThirstDrainMult + SleepDrainMult) * 0.3333333)
  2425.  
  2426. ; Debuggerific
  2427. trace(self, " GetWellnessDrainMult() HungerDrainMult: " + HungerDrainMult )
  2428. trace(self, " GetWellnessDrainMult() ThirstDrainMult: " + ThirstDrainMult )
  2429. trace(self, " GetWellnessDrainMult() SleepDrainMult: " + SleepDrainMult )
  2430. trace(self, " GetWellnessDrainMult() returning: " + WellnessDrainMult)
  2431.  
  2432. ; Return the averaged DrainMult
  2433. return WellnessDrainMult
  2434.  
  2435. EndFunction
  2436.  
  2437. ; Returns this Wellness tiers Disease Chance Pool Drain Multiplier
  2438. float Function GetWellnessPoolDrainMult(float WellnessFloor)
  2439.  
  2440. ; CAP IT
  2441. if DiseaseRiskPool < WellnessFloor
  2442. DiseaseRiskPool = WellnessFloor
  2443. endif
  2444.  
  2445. if CurrentDiseasePoolValueMult != 0
  2446. trace(self, " GetWellnessPoolDrainMult() - CurrentDiseasePoolValueMult: " + CurrentDiseasePoolValueMult + ", DiseaseRiskPool: " + DiseaseRiskPool + ", RETURNING: " + DiseaseRiskPool * CurrentDiseasePoolValueMult)
  2447. return DiseaseRiskPool * CurrentDiseasePoolValueMult
  2448. endif
  2449. trace(self, " GetWellnessPoolDrainMult() - CurrentDiseasePoolValueMult: " + CurrentDiseasePoolValueMult + ", DiseaseRiskPool: " + DiseaseRiskPool + ", RETURNING: 1.0")
  2450. return 1.0
  2451.  
  2452. EndFunction
  2453.  
  2454.  
  2455. effect Function GetCurrentEffect(ActorValue EffectActorValue, Effect[] EffectsArray)
  2456. float val = PlayerRef.GetValue(EffectActorValue)
  2457.  
  2458. ;loop through the arrays, and find the struct who's globalenum value matches what is store in the player actor value
  2459. int i = 0
  2460. int max = EffectsArray.length
  2461. while (i < max)
  2462. effect currentEffect = EffectsArray[i]
  2463.  
  2464. if currentEffect.GlobalEnum.GetValue() == val
  2465. trace(self, " GetCurrentEffect() EffectActorValue: " + EffectActorValue + "; Returning " + currentEffect)
  2466. return currentEffect
  2467. endif
  2468. i += 1
  2469. endwhile
  2470.  
  2471. trace(self, " GetCurrentEffect() didn't find an effect", 2)
  2472. return None
  2473.  
  2474. EndFunction
  2475.  
  2476. ;called by HC_DiseaseSleepinessEffectScript
  2477. Function SleepinessEffectToggle(bool IsPlayerSleepy)
  2478. trace(self, "SleepinessEffectToggle(): " + IsPlayerSleepy)
  2479. StartSleepDeprivationTimer(GetHoursUntilCurrentSleepCycleEnds())
  2480. EndFunction
  2481.  
  2482. ;called by HC_ImmunodeficiencyEffectScript
  2483. Function ImmunodeficiencyEffectToggle(bool IsPlayerImmunodeficient)
  2484.  
  2485. if IsPlayerImmunodeficient
  2486. ; Scale our wellness value
  2487. ImmunodeficiencyMult = ImmunodeficiencyDiseaseChanceMult
  2488. HandleSleepDeprivationTimer()
  2489. trace(self, "ImmunodeficiencyEffectToggle(): Scaling Disease Chance By: " + ImmunodeficiencyDiseaseChanceMult)
  2490. ; Tutorial Call - Immunodeficiency.
  2491. TryTutorial(ImmunodeficiencyTutorial, "ImmunodeficiencyTutorial")
  2492. else
  2493. ; Restore our wellness value
  2494. ImmunodeficiencyMult = 1.0
  2495. trace(self, "ImmunodeficiencyEffectToggle(): Player is back to normal!")
  2496. endif
  2497.  
  2498. EndFunction
  2499.  
  2500. ;called by HC_CaffeinatedEffectScript
  2501. Function CaffeinatedEffectToggle(ActiveMagicEffect CaffeinatedEffect)
  2502. HC_CaffeinatedEffect = CaffeinatedEffect
  2503. EndFunction
  2504.  
  2505. ;**************************************************************************************************
  2506. ;************************************** SLEEP EFFECTS ********************************
  2507. ;**************************************************************************************************
  2508.  
  2509. ;bedtype "enums"
  2510. int iBedType_NotApplicable = -1 const
  2511. int iBedType_SleepingBag = 0 const
  2512. int iBedType_Mattress = 1 const
  2513. int iBedType_Bed = 2 const
  2514.  
  2515. Group SleepEffects
  2516. globalvariable Property HC_Rule_SleepEffects const auto mandatory
  2517.  
  2518. ActorValue Property HC_SleepEffect const auto mandatory
  2519.  
  2520. int Property MinHoursForCuringSleepEffects = 2 const auto
  2521. {Need to at least sleep this long for sleep effects to be cured}
  2522.  
  2523. keyword[] Property SleepingBagKeywords const auto mandatory
  2524. {a bed with any of these keywords will be treated as a sleeping bag, wins over Mattress and Bed keywords}
  2525.  
  2526. keyword[] Property MattressKeywords const auto mandatory
  2527. {a bed with any of these keywords will be treated as a matress, wins over Bed keywords}
  2528.  
  2529. keyword[] Property BedKeywords const auto mandatory
  2530. {a bed with any of these keywords will be treated as a bed}
  2531.  
  2532. keyword[] Property CleanBedKeywords const auto mandatory
  2533.  
  2534. Effect[] Property SleepEffects const auto mandatory
  2535. {The order in this array, is the order they devolution after time passes since sleeping.
  2536. ***IMPORTANT REMINDER***
  2537. The first entry in this is a place hold for the Well Rested / Lover's Embrace effects, which are handled by pre-existing spells from base game not potions
  2538. }
  2539.  
  2540. int Property IndexOfSleepEffectsForWellRestedORLoversEmbrace = 0 const auto
  2541. {what index in SleepEffects represents WellRested}
  2542.  
  2543. int Property HighestIndexOfSleepEffectsCuredBySleepingBag = 4 const auto
  2544. {starting with this index in SleepEffects, you can cure this and higher effect while sleeping here}
  2545.  
  2546. int Property HighestIndexOfSleepEffectsCuredByMattress = 2 const auto
  2547. {starting with this index in SleepEffects, you can cure this and higher effect while sleeping here}
  2548.  
  2549. int Property HighestIndexOfSleepEffectsCuredByBed = 0 const auto
  2550. {starting with this index in SleepEffects, you can cure this and higher effect while sleeping here}
  2551.  
  2552. message Property HC_SleepInterruptedMsg_Mattress const auto mandatory
  2553. {autofill, message you get when you try to sleep longer than allowed}
  2554.  
  2555. message Property HC_SleepInterruptedMsg_SleepingBag const auto mandatory
  2556. {autofill, message you get when you try to sleep longer than allowed}
  2557.  
  2558. perk Property HC_WellRestedPerk const auto mandatory
  2559. Message Property WellRestedMessage const Auto
  2560. String Property WellRestedSWFname const Auto
  2561. Sound Property UIPerkWellRested Const Auto Mandatory
  2562.  
  2563. perk Property HC_LoversEmbracePerk const auto mandatory
  2564. Message Property LoversEmbraceMessage const Auto
  2565. String Property LoversEmbraceSWFname Const Auto
  2566. Sound Property UIPerkLoversEmbrace Const Auto Mandatory
  2567.  
  2568.  
  2569. spell Property WellRested const auto mandatory
  2570. {autofill, base game spell we'll need to dispell}
  2571.  
  2572. spell Property LoversEmbracePerkSpell const auto mandatory
  2573. {autofill, base game spell we'll need to dispell}
  2574.  
  2575. MagicEffect Property HC_Disease_Insomnia_Effect const auto mandatory
  2576. {autofill, comes from disease, will cause player to wake up early}
  2577.  
  2578. float Property InsomniaSleepMult = 0.5 Auto Const
  2579. {How much to scale our sleep since we are currently suffering from Insomnia}
  2580.  
  2581. MagicEffect Property HC_Disease_Sleepiness_Effect const auto mandatory
  2582. {autofill, comes from disease, will cause player to need sleep more often}
  2583.  
  2584. float Property DisaseSleepinessSleepDeprivationTimerMult = 0.5 const auto
  2585. {when player has Sleepiness disease effect, the Sleep Deprivation Timer Duration should be scaled by this amount}
  2586.  
  2587. Potion Property HC_Effect_Caffeinated const auto mandatory
  2588. {Drink this potion when you become Caffeinated to show the player the status.}
  2589.  
  2590. message Property HC_SE_Msg_Caffeinated const auto mandatory
  2591. {Autofilled message to display when Caffeinated}
  2592.  
  2593. float Property CaffeineInducedSleepDelay = 2.333 const auto
  2594. {How much time a caffeinated beverage (Nuka Cola / Cherry ) buys us.}
  2595.  
  2596. float Property ExtraCaffeineInducedSleepDelay = 7.0 const auto
  2597. {How much time a caffeinated beverage (Quantum ) buys us.}
  2598.  
  2599.  
  2600. EndGroup
  2601.  
  2602. float NextSleepUpdateDay ; Keep track of the game days passed we should next increment the sleep tiers.
  2603. float LastSleepUpdateDay ; Keep track of the game days passed between real sleeping (>= 3 hours)
  2604. float SleepStartDay ; Comes in as game days passed
  2605. float SleepStopDay ; Comes in as game days passed
  2606. float WaitStartDay ; Comes in as game days passed
  2607. float WaitStopDay ; Comes in as game days passed
  2608.  
  2609. message EarlyWakeMessageToShow ; The message we will show to the player to explain why we've woken them up.
  2610.  
  2611. bool ProcessingSleep = false
  2612. bool bFirstSleep = false
  2613. bool bSleepInterrupted = false
  2614.  
  2615. bool Function IsProcessingSleep()
  2616. ;for external access -- initial case is for preventing nerd rage from being triggered by us damaging you after sleeping
  2617. return ProcessingSleep
  2618. EndFunction
  2619.  
  2620. Event OnPlayerWaitStart(float afWaitStartTime, float afDesiredWaitEndTime)
  2621. WaitStartDay = afWaitStartTime
  2622. trace(self, "OnPlayerWaitStart() WaitStartDay: " + WaitStartDay)
  2623. EndEvent
  2624.  
  2625.  
  2626. Event OnPlayerWaitStop(bool abInterrupted)
  2627. WaitStopDay = Utility.GetCurrentGameTime()
  2628. trace(self, "OnPlayerWaitStop() WaitStopDay: " + WaitStopDay)
  2629.  
  2630. float GameHoursSpentWaiting = (WaitStopDay - WaitStartDay) * 24.0
  2631. trace(self, " OnPlayerWaitStop() GameHoursSpentWaiting: " + GameHoursSpentWaiting)
  2632. EndEvent
  2633.  
  2634.  
  2635. Event OnPlayerSleepStart(float afSleepStartTime, float afDesiredSleepEndTime, ObjectReference akBed)
  2636. ProcessingSleep = true
  2637. bSleepInterrupted = false
  2638. trace(self, "OnPlayerSleepStart() ProcessingSleep: " + ProcessingSleep + ", bSleepInterrupted: " + bSleepInterrupted)
  2639.  
  2640. SleepStartDay = afSleepStartTime
  2641. trace(self, " OnPlayerSleepStart() SleepStartDay: " + SleepStartDay)
  2642.  
  2643. ; Poll for disease...
  2644. if IsCleanBed(akbed)
  2645. else
  2646. CheckForDiseaseAndRestart()
  2647. endif
  2648.  
  2649. ; Then cancel all our timers... We'll restart when we wake.
  2650. CancelTimerGameTime(GameTimerID_SleepDeprivation)
  2651. CancelTimerGameTime(GameTimerID_Sustenance)
  2652. CancelTimerGameTime(GameTimerID_Disease)
  2653. CancelTimerGameTime(GameTimerID_Encumbrance)
  2654.  
  2655. ;store existing health and condition values
  2656. CacheValuesBeforeSleep()
  2657.  
  2658. WakeUpPlayerBasedOnBedType(akBed, afSleepStartTime, afDesiredSleepEndTime)
  2659.  
  2660. EndEvent
  2661.  
  2662.  
  2663. Event OnPlayerSleepStop(bool abInterrupted, ObjectReference akBed)
  2664. trace(self, "OnPlayerSleepStop()")
  2665.  
  2666. SleepStopDay = Utility.GetCurrentGameTime()
  2667. float oneHour = 1.0 / 24.0
  2668. float DaysSpentSleeping = SleepStopDay - SleepStartDay
  2669. bool bCanceledPreHour = false ; This is only used in the event that the player cancels sleep before an hour passes.
  2670. if DaysSpentSleeping < oneHour
  2671. trace(self, " OnPlayerSleepStop() < 1 hour DaysSpentSleeping: " + DaysSpentSleeping)
  2672. DaysSpentSleeping = oneHour
  2673. trace(self, " OnPlayerSleepStop() Updated DaysSpentSleeping: " + DaysSpentSleeping)
  2674. bCanceledPreHour = true
  2675. endif
  2676. int GameHoursSpentSleeping = ((DaysSpentSleeping * 24) + fEpsilon) as int
  2677.  
  2678. ; Making sure we don't show the error message if you cancel in time.
  2679. if abInterrupted
  2680. bSleepInterrupted = abInterrupted
  2681. trace(self, " OnPlayerSleepStop() SLEEP INTERRUPTED!")
  2682. if IsSleepingBag(akBed)
  2683. if GameHoursSpentSleeping < 3
  2684. CancelTimerGameTime(GameTimerID_DisplaySleepMessage)
  2685. EarlyWakeMessageToShow = none
  2686. trace(self, " OnPlayerSleepStop() Canceled < 3 hour in Sleeping Bag!")
  2687. endif
  2688. elseif !IsBed(akBed)
  2689. if GameHoursSpentSleeping < 5
  2690. CancelTimerGameTime(GameTimerID_DisplaySleepMessage)
  2691. EarlyWakeMessageToShow = none
  2692. trace(self, " OnPlayerSleepStop() Canceled < 5 hour in Dirty Mattress!")
  2693. endif
  2694. endif
  2695. endif
  2696.  
  2697. trace(self, " OnPlayerSleepStop() SleepStopDay: " + SleepStopDay)
  2698. trace(self, " OnPlayerSleepStop() DaysSpentSleeping: " + DaysSpentSleeping)
  2699. trace(self, " OnPlayerSleepStop() GameHoursSpentSleeping: " + GameHoursSpentSleeping)
  2700.  
  2701. ;remove adrenaline based on number of hours
  2702. int AdrenalineRanksToRemove
  2703.  
  2704. if GameHoursSpentSleeping == 1
  2705. AdrenalineRanksToRemove = 2
  2706. elseif GameHoursSpentSleeping == 2
  2707. AdrenalineRanksToRemove = 3
  2708. elseif GameHoursSpentSleeping == 3
  2709. AdrenalineRanksToRemove = 4
  2710. elseif GameHoursSpentSleeping == 4
  2711. AdrenalineRanksToRemove = 5
  2712. elseif GameHoursSpentSleeping == 5
  2713. AdrenalineRanksToRemove = 6
  2714. elseif GameHoursSpentSleeping == 6
  2715. AdrenalineRanksToRemove = 8
  2716. else
  2717. AdrenalineRanksToRemove = 10
  2718. endif
  2719.  
  2720. ;REMOVE RANKS WORTH OF ADRENALINE
  2721. int AdrelanineToRemove = AdrenalineRanksToRemove * killsForAdrenalinePerkLevel
  2722. trace(self, " OnPlayerSleepStop() AdrelanineToRemove: " + AdrelanineToRemove )
  2723. ModAdrenaline(-AdrelanineToRemove)
  2724.  
  2725. ; Do we have Insomnia? If we do, that sucks... We won't get much sleep like that.
  2726. if PlayerRef.HasMagicEffect(HC_Disease_Insomnia_Effect)
  2727.  
  2728. GameHoursSpentSleeping = (GameHoursSpentSleeping as float * InsomniaSleepMult) as int
  2729.  
  2730. ; Don't let you sleep less than 1 hour.
  2731. if GameHoursSpentSleeping < 1
  2732. GameHoursSpentSleeping = 1
  2733. ; No one with Insomnia is Well Rested.
  2734. elseif GameHoursSpentSleeping > 6
  2735. GameHoursSpentSleeping = 6
  2736. endif
  2737. trace(self, " OnPlayerSleepStop() - INSOMNIA! - GameHoursSpentSleeping: " + GameHoursSpentSleeping)
  2738.  
  2739. endif
  2740.  
  2741. ;Heal player's health and condition values based on how long he sleeped
  2742. UpdateHealingAfterSleep(GameHoursSpentSleeping)
  2743.  
  2744. ; Handle Encumbrance and then restarting the timer since we just woke up...
  2745. HandleEncumbranceTimer()
  2746. StartTimerGameTime(GameTimerInterval_Encumbrance, GameTimerID_Encumbrance)
  2747.  
  2748. ; Handle Sustenance and then restarting the timer since we just woke up...
  2749. HandleSustenanceTimer(bWasSleeping = true, bCanceledSleepPreHour = bCanceledPreHour)
  2750. StartTimerGameTime(GameTimerInterval_Sustenance, GameTimerID_Sustenance)
  2751.  
  2752. ; Handled disease OnPlayerSleepStart(). Restarting the timer since we just woke up...
  2753. StartTimerGameTime(GameTimerInterval_Disease, GameTimerID_Disease)
  2754.  
  2755. float ftimeUntilNextSleepUpdate = GetHoursUntilCurrentSleepCycleEnds()
  2756.  
  2757. ; The first sleep timer is a super short tutorial time.
  2758. ; We won't punish the player for sleeping before it expires.
  2759. if bFirstSleep
  2760. ftimeUntilNextSleepUpdate = GameTimerInterval_SleepDeprivation
  2761. bFirstSleep = false
  2762. endif
  2763.  
  2764. ; Update sleep effects based on bed and hours slept...
  2765. UpdateSleepEffectsAfterSleeping(GameHoursSpentSleeping, akBed, ftimeUntilNextSleepUpdate)
  2766.  
  2767. ProcessingSleep = false
  2768.  
  2769. EndEvent
  2770.  
  2771. Function StartSleepDeprivationTimer(float RestartTimerForThisManyGameHours = -1.0, bool ForceThisExactValue = false)
  2772. trace(self, " StartSleepDeprivationTimer() RestartTimerForThisManyGameHours: " + RestartTimerForThisManyGameHours)
  2773.  
  2774. float sleepInterval = RestartTimerForThisManyGameHours
  2775.  
  2776. if false == ForceThisExactValue
  2777.  
  2778. float intervalMult = 1
  2779.  
  2780. if PlayerRef.HasMagicEffect(HC_Disease_Sleepiness_Effect)
  2781. intervalMult = DisaseSleepinessSleepDeprivationTimerMult
  2782. endif
  2783.  
  2784. sleepInterval = GameTimerInterval_SleepDeprivation * intervalMult
  2785. if RestartTimerForThisManyGameHours > 0
  2786. sleepInterval = RestartTimerForThisManyGameHours * intervalMult
  2787. endif
  2788.  
  2789. StartTimerGameTime(sleepInterval, GameTimerID_SleepDeprivation)
  2790.  
  2791. trace(self, " StartSleepDeprivationTimer() starting timer with an interval of: " + sleepInterval)
  2792.  
  2793. else
  2794. StartTimerGameTime(sleepInterval, GameTimerID_SleepDeprivation)
  2795. endif
  2796.  
  2797. ; Store our value away.
  2798. NextSleepUpdateDay = utility.GetCurrentGameTime() + (sleepInterval / 24.0)
  2799.  
  2800. EndFunction
  2801.  
  2802. float Function GetHoursUntilCurrentSleepCycleEnds(bool abReturnGameDaysInstead= false)
  2803.  
  2804. float hoursUntilCurrentSleepCycleEnds = NextSleepUpdateDay - utility.GetCurrentGameTime()
  2805.  
  2806. if !abReturnGameDaysInstead
  2807. hoursUntilCurrentSleepCycleEnds *= 24
  2808. endif
  2809.  
  2810. if hoursUntilCurrentSleepCycleEnds < 0
  2811. return 0
  2812. endif
  2813. return hoursUntilCurrentSleepCycleEnds
  2814.  
  2815. EndFunction
  2816.  
  2817.  
  2818. ;*** WE NEED A "wakeup after X hours" FUNCTION, THIS ISN'T THE BEST WAY TO HANDLE THIS
  2819. ;***Ideally we could get code to prevent you from dialing in more than you can sleep
  2820. Function WakeUpPlayerBasedOnBedType(ObjectReference BedRef, float SleepStartTime, float DesiredTime)
  2821. trace(self, "WakeUpPlayerBasedOnBedType() - SleepStartTime: "+SleepStartTime+", DesiredTime: "+DesiredTime)
  2822.  
  2823. ; I've heard they give out rewards for lowering the number of divides...
  2824. float oneOverTwentyFour = 1.0/24.0
  2825.  
  2826. float WakeDay = DesiredTime
  2827.  
  2828. float MaxWakeDay
  2829.  
  2830. if IsBed(BedRef)
  2831. MaxWakeDay = SleepStartTime + 24.0 * oneOverTwentyFour
  2832. elseif IsSleepingBag(BedRef)
  2833. MaxWakeDay = SleepStartTime + 3.0 * oneOverTwentyFour
  2834. EarlyWakeMessageToShow = HC_SleepInterruptedMsg_SleepingBag
  2835. else ;treat everything else as mattress
  2836. MaxWakeDay = SleepStartTime + 5.0 * oneOverTwentyFour
  2837. EarlyWakeMessageToShow = HC_SleepInterruptedMsg_Mattress
  2838. endif
  2839. trace(self, " WakeUpPlayerBasedOnBedType() MaxWakeDay: " + MaxWakeDay)
  2840.  
  2841. if MaxWakeDay >= WakeDay
  2842. ;no need to force you to wake up
  2843. trace(self, " WakeUpPlayerBasedOnBedType() Letting them rest... MaxWakeDay: " + MaxWakeDay + " >= WakeDay: " + WakeDay)
  2844. RETURN
  2845. else
  2846. trace(self, " WakeUpPlayerBasedOnBedType() Setting WakeDay: " + WakeDay + " to MaxWakeDay: " + MaxWakeDay)
  2847. WakeDay = MaxWakeDay
  2848. endif
  2849.  
  2850. float currentGameTime
  2851. while (currentGameTime < WakeDay) && !bSleepInterrupted
  2852. utility.WaitMenuMode(0.5) ;sleeping happens pretty fast, need to catch it so we don't get more than an hour before we check again
  2853. currentGameTime = utility.GetCurrentGameTime()
  2854. trace(self, " WakeUpPlayerBasedOnBedType() WakeDay: " + WakeDay + ", currentGameTime: " + currentGameTime)
  2855. endwhile
  2856.  
  2857. ; Bail out on sleep interruption.
  2858. if bSleepInterrupted
  2859. trace(self, " WakeUpPlayerBasedOnBedType() CANCELED! bSleepInterrupted: " + bSleepInterrupted)
  2860. return
  2861. endif
  2862.  
  2863. ;"wake up" the player
  2864. PlayerRef.Moveto(PlayerRef) ;I worry a little bit about what this would do if the player was in a trigger, but in theory triggers should be able to handle this
  2865.  
  2866. ; Tutorial Call - Non Bed Wakeup.
  2867. TryTutorial(NonBedSleepTutorial, "NonBedSleepTutorial")
  2868.  
  2869. ; Start the timer to display our wake up message. Doing it like this prevents a broken save thumbnail.
  2870. StartTimerGameTime(GameTimerInterval_DisplaySleepMessage, GameTimerID_DisplaySleepMessage)
  2871.  
  2872. EndFunction
  2873.  
  2874. Function HandleSleepDeprivationTimer()
  2875. trace(self, " HandleSleepDeprivationTimer() LastSleepUpdateDay: " + LastSleepUpdateDay)
  2876.  
  2877. ; This is no longer the short first sleep timer.
  2878. bFirstSleep = false
  2879.  
  2880. float currentGameTime = Utility.GetCurrentGameTime()
  2881.  
  2882. ;either of these perks only last 24 hours, so when the timer expires, just remove them
  2883. playerRef.removePerk(HC_WellRestedPerk)
  2884. playerRef.removePerk(HC_LoversEmbracePerk)
  2885.  
  2886. ; Handle cycles that are longer than our current interval due to disease.
  2887. int IncrementEffectBy = 1
  2888. if PlayerRef.HasMagicEffect(HC_Disease_Sleepiness_Effect)
  2889. IncrementEffectBy = (((currentGameTime - LastSleepUpdateDay) * 24) / (GameTimerInterval_SleepDeprivation * DisaseSleepinessSleepDeprivationTimerMult)) as int
  2890. if IncrementEffectBy < 1
  2891. IncrementEffectBy = 1
  2892. endif
  2893. elseif iCaffeinated == 2
  2894. IncrementEffectBy = 0
  2895. endif
  2896.  
  2897.  
  2898. ApplyEffect(HC_Rule_SleepEffects, SleepEffects, HC_SleepEffect, DispellRestedSpells = true, IncrementEffectBy = IncrementEffectBy, bAnnounceFatigue = true)
  2899.  
  2900. if IncrementEffectBy
  2901. ; Tutorial Call - Tiredness.
  2902. TryTutorial(TirednessTutorial, "TirednessTutorial")
  2903. endif
  2904.  
  2905. ; Store this update time for handling no effect clearing sleeps.
  2906. LastSleepUpdateDay = currentGameTime
  2907. trace(self, " HandleSleepDeprivationTimer() and setting LastSleepUpdateDay: " + LastSleepUpdateDay)
  2908.  
  2909. EndFunction
  2910.  
  2911.  
  2912.  
  2913. Function UpdateSleepEffectsAfterSleeping(int GameHoursSpentSleeping, ObjectReference BedSleptIn, float TimeUntilNextSleepUpdate)
  2914. trace(self, " UpdateSleepEffectsAfterSleeping() GameHoursSpentSleeping: " + GameHoursSpentSleeping + ", TimeUntilNextSleepUpdate: " + TimeUntilNextSleepUpdate)
  2915.  
  2916. int CurrentSleepEffect = PlayerRef.GetValue(HC_SleepEffect) as int
  2917.  
  2918. ; Do you have Caffeine to sleep off?
  2919. if iCaffeinated
  2920. ; Put us back to our previous state, and turn off Caffeinated.
  2921. if iCaffeinated == 1
  2922. CurrentSleepEffect += 1
  2923. endif
  2924. HC_CaffeinatedEffect.Dispel()
  2925. HC_CaffeinatedEffect = none
  2926. iCaffeinated = 0
  2927. CaffeinatedCount = 0
  2928. ExtraCaffeinatedCount = 0
  2929. endif
  2930.  
  2931. int NewSleepEffect = 999
  2932.  
  2933. bool SleepingInBed = IsBed(BedSleptIn)
  2934.  
  2935. ;first make sure we sleep long enough
  2936. if GameHoursSpentSleeping >= MinHoursForCuringSleepEffects
  2937.  
  2938. ; Figure out where we could be at if we were allowed to take all of this sleep into account.
  2939. NewSleepEffect = CurrentSleepEffect - GameHoursSpentSleeping + 1
  2940. trace(self, " UpdateSleepEffectsAfterSleeping() GameHoursSpentSleeping: " + GameHoursSpentSleeping + ", CurrentSleepEffect: " + CurrentSleepEffect + ", NewSleepEffect: " + NewSleepEffect)
  2941.  
  2942. ;roll back SleepEffects based on bed type
  2943. if IsSleepingBag(BedSleptIn)
  2944. if NewSleepEffect < HighestIndexOfSleepEffectsCuredBySleepingBag
  2945. NewSleepEffect = HighestIndexOfSleepEffectsCuredBySleepingBag
  2946. trace(self, " UpdateSleepEffectsAfterSleeping() Sleeping Bag - HighestIndexOfSleepEffectsCuredBySleepingBag: " + HighestIndexOfSleepEffectsCuredBySleepingBag + ", Updated NewSleepEffect: " + NewSleepEffect)
  2947. endif
  2948.  
  2949. elseif IsMattress(BedSleptIn)
  2950. if NewSleepEffect < HighestIndexOfSleepEffectsCuredByMattress
  2951. NewSleepEffect = HighestIndexOfSleepEffectsCuredByMattress
  2952. trace(self, " UpdateSleepEffectsAfterSleeping() Mattress - HighestIndexOfSleepEffectsCuredByMattress: " + HighestIndexOfSleepEffectsCuredByMattress + ", Updated NewSleepEffect: " + NewSleepEffect)
  2953. endif
  2954.  
  2955. elseif SleepingInBed
  2956. if NewSleepEffect < HighestIndexOfSleepEffectsCuredByBed
  2957. NewSleepEffect = HighestIndexOfSleepEffectsCuredByBed
  2958. trace(self, " UpdateSleepEffectsAfterSleeping() Bed - HighestIndexOfSleepEffectsCuredByBed: " + HighestIndexOfSleepEffectsCuredByBed + ", Updated NewSleepEffect: " + NewSleepEffect)
  2959. endif
  2960.  
  2961. elseif NewSleepEffect < HighestIndexOfSleepEffectsCuredByMattress
  2962. ;unexpected, consider it mattress
  2963. NewSleepEffect = HighestIndexOfSleepEffectsCuredByMattress
  2964. trace(self, " UpdateSleepEffectsAfterSleeping() Other - HighestIndexOfSleepEffectsCuredByMattress: " + HighestIndexOfSleepEffectsCuredByMattress + ", Updated NewSleepEffect: " + NewSleepEffect)
  2965. endif
  2966.  
  2967. ; NewSleepEffect -= 1 ;because you cure down to the previous SleepEffectslee
  2968. trace(self, " UpdateSleepEffectsAfterSleeping() Final NewSleepEffect: " + NewSleepEffect)
  2969.  
  2970. endif
  2971.  
  2972. ;throw away well rested and lovers embrace, so you can't "top it off" by sleeping before it expires
  2973. if CurrentSleepEffect == IndexOfSleepEffectsForWellRestedORLoversEmbrace
  2974. CurrentSleepEffect += 1
  2975.  
  2976. playerRef.removePerk(HC_WellRestedPerk)
  2977. playerRef.removePerk(HC_LoversEmbracePerk)
  2978.  
  2979. endif
  2980.  
  2981. ;if you sleep for 7 hours in a bed, you get well rested.
  2982. if GameHoursSpentSleeping >= 7 && SleepingInBed
  2983. trace(self, " UpdateSleepEffectsAfterSleeping() GameHoursSpentSleeping >= 8 && SleepingInBed, will give well rested or lovers embrace.")
  2984.  
  2985. NewSleepEffect = IndexOfSleepEffectsForWellRestedORLoversEmbrace
  2986.  
  2987. ;apply the appropriate perk:
  2988. if Followers.GetNearbyInfatuatedRomanticCompanion()
  2989. playerRef.AddPerk(HC_LoversEmbracePerk)
  2990. LoversEmbraceMessage.Show()
  2991. Game.ShowPerkVaultBoyOnHUD(LoversEmbraceSwfName, UIPerkLoversEmbrace)
  2992.  
  2993. else
  2994. playerRef.AddPerk(HC_WellRestedPerk)
  2995. WellRestedMessage.Show()
  2996. Game.ShowPerkVaultBoyOnHUD(WellRestedSWFname, UIPerkWellRested)
  2997.  
  2998. endif
  2999.  
  3000. endif
  3001.  
  3002. ;only set it if it's better than the current effect
  3003. if NewSleepEffect < CurrentSleepEffect
  3004. trace(self, " UpdateSleepEffectsAfterSleeping() setting HC_SleepEffect to: " + NewSleepEffect)
  3005. PlayerRef.SetValue(HC_SleepEffect, NewSleepEffect)
  3006. CurrentSleepEffect = NewSleepEffect
  3007. else
  3008. trace(self, " UpdateSleepEffectsAfterSleeping() setting HC_SleepEffect to: " + CurrentSleepEffect)
  3009. PlayerRef.SetValue(HC_SleepEffect, CurrentSleepEffect)
  3010. endif
  3011.  
  3012. if GameHoursSpentSleeping < MinHoursForCuringSleepEffects
  3013.  
  3014. ; This means our clock is getting ready to expire
  3015. if TimeUntilNextSleepUpdate < 1
  3016.  
  3017. ; Apply effect to move us down in the tier since our time has expired.
  3018. ApplyEffect(HC_Rule_SleepEffects, SleepEffects, HC_SleepEffect, DispellRestedSpells = true, IncrementEffectBy = 1)
  3019.  
  3020. ; Store this out to correctly tweak that clock.
  3021. TimeUntilNextSleepUpdate = GameTimerInterval_SleepDeprivation + TimeUntilNextSleepUpdate
  3022.  
  3023. else
  3024.  
  3025. ; Don't show the wake message if your in a good state. It hides the fact you're getting worse.
  3026. bool displaySleepMessages = false
  3027. if CurrentSleepEffect > 1
  3028. displaySleepMessages = true
  3029. endif
  3030.  
  3031. ; This is a standard post sleep update. Apply it!
  3032. ApplyEffect(HC_Rule_SleepEffects, SleepEffects, HC_SleepEffect, DispellRestedSpells = true, bDisplayMessage = displaySleepMessages)
  3033.  
  3034. endif
  3035.  
  3036. ; Restart our timer taking into account our reduced time since we slept too short of a time.
  3037. StartSleepDeprivationTimer(RestartTimerForThisManyGameHours = TimeUntilNextSleepUpdate, ForceThisExactValue = false)
  3038.  
  3039. else
  3040.  
  3041. ; This is a standard post sleep update. Apply it!
  3042. ApplyEffect(HC_Rule_SleepEffects, SleepEffects, HC_SleepEffect, DispellRestedSpells = true, DisplayAfterAwakingMessage = true)
  3043. ; Store this update time for handling no effect clearing sleeps.
  3044. LastSleepUpdateDay = utility.GetCurrentGameTime()
  3045. ; And restart our timer for the full cycle.
  3046. StartSleepDeprivationTimer()
  3047.  
  3048. endif
  3049.  
  3050. EndFunction
  3051.  
  3052.  
  3053. bool Function IsSleepingBag(ObjectReference RefToCheck)
  3054. return CommonArrayFunctions.CheckObjectAgainstKeywordArray(RefToCheck, SleepingBagKeywords)
  3055. EndFunction
  3056.  
  3057. bool Function IsMattress(ObjectReference RefToCheck)
  3058. return CommonArrayFunctions.CheckObjectAgainstKeywordArray(RefToCheck, MattressKeywords)
  3059. EndFunction
  3060.  
  3061. bool Function IsBed(ObjectReference RefToCheck)
  3062. return CommonArrayFunctions.CheckObjectAgainstKeywordArray(RefToCheck, BedKeywords)
  3063. EndFunction
  3064.  
  3065. bool Function IsCleanBed(ObjectReference RefToCheck)
  3066. return CommonArrayFunctions.CheckObjectAgainstKeywordArray(RefToCheck, CleanBedKeywords)
  3067. EndFunction
  3068.  
  3069. ;--------------------------------------------------------------------------------------------------
  3070. ;------------------------------------ SLEEP EFFECTS -- HEALING ------------------------------
  3071. ;--------------------------------------------------------------------------------------------------
  3072. ;Change how the auto heal works when sleeping. Also see OnPlayerSleepXXX events above.
  3073.  
  3074. Group SleepEffectsHealing
  3075. ActorValue Property Health const auto mandatory ;Health
  3076. ActorValue Property EnduranceCondition const auto mandatory ;TORSO
  3077. ActorValue Property LeftAttackCondition const auto mandatory ;LEFT ARM
  3078. ActorValue Property LeftMobilityCondition const auto mandatory ;LEFT LEG
  3079. ActorValue Property PerceptionCondition const auto mandatory ;HEAD
  3080. ActorValue Property RightAttackCondition const auto mandatory ;RIGHT ARM
  3081. ActorValue Property RightMobilityCondition const auto mandatory ;RIGHT ARM
  3082. EndGroup
  3083.  
  3084.  
  3085. ;Pre-sleep cached values
  3086. float HealthCache
  3087. float EnduranceConditionCache
  3088. float LeftAttackConditionCache
  3089. float LeftMobilityConditionCache
  3090. float PerceptionConditionCache
  3091. float RightAttackConditionCache
  3092. float RightMobilityConditionCache
  3093.  
  3094. Function CacheValuesBeforeSleep()
  3095. HealthCache = PlayerRef.GetValue(Health)
  3096. EnduranceConditionCache = PlayerRef.GetValue(EnduranceCondition)
  3097. LeftAttackConditionCache = PlayerRef.GetValue(LeftAttackCondition)
  3098. LeftMobilityConditionCache = PlayerRef.GetValue(LeftMobilityCondition)
  3099. PerceptionConditionCache = PlayerRef.GetValue(PerceptionCondition)
  3100. RightAttackConditionCache = PlayerRef.GetValue(RightAttackCondition)
  3101. RightMobilityConditionCache = PlayerRef.GetValue(RightMobilityCondition)
  3102. EndFunction
  3103.  
  3104. Function UpdateHealingAfterSleep(int GameHoursSpentSleeping)
  3105.  
  3106. ; GetBaseValue() doesnt get that value with the permenant additions (Life Giver!).
  3107. ; But... Sleeping us has healed us to that true max... So let's use that!
  3108. float healthTrueMax = PlayerRef.GetValue(Health)
  3109. float enduranceTrueMax = PlayerRef.GetValue(EnduranceCondition)
  3110. float leftAttackTrueMax = PlayerRef.GetValue(LeftAttackCondition)
  3111. float leftMobilityTrueMax = PlayerRef.GetValue(LeftMobilityCondition)
  3112. float perceptionTrueMax = PlayerRef.GetValue(PerceptionCondition)
  3113. float rightAttackTrueMax = PlayerRef.GetValue(RightAttackCondition)
  3114. float rightMobilityTrueMax = PlayerRef.GetValue(RightMobilityCondition)
  3115.  
  3116. ;damage actorvalues back to cached values
  3117. DamageValuesBackToCachedValues() ;*** BETTER HANDLED BY CODE?
  3118.  
  3119. RestoreValueBasedOnHours(Health, GameHoursSpentSleeping, healthTrueMax )
  3120. RestoreValueBasedOnHours(EnduranceCondition, GameHoursSpentSleeping, enduranceTrueMax )
  3121. RestoreValueBasedOnHours(LeftAttackCondition, GameHoursSpentSleeping, leftAttackTrueMax )
  3122. RestoreValueBasedOnHours(LeftMobilityCondition, GameHoursSpentSleeping, leftMobilityTrueMax )
  3123. RestoreValueBasedOnHours(PerceptionCondition, GameHoursSpentSleeping, perceptionTrueMax )
  3124. RestoreValueBasedOnHours(RightAttackCondition, GameHoursSpentSleeping, rightAttackTrueMax )
  3125. RestoreValueBasedOnHours(RightMobilityCondition, GameHoursSpentSleeping, rightMobilityTrueMax)
  3126.  
  3127. EndFunction
  3128.  
  3129. ;***THIS MIGHT BE BETTER HANDLED BY CODE SIMPLY NOT AUTOHEALING IN HARDCORE MODE
  3130. Function DamageValuesBackToCachedValues()
  3131. DamageValueBackToCachedValue(Health, HealthCache)
  3132. DamageValueBackToCachedValue(EnduranceCondition, EnduranceConditionCache)
  3133. DamageValueBackToCachedValue(LeftAttackCondition, LeftAttackConditionCache)
  3134. DamageValueBackToCachedValue(LeftMobilityCondition, LeftMobilityConditionCache)
  3135. DamageValueBackToCachedValue(PerceptionCondition, PerceptionConditionCache)
  3136. DamageValueBackToCachedValue(RightAttackCondition, RightAttackConditionCache)
  3137. DamageValueBackToCachedValue(RightMobilityCondition, RightMobilityConditionCache)
  3138. EndFunction
  3139.  
  3140.  
  3141. Function DamageValueBackToCachedValue(ActorValue ActorValueToDamage, float CachedValue)
  3142. float currentVal = PlayerRef.GetValue(ActorValueToDamage)
  3143. float difference = currentVal - CachedValue
  3144.  
  3145. ;this shouldn't happen, but just in case, bail out if current value is less than cached value (suggesting some kind of on going effect that's not healed by sleeping)
  3146. if difference <= 0
  3147. trace(self, " DamageValueBackToCachedValue() [NO DIFFERENCE - BAILING OUT]: ActorValueToDamage: " + ActorValueToDamage + " - Difference: " + difference + ". currentVal:" + currentVal + " vs CachedValue: " + CachedValue)
  3148. RETURN
  3149. endif
  3150.  
  3151. trace(self, " DamageValueBackToCachedValue() [DIFFERENCE >0 - DAMAGING AV]: ActorValueToDamage: " + ActorValueToDamage + " - Difference: " + difference + ". currentVal:" + currentVal + " vs CachedValue: " + CachedValue)
  3152. PlayerRef.DamageValue(ActorValueToDamage, difference)
  3153. EndFunction
  3154.  
  3155. Function RestoreValueBasedOnHours(ActorValue ActorValueToRestore, int GameHoursSpentSleeping, float TrueMaxValue)
  3156. float valueToRestore = TrueMaxValue
  3157. int percentToRestore = 0
  3158.  
  3159. ; if GameHoursSpentSleeping <= 1
  3160. ; valueToRestore *= 0.00
  3161. ; percentToRestore = 0
  3162. ; elseif GameHoursSpentSleeping == 2
  3163. ; valueToRestore *= 0.15
  3164. ; percentToRestore = 15
  3165. ; elseif GameHoursSpentSleeping == 3
  3166. ; valueToRestore *= 0.25
  3167. ; percentToRestore = 25
  3168. ; elseif GameHoursSpentSleeping == 4
  3169. ; valueToRestore *= 0.45
  3170. ; percentToRestore = 45
  3171. ; elseif GameHoursSpentSleeping == 5
  3172. ; valueToRestore *= 0.75
  3173. ; percentToRestore = 75
  3174. ; else
  3175. ; valueToRestore *= 1.00
  3176. ; percentToRestore = 100
  3177. ; endif
  3178.  
  3179. trace(self, " RestoreValueBasedOnHours() For " + GameHoursSpentSleeping + " hours slept, restore " + percentToRestore + "% of TrueMaxValue: " + TrueMaxValue + " (valueToRestore: " + valueToRestore + ") to ActorValueToRestore: " + ActorValueToRestore)
  3180. ; PlayerRef.RestoreValue(ActorValueToRestore, valueToRestore)
  3181.  
  3182. EndFunction
  3183.  
  3184. ;**************************************************************************************************
  3185. ;*********************************** ENCUMBRANCE AND LIMB CONDITION *****************************
  3186. ;**************************************************************************************************
  3187.  
  3188. Group EncumbranceAndLimbCondition
  3189.  
  3190. globalvariable Property HC_Rule_NoLimbConditionHeal const auto mandatory
  3191. globalvariable Property HC_Rule_DamageWhenEncumbered const auto mandatory
  3192.  
  3193. potion Property HC_EncumbranceEffect_OverEncumbered const auto mandatory
  3194.  
  3195. spell Property HC_ReduceCarryWeightAbility Auto Const Mandatory
  3196.  
  3197. EndGroup
  3198.  
  3199. Function HandleEncumbranceTimer()
  3200. trace(self, " HandleEncumbranceTimer()")
  3201. ;make the player drink the potion that turns on the encumberance effect (similar to how sleep effects work)
  3202. ;spell effects in potion are conditioned on player being encumbered
  3203. PlayerRef.EquipItem(HC_EncumbranceEffect_OverEncumbered, abSilent = true)
  3204. StartTimerGameTime(GameTimerInterval_Encumbrance, GameTimerID_Encumbrance)
  3205. EndFunction
  3206.  
  3207. Function RemoveReduceCarryWeightAbility(actor ActorToRemoveSpellFrom)
  3208. ;Remove the ability that reduces carrying capacity (effect in ability is conditioned on HC_Rule_DamageWhenEncumbered)
  3209. if ActorToRemoveSpellFrom && true == ActorToRemoveSpellFrom.HasSpell(HC_ReduceCarryWeightAbility)
  3210. ActorToRemoveSpellFrom.removeSpell(HC_ReduceCarryWeightAbility)
  3211. endif
  3212. EndFunction
  3213.  
  3214. Function AddReduceCarryWeightAbility(actor ActorToAddSpellTo)
  3215. ;Add the ability that reduces carrying capacity (effect in ability is conditioned on HC_Rule_DamageWhenEncumbered)
  3216. if ActorToAddSpellTo && false == ActorToAddSpellTo.HasSpell(HC_ReduceCarryWeightAbility)
  3217. ActorToAddSpellTo.addSpell(HC_ReduceCarryWeightAbility, false)
  3218. endif
  3219. EndFunction
  3220.  
  3221.  
  3222. ;**************************************************************************************************
  3223. ;*********************************** COMPANION HEALING *****************************
  3224. ;**************************************************************************************************
  3225.  
  3226. Group CompanionHealing
  3227. GlobalVariable Property HC_Rule_CompanionNoHeal const auto mandatory
  3228. {autofill}
  3229.  
  3230. ReferenceAlias Property Companion const auto mandatory
  3231. {Companion alias on the Followers quest}
  3232.  
  3233. ReferenceAlias Property DogmeatCompanion const auto mandatory
  3234. {DogmeatCompanion alias on the Followers quest}
  3235.  
  3236. float Property DismissIfBleedingOutDistance = 10000.0 const auto
  3237. {this needs to be less than the unload distance
  3238. because unloading causes actors to stop bleeing out, even if you SetNoBleedoutRecovery()}
  3239.  
  3240. keyword Property playerCanStimpak auto const mandatory
  3241. {autofill}
  3242.  
  3243. ActorValue Property HC_IsCompanionInNeedOfHealing Auto Const Mandatory
  3244. {autofill; used to manage player leaving companion behind when bleeding out, because going into low clears bleedout state, we need to manage it ourselves}
  3245.  
  3246. EndGroup
  3247.  
  3248.  
  3249. Event FollowersScript.CompanionChange(FollowersScript akSender, Var[] akArgs)
  3250. Actor ActorThatChanged = akArgs[0] as actor
  3251. bool IsNowCompanion = akArgs[1] as bool
  3252.  
  3253. trace(self, "FollowersScript.CompanionChange() ActorThatChanged: " + ActorThatChanged + ", IsNowCompanion: " + IsNowCompanion)
  3254.  
  3255. CompanionSetNoBleedoutRecovery(ActorThatChanged, IsNowCompanion)
  3256.  
  3257. AddReduceCarryWeightAbility(ActorThatChanged)
  3258.  
  3259. ;if we are no longer a companion, clear our need for healing
  3260. if false == IsNowCompanion
  3261. SetIsInNeedOfHealing(ActorThatChanged, false)
  3262. endif
  3263.  
  3264. EndEvent
  3265.  
  3266. bool Function PlayerCanHeal(Actor ActorToHeal)
  3267. trace(self, "PlayerCanHeal() ActorToHeal: " + ActorToHeal)
  3268.  
  3269. trace(self, "PlayerCanHeal() playerCanStimpak: " + playerCanStimpak)
  3270.  
  3271. if ActorToHeal.HasKeyword(playerCanStimpak)
  3272. trace(self, "PlayerCanHeal() TRUE -- ActorToHeal: " + ActorToHeal)
  3273. return true
  3274. endif
  3275.  
  3276. trace(self, "PlayerCanHeal() FALSE -- ActorToHeal: " + ActorToHeal)
  3277. return false
  3278. EndFunction
  3279.  
  3280. bool Function PlayerCanRepair(Actor ActorToHeal)
  3281. ;DLC01 keyword used to repair robots
  3282. keyword DLC01PlayerCanRepairKit = Game.GetFormFromFile(0x01004F13, "DLCRobot.esm") as keyword
  3283.  
  3284. if DLC01PlayerCanRepairKit && ActorToHeal.HasKeyword(DLC01PlayerCanRepairKit)
  3285. trace(self, "PlayerCanRepair() TRUE -- ActorToHeal: " + ActorToHeal)
  3286. return true
  3287. endif
  3288.  
  3289. trace(self, "PlayerCanRepair() FALSE -- ActorToHeal: " + ActorToHeal)
  3290. return false
  3291.  
  3292. EndFunction
  3293.  
  3294. bool Function PlayerCanHealOrRepair(Actor ActorToHeal)
  3295.  
  3296. return PlayerCanHeal(ActorToHeal) || PlayerCanRepair(ActorToHeal)
  3297.  
  3298. EndFunction
  3299.  
  3300. Function CompanionSetNoBleedoutRecovery(Actor CompanionActor, bool ShouldSetNoBleedoutRecovery)
  3301. trace(self, "CompanionSetNoBleedoutRecovery CompanionActor: " + CompanionActor + ", ShouldSetNoBleedoutRecovery: " + ShouldSetNoBleedoutRecovery)
  3302.  
  3303. if ShouldSetNoBleedoutRecovery && IsGlobalTrue(HC_Rule_CompanionNoHeal)
  3304. if PlayerCanHealOrRepair(CompanionActor)
  3305. trace(self, " CompanionSetNoBleedoutRecovery calling setNoBleedoutRecovery(true)")
  3306. CompanionActor.SetNoBleedoutRecovery(true)
  3307. else
  3308. trace(self, " PlayerCanHealOrRepair == false. CompanionSetNoBleedoutRecovery IS NOT calling setNoBleedoutRecovery(true)")
  3309. endif
  3310. else
  3311. trace(self, " CompanionSetNoBleedoutRecovery calling setNoBleedoutRecovery(false)")
  3312. CompanionActor.SetNoBleedoutRecovery(false)
  3313. endif
  3314. EndFunction
  3315.  
  3316. Function SetIsInNeedOfHealing(actor ActorToSet, bool IsInNeedOfHealing)
  3317. if IsInNeedOfHealing
  3318. ActorToSet.SetValue(HC_IsCompanionInNeedOfHealing, 1)
  3319. else
  3320. ActorToSet.SetValue(HC_IsCompanionInNeedOfHealing, 0)
  3321. endif
  3322. EndFunction
  3323.  
  3324. bool Function IsInNeedOfHealing(actor ActorToCheck)
  3325. return ActorToCheck.GetValue(HC_IsCompanionInNeedOfHealing) == 1
  3326. EndFunction
  3327.  
  3328. Event ReferenceAlias.OnEnterBleedout(ReferenceAlias akSender)
  3329. if IsGlobalTrue(HC_Rule_CompanionNoHeal) == false
  3330. ;BAIL OUT, not in hardcore mode
  3331. RETURN
  3332. endif
  3333. trace(self, "ReferenceAlias.OnEnterBleedout() akSender: " + akSender)
  3334.  
  3335. ;make sure it's someone the player can heal:
  3336. actor actorRef = akSender.GetActorReference()
  3337. if PlayerCanHealOrRepair(actorRef)
  3338. SetIsInNeedOfHealing(actorRef, true)
  3339. RegisterForDistanceGreaterThanEvent(PlayerRef, akSender, DismissIfBleedingOutDistance) ;for dismissing companion if player gets too far while they are bleeding out
  3340. ; Tutorial Call - Downed Companion.
  3341. TryTutorial(CompanionDownedTutorial, "CompanionDownedTutorial")
  3342. endif
  3343.  
  3344. EndEvent
  3345.  
  3346. Event Actor.OnPlayerHealTeammate(Actor akSender, Actor akTeammate)
  3347. trace(self, "Actor.OnPlayerHealTeammate() akTeammate: " + akTeammate)
  3348. SetIsInNeedOfHealing(akTeammate, false)
  3349. EndEvent
  3350.  
  3351.  
  3352. Event OnDistanceGreaterThan(ObjectReference akObj1, ObjectReference akObj2, float afDistance)
  3353. trace(self, "OnDistanceGreaterThan() will check for bleedingout and dismiss companion")
  3354.  
  3355. ;assume this is the companion and player event since that is the only one we registered for
  3356. actor ActorLeftBehind = akObj2 as Actor
  3357.  
  3358. if ActorLeftBehind.isBleedingOut() || IsInNeedOfHealing(ActorLeftBehind)
  3359. trace(self, " OnDistanceGreaterThan() bleedingout or IsInNeedOfHealing, will dismiss companion")
  3360.  
  3361. if ActorLeftBehind.GetRace() == Game.GetCommonProperties().DogmeatRace
  3362. Followers.DismissDogmeatCompanion(ShowLocationAssignmentListIfAvailable = false)
  3363. else
  3364. Followers.DismissCompanion(ActorLeftBehind, ShowLocationAssignmentListIfAvailable = false)
  3365. endif
  3366.  
  3367. SetIsInNeedOfHealing(ActorLeftBehind, false)
  3368. ActorLeftBehind.EvaluatePackage()
  3369. ActorLeftBehind.MoveToPackageLocation()
  3370. endif
  3371.  
  3372. EndEvent
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement