Sakatraka Posted March 18, 2019 Posted March 18, 2019 The new version of JContainers SE It is now possible to download it directly from nexus
Tron91 Posted March 18, 2019 Posted March 18, 2019 https://www.nexusmods.com/skyrimspecialedition/mods/13956 FISSES got an update
Tron91 Posted March 18, 2019 Posted March 18, 2019 https://www.nexusmods.com/skyrimspecialedition/mods/18160 SKSE64 Havok Fix updated https://www.nexusmods.com/skyrimspecialedition/mods/4224 Go To Bed updated
Celedhring Posted March 18, 2019 Posted March 18, 2019 Sexlab Adventures 0.72 (Oldrim version) Works fine as far as I can tell with my SSE game with SKSE 2.0.12. (I made sure NOT to update the latest SKSE breaking patch from Bugstheda) About to try out Apropos 2 with SSE to see how well it works. UPDATES: Apropos 2 shows menu but doesn't work due to requiring an appropriate install of JContainers. Things in the Dark (Oldrim) works pretty well with SKSE 2.0.12. Installing Things in the Dark (Modified) will not allow you to enter Ibn as a slave if you go by the spider statute near the Helgen cave entrance - you'll only get the servant option which I fixed by uninstalling that mod, then reinstalling Things in the Dark. I didn't crash even once in Ibn in Skyrim SE. *shocked* Further testing showed that Sexlab Adventures (Oldrim) Proximity Rape will "hang" on occasion and you have to restart the rape mechanism. Which sucks as it was one of the very few mods that can start 3 person/creature sex animations.
Pinute Posted March 19, 2019 Posted March 19, 2019 Thanks for that very helpful chart, tasairis. I could tell at a glance that I'm pretty much ready to upgrade.
GothicRose30 Posted March 19, 2019 Posted March 19, 2019 I can confirm that Passive Weapon Enchantment Recharging has been updated to 1.5.73 SKSE64 2.0.15 (Updated on March 18, 2019) (@Sakatraka did mention this a few messages up from mine) https://www.nexusmods.com/skyrimspecialedition/mods/14491?tab=files Nexus Mods has updated JContainers on their site aswell (@Sakatraka did mention this a few messages up from mine) (Updated March 18, 2019) https://www.nexusmods.com/skyrimspecialedition/mods/16495?tab=files HDT High Heels has been updated to 1.5.73 SKSE64 2.0.15 (Updated on March 17, 2019) http://www.9damao.com/thread-39231-1-1.html Picture Proof:
Sakatraka Posted March 19, 2019 Posted March 19, 2019 FlowerGirls SE Adventures patch ( voiced quests and alters some vanilla quest ) Updated
seiryuufang Posted March 19, 2019 Posted March 19, 2019 SL Disparity converts easily enough, but won't connect to SkyrimSE's version of NiOverride. Simply adding Oldrim files to scripts doesn't fix either. Will probably need someone to find a way to connect Disparity's NiOverride requirement to current Skee/Racemenu.
Yoxgg04 Posted March 19, 2019 Posted March 19, 2019 *Payprus was updated on nexus *Sexlab SE was also updated
Gh0sTG0 Posted March 19, 2019 Posted March 19, 2019 Hm... What to do if mod SLA Monitor Widget is marked as "convertable", but it has skyui in masterfiles? Should I install skyui, skyuiSE, both of them? What to do with editing masterfiles?
Guest Posted March 19, 2019 Posted March 19, 2019 18 hours ago, GothicRose30 said: I can confirm that Passive Weapon Enchantment Recharging has been updated to 1.5.73 SKSE64 2.0.15 (Updated on March 18, 2019) (@Sakatraka did mention this a few messages up from mine) https://www.nexusmods.com/skyrimspecialedition/mods/14491?tab=files Nexus Mods has updated JContainers on their site aswell (@Sakatraka did mention this a few messages up from mine) (Updated March 18, 2019) https://www.nexusmods.com/skyrimspecialedition/mods/16495?tab=files HDT High Heels has been updated to 1.5.73 SKSE64 2.0.15 (Updated on March 17, 2019) http://www.9damao.com/thread-39231-1-1.html Picture Proof: translations hdtSSEHH hdtHighHeel_english.7z
Aylis Posted March 20, 2019 Posted March 20, 2019 Wohoo! Now Random Sex is the last mod i need updated.
tasairis Posted March 20, 2019 Author Posted March 20, 2019 8 hours ago, Gh0sTG0 said: Hm... What to do if mod SLA Monitor Widget is marked as "convertable", but it has skyui in masterfiles? Should I install skyui, skyuiSE, both of them? What to do with editing masterfiles? I don't know what you have but last I knew SLA Monitor Widget.esp did not have SkyUI.esp as a master. 1
tasairis Posted March 20, 2019 Author Posted March 20, 2019 11 hours ago, seiryuufang said: SL Disparity converts easily enough, but won't connect to SkyrimSE's version of NiOverride. Simply adding Oldrim files to scripts doesn't fix either. Will probably need someone to find a way to connect Disparity's NiOverride requirement to current Skee/Racemenu. Yes indeed, apparently I never finished adding that comment in my list...
Tron91 Posted March 20, 2019 Posted March 20, 2019 17 minutes ago, tasairis said: Yes indeed, apparently I never finished adding that comment in my list... Is this one problem for Disparity? Spoiler https://imgur.com/a/lbkXNQc
tasairis Posted March 20, 2019 Author Posted March 20, 2019 7 minutes ago, Tron91 said: Is this one problem for Disparity? Hide contents https://imgur.com/a/lbkXNQc You mean the italics? No problem, just means the mod is injecting forms into (in this case) Skyrim.esm.
Tron91 Posted March 20, 2019 Posted March 20, 2019 SexLab Disparity:: Need to test more but so far I got this!! https://imgur.com/a/ShosVEV Modified scripts to get it working. _fwb_modifiers.psc Spoiler Scriptname _fwb_modifiers extends Quest Int Function VersionID() Return 1306 EndFunction Int version = 1306 ; FOLDSTART - Properties String Property ModName Auto Keyword Property playerHomeKeyword Auto Keyword Property jailKeyword Auto Quest Property mcm Auto ; DO NOT cast this to _fwb_sexlab, do not pollute modifiers with SexLab types. Quest Property fwb_sexlab Auto ; NiOverride version int Property SKEE_VERSION = 1 AutoReadOnly int Property NIOVERRIDE_VERSION = 4 AutoReadOnly int Property NIOVERRIDE_SCRIPT_VERSION = 6 AutoReadOnly ; XPMSE version float Property XPMSE_VERSION = 3.0 AutoReadOnly float Property XPMSELIB_VERSION = 3.0 AutoReadOnly ; Spells Spell Property dummySpell Auto ; Deprecated, no longer used - is set to None Spell[] Property spellDebuffs Auto Spell[] Property spellBuffs Auto ; These have the new spells for update 13 Spell[] Property spellDebuffs_U13 Auto Spell[] Property spellBuffs_U13 Auto Spell Property visualEffectsSpell Auto Spell Property animStaggerEffectSpell Auto ; The internal stagger animation needs a special spell, due to vanilla stagger being an archetype not a script. ; These replace the old property - which will not have latest data if the player does an update Spell[] spellsDown Spell[] spellsUp ; Factions - deprecated - no longer used - are set to None Faction Property zadAnimatingFaction Auto Faction Property sexlabAnimatingFaction Auto ; FOLDEND - Properties ; FOLDSTART - NiNodes String NINODE_BREAST_LEFT = "NPC L Breast" String NINODE_BREAST_RIGHT = "NPC R Breast" ; Used for "Torpedo fix" String NINODE_BREAST01_LEFT = "NPC L Breast01" String NINODE_BREAST01_RIGHT = "NPC R Breast01" String NINODE_BELLY = "NPC Belly" String NINODE_BUTT_LEFT = "NPC L Butt" String NINODE_BUTT_RIGHT = "NPC R Butt" String NINODE_SCHLONG = "NPC Genitals01 [Gen01]" ; FOLDEND - NiNodes ; FOLDSTART - Keys String keyInUpdate = "fwb_mcm_in_update" String startedKey = "fwb_modifiers_enabled" String updateIntervalKey = "fwb_update_interval" String keyEventsEnabled = "fwb_EventsEnabled" String keyVisualEffectsEnabled = "fwb_VisualEffectsEnabled" String keyUseSlifForNodes = "fwb_UseSlifForNodes" String keyEnableAttackSpeed = "fwb_EnableAttackSpeedChanges" String keySliderNames = "fwb_sliderNames_" String keySliderValues = "fwb_sliderValues_" String keySliderDefaults = "fwb_sliderDefaults_" String keySliderFormats = "fwb_sliderFormats_" String keySliderSteps = "fwb_sliderSteps_" String keySliderMin = "fwb_sliderMinKey_" String keySliderMax = "fwb_sliderMaxKey_" String keyMcmModifiedFlag = "fwb_valuesChangedInMcm" String keyEffectValues = "fbw_effectValues" String keyCurrentEffectValues = "fbw_currentEffectValues" String keyLimitValuesLo = "fwb_limitValuesLo" String keyLimitValuesHi = "fwb_limitValuesHi" String keyMasterDebuff = "fwb_masterDebuff" String keyMasterBuff = "fwb_masterBuff" String keyIsUpdateEnabled = "fwb_effect_update_enabled" String keyMmeEnables = "fwb_mmeUpdateEnables" String keySlaEnables = "fwb_slaUpdateEnables" String keyRapeCount = "fwb_currentKnownRapeCount" String keyRapeTime = "fwb_lastKnownRapeTime" String keyIsmStrengths = "fwb_ISM_strengths" String keyWntEnables = "fwb_wearTearEnables" String keyCombatEventScale = "fwb_CombatEventScale" String keySprintEventScale = "fwb_SprintEventScale" String keyStumbleStamina = "fwb_stumbleStaminaLoss" String keyTripStamina = "fwb_tripStaminaLoss" String keyTripRapeChance = "fwb_tripRapeChance" String keyFallStamina = "fwb_fallStaminaLoss" String keyFallHealth = "fwb_fallHealthLoss" String keyFallRapeChance = "fwb_fallRapeChance" String keyUseInternalAnimations = "fwb_useInternalAnimations" String keyRapeDuringSolo = "fwb_rapeDuringSolo" String keyRapeStaminaLoss = "fwb_rapeStaminaLoss" String keyRapeHealthLoss = "fwb_rapeHealthLoss" String keyRapistsMinimum = "fwb_rapistsMinimum" String keyRapistsMaximum = "fwb_rapistsMaximum" ; This is for use by modifiers itself - thread code doesn't know or care about it String keyThreadEventMutex = "fwb_threadEventMutex" String keyMorphsEnabled = "fwb_morphsEnabled" String keyMorphMode = "fwb_morphMode" String keyMorphMasterWeights = "fwb_morphMasterWeights" String keyMorphMasterScales = "fwb_morphMasterScales" String keyMorphNames = "fwb_morphNames" String keyMorphWeights = "fwb_morphWeights" String keyMorphOffsets = "fwb_morphOffsets" String keyPlayerMorphValues = "fwb_playerMorphValues" String keyMorphNodeValues = "fwb_morphNodeValues" String keyPlayerStates = "fwb_playerStates" String keyBreasts = "breasts" String keyBelly = "belly" String keyButt = "butt" String keyBody = "body" ; FOLDEND - Keys ; FOLDSTART - Indices Int ixDebuffMax Int ixDebuffFrom Int ixDebuffTo Int ixBuffMax Int ixBuffFrom Int ixBuffTo Int ixStart Int ixEnd ; playerStates indices Int ixBreast Int ixBelly Int ixButt Int ixBody Int ixCarryWeight ; unused indices ixMagicka = 5 ixMagickaRate = 6 ixHealth = 7 ixHealthRate = 8 ixStamina = 9 ixStaminaRate = 10 Int mmMilk Int mmBreastFull Int mmPain Int slArousal Int slDenial Int slRaped Int slAddicted Int wtAbuse Int wtCreature Int wtDaedric Int wtVaginal Int wtAnal Int wtOral ; FOLDEND - Indices ; FOLDSTART - Variables Bool configurationChanged Bool playerChanged Actor player Float defaultUpdateInterval Float masterDebuff Float masterBuff Float[] playerStates Float[] oldPlayerStates Bool slifPresent Bool weaponSpeedsModified Bool mmePresent Int[] mmeEnabled String[] mmePageNames Float[] mmeStates Float[] oldMmeStates Bool slaPresent Int[] slaEnabled String[] slaPageNames Float[] slaStates Float[] oldSlaStates Int sexLabRapeCount Float greetingDistance Float[] ismStrengths Bool wntPresent Int[] wntEnabled String[] wntPageNames Float[] wntStates Float[] oldWntStates Float[] breastValues Float[] bellyValues Float[] buttValues Float[] bodyValues Float[] mmeMilkValues Float[] mmeBreastPercentValues Float[] mmePainPercentValues Float[] slaArousalValues Float[] slaDenialValues Float[] slaRapedValues Float[] slaAddictionValues Float[] wntAbuseValues Float[] wntCreatureValues Float[] wntDaedricValues Float[] wntVaginalValues Float[] wntAnalValues Float[] wntOralValues Bool morphsEnabled String morphMode Float[] morphMasterWeights Float[] morphMasterScales Float[] morphWeights Float[] morphOffsets Float[] morphPrescales String[] morphNames Float[] playerMorphValues Float[] weightedMorphs Float[] morphNodeValues Float[] currentModifiers Float[] breastModifiers Float[] bellyModifiers Float[] buttModifiers Float[] bodyModifiers Float[] mmeMilkModifiers Float[] mmeBreastPercentModifiers Float[] mmePainPercentModifiers Float[] slaArousalModifiers Float[] slaDenialModifiers Float[] slaRapedModifiers Float[] slaAddictionModifiers Float[] wntAbuseModifiers Float[] wntCreatureModifiers Float[] wntDaedricModifiers Float[] wntVaginalModifiers Float[] wntAnalModifiers Float[] wntOralModifiers Float[] effectValues Float[] oldEffectValues Int[] currentEffectValues Int[] effectTypes Float[] effectScalesUp Float[] effectScalesDown String[] avNames Float[] clampLower Float[] clampUpper Float sexEventCooldownSeconds = 30.0 Float sexEventCooldownExpire Float wobbleEventCooldownSeconds = 12.0 Float wobbleEventCooldownSecondsForCombat = 6.0 Float wobbleEventCooldownExpired ; FOLDEND - Variables ; FOLDSTART - Chances Float stumbleChance Float bleedoutChance ; tripChance Float fallChance Float dropChance Float masturbateChance Float rapeChance Int stumbleChance_x100 Int bleedoutChance_x100 Int fallChance_x100 Int dropChance_x100 Int masturbateChance_x100 Int rapeChance_x100 Float tripRapeChance ; bleedoutRapeChance Float fallRapeChance Int tripRapeChance_x100 Int fallRapeChance_x100 ; FOLDEND - Chances ; FOLDSTART - Effect indices Int exMagicka ; 0 Int exMagickaRate ; 1 Int exHealth ; 2 Int exHealthRate ; 3 Int exStamina ; 4 Int exStaminaRate ; 5 Int exMoveSpeed ; 6 Int exCarryWeight ; 7 Int exMeleeDamage ; 8 Int exUnarmed ; 9 Int exAttackSpeed ; 10 Int exBowSpeed ; 11 Int exArchery ; 12 Int exOneHanded ; 13 Int exTwoHanded ; 14 Int exBlock ; 15 Int exHeavyArmor ; 16 Int exLightArmor ; 17 Int exSneak ; 18 Int exLockpicking ; 19 Int exPickpocket ; 20 Int exSpeech ; 21 Int exAlteration ; 22 Int exConjuration ; 23 Int exDestruction ; 24 Int exIllusion ; 25 Int exRestoration ; 26 Int exEnchanting ; 27 Int exAlchemy ; 28 Int exSmithing ; 29 Int exVisionBlur ; 30 Int exVisionTunnel ; 31 Int exVisionDouble ; 32 Int exVisionVibrant ; 33 Int exStumble ; 34 Int exBleedout ; 35 Int exFall ; 36 Int exDrop ; 37 Int exMasturbate ; 38 Int exRape ; 39 Int effectCount ; 40 ; FOLDEND - Effect indices STATE Disabled Event OnUpdate() _fw_utils.Info("FWB Modifiers - OnUpdate while Disabled") EndEvent Bool Function StartMod() GotoState("Starting") ;Debug.Notification(ModName + " Starting Modifiers") If ResetInternal() StorageUtil.SetIntValue(None, startedKey, 1) _fw_utils.Info("FWB Modifers.StartMod starting periodic updates") ; Don't start fwb_sexlab here now - started only on demand. ; Update after a short delay, so player gets immediate feedback on mod start GotoState("Enabled") CheckForExternalMods() ; Force an MCM update on mod-start - we need this so that states are considered changed and get recomputed. StorageUtil.SetIntValue(None, keyMcmModifiedFlag, 1) RegisterForSingleUpdate(5.0) Return True Else GotoState("Disabled") _fw_utils.Info("FWB Modifiers.ResetInternal failed") Return False; EndIf EndFunction Function StopMod() EndFunction EndState STATE Starting Event OnUpdate() _fw_utils.Info("FWB Modifiers - OnUpdate during Startup") EndEvent Bool Function StartMod() Return False EndFunction Function StopMod() EndFunction EndState STATE Stopping Event OnUpdate() _fw_utils.Info("FWB Modifiers - OnUpdate during Shutdown") EndEvent Bool Function StartMod() Return False EndFunction Function StopMod() EndFunction EndState STATE Enabled Function StopMod() GotoState("Stopping") ;Debug.Notification(ModName + " Stopping Modifiers") _fw_utils.Info("FWB Modifers.StopMod stopping periodic update") If fwb_sexlab.IsRunning() _fw_utils.Info("FWB Modifers.StopMod stopping sexlab handler quest") fwb_sexlab.Stop() EndIf StorageUtil.SetIntValue(None, startedKey, 0) GotoState("Disabled") EndFunction ; TODO - move this to the MCM quest, where it belongs? ; Can't listen for the game load event in this quest, but we have an alias with a script that calls this. Function HandleGameLoad() If InDebug() _fw_utils.DebugSpam_SetInfo() EndIf _fw_utils.Info("FWB HandleGameLoad") _fwb_mcm mcmScript = mcm As _fwb_mcm Int mcmVersion = mcmScript.GetInstalledVersionID() Int mcmRelease = mcmScript.GetReleaseVersionID() _fw_utils.Info("FWB Installed Version ID: " + mcmVersion + ", current version: " + version + ", Release Version ID: " + mcmRelease) If version != mcmVersion || version != mcmRelease || mcmVersion != mcmRelease ModName = mcmScript.ModName _fw_utils.Info("FWB update from HandleGameLoad, version is " + version + ", should be " + mcmRelease) ; Need update StorageUtil.SetIntValue(None, keyInUpdate, 1) StopMod() Utility.Wait(1.0) (mcm As _fwb_mcm).Update() String versionName = mcmScript.GetVersionName() If StartMod() (mcm As _fwb_mcm).EnableFromUpdate() StorageUtil.UnsetIntValue(None, keyInUpdate) version = mcmRelease _fw_utils.Info("FWB update from HandleGameLoad complete at version " + version) Debug.Notification(ModName + " auto-updated to version " + versionName) Else _fw_utils.Info("FWB update from HandleGameLoad failed to StartMod at version " + version + " MCM at " + mcmVersion + " (" + versionName +")") Debug.Notification("SexLab Disparity auto-update to " + versionName + " FAILED") EndIf Else _fw_utils.Info("FWB reset soft-deps in HandleLoadGame due to no update at version " + version) ; If not updated, it's still possible mods removed since we were last loaded. slifPresent = False slaPresent = False wntPresent = False mmePresent = False CheckForExternalMods() RegisterEventListeners() EndIf ; Reset these, but not to zero, allow some time before they can happen, because load is a vulnerable period. wobbleEventCooldownExpired = wobbleEventCooldownSeconds sexEventCooldownExpire = sexEventCooldownSeconds ;Debug.Notification(ModName + " handled game load") EndFunction Event OnUpdate() ;Debug.Notification(ModName + " OnUpdate") _fw_utils.Info("FWB - OnUpdate") configurationChanged = ReadConfigurationValues() _fw_utils.Info("FWB - configurationChanged: " + configurationChanged) playerChanged = ReadPlayerState() _fw_utils.Info("FWB - playerChanged: " + playerChanged) If configurationChanged || playerChanged _fw_utils.Info("FWB - OnUpdate - update intentions, modifiers, effect values") UpdateIntentions() CombineModifiers() EffectValuesFromModifiers() EndIf If StorageUtil.GetIntValue(None, keyIsUpdateEnabled, 1) _fw_utils.Info("FWB - OnUpdate - update effects") ; Check the effects are OK, even if we didn't change anything. UpdateEffects() ; Not just visual effects, this is everything. If StorageUtil.GetIntValue(None, keyEventsEnabled) _fw_utils.Info("FWB - OnUpdate - trigger events") CheckAndTriggerEvents(); EndIf EndIf ; Queue next update Float updateInterval = StorageUtil.GetFloatValue(None, updateIntervalKey, defaultUpdateInterval) RegisterForSingleUpdate(updateInterval) EndEvent ; You should only call this while Enabled, the empty state version always returns false Bool Function CheckForSLIF() If _fwb_slif.CheckForSlif() If !slifPresent slifPresent = True SignalConfigurationChanged() EndIf Else If slifPresent slifPresent = False ; Disable useSlifForNodes in configuration if SLIF vanished. StorageUtil.SetIntValue(None, keyUseSlifForNodes, 0) SignalConfigurationChanged() EndIf EndIf Return slifPresent EndFunction ; You should only call this while Enabled, the empty state version always returns false Bool Function CheckForSLA() _fw_utils.Info("FWB - CheckForSLA...") Int slaIndex = Game.GetModByName("SexLabAroused.esm") _fw_utils.Info("FWB - CheckForSLA - SLA index " + slaIndex) If 255 != slaIndex _fw_utils.Info("FWB CheckForSLA - SLA found, was " + slaPresent) If !slaPresent slaPresent = True SignalConfigurationChanged() EndIf UpdateSlaValues() Else _fw_utils.Info("FWB CheckForSLA - SLA not found, was " + slaPresent) If slaPresent slaPresent = False SignalConfigurationChanged() EndIf EndIf Return slaPresent EndFunction ; You should only call this while Enabled, the empty state version always returns false Bool Function CheckForMME() Int mmeIndex = Game.GetModByName("MilkModNEW.esp") If 255 != mmeIndex ;Debug.Notification(ModName + " - MME ESP is present at index " + mmeIndex) If !mmePresent mmePresent = True SignalConfigurationChanged() EndIf mmePageNames = new String[3] mmePageNames[0] = "Milk-Weight" mmePageNames[1] = "Breasts-Percent-Full" mmePageNames[2] = "Pain-Percentage" mmeStates = new Float[3] oldMmeStates = new Float[3] UpdateMmeValues() Else If mmePresent mmePresent = False SignalConfigurationChanged() EndIf EndIf Return mmePresent EndFunction ; You should only call this while Enabled, the empty state version always returns false Bool Function CheckForApropos2() ; TODO - change SLA and MME to have detection handling in the shim like this! If _fwb_apropos2.IsAproposPresent() If !wntPresent wntPresent = True SignalConfigurationChanged() EndIf wntStates = new Float[6] oldWntStates = new Float[6] wntPageNames = new String[6] wntPageNames[0] = "OVERALL" wntPageNames[1] = "CREATURE" wntPageNames[2] = "DAEDRIC" wntPageNames[3] = "VAGINAL" wntPageNames[4] = "ANAL" wntPageNames[5] = "ORAL" UpdateAproposValues() Else If wntPresent wntPresent = False SignalConfigurationChanged() EndIf EndIf Return wntPresent EndFunction EndState ;--------------------------------------------------------------------------------------------------------------- ; EMPTY state ;--------------------------------------------------------------------------------------------------------------- Bool Function StartMod() GotoState("Disabled") Return StartMod() EndFunction Function StopMod() EndFunction Event OnUpdate() ; Empty EndEvent Function Reset() ResetInternal() StorageUtil.SetIntValue(None, startedKey, 0) GotoState("Disabled") EndFunction Function SignalConfigurationChanged() StorageUtil.SetIntValue(None, keyMcmModifiedFlag, 1) EndFunction ; Re-read all the configuration values set by the MCM, but only if called with forceRead True, or if MCM has signalled them as changed somehow. ; It only returns TRUE if it reads some values - which basically means recalculate everything. Bool Function ReadConfigurationValues(bool forceRead = False) _fw_utils.Info("FWB - ReadConfigurationValues: forceRead: " + forceRead + ", mcmChanged: " + StorageUtil.GetIntValue(None, keyMcmModifiedFlag, 1)) If !forceRead && 0 == StorageUtil.GetIntValue(None, keyMcmModifiedFlag, 1) Return False EndIf _fw_utils.Info("FWB - ReadConfigurationValues - read configuration values from MCM") StorageUtil.SetIntValue(None, keyMcmModifiedFlag, 0) breastValues = StorageUtil.FloatListToArray(mcm, keySliderValues + keyBreasts) bellyValues = StorageUtil.FloatListToArray(mcm, keySliderValues + keyBelly) buttValues = StorageUtil.FloatListToArray(mcm, keySliderValues + keyButt) bodyValues = StorageUtil.FloatListToArray(mcm, keySliderValues + keyBody) _fw_utils.Info("FWB - ReadConfigurationValues slaPresent: " + slaPresent + ", wntPresent: " + wntPresent + ", mmePresent: " + mmePresent + ", morphs: " + StorageUtil.GetIntValue(mcm, keyMorphsEnabled)) ; While it seems counter-intuitive to zero Modifiers rather than Values here, Values aren't used if disabled, Modifiers CAN be. ; See CombineModifiers() If slaPresent ; Read SLA per-input enables slaEnabled = StorageUtil.IntListToArray(mcm, keySlaEnables) _fw_utils.Info("FWB ReadConfigurationValues - slaEnabled " + slaEnabled[0] + " " + slaEnabled[1] + " " + slaEnabled[2] + " " + slaEnabled[3]) If slaEnabled[slArousal] slaArousalValues = StorageUtil.FloatListToArray(mcm, keySliderValues + slaPageNames[slArousal] ) Else ZeroArray(slaArousalModifiers) EndIf If slaEnabled[slDenial] slaDenialValues = StorageUtil.FloatListToArray(mcm, keySliderValues + slaPageNames[slDenial] ) Else ZeroArray(slaDenialModifiers) EndIf If slaEnabled[slRaped] slaRapedValues = StorageUtil.FloatListToArray(mcm, keySliderValues + slaPageNames[slRaped] ) Else ZeroArray(slaRapedModifiers) EndIf If slaEnabled[slAddicted] slaAddictionValues = StorageUtil.FloatListToArray(mcm, keySliderValues + slaPageNames[slAddicted] ) Else ZeroArray(slaAddictionModifiers) EndIf Else ZeroArray(slaArousalModifiers) ZeroArray(slaDenialModifiers) ZeroArray(slaRapedModifiers) ZeroArray(slaAddictionModifiers) EndIf If wntPresent ; Read APROPOS per-input enables wntEnabled = StorageUtil.IntListToArray(mcm, keyWntEnables) ;_fw_utils.Info("FWB ReadConfigurationValues - wntEnabled, read " + wntEnabled.Length + " enabled values") ;_fw_utils.Info("FWB ReadConfigurationValues - wntEnabled " + wntEnabled[0] + " " + wntEnabled[1] + " " + wntEnabled[2] + " " + wntEnabled[3] + " " + wntEnabled[4] + " " + wntEnabled[5]) If wntEnabled[wtAbuse] wntAbuseValues = StorageUtil.FloatListToArray(mcm, keySliderValues + wntPageNames[wtAbuse] ) Else ZeroArray(wntAbuseModifiers) EndIf If wntEnabled[wtCreature] wntCreatureValues = StorageUtil.FloatListToArray(mcm, keySliderValues + wntPageNames[wtCreature] ) Else ZeroArray(wntCreatureModifiers) EndIf If wntEnabled[wtDaedric] wntDaedricValues = StorageUtil.FloatListToArray(mcm, keySliderValues + wntPageNames[wtDaedric] ) Else ZeroArray(wntDaedricModifiers) EndIf If wntEnabled[wtVaginal] wntVaginalValues = StorageUtil.FloatListToArray(mcm, keySliderValues + wntPageNames[wtVaginal] ) Else ZeroArray(wntVaginalModifiers) EndIf If wntEnabled[wtAnal] wntAnalValues = StorageUtil.FloatListToArray(mcm, keySliderValues + wntPageNames[wtAnal] ) Else ZeroArray(wntAnalModifiers) EndIf If wntEnabled[wtOral] wntOralValues = StorageUtil.FloatListToArray(mcm, keySliderValues + wntPageNames[wtOral] ) Else ZeroArray(wntOralModifiers) EndIf Else ZeroArray(wntAbuseModifiers) ZeroArray(wntCreatureModifiers) ZeroArray(wntDaedricModifiers) ZeroArray(wntVaginalModifiers) ZeroArray(wntAnalModifiers) ZeroArray(wntOralModifiers) EndIf If mmePresent ; Read MME per-input enables mmeEnabled = StorageUtil.IntListToArray(mcm, keyMmeEnables) If mmeEnabled[mmMilk] mmeMilkValues = StorageUtil.FloatListToArray(mcm, keySliderValues + mmePageNames[mmMilk] ) Else ZeroArray(mmeMilkModifiers) EndIf If mmeEnabled[mmBreastFull] mmeBreastPercentValues = StorageUtil.FloatListToArray(mcm, keySliderValues + mmePageNames[mmBreastFull] ) Else ZeroArray(mmeBreastPercentModifiers) EndIf If mmeEnabled[mmPain] mmePainPercentValues = StorageUtil.FloatListToArray(mcm, keySliderValues + mmePageNames[mmPain] ) Else ZeroArray(mmePainPercentModifiers) EndIf Else ZeroArray(mmeMilkModifiers) ZeroArray(mmeBreastPercentModifiers) ZeroArray(mmePainPercentModifiers) EndIf ; Morphs morphsEnabled = 0 != StorageUtil.GetIntValue(mcm, keyMorphsEnabled) morphMode = StorageUtil.GetStringValue(mcm, keyMorphMode) morphNames = StorageUtil.StringListToArray(mcm, keyMorphNames) morphMasterWeights = StorageUtil.FloatListToArray(mcm, keyMorphMasterWeights) morphMasterScales = StorageUtil.FloatListToArray(mcm, keyMorphMasterScales) morphWeights = StorageUtil.FloatListToArray(mcm, keyMorphWeights) morphOffsets = StorageUtil.FloatListToArray(mcm, keyMorphOffsets) tripRapeChance = StorageUtil.GetFloatValue(mcm, keyTripRapeChance) tripRapeChance_x100 = (tripRapeChance As Int) * 100 fallRapeChance = StorageUtil.GetFloatValue(mcm, keyFallRapeChance) fallRapeChance_x100 = (fallRapeChance As Int) * 100 clampLower = StorageUtil.FloatListToArray(mcm, keyLimitValuesLo) clampUpper = StorageUtil.FloatListToArray(mcm, keyLimitValuesHi) masterDebuff = StorageUtil.GetFloatValue(mcm, keyMasterDebuff, 100.0) masterBuff = StorageUtil.GetFloatValue(mcm, keyMasterBuff, 100.0) ; the stamina and health instant changes are read on demand, not here, as they're used rarely, same with reallyDrop (read in effect) If InDebug() If !breastValues.Length || !bellyValues.Length || !buttValues.Length || !bodyValues.Length || !clampLower.Length || !clampUpper.Length || !slaArousalValues.Length || !slaDenialValues.Length || !slaRapedValues.Length || !slaAddictionValues.Length _fw_utils.Info("FWB - ReadConfigurationValues - empty array - breasts: " + breastValues.Length \ + ", belly: " + bellyValues.Length + ", butt: " + buttValues.Length + ", body: " + bodyValues.Length \ + ", clampLower: " + clampLower.Length + ", clampUpper: " + clampUpper \ + ", slaArousal: " + slaArousalValues.Length + ", slaDenial: " + slaDenialValues.Length \ + ", slaRape: " + slaRapedValues.Length + ", slaAddicted: " + slaAddictionValues.Length) EndIf EndIf ;Debug.Notification(ModName + " configuration changed - read MCM values") Return True EndFunction ; This is used to SET playerChanged, it doesn't depend on it. Bool Function ReadPlayerState() _fw_utils.Info("FWB Start read player state") oldPlayerStates[0] = playerStates[0] oldPlayerStates[1] = playerStates[1] oldPlayerStates[2] = playerStates[2] oldPlayerStates[3] = playerStates[3] oldPlayerStates[4] = playerStates[4] Bool useSlif = slifPresent && 0 != StorageUtil.GetIntValue(None, keyUseSlifForNodes, 0) If !useSlif || !_fwb_slif.GetNodeValues(player, playerStates) ; Get actual node values instead of SLIF Float breastScaleL = NetImmerse.GetNodeScale(player, NINODE_BREAST_LEFT, false) Float breastScaleR = NetImmerse.GetNodeScale(player, NINODE_BREAST_RIGHT, false) Float bellyScale = NetImmerse.GetNodeScale(player, NINODE_BELLY, false) Float buttScaleL = NetImmerse.GetNodeScale(player, NINODE_BUTT_LEFT, false) Float buttScaleR = NetImmerse.GetNodeScale(player, NINODE_BUTT_RIGHT, false) Float bodyWeight = player.GetActorBase().GetWeight() Float breastScale = (breastScaleL + breastScaleR) * 0.5 Float buttScale = (buttScaleL + buttScaleR) * 0.5 playerStates[0] = breastScale playerStates[1] = bellyScale playerStates[2] = buttScale playerStates[3] = bodyWeight EndIf If morphsEnabled If !useSlif || !_fwb_slif.GetMorphValues(player, morphNames, playerMorphValues) GetPlayerMorphValues() EndIf RecalculateMorphContributions() EndIf ; Carry weight has special processing: we use the base value, but it shouldn't trigger rebuilds of "intentions". ; This returns FALSE even if carryWt changed - carryWt shouldn't trigger recalc of "intentions", but is still used to apply effects, regardless playerStates[4] = player.GetBaseActorValue(avNames[ixCarryWeight]) StorageUtil.FloatListCopy(mcm, keyPlayerStates, playerStates) ; Ensures that SLA is actually present first. UpdateSlaValues() ; Only does anything if wntPresent UpdateAproposValues() ; This will only do anything if mmePresent is True UpdateMmeValues() _fw_utils.Info("FWB Got NEW player state") If playerStates[0] != oldPlayerStates[0] || playerStates[1] != oldPlayerStates[1] || playerStates[2] != oldPlayerStates[2] \ || playerStates[3] != oldPlayerStates[3] _fw_utils.Info("FWB Player state changed") Return True EndIf ; For all these optional components, the ***Values array is reset on configuration change that disables them wholly or in part. ; Their states are left with 'junk' in and shouldn't be checked or used. if (slaEnabled[0] && oldSlaStates[0] != slaStates[0]) || (slaEnabled[1] && oldSlaStates[1] != slaStates[1]) \ || (slaEnabled[2] && oldSlaStates[2] != slaStates[2]) || (slaEnabled[3] && oldSlaStates[3] != slaStates[3]) _fw_utils.Info("FWB Player state changed due to SLA") Return True EndIf If wntPresent if (wntEnabled[0] && oldWntStates[0] != wntStates[0]) || (wntEnabled[1] && oldWntStates[1] != wntStates[1]) \ || (wntEnabled[2] && oldWntStates[2] != wntStates[2]) || (wntEnabled[3] && oldWntStates[3] != wntStates[3]) \ || (wntEnabled[4] && oldWntStates[4] != wntStates[4]) || (wntEnabled[5] && oldWntStates[5] != wntStates[5]) _fw_utils.Info("FWB Player state changed due to APROPOS") Return True EndIf EndIf If mmePresent If (mmeEnabled[0] && oldMmeStates[0] != mmeStates[0]) || (mmeEnabled[1] && oldMmeStates[1] != mmeStates[1]) \ || (mmeEnabled[2] && oldMmeStates[2] != mmeStates[2]) _fw_utils.Info("FWB Player state changed due to MME") Return True EndIf EndIf _fw_utils.Info("FWB player state UNCHANGED") Return False EndFunction Function UpdateIntentions() ; We have a set of node values... ; And we have a number of sets of debuff/buff values that are driven by each node value. ; Each computes a pair of output values for a stat or skill as a modifier percentage. ; Need to sum these up and clamp them to derive the final intended debuff and buff values. ;Debug.Notification(ModName + " Calculate modifiers") _fw_utils.Info("FWB UpdateIntentions - calculate modifiers\n") If configurationChanged || playerStates[ixBreast] != oldPlayerStates[ixBreast] _fw_utils.Info("FWB update BREASTS, was " + oldPlayerStates[ixBreast] + ", now " + playerStates[ixBreast]) CalculateNodeModifers(breastValues, playerStates[ixBreast], breastModifiers, "breasts") EndIf If configurationChanged || playerStates[ixBelly] != oldPlayerStates[ixBelly] _fw_utils.Info("FWB update BELLY, was " + oldPlayerStates[ixBelly] + ", now " + playerStates[ixBelly]) CalculateNodeModifers(bellyValues, playerStates[ixBelly], bellyModifiers, "belly") EndIf If configurationChanged || playerStates[ixButt] != oldPlayerStates[ixButt] _fw_utils.Info("FWB update BUTT, was " + oldPlayerStates[ixButt] + ", now " + playerStates[ixButt]) CalculateNodeModifers(buttValues, playerStates[ixButt], buttModifiers, "butt") EndIf If configurationChanged || playerStates[ixBody] != oldPlayerStates[ixBody] _fw_utils.Info("FWB update BODY, was " + oldPlayerStates[ixBody] + ", now " + playerStates[ixBody]) CalculateNodeModifers(bodyValues, playerStates[ixBody], bodyModifiers, "body") EndIf If slaPresent _fw_utils.Info("FWB UpdateIntentions - slaPresent - arousal " + slaEnabled[0] + ", denial " + slaEnabled[1] + ", rape " + slaEnabled[2] + ", addict " + slaEnabled[3]) If slaEnabled[0] && (configurationChanged || (slaStates[0] != oldSlaStates[0])) _fw_utils.Info("FWB update SLA AROUSAL, was " + oldSlaStates[0] + ", now " + slaStates[0]) CalculateNodeModifers(slaArousalValues , slaStates[0], slaArousalModifiers, "sla-arousal") EndIf If slaEnabled[1] && (configurationChanged || (slaStates[1] != oldSlaStates[1])) _fw_utils.Info("FWB update SLA DENIAL, was " + oldSlaStates[1] + ", now " + slaStates[1]) CalculateNodeModifers(slaDenialValues , slaStates[1], slaDenialModifiers, "sla-denial") EndIf If slaEnabled[2] && (configurationChanged || (slaStates[2] != oldSlaStates[2])) _fw_utils.Info("FWB update SLA RAPED, was " + oldSlaStates[2] + ", now " + slaStates[2]) CalculateNodeModifers(slaRapedValues , slaStates[2], slaRapedModifiers, "sla-raped") EndIf If slaEnabled[3] && (configurationChanged || (slaStates[3] != oldSlaStates[3])) _fw_utils.Info("FWB update SLA ADDICTED, was " + oldSlaStates[3] + ", now " + slaStates[3]) CalculateNodeModifers(slaAddictionValues , slaStates[3], slaAddictionModifiers, "sla-addicted") EndIf EndIf If wntPresent If wntEnabled[0] && (configurationChanged || (wntStates[0] != oldWntStates[0])) CalculateNodeModifers(wntAbuseValues, wntStates[0], wntAbuseModifiers, "wnt-abuse") EndIf If wntEnabled[1] && (configurationChanged || (wntStates[1] != oldWntStates[1])) CalculateNodeModifers(wntCreatureValues, wntStates[1], wntCreatureModifiers, "wnt-creature") EndIf If wntEnabled[2] && (configurationChanged || (wntStates[2] != oldWntStates[2])) CalculateNodeModifers(wntDaedricValues, wntStates[2], wntDaedricModifiers, "wnt-daedric") EndIf If wntEnabled[3] && (configurationChanged || (wntStates[3] != oldWntStates[3])) CalculateNodeModifers(wntVaginalValues, wntStates[3], wntVaginalModifiers, "wnt-vaginal") EndIf If wntEnabled[4] && (configurationChanged || (wntStates[4] != oldWntStates[4])) CalculateNodeModifers(wntAnalValues, wntStates[4], wntAnalModifiers, "wnt-anal") EndIf If wntEnabled[5] && (configurationChanged || (wntStates[5] != oldWntStates[5])) CalculateNodeModifers(wntOralValues, wntStates[5], wntOralModifiers, "wnt-oral") EndIf EndIf If mmePresent If mmeEnabled[0] && (configurationChanged || (mmeStates[0] != oldMmeStates[0])) _fw_utils.Info("FWB update MME MILK WT, was " + oldMmeStates[0] + ", now " + mmeStates[0]) CalculateNodeModifers(mmeMilkValues , mmeStates[0], mmeMilkModifiers, "mme-milk") EndIf If mmeEnabled[1] && (configurationChanged || (mmeStates[1] != oldMmeStates[1])) _fw_utils.Info("FWB update MME BREAST-%, was " + oldMmeStates[1] + ", now " + mmeStates[1]) CalculateNodeModifers(mmeBreastPercentValues , mmeStates[1], mmeBreastPercentModifiers, "mme-breast-pct") EndIf If mmeEnabled[2] && (configurationChanged || (mmeStates[2] != oldMmeStates[2])) _fw_utils.Info("FWB update MME PAIN, was " + oldMmeStates[2] + ", now " + mmeStates[2]) CalculateNodeModifers(mmePainPercentValues , mmeStates[2], mmePainPercentModifiers, "mme-pain-pct") EndIf EndIf EndFunction ; Calculate modifierValues[] for a given input, doing interpolation on From -> To values. ; setup contains the MCM configuration data for all the sliders for a given page. ; value is the state of the INPUT value for that page. ; modifierValues is the set of OUTPUT values for the page, and it has a 1 to 1 mapping with the sliders. Function CalculateNodeModifers(Float[] setup, Float value, Float[] modifierValues, String debugName) ; Per item config is interpreted so +ve value means apply a buff, -ve value means apply a debuff, regardless of the source control value. ;_fw_utils.Info("FWB CalculateNodeModifers: " + debugName + " setup " + setup.Length + ", value " + value + ", modifierValues " + modifierValues.Length) Float debuffScale = setup[ixDebuffMax] * 0.01 Float debuffFrom = setup[ixDebuffFrom] Float debuffTo = setup[ixDebuffTo] Float interpolated = Interpolate(debuffFrom, debuffTo, value) Float effectiveDebuff = interpolated * debuffScale ; Can shortcut if == 0.0 or 1.0 ;_fw_utils.Info("FWB interpolated " + debugName + " debuff value " + interpolated + " * " + debuffScale + " => " + effectiveDebuff) Float buffScale = setup[ixBuffMax] * 0.01 Float buffFrom = setup[ixBuffFrom] Float buffTo = setup[ixBuffTo] interpolated = Interpolate(buffFrom, buffTo, value) Float effectiveBuff = interpolated * buffScale ;_fw_utils.Info("FWB interpolated " + debugName + " buff value " + interpolated + " * " + debuffScale + " => " + effectiveDebuff) Int ii = ixStart While ii < ixEnd Float debuff = setup[ii] * effectiveDebuff Float buff = setup[ii+1] * effectiveBuff modifierValues[ii] = debuff modifierValues[ii+1] = buff ii += 2 EndWhile If InDebug() _fw_utils.Info("FWB - CalculateNodeModifers - " + debugName + ", value: " + value) _fw_utils.Info(" >>>> " + debugName + " calculated D " + _fw_utils.FormatFloat_N1(effectiveDebuff) + ", B " + _fw_utils.FormatFloat_N1(effectiveBuff)) ii = ixStart While ii < ixEnd _fw_utils.Info(" #### " + ii + " => " + modifierValues[ii] + " ## " + modifierValues[ii+1]) ii += 2 EndWhile EndIf EndFunction Float Function Interpolate(Float from, Float to, Float value) ; If player sets zero range, then we're always clamped above or below, but we can't tell the direction (so assume ascending) If to == from If value < from Return 0.0 Else Return 1.0 EndIF EndIf Float p =(value - from) / (to - from) If p < 0.0 p = 0.0 ElseIf p > 1.0 p = 1.0 EndIf Return p EndFunction ; Calculate the overall currentModifiers from xxxxModifiers - collapses all the different inputs down to a single set. Function CombineModifiers() ; Add up the new modifiers Int ii = ixStart If mmePresent && (mmeEnabled[0] || mmeEnabled[1] || mmeEnabled[2]) ;_fw_utils.Info("FWB update modifers from " + ixStart + " to " + ixEnd + " with MME values included") While ii <= ixEnd currentModifiers[ii] = breastModifiers[ii] + bellyModifiers[ii] + buttModifiers[ii] + bodyModifiers[ii] \ + slaArousalModifiers[ii] + slaDenialModifiers[ii] + slaRapedModifiers[ii] + slaAddictionModifiers[ii] \ + mmeMilkModifiers[ii] + mmeBreastPercentModifiers[ii] + mmePainPercentModifiers[ii] ii += 1 EndWhile Else ; ELSE NOT A BUG - notice that SLA is also processed above - this avoids double loop traversal. ; Always add in SLA, because it's almost certainly present... MME is a bit more situational. ;_fw_utils.Info("FWB update modifers from " + ixStart + " to " + ixEnd + " without MME") While ii <= ixEnd currentModifiers[ii] = breastModifiers[ii] + bellyModifiers[ii] + buttModifiers[ii] + bodyModifiers[ii] \ + slaArousalModifiers[ii] + slaDenialModifiers[ii] + slaRapedModifiers[ii] + slaAddictionModifiers[ii] ii += 1 EndWhile EndIf If wntPresent && (wntEnabled[0] || wntEnabled[1] || wntEnabled[2] || wntEnabled[3] || wntEnabled[4] || wntEnabled[5]) ii = ixStart While ii <= ixEnd ; You'd think I could use += but NO, Papyrus is too broken currentModifiers[ii] = currentModifiers[ii] + wntAbuseModifiers[ii] + wntCreatureModifiers[ii] + wntDaedricModifiers[ii] \ + wntVaginalModifiers[ii] + wntAnalModifiers[ii] + wntOralModifiers[ii] ii += 1 EndWhile EndIf If InDebug() ii = ixStart _fw_utils.Info("FWB - CombineModifiers - recalculate currentModifiers[]") While ii <= ixEnd _fw_utils.Info(" [" + ii + "] " + currentModifiers[ii]) ii += 1 EndWhile EndIf EndFunction ; Applies master slider and clamps to limits. currentModifiers => effectValues. Function EffectValuesFromModifiers() ;Debug.Notification(ModName + " Master: D " + _fw_utils.FormatFloat_N0(masterDebuff) + ", B " + _fw_utils.FormatFloat_N0(masterBuff) ) ; Collpase the pairs, clean up index base and clamp ; Ultimate product of this is the effectValues array. Int mm = 0 ; Effect index Int ii = ixStart ; Intention index While mm < effectCount ;_fw_utils.Info("FWB update effect (counts: " + oldEffectValues.Length + " " + effectValues.Length + " " + currentModifiers.Length \ ; + " " + clampLower.Length + " " +clampUpper.Length + ") index " + mm) ;_fw_utils.Info("FWB from " + oldEffectValues[mm] + " to " + effectValues[mm]) ;_fw_utils.Info("FWB clampLower / clampUpper " + clampLower[mm] + " / " + clampUpper[mm] + " input " + value) oldEffectValues[mm] = effectValues[mm] Float value = 0.01 * ((masterDebuff * currentModifiers[ii]) + (masterBuff * currentModifiers[ii + 1])) ; Clamping If value < clampLower[mm] value = clampLower[mm] ElseIf value > clampUpper[mm] value = clampUpper[mm] EndIf effectValues[mm] = value ;_fw_utils.Info("FWB update effect value " + mm + " clamped to " + value) ii += 2 mm += 1 EndWhile ; Store the final effectValues for debugging StorageUtil.FloatListCopy(mcm, keyEffectValues, effectValues) ;_fw_utils.Info("FWB stored effect values to " + keyEffectValues) If InDebug() _fw_utils.Info("FWB - EffectValuesFromModifiers - combine and limit final effects scale list") mm = 0 While mm < effectCount _fw_utils.Info(" [" + mm + "] " + effectValues[mm]) mm += 1 EndWhile EndIf EndFunction ; Transform each effectValue into the correct domain for its final application Function UpdateEffects() ; Check all effects are in place as intended. ;Debug.Notification(ModName + " Update Effects") ; Convert effect values into integers _fw_utils.Info("FWB UPDATE EFFECTS") Float updateInterval = StorageUtil.GetFloatValue(None, updateIntervalKey, defaultUpdateInterval) ; Force updates on carryWeight if its base value has changed If playerStates[ixCarryWeight] != oldPlayerStates[ixCarryWeight] currentEffectValues[ixCarryWeight] = 1 + (effectValues[ixCarryWeight] as Int) EndIf Int ii = effectValues.Length While ii ii -= 1 Float value = effectValues[ii] ; We don't actually USE the int value to set the effect, it's just used to prevent updating on tiny deltas. Int processedEffectValue = value as Int If configurationChanged || processedEffectValue != currentEffectValues[ii] currentEffectValues[ii] = processedEffectValue Int effectType = effectTypes[ii] If 0 == effectType ; Straight percentage effect UpdateSingleModifier(ii, value, 0.5) ElseIf 1 == effectType ; This is no longer used for attack or bow speed, because they need to SetAV to work around Skyrim bugs. ; This is used for Magicka, Health, Stamina REGENERATION rates, because we can't be sure that some rude mod hasn't set the base value to something silly. If value < 0.0 value *= effectScalesDown[ii] Else value *= effectScalesUp[ii] EndIf UpdateSingleModifier(ii, value, 0.01) ElseIf 2 == effectType ; Base scaled Percentage effect. e.g. carry weight = 50% * current-base = +150 weight bonus ; Currently, carry weight is the only item using this type Float baseValue = playerStates[ixCarryWeight] UpdateSingleModifier(ii, value * baseValue * 0.01, 0.5) ElseIf 3 == effectType ; Various custom effect processing steps ; Movement speed - currently uses vanilla percentage ; For chances, a limit of 1,000 means the chance is at most 1,000 * 3 / 60 ; = 50% at interval 3 secs, or 100% at intervals of 6 secs or over ; TODO: replace simplistic chance per interval with a tracked random deviance from expected rate. If ii == exMoveSpeed UpdateSingleModifier(ii, value, 0.5) ElseIf ii == exStumble stumbleChance = -value * updateInterval / 60.0 stumbleChance_x100 = (stumbleChance * 100.0) as Int _fw_utils.Info("FWB - recalc stumble - " + value + " => " + stumbleChance_x100) ElseIf ii == exBleedout bleedoutChance = -value * updateInterval / 60.0 bleedoutChance_x100 = (bleedoutChance * 100.0) as Int _fw_utils.Info("FWB - recalc trip - " + value + " => " + bleedoutChance_x100) ElseIf ii == exFall fallChance = -value * updateInterval / 60.0 fallChance_x100 = (fallChance * 100.0) as Int _fw_utils.Info("FWB - recalc fall - " + value + " => " + fallChance_x100) ElseIf ii == exDrop dropChance = -value * updateInterval / 60.0 dropChance_x100 = (dropChance * 100.0) as Int _fw_utils.Info("FWB - recalc drop - " + value + " => " + dropChance_x100) ElseIf ii == exMasturbate masturbateChance = -value * updateInterval / 60.0 masturbateChance_x100 = (masturbateChance * 100.0) as Int _fw_utils.Info("FWB - recalc mast - " + value + " => " + masturbateChance_x100) ElseIf ii == exRape rapeChance = -value * updateInterval / 60.0 rapeChance_x100 = (rapeChance * 100.0) as Int _fw_utils.Info("FWB - recalc rape - " + value + " => " + masturbateChance_x100) EndIf ElseIf 4 == effectType If ii == exVisionBlur ismStrengths[0] = value ElseIf ii == exVisionTunnel ismStrengths[1] = value ElseIf ii == exVisionDouble ismStrengths[2] = value ElseIf ii == exVisionVibrant ismStrengths[3] = value EndIf StorageUtil.FloatListCopy(mcm, keyIsmStrengths, ismStrengths) If StorageUtil.GetIntValue(None, keyVisualEffectsEnabled) AddSimpleSpell(visualEffectsSpell) EndIf ElseIf 5 == effectType _fw_utils.Info("FWB - AV value for " + ii + " at " + value) If StorageUtil.GetIntValue(None, keyEnableAttackSpeed, 1) _fw_utils.Info("FWB - UpdateEffects - attack speed changes enabled") If value < 0.0 value *= effectScalesDown[ii] Else value *= effectScalesUp[ii] EndIf value += 1.0 _fw_utils.Info("FWB - UpdateEffects - calculated value for " + ii + " is " + value) If ii == exAttackSpeed _fw_utils.Info("FWB - UpdateEffects - Set weapon speeds to " + value) ; Set left and right weapons... player.SetActorValue("WeaponSpeedMult", value) player.SetActorValue("LeftWeaponSpeedMult", value) ElseIf ii == exBowSpeed _fw_utils.Info("FWB - UpdateEffects - Set bow speed to " + value) ; Set bow speed modifier (slowdown from aiming perk) player.SetActorValue("BowSpeedBonus", value) EndIf weaponSpeedsModified = True Else _fw_utils.Info("FWB - UpdateEffects - attack speed changes disabled") If weaponSpeedsModified _fw_utils.Info("FWB - UpdateEffects - attack speed changes disabled - restore defaults") weaponSpeedsModified = False ; Restore defaults... Hopefully. player.SetActorValue("WeaponSpeedMult", 1.0) player.SetActorValue("LeftWeaponSpeedMult", 1.0) player.SetActorValue("BowSpeedBonus", 1.0) EndIf EndIf EndIf EndIf EndWhile StorageUtil.IntListCopy(mcm, keyCurrentEffectValues, currentEffectValues) EndFunction Function UpdateSingleModifier(Int ii, Float value, Float zeroThreshold) ;Debug.Notification(ModName + " Update " + ii + " to " + _fw_utils.FormatFloat_N1(value)) ; Update the effect Spell debuff = spellsDown[ii] Spell buff = spellsUp[ii] If value > zeroThreshold ; Buff RemoveSpell(debuff) If buff != dummySpell RefreshScaledSpell(buff, value) EndIf ElseIf value < -zeroThreshold ; Debuff RemoveSpell(buff) If debuff != dummySpell RefreshScaledSpell(debuff, -value) EndIf Else RemoveSpell(buff) RemoveSpell(debuff) EndIf EndFunction Function ResetSpells() _fw_utils.Info("FWB - ResetSpells - begin") Int ii = spellsDown.Length While ii ii -= 1 RemoveSpell(spellsDown[ii]) EndWhile ii = spellsUp.Length While ii ii -= 1 RemoveSpell(spellsUp[ii]) EndWhile ii = currentEffectValues.Length While ii ii -= 1 currentEffectValues[ii] = 0 effectValues[ii] = 0.0 EndWhile _fw_utils.Info("FWB - ResetSpells - end") EndFunction ; This works with abilities Function RefreshScaledSpell(Spell singleEffectSpell, Float magnitude) _fw_utils.Info("FWB - RefreshScaledSpell " + singleEffectSpell.GetName() + " at " + magnitude) If Player.HasSpell(singleEffectSpell) _fw_utils.Info("FWB - RefreshScaleSpell - spell already present, remove") Player.RemoveSpell(singleEffectSpell) EndIf If magnitude _fw_utils.Info("FWB - RefreshScaleSpell - add and set spell magnitude") singleEffectSpell.SetNthEffectMagnitude(0, magnitude) Player.AddSpell(singleEffectSpell, false) EndIf EndFunction Function RefreshFormListSpells(FormList spellList, Float magnitude) Int ii = spellList.GetSize() While ii ii -= 1 Spell targetSpell = spellList.GetAt(ii) as Spell RefreshScaledSpell(targetSpell, magnitude) EndWhile EndFunction ; Works with abilities Function RemoveSpell(Spell targetSpell) If Player.HasSpell(targetSpell) _fw_utils.Info("FWB - RemoveSpell " + targetSpell.GetName()) Player.RemoveSpell(targetSpell) EndIf EndFunction Function AddSimpleSpell(Spell targetSpell) If !Player.HasSpell(targetSpell) _fw_utils.Info("FWB - AddSimpleSpell " + targetSpell.GetName()) Player.AddSpell(targetSpell, false) EndIf EndFunction ; TODO - MCM options for random timing scales, in combat and out of combat Function CheckAndTriggerEvents() ; Only stumble, fall, or drop things when we run with scissors or sneak. ; Mutex blocks all events, including falls, weapons, etc. Int threadEventMutex = StorageUtil.GetIntValue(None, keyThreadEventMutex) Bool notInMenu = !Utility.IsInMenuMode() && !UI.IsMenuOpen("Dialogue Menu") _fw_utils.Info("FWB - CheckAndTriggerEvents - mutex: " + threadEventMutex + ", notInMenu: " + notInMenu) _fw_utils.Info(" Health info: " + _fw_utils.DumpActorValue(player, "Health")) _fw_utils.Info(" Stamina info: " + _fw_utils.DumpActorValue(player, "Stamina")) If threadEventMutex <= 0 && notInMenu Float timeNow = Utility.GetCurrentRealTime() Bool inCombat = player.IsInCombat() _fw_utils.Info("FWB - CheckAndTriggerEvents - inCombat: " + inCombat + ", timeNow: " + timeNow + ", sexEventCooldownExpire: " + sexEventCooldownExpire + ", wobbleEventCooldownExpired: " + wobbleEventCooldownExpired) If timeNow > sexEventCooldownExpire If !inCombat && (masturbateChance_x100 > 0 || rapeChance_x100 > 0) Int maxRandom = 10000 ; TO-DO - Maybe add this via MCM later ... Supposed to be per-minute (real time). ; Consider rape, then masturbate first. If either of these happens, don't check for trips, falls, drops, etc. ; Let sneaking block masturbate, so the player has -some- control over it. Bool isSneaking = player.IsSneaking() _fw_utils.Info("FWB - check masturbate - sneaking " + isSneaking + " - chance " + masturbateChance_x100) If masturbateChance_x100 > 0 && !isSneaking Int randomValue = Utility.RandomInt(0, maxRandom) If randomValue < masturbateChance_x100 ; This is a costly check, so trying to avoid it until no alternative. If !IsAnimating(player) _fw_utils.Info("FWB - trigger StartMasturbate") StartMasturbate(timeNow) EndIf Return EndIf EndIf _fw_utils.Info("FWB - pre-rape check - chance " + rapeChance_x100) If rapeChance_x100 > 0 && IsRapeAllowed() Int randomValue = Utility.RandomInt(0, maxRandom) _fw_utils.Info("FWB - rape random " + randomValue + " out of " + maxRandom) If randomValue < rapeChance_x100 ; IsAnimating is a costly check, so trying to avoid it until no alternative. IsBrawlHazard isn't so cheap either. If !IsBrawlHazard() && !IsAnimating(player) _fw_utils.Info("FWB - trigger StartRape") StartRape(timeNow) Else _fw_utils.Info("FWB - rape abandoned due to animating or brawl risk") EndIf Return EndIf EndIf EndIf EndIf ; These events can happen IN combat, but the chance varies according to player preference. If timeNow > wobbleEventCooldownExpired If player.IsRunning() || player.IsSprinting() || player.IsSneaking() Float combatScale = StorageUtil.GetFloatValue(mcm, keyCombatEventScale, 4.0) Float sprintScale = StorageUtil.GetFloatValue(mcm, keySprintEventScale, 1.0) _fw_utils.Info("FWB - check wobble events: stumble " + stumbleChance_x100 + ", bleedout " + bleedoutChance_x100 + ", fall " + fallChance_x100 + ", combatScale " + combatScale + ", sprintScale " + sprintScale) If stumbleChance_x100 > 0 || bleedoutChance_x100 > 0 || fallChance_x100 > 0 || dropChance_x100 > 0 ; Only check if something else isn't happening (this check is quite costly) If !IsAnimating(player) Bool didSomething = False Int maxRandom = 10000 ; TO-DO - Maybe add this via MCM later ... If inCombat maxRandom = ((maxRandom as Float) / combatScale) as Int ; chance increased to per 15 seconds - TO-DO - add scale up to MCM. EndIf If player.IsSprinting() maxRandom = ((maxRandom as Float) / sprintScale) as Int EndIf ; Test most severe events first, they block trivial events if they occur. If fallChance_x100 > 0 Int randomValue = Utility.RandomInt(0, maxRandom) If randomValue < fallChance_x100 _fw_utils.Info("FWB - trigger ApplyFall") ApplyFall() Int checkForRape = Utility.RandomInt(0, maxRandom) If checkForRape <= fallRapeChance_x100 _fw_utils.Info("FWB - trigger StartRape from fall with " + checkForRape + " out of " + maxRandom + " with chance " + fallRapeChance_x100) StartRape(timeNow) EndIf didSomething = True; ; drop is a certainty maxRandom = 0 EndIf EndIf If bleedoutChance_x100 > 0 && !didSomething Int randomValue = Utility.RandomInt(0, maxRandom) If randomValue < bleedoutChance_x100 _fw_utils.Info("FWB - trigger ApplyBleedout") ApplyBleedout() Int checkForRape = Utility.RandomInt(0, maxRandom) If checkForRape <= tripRapeChance_x100 _fw_utils.Info("FWB - trigger StartRape from bleedout with " + checkForRape + " out of " + maxRandom + " with chance " + tripRapeChance_x100) StartRape(timeNow) EndIf didSomething = True maxRandom /= 10 ; Chance of concurrent drop increased. EndIf EndIf If stumbleChance_x100 > 0 && !didSomething ; Stumble Int randomValue = Utility.RandomInt(0, maxRandom) If randomValue < stumbleChance_x100 ;Debug.Notification(ModName + " Stumble") _fw_utils.Info("FWB - trigger ApplyStumble") ApplyStumble() didSomething = True maxRandom /= 4 ; Chance of concurrent drop increased EndIf EndIf ; Drop weapons - only when already drawn If dropChance_x100 > 0 && player.IsWeaponDrawn() Int randomValue = Utility.RandomInt(0, maxRandom) If randomValue < dropChance_x100 Bool dropBoth = randomValue*2 < dropChance_x100 _fw_utils.Info("FWB - trigger DropWeapons - both: " + dropBoth) DropWeapons(dropBoth) ; half the time, drop both If !didSomething _fw_utils.Info("FWB - trigger ApplyStumble to hint at weapon drop") ApplyStumble() ; Visual cue that something happened. EndIf EndIf EndIf If didSomething If inCombat _fw_utils.Info("FWB - events - did SOMETHING in combat") wobbleEventCooldownExpired = timeNow + wobbleEventCooldownSecondsForCombat Else _fw_utils.Info("FWB - events - did SOMETHING out of combat") wobbleEventCooldownExpired = timeNow + wobbleEventCooldownSeconds EndIf EndIf EndIf EndIf EndIf EndIf EndIf _fw_utils.Info("FWB - CheckAndTriggerEvents - DONE") _fw_utils.Info(" Health info: " + _fw_utils.DumpActorValue(player, "Health")) _fw_utils.Info(" Stamina info: " + _fw_utils.DumpActorValue(player, "Stamina")) EndFunction ; This applies a Spell, not an ability Function ApplyStumble() If StorageUtil.GetIntValue(None, keyUseInternalAnimations) && animStaggerEffectSpell animStaggerEffectSpell.Cast(player) Else Spell stumbleSpell = spellsDown[exStumble] stumbleSpell.Cast(player) EndIf DamageActorValueByIndex(exStamina, keyStumbleStamina, false) ;Debug.Notification(ModName + " Stumble " + stumbleSpell.GetName()) EndFunction ; Also spell, not ability based. Function ApplyBleedout() Spell bleedoutSpell = spellsDown[exBleedout] bleedoutSpell.Cast(player) DamageActorValueByIndex(exStamina, keyTripStamina, false) ;Debug.Notification(ModName + " Cast bleedout - " + bleedoutSpell.GetName()) EndFunction ; Spell based Function ApplyFall() Spell fallSpell = spellsDown[exFall] fallSpell.Cast(player) DamageActorValueByIndex(exStamina, keyFallStamina, false) DamageActorValueByIndex(exHealth, keyFallHealth, true) EndFunction ; Modifies AV directly. Function DamageActorValueByIndex(Int index, String keyName, Bool makeSafe) ; Percentage isn't a percentage, it's 0.0 to 1.0 String valueName = avNames[index] Float percentageLoss = StorageUtil.GetFloatValue(mcm, keyName) Float currentValue = player.GetAV(valueName) Float loss = currentValue * percentageLoss * 0.01 _fw_utils.Info("FWB - DamageActorValueByIndex [" + index + "] (" + valueName + "), key = " + keyName + ", safe = " + makeSafe + ", by " + percentageLoss + "%, currently " + currentValue + " => " + loss) _fw_utils.Info(" Stat info: " + _fw_utils.DumpActorValue(player, valueName)) If makeSafe && (currentValue - loss) < 1.0 _fw_utils.Info("FWB - DamageActorValueByIndex - bottomed out - skipped") Return EndIf If loss >= 1.0 _fw_utils.Info("FWB - DamageActorValueByIndex - DO " + loss + " DAMAGE to " + valueName ) player.DamageAV(valueName, loss) EndIf EndFunction ; Casts a spell that does the hard work. Function DropWeapons(Bool dropBoth) If dropBoth Spell dropWeaponsSpell = spellsDown[exDrop] dropWeaponsSpell.Cast(player) Else Spell dropWeaponSpell = spellsUp[exDrop] dropWeaponSpell.Cast(player) EndIf ; The deviously helpless weapon-drop mod event dhlp-weapondrop isn't just a notification, it's a request to DHLP to drop the weapons. ; It runs weapon drop code in response. ; As SLD can drop weapons on its own, just fine, instead of sending the event, we should be able to respond to it. ; This would allow FHU (or other mods) to drop weapons via SLD. ; Will look into it when FHU support goes in. ; See WD_Util (line 1243) in DHLP, and sr_inflateQuest (line 239) in FHU. ; I have NO CLUE why DHLP decided to base drop chance on 100 - Magicka ... won't be emulating that, or will at least be optional. endFunction ; Deprecated - for testing only Bool Function DropHand(Int hand) ; Returns true if you might need to drop the other hand. Bool dropAgain = True Int handType = player.GetEquippedItemType(hand) If handType If 9 == handType ; Spell UnequipSpell(hand) ElseIf 10 == handType ; Shield DropOrUnequipShield() ElseIf (handType >= 5 && handType < 9) || 12 == handType ; 2H DropOrUnequip2H() dropAgain = False Else ; 1H DropOrUnequip1H(hand) EndIf EndIf Return dropAgain EndFunction ; Deprecated - for testing only - removes an equipped spell "weapon" Function UnequipSpell(Int hand) Spell equippedSpell = player.GetEquippedSpell(hand) If equippedSpell player.UnequipSpell(equippedSpell, hand) Debug.Notification("You lose focus on your " + equippedSpell.GetName() + " spell") EndIf EndFunction ; TODO - UnequipItem can destroy charges if game doesn't have the fix for it? Test this. Function DropOrUnequipShield() Armor equippedShield = player.GetEquippedShield() If equippedShield player.UnequipItem(equippedShield, abPreventEquip = False, abSilent = True) Debug.Notification("You lose grip on your shield") EndIf EndFunction Function DropOrUnequip1H(Int hand) Weapon equipped = player.GetEquippedWeapon(0 == hand) ; true = left hand If equipped player.UnequipItem(equipped, abPreventEquip = False, abSilent = True) Debug.Notification("Your weapon slips from your hand") EndIf EndFunction Function DropOrUnequip2H() Weapon equipped = player.GetEquippedWeapon() If equipped player.UnequipItem(equipped, abPreventEquip = False, abSilent = True) Debug.Notification("Your weapon slips out of your hands") EndIf EndFunction Function StartMasturbate(Float timeNow) If timeNow > sexEventCooldownExpire If StorageUtil.GetIntValue(None, keyThreadEventMutex) <= 0 ; Cooldown should allow enough time to block additional events occuring before sex starts and we're 'animating'. sexEventCooldownExpire = timeNow + sexEventCooldownSeconds _fw_utils.Info("FWB - StartMasturbate origin") _fwb_sexwrap.StartMasturbate(GetSexLabQuest(), player) Else _fw_utils.Info("FWB - StartMasturbate blocked by mutex") EndIf Else _fw_utils.Info("FWB - StartMasturbate blocked by cooldown") EndIf EndFunction Function StartRape(Float timeNow) If timeNow > sexEventCooldownExpire If StorageUtil.GetIntValue(None, keyThreadEventMutex) <= 0 ; Cooldown should allow enough time to block additional events occuring before sex starts and we're 'animating'. sexEventCooldownExpire = timeNow + sexEventCooldownSeconds _fw_utils.Info("FWB - StartRape origin") _fwb_sexwrap.StartRape(GetSexLabQuest(), player) Else _fw_utils.Info("FWB - StartRape blocked by mutex") EndIf Else _fw_utils.Info("FWB - StartRape blocked by cooldown") EndIf EndFunction Function StartOrgy() Float timeNow = Utility.GetCurrentRealTime() If timeNow > sexEventCooldownExpire If StorageUtil.GetIntValue(None, keyThreadEventMutex) <= 0 ; Cooldown should allow enough time to block additional events occuring before sex starts and we're 'animating'. sexEventCooldownExpire = timeNow + sexEventCooldownSeconds _fw_utils.Info("FWB - StartOrgy origin") _fwb_sexwrap.StartOrgy(GetSexLabQuest(), player) Else _fw_utils.Info("FWB - StartOrgy blocked by mutex") EndIf Else _fw_utils.Info("FWB - StartMasturbate blocked by cooldown") EndIf EndFunction Event OnSexSceneEnd(Int slotNumber, String actType) ; Bump out cooldown, so we get that much time before another rape - as this could easily have taken longer than cooldown... Float timeNow = Utility.GetCurrentRealTime() sexEventCooldownExpire = timeNow + sexEventCooldownSeconds _fw_utils.Info("FWB got OnSexSceneEnd in modifiers, for slot " + slotNumber) String actName = actType If "solo" == actType actName = "- " + StorageUtil.GetStringValue(player, "fwb_soloLastAnimationPlayed") ElseIf "rape" == actType actName = "- " + StorageUtil.GetStringValue(player, "fwb_rapeLastAnimationPlayed") EndIf EndEvent Quest Function GetSexLabQuest() If !fwb_sexlab.IsRunning() fwb_sexlab.Start() EndIf Return fwb_sexlab EndFunction Event OnDeviousSuspend(string eventName, string strArg, float numArg, Form sender) _fw_utils.Info("FWB - received dhlp-Suspend event") StorageUtil.AdjustIntValue(None, keyThreadEventMutex, 1) EndEvent Event OnDeviousResume(string eventName, string strArg, float numArg, Form sender) _fw_utils.Info("FWB - received dhlp-Resume event") StorageUtil.AdjustIntValue(None, keyThreadEventMutex, -1) EndEvent Bool Function IsAnimating(Actor who) If !who.Is3DLoaded() || who.IsDisabled()|| who.IsOnMount() || who.IsSwimming() || who.GetSitState() || who.GetSleepState() \ || who.IsBleedingOut() || who.IsFlying() || who.IsInKillMove() || who.IsDead() || who.GetCurrentScene() Return True EndIf ; Check mutex here too, just in case it got set between earlier checks and this. Return _fwb_dd.InAnimatingFaction(who) || _fwb_sexwrap.InAnimatingFaction(who) || StorageUtil.GetIntValue(None, keyThreadEventMutex) > 0 EndFunction Bool Function IsPlayerHome() Location current = player.GetCurrentLocation() Return current && current.HasKeyword(playerHomeKeyword) EndFunction Bool Function IsLocationRapeExcluded() Location current = player.GetCurrentLocation() Return current && (current.HasKeyword(playerHomeKeyword) || current.HasKeyword(jailKeyword)) EndFunction ; Check for vanilla quest states that might be ruined by running rape code, particularly the cloak, which could cause a brawl bug. ; Return True is there is a hazard. Bool Function IsBrawlHazard() Quest dialogIntimidateQuest = Quest.GetQuest("DGIntimidateQuest") If dialogIntimidateQuest && dialogIntimidateQuest.IsRunning() Return True EndIf Quest companions = Quest.GetQuest("C00") If companions && companions.IsRunning() && 20 == companions.GetStage() Return True EndIf Quest favor17 = Quest.GetQuest("Favor17") If favor17 && favor17.IsRunning() Return True EndIf Quest riften19 = Quest.GetQuest("FreeformRiften19") If riften19 && riften19.IsRunning() && 30 == riften19.GetStage() Return True EndIf Return False EndFunction Bool Function IsRapeAllowed() Return _fwb_sexwrap.GetRapePossible() && !IsLocationRapeExcluded() && !player.IsWeaponDrawn() && !player.IsSneaking() EndFunction Function GetPlayerMorphValues() ; May need to push this out to another quest if it seems time consuming. If !_fwb_slif.GetNiMorphValues(player, morphNames, playerMorphValues) Int ii = playerMorphValues.Length While ii ii -= 1 playerMorphValues[ii] = 0.0 EndWhile EndIf EndFunction Function RecalculateMorphContributions() Int ii = playerMorphValues.Length While ii ii -= 1 Float value = (playerMorphValues[ii] * morphPrescales[ii] + morphOffsets[ii]) + 0.5 If value < 0.0 value = 0.0 ElseIf value > 1.0 value = 1.0 EndIf Float weight = morphWeights[ii] weightedMorphs[ii] = value * weight ;_fw_utils.Info("FWB - MorphContributions - " + value + " * " + weight + " => weightedMorph[" + ii + "] = " + weightedMorphs[ii]) EndWhile Float breastMorph = 0.0 Float breastWeightTotal ii = 8 While ii ii -= 1 breastMorph += weightedMorphs[ii] breastWeightTotal += morphWeights[ii] EndWhile Float bellyMorph = weightedMorphs[8] + weightedMorphs[9] + weightedMorphs[10] + weightedMorphs[11] Float bellyWeightTotal = morphWeights[8] + morphWeights[9] + morphWeights[10] + morphWeights[11] Float buttMorph = weightedMorphs[12] + weightedMorphs[13] + weightedMorphs[14] + weightedMorphs[15] + weightedMorphs[16] Float buttWeightTotal = morphWeights[12] + morphWeights[13] + morphWeights[14] + morphWeights[15] + morphWeights[16] ;_fw_utils.Info("FWB - MorphContributions - raw morph totals: breasts " + breastMorph + ", belly " + bellyMorph + ", butt " + buttMorph) morphNodeValues[0] = 1.0 morphNodeValues[1] = 1.0 morphNodeValues[2] = 1.0 ;_fw_utils.Info("FWB - MorphContributions - pre-scaled morph totals: breasts " + breastMorph + ", belly " + bellyMorph + ", butt " + buttMorph) If breastWeightTotal > 0.0 morphNodeValues[0] = (breastMorph / breastWeightTotal) * morphMasterScales[0] * 2.0 EndIf If bellyWeightTotal > 0.0 morphNodeValues[1] = (bellyMorph / bellyWeightTotal) * morphMasterScales[1] * 2.0 EndIf If buttWeightTotal > 0.0 morphNodeValues[2] = (buttMorph / buttWeightTotal) * morphMasterScales[2] * 2.0 EndIf StorageUtil.FloatListCopy(mcm, keyPlayerMorphValues, playerMorphValues) StorageUtil.FloatListCopy(mcm, keyMorphNodeValues, morphNodeValues) If "REPLACE" == morphMode playerStates[0] = 0.01 * (playerStates[0] * (100.0 - morphMasterWeights[0]) + morphNodeValues[0] * morphMasterWeights[0]) playerStates[1] = 0.01 * (playerStates[1] * (100.0 - morphMasterWeights[1]) + morphNodeValues[1] * morphMasterWeights[1]) playerStates[2] = 0.01 * (playerStates[2] * (100.0 - morphMasterWeights[2]) + morphNodeValues[2] * morphMasterWeights[2]) Else Float combinedBreast = playerStates[0] * morphNodeValues[0] Float combinedBelly = playerStates[1] * morphNodeValues[1] Float combinedButt = playerStates[2] * morphNodeValues[2] playerStates[0] = 0.01 * (playerStates[0] * (100.0 - morphMasterWeights[0]) + combinedBreast * morphMasterWeights[0]) playerStates[1] = 0.01 * (playerStates[1] * (100.0 - morphMasterWeights[1]) + combinedBelly * morphMasterWeights[1]) playerStates[2] = 0.01 * (playerStates[2] * (100.0 - morphMasterWeights[2]) + combinedButt * morphMasterWeights[2]) EndIf _fw_utils.Info("FWB - MorphMode is " + morphMode) _fw_utils.Info("FWB - MorphContributions - morph totals: breasts " + morphNodeValues[0] + ", belly " + morphNodeValues[1] + ", butt " + morphNodeValues[2]) _fw_utils.Info("FWB - MorphContributions - master weights: breasts " + morphMasterWeights[0] + ", belly " + morphMasterWeights[1] + ", butt " + morphMasterWeights[2]) _fw_utils.Info("FWB - MorphContributions - final values: breasts " + playerStates[0] + ", belly " + playerStates[1] + ", butt " + playerStates[2]) EndFunction Function ZeroArray(Float[] toZero) Int ii = toZero.Length While ii ii -= 1 toZero[ii] = 0.0 EndWhile EndFunction ; Only call this from Enabled state, as you can see below, does nothing in empty state. Function CheckForExternalMods() CheckForSlif(); Preferred pattern CheckForSLA() ; Weird pattern CheckForMME() CheckForApropos2() EndFunction Bool Function CheckForSlif() slifPresent = False Return False EndFunction Bool Function CheckForSLA() slaPresent = False Return False EndFunction Bool Function CheckForApropos2() wntPresent = False Return False EndFunction Bool Function CheckForMME() mmePresent = False Return False EndFunction Function HandleGameLoad() EndFunction Function ResetSLA() _fw_utils.Info("FWB - ResetSLA") ; Set these up even if we don't have SLA; it's just safer slaStates = new Float[4] oldSlaStates = new Float[4] slaPageNames = new String[4] slaPageNames[0] = "Arousal" slaPageNames[1] = "Denial" slaPageNames[2] = "Raped" slaPageNames[3] = "Addiction" ; So this will not be considered changed on the coming update. sexLabRapeCount = _fwb_sla.GetVictimCount(player) slaStates[slRaped] = 1000.0 ; This is days since last rape, so high value means set because we don't know how long it's been. oldSlaStates[slRaped] = 1000.0 StorageUtil.UnsetFloatValue(mcm, keyRapeTime) StorageUtil.UnsetFloatValue(mcm, keyRapeCount) EndFunction ; Unfortunately - retrieving SLA arousal or time-rate is potentially very expensive, with all kind of consequent calls bound into it. ; SLA doesn't cache the current value in storage util, which was a poor decision IMHO. ; Every mod that wants to get the value triggers a recalc, and the racalcs are costly, and may do all kinds of unexpected updates. ; For this reason amongst many others, SLA needs to go away. It may be better than its predecessor, but it's still not well behaved. ; In the next release, I want to split SLA updates out into another quest, but for now, I just have to suck it up and call into SLA directly. Function UpdateSlaValues() If slaPresent oldSlaStates[0] = slaStates[0] oldSlaStates[1] = slaStates[1] oldSlaStates[2] = slaStates[2] oldSlaStates[3] = slaStates[3] slaStates[slArousal] = _fwb_sla.GetArousal(player) slaStates[slDenial] = _fwb_sla.GetDaysSinceOrgasm(player) slaStates[slAddicted] = _fwb_sla.GetTimeRate(player) ; Rape value is more complex, as we have to track time. What we actually track is 'days since last known rape' Int newRapeCount = _fwb_sla.GetVictimCount(player) if newRapeCount != sexLabRapeCount sexLabRapeCount = newRapeCount StorageUtil.SetFloatValue(mcm, keyRapeCount, sexLabRapeCount) StorageUtil.SetFloatValue(mcm, keyRapeTime, Utility.GetCurrentGameTime()) slaStates[slRaped] = 0.0 Else slaStates[slRaped] = CalculateDaysSinceRape() EndIf EndIf EndFunction Float Function CalculateDaysSinceRape() Float lastRaped = StorageUtil.GetFloatValue(mcm, keyRapeTime, -1.0) If lastRaped < 0.0 Return 1000.0 EndIf Return Utility.GetCurrentGameTime() - lastRaped EndFunction Function UpdateAproposValues() if wntPresent oldWntStates[0] = wntStates[0] oldWntStates[1] = wntStates[1] oldWntStates[2] = wntStates[2] oldWntStates[3] = wntStates[3] oldWntStates[4] = wntStates[4] oldWntStates[5] = wntStates[5] ;_fw_utils.Info("FWB update w+t values: player " + player.GetName()) ;_fw_utils.Info("FWB update w+t values: wntStates: " + wntStates.Length) ;_fw_utils.Info("FWB update w+t values: OldWntStates: " + oldWntStates.Length) Bool ok = _fwb_apropos2.GetWearAndTear(player, wntStates) ; If this fails, sets all zeros, which is fine. _fw_utils.Info("FWB update w+t values: success " + ok) EndIf EndFunction Function UpdateMmeValues() If mmePresent oldMmeStates[0] = mmeStates[0] oldMmeStates[1] = mmeStates[1] oldMmeStates[2] = mmeStates[2] mmeStates[mmMilk] = _fwb_mme.GetMilk(player) Float mmeMilkMax = _fwb_mme.GetMilkMax(player) If mmeMilkMax < 1.0 mmeMilkMax = 1.0 EndIf mmeStates[mmBreastFull] = mmeStates[mmMilk] / mmeMilkMax Float mmePain = _fwb_mme.GetPain(player) Float mmePainMax = _fwb_mme.GetPainMax(player) If mmePainMax < 1.0 mmePainMax = 1.0 EndIf mmeStates[mmPain] = mmePain / mmePainMax EndIf EndFunction ; FOLDSTART - XMPSE Bool Function CheckXpmseRequirements(Actor akActor, bool isFemale) Return CheckXMPSE() && CheckSkeleton(akActor, isFemale) && CheckNioScripts() EndFunction ; So we can trace and diagnose a particular missing requirement if needed. Bool Function CheckXMPSE() Return XPMSELib.CheckXPMSELibVersion(XPMSELIB_VERSION) EndFunction Bool Function CheckSkeleton(Actor akActor, bool isFemale) Return XPMSELib.CheckXPMSEVersion(akActor, isFemale, XPMSE_VERSION, true) EndFunction Bool Function CheckNio() Return SKSE.GetPluginVersion("NiOverride") >= NIOVERRIDE_VERSION || SKSE.GetPluginVersion("SKEE") >= SKEE_VERSION EndFunction Bool Function CheckNioScripts() Return CheckNio() && NiOverride.GetScriptVersion() >= NIOVERRIDE_SCRIPT_VERSION EndFunction ; FOLDEND - XMPSE Function InitializeData() _fw_utils.Info("FWB - InitializeData 90 / 40") ; Node values, core base AVs, and carry-weight oldPlayerStates = new Float[5] playerStates = new Float[5] ismStrengths = new Float[4] currentModifiers = new Float[90] breastModifiers = new Float[90] bellyModifiers = new Float[90] buttModifiers = new Float[90] bodyModifiers = new Float[90] slaArousalModifiers = new Float[90] slaDenialModifiers = new Float[90] slaRapedModifiers = new Float[90] slaAddictionModifiers = new Float[90] ; We have to init values for SLA because they are ALWAYS used but aren't created unless SLA is present. slaArousalValues = new Float[90] slaDenialValues = new Float[90] slaRapedValues = new Float[90] slaAddictionValues = new Float[90] wntAbuseModifiers = new Float[90] wntCreatureModifiers = new Float[90] wntDaedricModifiers = new Float[90] wntVaginalModifiers = new Float[90] wntAnalModifiers = new Float[90] wntOralModifiers = new Float[90] mmeMilkModifiers = new Float[90] mmeBreastPercentModifiers = new Float[90] mmePainPercentModifiers = new Float[90] oldEffectValues = new Float[40] effectValues = new Float[40] currentEffectValues = new Int[40] effectTypes = new Int[40] effectScalesUp = new Float[40] effectScalesDown = new Float[40] avNames = new String[40] morphsEnabled = False morphMasterWeights = new Float[3] morphMasterScales = new Float[3] morphNodeValues = new Float[3] morphWeights = new Float[17] morphOffsets = new Float[17] morphPrescales = new Float[17] playerMorphValues = new Float[17] weightedMorphs = new Float[17] weaponSpeedsModified = False morphMasterScales[0] = 1.0 morphMasterScales[1] = 1.0 morphMasterScales[2] = 1.0 Int ii = morphPrescales.Length While ii ii -= 1 morphPrescales[ii] = 0.25 EndWhile Float invertScale = -0.25 morphPrescales[0] = invertScale ; Breasts INVERT -ve bigger morphPrescales[1] = invertScale ; BreastsSmall INVERT -ve bigger morphPrescales[6] = invertScale ; BreastFlatness INVERT -ve less flat morphPrescales[11] = invertScale ; TummyTuck INVERT -ve bigger morphPrescales[12] = invertScale ; Butt INVERT -ve bigger morphPrescales[13] = invertScale ; ButtSmall INVERT -ve bigger ; 0 = direct, 1 = fixed bi-scale, 2 base scale, 3 = movement effectTypes[exMagicka ] = 0 effectTypes[exMagickaRate] = 1 effectTypes[exHealth ] = 0 effectTypes[exHealthRate ] = 1 effectTypes[exStamina ] = 0 effectTypes[exStaminaRate] = 1 effectTypes[exMoveSpeed ] = 3 effectTypes[exCarryWeight] = 2 effectTypes[exMeleeDamage] = 0 ; maybe ??? effectTypes[exUnarmed ] = 0 ; maybe ??? effectTypes[exAttackSpeed] = 5 effectTypes[exBowSpeed ] = 5 effectTypes[exVisionBlur ] = 4 effectTypes[exVisionTunnel] = 4 effectTypes[exVisionDouble] = 4 effectTypes[exVisionVibrant] = 4 effectTypes[exStumble ] = 3 effectTypes[exBleedout ] = 3 effectTypes[exFall ] = 3 effectTypes[exDrop ] = 3 effectTypes[exMasturbate ] = 3 effectTypes[exRape ] = 3 ; Only needed for items with type 1 ; Allow magicka/heal/stamina to go UP to 10x normal rate Float recoveryMaxScale = 10.0 ; TO-DO - put this in the MCM effectScalesUp[exMagickaRate] = 0.03 * recoveryMaxScale ; Magicka Rate (base 3.0) effectScalesDown[exMagickaRate] = 0.03 ; Magicka Rate (base 3.0) effectScalesUp[exHealthRate ] = 0.007 * recoveryMaxScale ; Heal Rate (base 0.7) effectScalesDown[exHealthRate ] = 0.007 ; Heal Rate (base 0.7) effectScalesUp[exStaminaRate] = 0.05 * recoveryMaxScale ; Stamina Rate (base 5.0) effectScalesDown[exStaminaRate] = 0.05 ; Stamina Rate (base 5.0) ; Attack and bow speed are special because we set the AV directly rather than modifying it. The SetAV code has the magic +1.0 needed to make these come out right. effectScalesUp[exAttackSpeed] = 0.03 ; max of 4 effectScalesDown[exAttackSpeed] = 0.007 ; We want final value around 0.3 at -100, but we add one, so -0.7 is the target effectScalesUp[exBowSpeed ] = -0.001 ; 0.1 is "best" ... slowest bow - only slows time to 90% of normal, because the perk breaks otherwise. effectScalesDown[exBowSpeed ] = -0.005 ; Gives a final value of 1.5 at full debuff (-100) ; Bow speed determines the time scaling effect if you press the zoom in key while using a bow. ; The larger the number the faster time runs, which is WORSE for the player. The idea is the perk slows down time, by applying a scalar to time < 1.0 ; This has to be a very modest buff, otherwise the second grade perk breaks. Could detect the perk, but I'm reluctant to add more overhead to the calculation. ; These are used for GetAV - so most aren't used at all avNames[0] = "Magicka" avNames[1] = "MagickaRate" avNames[2] = "Health" avNames[3] = "HealRate" avNames[4] = "Stamina" avNames[5] = "StaminaRate" avNames[6] = "SpeedMult" avNames[7] = "CarryWeight" avNames[8] = "MeleeDamage" avNames[9] = "UnarmedDamage" avNames[10] = "WeaponSpeedMult" ; As we now handle this through direct AV set, also need to update LeftWeaponSpeedMult. This is done through hacky magic :( avNames[11] = "BowSpeedBonus" avNames[12] = "Marksman" avNames[13] = "OneHanded" avNames[14] = "TwoHanded" avNames[15] = "Block" avNames[16] = "HeavyArmor" avNames[17] = "LightArmor" avNames[18] = "Sneak" avNames[19] = "Lockpicking" avNames[20] = "Pickpocket" avNames[21] = "Speech" avNames[22] = "Alteration" avNames[23] = "Conjuration" avNames[24] = "Destruction" avNames[25] = "Illusion" avNames[26] = "Restoration" avNames[27] = "Enchanting" avNames[28] = "Alchemy" avNames[29] = "Smithing" ; Not AVs avNames[30] = "+Vision Blur" avNames[31] = "+Vision Tunnel" avNames[32] = "+Vision Double" avNames[33] = "+Vision Vibrant" avNames[34] = "+Stagger" avNames[35] = "+Bleedout" avNames[36] = "+Fall" avNames[37] = "+DropWeapon" avNames[38] = "+Masturbate" avNames[39] = "+Rape" ; Limits clampLower = StorageUtil.FloatListToArray(mcm, keyLimitValuesLo) clampUpper = StorageUtil.FloatListToArray(mcm, keyLimitValuesHi) _fw_utils.Info("FWB - InitializeData complete") EndFunction Function BuildSpellLists() _fw_utils.Info("FWB BuildSpellLists") spellsDown = new Spell[38] spellsUp = new Spell[38] Int ii = spellDebuffs.Length While ii ii -= 1 _fw_utils.Info("FWB Building spell list - copy debuff " + ii + " " + spellDebuffs[ii].GetName()) spellsDown[ii] = spellDebuffs[ii] spellsUp[ii] = spellBuffs[ii] EndWhile ii = spellBuffs_U13.Length While ii ii -= 1 spellsDown[exStumble + ii] = spellDebuffs_U13[ii] spellsUp[exStumble + ii] = spellDebuffs_U13[ii] EndWhile EndFunction Function InitializeQuasiConstants() _fw_utils.Info("FWB InitializeQuasiConstants") defaultUpdateInterval = 11.0 ixBreast = 0 ixBelly = 1 ixButt = 2 ixBody = 3 ixCarryWeight = 4 ; SLA slArousal = 0 slDenial = 1 slRaped = 2 slAddicted = 3 ; APROPOS wtAbuse = 0 ; I put this first, as it's the global measure, and you can set up W&T effects with only this one and catch everything in a lazy way. wtCreature = 1 wtDaedric = 2 wtVaginal = 3 wtAnal = 4 wtOral = 5 ; MME mmMilk = 0 mmBreastFull = 1 mmPain = 2 ; Master values masterDebuff = 100.0 masterBuff = 100.0 ; Indices ixDebuffMax = 0 ixDebuffFrom = 2 ixDebuffTo = 4 ixBuffMax = 1 ixBuffFrom = 3 ixBuffTo = 5 ixStart = 10 ixEnd = 89 ; Effect indices effectCount = 40 exMagicka = 0 exMagickaRate = 1 exHealth = 2 exHealthRate = 3 exStamina = 4 exStaminaRate = 5 exMoveSpeed = 6 exCarryWeight = 7 exMeleeDamage = 8 exUnarmed = 9 exAttackSpeed = 10 exBowSpeed = 11 exArchery = 12 exOneHanded = 13 exTwoHanded = 14 exBlock = 15 exHeavyArmor = 16 exLightArmor = 17 exSneak = 18 exLockpicking = 19 exPickpocket = 20 exSpeech = 21 exAlteration = 22 exConjuration = 23 exDestruction = 24 exIllusion = 25 exRestoration = 26 exEnchanting = 27 exAlchemy = 28 exSmithing = 29 exVisionBlur = 30 exVisionTunnel = 31 exVisionDouble = 32 exVisionVibrant = 33 exStumble = 34 exBleedout = 35 exFall = 36 exDrop = 37 exMasturbate = 38 exRape = 39 BuildSpellLists() EndFunction Bool Function ResetInternal() _fw_utils.Info("FWB - ResetInternal") InitializeQuasiConstants() mmePresent = False player = Game.GetPlayer() ReadConfigurationValues(True) configurationChanged = True ; Note that this check doesn't demand that the PC is female. ; Though the PC *should* be female, this is just checking the library and skeleton version. If !CheckXpmseRequirements(player, _fw_utils.IsFemale(player)) _fw_utils.Info("FWB ResetInternal failed due to XMPSE requirements not met") Debug.MessageBox("Stale/missing/wrong XMPSE/NiOverride skeleton or libraries. Cannot start.") StopMod() Return False EndIf InitializeData() ResetSpells() ; If these aren't False, then soft-dep arrays might not get created. slifPresent = False slaPresent = False wntPresent = False mmePresent = False ; Even if we don't have SLA; it's just safer ; - SLA is an oddity in how it's processed, don't replicate this pattern, replicate the CheckForMME pattern. ResetSLA() ; No point checking for mod presence here, as we won't be enabled. RegisterEventListeners() Return True EndFunction Function RegisterEventListeners() _fw_utils.Info("FWB modifiers - Register Event Listeners") RegisterForModEvent("_fwb_SexSceneEnd", "OnSexSceneEnd") RegisterForModEvent("dhlp-Suspend", "OnDeviousSuspend") RegisterForModEvent("dhlp-Resume", "OnDeviousResume") EndFunction Bool Function InDebug() Return False EndFunction _fwb_dd.psc Spoiler Scriptname _fwb_dd Hidden {Interfaces with Zad Devious Devices functions in a safe way.} ; This returns a Float for DD reasons. Version 4.2 is version 10. Float Function GetDeviousVersion() Global String ddFile = "Devious Devices - Integration.esm" Int questId = 0x0000F624 Int ddIndex = Game.GetModByName(ddFile) If 255 != ddIndex zadLibs ddLibs = Game.GetFormFromFile(questId, ddFile) As zadLibs If ddLibs Return ddLibs.GetVersion() EndIf EndIf Return -1.0 EndFunction ; This returns a string for display, but it may not be updated reliably? String Function GetDeviousVersionString() Global String ddFile = "Devious Devices - Integration.esm" Int questId = 0x0000F624 Int ddIndex = Game.GetModByName(ddFile) If 255 != ddIndex zadLibs ddLibs = Game.GetFormFromFile(questId, ddFile) As zadLibs If ddLibs Return ddLibs.GetVersionString() EndIf EndIf Return "NOT FOUND" EndFunction ; Makes the player fall over in a device animation respectful way. ; Returns False if Trip could not be called. Bool Function Trip(Actor who) Global String ddFile = "Devious Devices - Integration.esm" Int questId = 0x0000F624 Int ddIndex = Game.GetModByName(ddFile) If 255 != ddIndex zadLibs ddLibs = Game.GetFormFromFile(questId, ddFile) As zadLibs If ddLibs If ddLibs.GetVersion() >= 7.0 ddLibs.Trip(who) Return True EndIf EndIf EndIf Return False EndFunction ; True if the actor is wearing heavy bondage items - checks the worn keyword Bool Function HasHeavyBondage(Actor who) Global String ddFile = "Devious Devices - Integration.esm" Int keywordId = 0x0005226C Int ddIndex = Game.GetModByName(ddFile) If 255 != ddIndex Keyword heavyBondage = Game.GetFormFromFile(keywordId, ddFile) as Keyword _fw_utils.Info("FWB_DD - HasHeavyBondage - actor is '" + who.GetActorBase().GetName() + "' and keyword is: " + heavyBondage) If heavyBondage Return who.WornHasKeyword(heavyBondage) EndIf EndIf Return False EndFunction ; True if the actor is wearing a blindfold. Bool Function HasBlindfold(Actor who) Global String asFile = "Devious Devices - Assets.esm" Int deviousBlindfoldId = 0x00011B1A Int asIndex = Game.GetModByName(asFile) If 255 != asIndex Keyword blindfold = Game.GetFormFromFile(deviousBlindfoldId, asFile) as Keyword If blindfold Return who.WornHasKeyword(blindfold) EndIf EndIf Return False EndFunction ; True if the actor is wearing any kind of gag. Bool Function HasGag(Actor who) Global String asFile = "Devious Devices - Assets.esm" Int deviousGagId = 0x00007EB8 Int asIndex = Game.GetModByName(asFile) If 255 != asIndex Keyword gag = Game.GetFormFromFile(deviousGagId, asFile) as Keyword If gag Return who.WornHasKeyword(gag) EndIf EndIf Return False EndFunction ; True if the actor is wearing a non-open gag (blocks sex/food). Bool Function HasSolidGag(Actor who) Global String asFile = "Devious Devices - Assets.esm" Int deviousGagId = 0x00007EB8 Int permitOralId = 0x0000FAC9 Int asIndex = Game.GetModByName(asFile) If 255 != asIndex Keyword gag = Game.GetFormFromFile(deviousGagId, asFile) as Keyword If gag Keyword permitOral = Game.GetFormFromFile(permitOralId, asFile) as Keyword If permitOral Return who.WornHasKeyword(gag) && !who.WornHasKeyword(permitOral) EndIf EndIf EndIf Return False EndFunction ; True if the actor is wearing an open gag (doesn't block sex/food). Bool Function HasOpenGag(Actor who) Global String asFile = "Devious Devices - Assets.esm" Int deviousGagId = 0x00007EB8 Int permitOralId = 0x0000FAC9 Int asIndex = Game.GetModByName(asFile) If 255 != asIndex Keyword gag = Game.GetFormFromFile(deviousGagId, asFile) as Keyword If gag Keyword permitOral = Game.GetFormFromFile(permitOralId, asFile) as Keyword If permitOral Return who.WornHasKeyword(gag) && who.WornHasKeyword(permitOral) EndIf EndIf EndIf Return False EndFunction ; True if the actor is wearing a belt of some kind. Bool Function HasBelt(Actor who) Global String asFile = "Devious Devices - Assets.esm" Int deviousBeltId = 0x00003330 Int asIndex = Game.GetModByName(asFile) If 255 != asIndex Keyword belt = Game.GetFormFromFile(deviousBeltId, asFile) as Keyword If belt Return who.WornHasKeyword(belt) EndIf EndIf Return False EndFunction ; True if the actor is wearing a closed belt (blocks all sex). Bool Function HasClosedBelt(Actor who) Global String asFile = "Devious Devices - Assets.esm" Int deviousBeltId = 0x00003330 Int permitAnalId = 0x0000FACA Int asIndex = Game.GetModByName(asFile) If 255 != asIndex Keyword belt = Game.GetFormFromFile(deviousBeltId, asFile) as Keyword If belt Keyword permitAnal = Game.GetFormFromFile(permitAnalId, asFile) as Keyword If permitAnal Return who.WornHasKeyword(belt) && !who.WornHasKeyword(permitAnal) EndIf EndIf EndIf Return False EndFunction ; True if the actor is wearing an open belt (doesn't block anal). Bool Function HasOpenBelt(Actor who) Global String asFile = "Devious Devices - Assets.esm" Int deviousBeltId = 0x00003330 Int permitAnalId = 0x0000FACA Int asIndex = Game.GetModByName(asFile) If 255 != asIndex Keyword belt = Game.GetFormFromFile(deviousBeltId, asFile) as Keyword If belt Keyword permitAnal = Game.GetFormFromFile(permitAnalId, asFile) as Keyword If permitAnal Return who.WornHasKeyword(belt) && who.WornHasKeyword(permitAnal) EndIf EndIf EndIf Return False EndFunction ; True if the actor has vaginal access (and by implication, whether it is blocked - by any means). Bool Function HasVaginalAccess(Actor who) Global String asFile = "Devious Devices - Assets.esm" String ddFile ="Devious Devices - Integration.esm" Int deviousBeltId = 0x00003330 Int vaginalPlugId = 0x0001DD7C Int inflatablePlugVaginalId = 0x0005D9CA Int hobbleSkirtId = 0x0005F4BA Int lockableId = 0x00003894 Int inflationStateId = 0x0005D9C8 Int asIndex = Game.GetModByName(asFile) Int ddIndex = Game.GetModByName(ddFile) If 255 != asIndex && 255 != ddIndex Keyword belt = Game.GetFormFromFile(deviousBeltId, asFile) as Keyword Keyword plug = Game.GetFormFromFile(vaginalPlugId, asFile) as Keyword Keyword inflatable = Game.GetFormFromFile(inflatablePlugVaginalId, ddFile) as Keyword Keyword skirt = Game.GetFormFromFile(hobbleSkirtId, ddFile) as Keyword Keyword lockable = Game.GetFormFromFile(lockableId, asFile) as Keyword _fw_utils.Info("_fwb_dd.HasVaginalAccess: keywords: " + belt + " " + plug + " " + inflatable + " " + skirt + " " + lockable) If belt && plug && inflatable && skirt && lockable If who.WornHasKeyword(belt) \ || who.WornHasKeyword(skirt) \ || (who.WornHasKeyword(plug) && who.WornHasKeyword(lockable)) Return False EndIf If who.WornHasKeyword(inflatable) If Game.GetPlayer() == who GlobalVariable inflation = Game.GetFormFromFile(inflationStateId, ddFile) as GlobalVariable If inflation Return inflation.GetValueInt() <= 0 EndIf Else ; This assumes that the inflatable plug is inflated for all NPCs. Return False EndIf EndIf EndIf EndIf Return True EndFunction ; True if the actor has anal access (and by implication, whether it is blocked - by any means). Bool Function HasAnalAccess(Actor who) Global String asFile = "Devious Devices - Assets.esm" String ddFile = "Devious Devices - Integration.esm" Int deviousBeltId = 0x00003330 Int analPlugId = 0x0001DD7D Int inflatablePlugAnalId = 0x0005D9C9 Int hobbleSkirtId = 0x0005F4BA Int lockableId = 0x00003894 Int inflationStateId = 0x0005D9C8 Int asIndex = Game.GetModByName(asFile) Int ddIndex = Game.GetModByName(ddFile) If 255 != asIndex && 255 != ddIndex Keyword belt = Game.GetFormFromFile(deviousBeltId, asFile) as Keyword Keyword plug = Game.GetFormFromFile(analPlugId, asFile) as Keyword Keyword inflatable = Game.GetFormFromFile(inflatablePlugAnalId, ddFile) as Keyword Keyword skirt = Game.GetFormFromFile(hobbleSkirtId, ddFile) as Keyword Keyword lockable = Game.GetFormFromFile(lockableId, asFile) as Keyword _fw_utils.Info("_fwb_dd.HasAnalAccess: keywords: " + belt + " " + plug + " " + inflatable + " " + skirt + " " + lockable) If belt && plug && inflatable && skirt && lockable If who.WornHasKeyword(belt) \ || who.WornHasKeyword(skirt) \ || (who.WornHasKeyword(plug) && who.WornHasKeyword(lockable)) Return False EndIf If who.WornHasKeyword(inflatable) If Game.GetPlayer() == who GlobalVariable inflation = Game.GetFormFromFile(inflationStateId, ddFile) as GlobalVariable If inflation Return inflation.GetValueInt() <= 0 EndIf Else ; This assumes that the inflatable plug is inflated for all NPCs. Return False EndIf EndIf EndIf EndIf Return True EndFunction Bool Function InAnimatingFaction(Actor who) Global String ddFile ="Devious Devices - Integration.esm" Int factionId = 0x00029567 Int ddIndex = Game.GetModByName(ddFile) If 255 != ddIndex Faction animatingFaction = Game.GetFormFromFile(factionId, ddFile) As Faction If animatingFaction Return who.IsInFaction(animatingFaction) EndIf EndIf Return False EndFunction Function SetInAnimatingFaction(Actor who, Bool inFaction) Global String ddFile ="Devious Devices - Integration.esm" Int factionId = 0x00029567 Int ddIndex = Game.GetModByName(ddFile) If 255 != ddIndex Faction animatingFaction = Game.GetFormFromFile(factionId, ddFile) As Faction If animatingFaction If inFaction who.AddToFaction(animatingFaction) who.SetFactionRank(animatingFaction, 1) Else who.RemoveFromFaction(animatingFaction) EndIf EndIf EndIf EndFunction
pburnt Posted March 20, 2019 Posted March 20, 2019 1 hour ago, tasairis said: You mean the italics? No problem, just means the mod is injecting forms into (in this case) Skyrim.esm. Thanks for keeping us up to date. I really appreciate it. Has anyone tried the Umbra CC? It's the only content that has looked interesting to me so far.
Tron91 Posted March 20, 2019 Posted March 20, 2019 If some one needs my converted version of SexLab Disparity for testing, pm me.
Fish0 Posted March 20, 2019 Posted March 20, 2019 11 hours ago, Gh0sTG0 said: Hm... What to do if mod SLA Monitor Widget is marked as "convertable", but it has skyui in masterfiles? Should I install skyui, skyuiSE, both of them? What to do with editing masterfiles? Most mods that require SkyUI only require it for the MCM menu, which will work perfectly fine with SkyUI SE. 1
TamH70 Posted March 20, 2019 Posted March 20, 2019 @OP, you are doing good work. There are still too many mods I'd like to use that are not updated yet for me to let Bethesda mess me around again, but the situation seems to be improving rather quickly. Thanks, Tam.
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now