Scriptname _00E_Theriantrophist_AlchemyControl extends ReferenceAlias ;===================================================================================== ; PROPERTIES ;===================================================================================== Keyword Property _00E_Theriantrophist_DarkBloodEffect Auto Keyword Property _00E_Theriantrophist_Effect Auto Keyword Property _00E_Theriantrophist_ChymikumLife Auto {the perk that allows the player to drink theriantrophist potions} Actor Property PlayerREF Auto Perk Property _00E_Class_Theriantrophist_P01_WerewolfBlood Auto Message Property _00E_Theriantrophist_ReallyWantToBrewPotion Auto Message Property _00E_FS_Theriantrophist_PotionFortified Auto MagicEffect Property _00E_Theriantrophist_NoEffect Auto Perk Property _00E_Class_Theriantrophist_P03_GreyAlchemist_01 Auto Perk Property _00E_Class_Theriantrophist_P03_GreyAlchemist_02 Auto Perk Property _00E_Class_Theriantrophist_P03_GreyAlchemist_03 Auto MagicEffect Property _00E_Theriantrophist_AlchChymikum_FireClaws Auto MagicEffect Property _00E_Theriantrophist_AlchChymikum_Armor Auto MagicEffect Property _00E_Theriantrophist_AlchChymikum_Damage Auto MagicEffect Property _00E_Theriantrophist_AlchChymikum_FrostClaws Auto MagicEffect Property _00E_Theriantrophist_AlchChymikum_Health Auto MagicEffect Property _00E_Theriantrophist_AlchChymikum_ShockClaws Auto MagicEffect Property _00E_Theriantrophist_AlchChymikum_Speed Auto MagicEffect Property _00E_Theriantrophist_AlchChymikum_Stamina Auto MagicEffect Property _00E_AlchReduceArcaneFever Auto MagicEffect Property _00E_AlchRestoreMagicka Auto MagicEffect Property _00E_AlchRestoreStamina Auto MagicEffect Property AlchFortifyHealth Auto MagicEffect Property AlchFortifyHealRate Auto MagicEffect Property AlchFortifyMagicka Auto MagicEffect Property AlchFortifyMagickaRate Auto MagicEffect Property AlchFortifyStamina Auto MagicEffect Property AlchFortifyStaminaRate Auto MagicEffect Property AlchInvisibillity Auto MagicEffect Property AlchWaterbreathing Auto MagicEffect Property AlchResistFire Auto MagicEffect Property AlchResistFrost Auto MagicEffect Property AlchResistMagic Auto MagicEffect Property AlchResistShock Auto MagicEffect Property AlchFortifyAlchemy Auto MagicEffect Property AlchFortifyAlteration Auto MagicEffect Property AlchFortifyBarter Auto MagicEffect Property AlchFortifyBlock Auto MagicEffect Property AlchFortifyCarryWeight Auto MagicEffect Property AlchFortifyConjuration Auto MagicEffect Property AlchFortifyDestruction Auto MagicEffect Property AlchFortifyEnchanting Auto MagicEffect Property AlchFortifyHeavyArmor Auto MagicEffect Property AlchFortifyIllusion Auto MagicEffect Property AlchFortifyLightArmor Auto MagicEffect Property AlchFortifyLockpicking Auto MagicEffect Property AlchFortifyMarksman Auto MagicEffect Property AlchFortifyOneHanded Auto MagicEffect Property AlchFortifyPersuasion Auto MagicEffect Property AlchFortifyPickpocket Auto MagicEffect Property AlchFortifySmithing Auto MagicEffect Property AlchFortifySneak Auto MagicEffect Property AlchFortifyTwoHanded Auto MagicEffect Property AlchRestoreMagicka Auto MagicEffect Property AlchRestoreStamina Auto Int Property GreyAlchemist2PotionDurationLimitInSeconds = 180 Autoreadonly Hidden {The potion duration of all werewolf potions is limited to this amount if the player has the first and second perk grey alchemist} Int Property GreyAlchemist1PotionDurationLimitInSeconds = 120 Autoreadonly Hidden {The potion duration of all werewolf potions is limited to this amount if the player has the first perk grey alchemist} Int Property NoAlchemistPotionDurationLimitInSeconds = 90 Autoreadonly Hidden {The potion duration of all werewolf potions is limited to this amount if the player has not the perk grey alchemist} _00E_FS_NQ11_Functions Property FS_NQ11 Auto Int Property RenamedPotions Hidden Int Function Get() Int result = JMap.getObj(JDB.root(), "EnderalFS.RenamedPotions") if (result == 0) result = JFormMap.object() JMap.setObj(JDB.root(), "EnderalFS.RenamedPotions", result) EndIf return result EndFunction EndProperty Int Property ModelChangedPotions Hidden Int Function Get() Int result = JMap.getObj(JDB.root(), "EnderalFS.ModelChangedPotions") If (result == 0) result = JFormMap.object() JMap.setObj(JDB.root(), "EnderalFS.ModelChangedPotions", result) EndIf return result EndFunction EndProperty bool bDoneDarkBlood = false bool bDoneChymikum = false int PotionsMixedOnLastTest = 0 ; OBSOLETE AFTER 1.5.3.0. Needed for version update int criticalSectionProcesses = 0 ; OBSOLETE AFTER 1.5.3.0. Needed for version update ;===================================================================================== ; FUNCTIONS ;===================================================================================== Function _UpdatePotion(Potion item, Int count, Bool bIsInCraftingMode) Int i MagicEffect[] potionEffects = item.GetMagicEffects() Int nPotionEffects = potionEffects.Length Bool bIsTheriantrophistPotion = item.HasKeyword(_00E_Theriantrophist_Effect) MagicEffect firstTheriantrophistEffect = None If bIsTheriantrophistPotion && bIsInCraftingMode ; FRESHLY BREWN THERIANTROPHIST POTION PlayerREF.removeItem(item, count, abSilent = true) Bool bRemoveTheriantrophistEffects = False If !PlayerREF.hasPerk(_00E_Class_Theriantrophist_P01_WerewolfBlood) If _00E_Theriantrophist_ReallyWantToBrewPotion.Show() != 1 bRemoveTheriantrophistEffects = True EndIf EndIf MagicEffect[] newEffects = new MagicEffect[10] Float[] newMagnitudes = new Float[10] Int[] newAreas = new Int[10] Int[] newDurations = new Int[10] Int nNewEffects = 0 If bRemoveTheriantrophistEffects i = 0 While i < nPotionEffects && nNewEffects < newEffects.Length If potionEffects[i].HasKeyword(_00E_Theriantrophist_Effect) == False newEffects[nNewEffects] = potionEffects[i] newMagnitudes[nNewEffects] = item.getNthEffectMagnitude(i) newAreas[nNewEffects] = item.getNthEffectArea(i) newDurations[nNewEffects] = item.getNthEffectDuration(i) nNewEffects += 1 EndIf i += 1 EndWhile If nNewEffects == 0 newEffects[nNewEffects] = _00E_Theriantrophist_NoEffect nNewEffects += 1 EndIf Else Int maxDuration = NoAlchemistPotionDurationLimitInSeconds Int durationBonus = PlayerREF.GetAV("BypassVendorStolenCheck") as Int If PlayerREF.hasPerk(_00E_Class_Theriantrophist_P03_GreyAlchemist_03) maxDuration = -1 ; no duration mali are required ElseIf PlayerREF.hasPerk(_00E_Class_Theriantrophist_P03_GreyAlchemist_02) maxDuration = GreyAlchemist2PotionDurationLimitInSeconds ElseIf PlayerREF.hasPerk(_00E_Class_Theriantrophist_P03_GreyAlchemist_01) maxDuration = GreyAlchemist1PotionDurationLimitInSeconds Endif i = 0 While i < nPotionEffects && nNewEffects < newEffects.Length newEffects[nNewEffects] = potionEffects[i] newMagnitudes[nNewEffects] = item.getNthEffectMagnitude(i) newAreas[nNewEffects] = item.getNthEffectArea(i) newDurations[nNewEffects] = item.getNthEffectDuration(i) If newEffects[nNewEffects].HasKeyword(_00E_Theriantrophist_Effect) If firstTheriantrophistEffect == None firstTheriantrophistEffect = newEffects[nNewEffects] EndIf If maxDuration >= 0 && newDurations[nNewEffects] > maxDuration newDurations[nNewEffects] = maxDuration EndIf If durationBonus > 0 newDurations[nNewEffects] = newDurations[nNewEffects] + durationBonus EndIf EndIf nNewEffects += 1 i += 1 EndWhile If durationBonus > 0 _00E_FS_Theriantrophist_PotionFortified.Show(durationBonus) EndIf EndIf Potion newPotion = Potion.CreatePotion(newEffects, newMagnitudes, newAreas, newDurations, nNewEffects) If JFormMap.hasKey(RenamedPotions, newPotion) == False _RenamePotion(newPotion, newEffects, nNewEffects, bRemoveTheriantrophistEffects) _SetPotionModel(newPotion, firstTheriantrophistEffect, newEffects[0]) EndIf PlayerREF.addItem(newPotion, count, abSilent = true) If bRemoveTheriantrophistEffects == False _UpdateNQ11(newPotion) EndIf ElseIf bIsTheriantrophistPotion && bIsInCraftingMode == False ; OLD THERIANTROPHIST POTION i = 0 While i < nPotionEffects && !firstTheriantrophistEffect If potionEffects[i].HasKeyword(_00E_Theriantrophist_Effect) firstTheriantrophistEffect = potionEffects[i] EndIf i += 1 EndWhile _RenamePotion(item, potionEffects, nPotionEffects, False) _SetPotionModel(item, firstTheriantrophistEffect, potionEffects[0]) _UpdateNQ11(item) Else ; COMMON POTION _RenamePotion(item, potionEffects, nPotionEffects, True) _SetPotionModel(item, None, potionEffects[0]) EndIf EndFunction Function _RenamePotion(Potion p, MagicEffect[] potionEffects, Int nPotionEffects, Bool bCommonPotion) String name = "" If bCommonPotion If p.isPoison() name = Game.GetGameSettingString("sCreatedPoisonNamePrefix") Else name = Game.GetGameSettingString("sCreatedPotionNamePrefix") Endif EndIf Int nEffectsAdded = 0 Int i = 0 While i < nPotionEffects && nEffectsAdded < 2 If nEffectsAdded > 0 name += ", " EndIf name += potionEffects[i].getName() nEffectsAdded += 1 i += 1 EndWhile JFormMap.setStr(RenamedPotions, p, name) p.setName(name) EndFunction Function _SetPotionModel(Potion p, MagicEffect firstTheriantrophistEffect, MagicEffect firstEffect) string modelName string modelPath = "" If firstTheriantrophistEffect If firstTheriantrophistEffect == _00E_Theriantrophist_AlchChymikum_FireClaws modelName = "ChymikumFire" ElseIf firstTheriantrophistEffect == _00E_Theriantrophist_AlchChymikum_Armor modelName = "ChymikumArmor" ElseIf firstTheriantrophistEffect == _00E_Theriantrophist_AlchChymikum_Damage modelName = "ChymikumDamage" ElseIf firstTheriantrophistEffect == _00E_Theriantrophist_AlchChymikum_FrostClaws modelName = "ChymikumFrost" ElseIf firstTheriantrophistEffect == _00E_Theriantrophist_AlchChymikum_Health modelName = "ChymikumLife" ElseIf firstTheriantrophistEffect == _00E_Theriantrophist_AlchChymikum_ShockClaws modelName = "ChymikumShock" ElseIf firstTheriantrophistEffect == _00E_Theriantrophist_AlchChymikum_Speed modelName = "ChymikumSpeed" ElseIf firstTheriantrophistEffect == _00E_Theriantrophist_AlchChymikum_Stamina modelName = "ChymikumStamina" Else modelName = "DarkBloodPotion" Endif modelPath = "meshes\\enderal\\forgottenstories\\theriantrophist\\" + modelName + ".nif" ElseIf firstEffect && p.isPoison() == False If firstEffect == _00E_AlchReduceArcaneFever modelPath = "Meshes\\Clutter\\Quest\\MS12WhitePhialRepaired.nif" ElseIf firstEffect == _00E_AlchRestoreMagicka || firstEffect == AlchRestoreMagicka modelPath = "Meshes\\Clutter\\Potions\\PotionMagickaLesser.nif" ElseIf firstEffect == _00E_AlchRestoreStamina || firstEffect == AlchRestoreStamina modelPath = "Meshes\\Clutter\\Potions\\PotionStaminaLesser.nif" ElseIf firstEffect == AlchFortifyHealth modelPath = "Meshes\\Clutter\\Potions\\PotionFortifyHealthLesser.nif" ElseIf firstEffect == AlchFortifyHealRate modelPath = "Meshes\\Clutter\\Potions\\PotionFortifyHealRateLesser.nif" ElseIf firstEffect == AlchFortifyMagicka modelPath = "Meshes\\Clutter\\Potions\\PotionMagickaExtra.nif" ElseIf firstEffect == AlchFortifyMagickaRate modelPath = "Meshes\\Clutter\\Potions\\PotionFortifyMagiRateLesser.nif" ElseIf firstEffect == AlchFortifyStamina modelPath = "Meshes\\Clutter\\Potions\\PotionFortifyStaminaLesser.nif" ElseIf firstEffect == AlchFortifyStaminaRate modelPath = "Meshes\\Clutter\\Potions\\PotionFortifyStamRateLesser.nif" ElseIf firstEffect == AlchInvisibillity || firstEffect == AlchWaterbreathing modelPath = "Meshes\\Clutter\\Potions\\PotionInvisibiltyLesser.nif" ElseIf firstEffect == AlchResistFire modelPath = "Meshes\\Clutter\\Potions\\PotionResistFire50.nif" ElseIf firstEffect == AlchResistFrost modelPath = "Meshes\\Clutter\\Potions\\PotionResistFrost50.nif" ElseIf firstEffect == AlchResistMagic modelPath = "Meshes\\Clutter\\Potions\\PotionResistMagicka50.nif" ElseIf firstEffect == AlchResistShock modelPath = "Meshes\\Clutter\\Potions\\PotionResistShock50.nif" ElseIf firstEffect == AlchFortifyAlchemy || firstEffect == AlchFortifyAlteration || firstEffect == AlchFortifyBarter || firstEffect == AlchFortifyBlock modelPath = "Meshes\\Clutter\\Potions\\PotionFortifySkill01.nif" ElseIf firstEffect == AlchFortifyCarryWeight || firstEffect == AlchFortifyConjuration || firstEffect == AlchFortifyDestruction || firstEffect == AlchFortifyEnchanting modelPath = "Meshes\\Clutter\\Potions\\PotionFortifySkill01.nif" ElseIf firstEffect == AlchFortifyHeavyArmor || firstEffect == AlchFortifyIllusion || firstEffect == AlchFortifyLightArmor || firstEffect == AlchFortifyLockpicking modelPath = "Meshes\\Clutter\\Potions\\PotionFortifySkill01.nif" ElseIf firstEffect == AlchFortifyMarksman || firstEffect == AlchFortifyOneHanded || firstEffect == AlchFortifyPersuasion || firstEffect == AlchFortifyPickpocket modelPath = "Meshes\\Clutter\\Potions\\PotionFortifySkill01.nif" ElseIf firstEffect == AlchFortifySmithing || firstEffect == AlchFortifySneak || firstEffect == AlchFortifyTwoHanded modelPath = "Meshes\\Clutter\\Potions\\PotionFortifySkill01.nif" EndIf EndIf If modelPath != "" p.SetWorldModelPath(modelPath) JFormMap.setStr(ModelChangedPotions, p, modelPath) EndIf EndFunction Function _UpdateNQ11(Potion newPotion) If (bDoneChymikum && bDoneDarkBlood) || FS_NQ11.IsRunning() == False Return EndIf Bool bUpdateNQ11 = False If newPotion.HasKeyword(_00E_Theriantrophist_ChymikumLife) && FS_NQ11.GetStage() >= 10 && !bDoneChymikum bDoneChymikum = True bUpdateNQ11 = True EndIf If newPotion.HasKeyword(_00E_Theriantrophist_DarkBloodEffect) && FS_NQ11.GetStage() >= 10 && !bDoneDarkBlood bDoneDarkBlood = True bUpdateNQ11 = True EndIf If bUpdateNQ11 && FS_NQ11.GetStage() < 17 FS_NQ11.ShowTutorial(2) If bDoneChymikum && bDoneDarkBlood _SetNewStageNQ11(17) ElseIf bDoneChymikum _SetNewStageNQ11(15) ElseIf bDoneDarkBlood _SetNewStageNQ11(16) EndIf EndIf EndFunction Function _SetNewStageNQ11(Int newStage) If newStage > FS_NQ11.GetStage() FS_NQ11.SetStage(newStage) EndIf EndFunction ;===================================================================================== ; EVENTS ;===================================================================================== Event OnItemAdded(Form baseItem, int count, ObjectReference itemRef, ObjectReference source) Potion item = baseItem as Potion If item Bool bIsInCraftingMode = UI.IsMenuOpen("Crafting Menu") ; Ignore not-custom potions (with FormID not starting with 0xFF) or already registered potions If (Math.LogicalAnd(item.GetFormID(), 0xFF000000) == 0xFF000000) && JFormMap.hasKey(RenamedPotions, item) == False _UpdatePotion(item, count, bIsInCraftingMode) EndIf EndIf EndEvent Event OnItemRemoved(Form baseItem, int count, ObjectReference itemRef, ObjectReference dest) ; Probably a potion is consumed Potion item = baseItem as Potion if item && dest == None ; we want to prevent that all potions that have been brewed are collected in this list ; and cause performance issues. So we risk that we loose track of them by removing them ; from this list. In this case, the name will be the old vanilla skyrim one if (PlayerREF.getItemCount(item) == 0) JFormMap.removeKey(RenamedPotions, item) JFormMap.removeKey(ModelChangedPotions, item) Endif Endif EndEvent Int curScriptVersion = 0 Int Property LATEST_SCRIPT_VERSION = 3 AutoReadOnly Event OnInit() curScriptVersion = LATEST_SCRIPT_VERSION EndEvent Function _UpdateToVersion3() Potion p Int i Int potionArrayID = JFormMap.allKeys(RenamedPotions) JFormMap.clear(RenamedPotions) JFormMap.clear(ModelChangedPotions) ; Update already cached potions Int nPotions = JArray.count(potionArrayID) i = 0 While i < nPotions p = JArray.getForm(potionArrayID, i, None) as Potion If p && Math.LogicalAnd(p.GetFormID(), 0xFF000000) == 0xFF000000 _UpdatePotion(p, 1, False) EndIf i += 1 EndWhile ; Update potions in the player's inventory Int nItems = PlayerREF.GetNumItems() i = 0 While i < nItems p = PlayerREF.GetNthForm(i) as Potion If p && Math.LogicalAnd(p.GetFormID(), 0xFF000000) == 0xFF000000 && JFormMap.hasKey(RenamedPotions, p) == False _UpdatePotion(p, 1, False) EndIf i += 1 EndWhile Debug.Trace("_00E_Theriantrophist_AlchemyControl: _UpdateToVersion3 done") EndFunction Event OnPlayerLoadGame() Bool bRestoreNamesModels = True ; Version update If curScriptVersion < LATEST_SCRIPT_VERSION Int oldScriptVersion = curScriptVersion curScriptVersion = LATEST_SCRIPT_VERSION If oldScriptVersion < 3 _UpdateToVersion3() bRestoreNamesModels = False EndIf EndIf ; Fix 1.5.3.0 _IsSelfBrewnPotion stuck in permanent Wait loop. ; It may take a looong time If criticalSectionProcesses > 0 RegisterForSingleUpdate(0.1) EndIf ; Restore names and models If bRestoreNamesModels Potion k Int potionNames = RenamedPotions k = JFormMap.nextKey(potionNames, previousKey = None, endKey = None) as Potion while k != None k.setName(JFormMap.getStr(potionNames, k)) k = JFormMap.nextKey(potionNames, k, endKey = None) as Potion endwhile Int potionModels = ModelChangedPotions k = JFormMap.nextKey(potionModels, previousKey = None, endKey = None) as Potion while k != None k.SetWorldModelPath(JFormMap.getStr(potionModels, k)) k = JFormMap.nextKey(potionModels, k, endKey = None) as Potion endwhile EndIf EndEvent Event OnUpdate() ; Fix 1.5.3.0 _IsSelfBrewnPotion stuck in permanent Wait loop. If criticalSectionProcesses <= 0 Utility.WaitMenuMode(0.1) ; Wait a bit more, just in case If criticalSectionProcesses <= 0 ;Debug.Notification("Unfucked _IsSelfBrewnPotion") Return EndIf EndIf PotionsMixedOnLastTest = Game.QueryStat("Potions Mixed") + Game.QueryStat("Poisons Mixed") criticalSectionProcesses = 0 RegisterForSingleUpdate(0.1) EndEvent