For Modders - SkyrimLL/SDPlus GitHub Wiki
[Draft]
SD+ provides integration with other mods in two ways:
- Using Mod Events - A full list of mod events is available in the 'player alias script'.
- Using StorageUtil variables
ModEvents - In
These events are registered by SD+ and meant to be triggered by other mods. Some events rely on optional StorageUtil variables or extra parameters for customization.
For example, if you want to trigger a sex scene from SD+ with an NPC after a dialogue.
akActor.SendModEvent("PCSubSex")
Start Enslavement
akActor.SendModEvent(“PCSubEnslave")
akActor.SendModEvent(“PCSubEnslave", “Consensual") ; storageUtil: _SD_iSold
Transfer ownership
akActor.SendModEvent("PCSubTransfer", "Consensual") ; storageUtil: _SD_iSold
Release from enslavement
SendModEvent("PCSubFree")
Allow slave to join the owner's faction
SendModEvent(“SDEmancipateSlave")
Add/remove a punishment item to the slave
SendModEvent(“SDPunishSlave")
SendModEvent(“SDRewardSlave")
Start Sex scene
akActor.SendModEvent("PCSubSex")
akActor.SendModEvent("PCSubSex", "GangBang")
akActor.SendModEvent("PCSubSex", "SoloShow")
Start Whipping scene
akActor.SendModEvent("PCSubWhip")
akActor.SendModEvent("PCSubPunish")
Start Entertainment scene
akActor.SendModEvent("PCSubEntertain")
akActor.SendModEvent("PCSubEntertain", "GangBang")
akActor.SendModEvent("PCSubEntertain", "SoloShow")
Refresh and display enslavement status
SendModEvent("PCSubStatus") ;
Start Spriggan infection
akActor.SendModEvent(“SDSprigganEnslave")
Start Spriggan punishment
akActor.SendModEvent(“SDSprigganPunish")
Teleport to Dreamworld
SendModEvent(“SDDreamworldPull")
SendModEvent(“SDDreamworldPull", 15) ; or 100 - optional parameter is a quest ID for variations of events going into Dreamworld. Not used yet. Use default for now.
Update API documentation for Dreamworld event and add these:
Whipping scene (hit pride and self-esteem): PCSubWhip
Master/slave sex scene (hit pride?): PCSubSex
Consensual enslavement (i.e. "I need a strong hand to guide me"): PCSubSubmit
Entertainment Scenes (hit pride and self-esteem): PCSubEntertain
Punishment/Reward scenes (depends if the enslavement is consensual or not - increase or hit self-esteem): PCSubPunish (for scenes) SDPunishSlave/SDRewardSlave (for devices)
Locking up in cage (this one especially makes sense to hit pride and self-esteem): PCSubCaged
Coveted submit (rape): PCSubCoveted
Coveted resist (stripped): PCSubStripped
New events
Change slave stance between "crawlin", "kneeling" and "standing": PCSubStance
Trust slave to activate things: PCSubTrustAction
Trust slave to fight (wear armor and weapon): PCSubTrustFight
Change slave face (racemenu or shave head): PCSubChangeLook
Remove leash to master (free roaming, shock collar): PCSubUnleash
Add short leash to master (choking collar): PCSubLeash
Force master to follow slave around (master follower): PCSubMasterFollow
Start or stop master travel routine (if enabled): PCSubMasterTravel
Add to Coveted effect: SDSanguineDreamworldMod
Pause visits to Dreamworld: OnSDDreamworldSuspend
Resume visits to Dreamworld: OnSDDreamworldResume
New storageUtil variables
StorageUtil.SetIntValue(kPlayer , "_SD_iDisableDreamworld", 0)
StorageUtil.SetIntValue(kPlayer, "_SD_iMasterTravelDelay", 1) ; in Days
indexBannedActors = StorageUtil.FormListFind(akPlayer, "_SD_lBannedSlaveryActors", akActor as Form)
indexBannedFaction = StorageUtil.FormListFind(akPlayer, "_SD_lBannedSlaveryFactions", akActor as Form)
ModEvent - Out
These are signals SD+ sends out at certain stages of enslavement. Other mods can register for these events and add their own customizations to the enslavement process.
Entering and leaving Dreamworld
SendModEvent("SDInDreamworldStart")
SendModEvent("SDInDreamworldStop")
Entering and leaving enslavement
SendModEvent("SDEnslavedStart")
SendModEvent("SDEnslavedStop")
Entering and leaving 'escaped' status
SendModEvent("SDEscapeStart")
SendModEvent("SDEscapeStop")
Player is on the road to Mistwatch with Thugs
SendModEvent("SDThugTransitStart")
SendModEvent("SDThugTransitStop")
Entering and leaving Spriggan infection
SendModEvent("SDSprigganStart")
SendModEvent("SDSprigganStop")
Changing look of player
SendModEvent("PCSubChangeLook")
StorageUtil variables
Most parameters of the new enslavement process are controlled by StorageUtil variables. Some variables are meant for the player/slave. Some variables are meant for the NPC owner. You can use these variables to make owners 'remember' the player/slave if they happen to meet again after an enslavement.
The principle of the API is simple - it uses messaging through variable in StorageUtil.
Here are a few commands already available.
Check if the player is enslaved:
StorageUtil.GetIntValue(Game.GetPlayer(), "_SD_iEnslaved")
Check if the player is infected by a Spriggan host:
StorageUtil.GetIntValue(Game.GetPlayer(), "_SD_iSprigganInfected")
Prevent an NPC/Follower from being stripped if enslaved (for special cases using Outfits, like the SexBot in SexLab Stories or Ali the Succubus in Alicia).
StorageUtil.SetIntValue( akActor, "_SD_iCanBeStripped", 0)
Global variables exposed by SD+
; 0 = any / 1 = same sex only / 2 = opposite sex only
iGenderRestrictions = StorageUtil.GetIntValue(kPlayer, "_SD_iGenderRestrictions")
Global variables initialized once by SD+
StorageUtil.SetIntValue(kSlave, "_SD_iAPIInit", 1)
; Gameplay preferences
StorageUtil.SetIntValue(kSlave, "_SD_iDisablePlayerMovementWhipping", 0)
StorageUtil.SetIntValue(kSlave, "_SD_iDisablePlayerMovementPunishment", 1)
StorageUtil.SetIntValue(kSlave, "_SD_iDisablePlayerAutoKneeling", 1)
StorageUtil.SetIntValue(kSlave, "_SD_iDisableDreamworldOnSleep", 0)
StorageUtil.GetIntValue(kSlave, "_SD_iDisableFollowerAutoKneeling") ; turn follower auto kneeling on and off (0 or 1)
Variables set when enslavement starts
_SDGVP_enslaved.SetValue( 1 )
; API variables
StorageUtil.SetIntValue(kSlave, "_SD_iEnslaved", 1)
StorageUtil.SetFormValue(kSlave, "_SD_CurrentOwner", kMaster)
StorageUtil.SetFormValue(kSlave, "_SD_LeashCenter", kMaster)
StorageUtil.SetIntValue(kSlave, "_SD_iLeashLength", 200)
StorageUtil.SetStringValue(kSlave, "_SD_sDefaultStance", "Kneeling")
StorageUtil.SetStringValue(kSlave, "_SD_sDefaultStanceFollower", "Kneeling" )
StorageUtil.SetFloatValue(kSlave, "_SD_fLastEnslavedGameTime", StorageUtil.GetFloatValue(kSlave, "_SD_fEnslavedGameTime"))
StorageUtil.SetFloatValue(kSlave, "_SD_fEnslavedGameTime", _SDGVP_gametime.GetValue())
StorageUtil.SetFloatValue(kSlave, "_SD_fPunishmentGameTime", 0.0)
StorageUtil.SetFloatValue(kSlave, "_SD_fPunishmentDuration", 0.0)
StorageUtil.SetIntValue(kSlave, "_SD_iSexCountToday", 0)
StorageUtil.SetIntValue(kSlave, "_SD_iPunishmentCountToday", 0)
StorageUtil.SetIntValue(kSlave, "_SD_iSubmissiveCountToday", 0)
StorageUtil.SetIntValue(kSlave, "_SD_iAngerCountToday", 0)
StorageUtil.SetIntValue(kSlave, "_SD_iSexCountTotal", 0)
StorageUtil.SetIntValue(kSlave, "_SD_iPunishmentCountTotal", 0)
StorageUtil.SetIntValue(kSlave, "_SD_iSubmissiveCountTotal", 0)
StorageUtil.SetIntValue(kSlave, "_SD_iAngerCountTotal", 0)
; Relationship type with NPC ( -4 to 4 is normal Skyrim relationship rank)
; 7: Slave (submissive)
; 6: Slave (neutral)
; 5: Slave (hostile)
; 4: Lover
; 3: Ally
; 2: Confidant
; 1: Friend
; 0: Acquaintance
; -1: Rival
; -2: Foe
; -3: Enemy
; -4: Archnemesis
; -5: Master (hostile)
; -6: Master (neutral)
; -7: Master (submissive)
StorageUtil.SetIntValue(kMaster, "_SD_iOriginalRelationshipRank", kMaster.GetRelationshipRank(kSlave))
If (!StorageUtil.HasIntValue(kMaster, "_SD_iRelationshipType"))
StorageUtil.SetIntValue(kMaster, "_SD_iRelationshipType", kMaster.GetRelationshipRank(kSlave))
EndIf
If (!StorageUtil.HasIntValue(kMaster, "_SD_iForcedSlavery"))
StorageUtil.SetIntValue(kMaster, "_SD_iForcedSlavery", 1)
EndIf
If (!StorageUtil.HasIntValue(kSlave, "_SD_iSlaveryLevel"))
StorageUtil.SetIntValue(kSlave, "_SD_iSlaveryLevel", 0)
EndIf
; Slavery level is calculated from 'exposure'
StorageUtil.GetIntValue(kSlave, "_SD_iSlaveryExposure")
StorageUtil.SetIntValue(kSlave, "_SD_iSanguineBlessings", _SDGVP_sanguine_blessings.GetValue() as Int )
; Tracking also _SD_iSub and _SD_iDom (through the player's answers to Resist or Submit menus
; - Master personality profile
; 0 - Simple profile. No additional constraints
; Endgame: Sell slave to slave trader.
; 1 - Comfortable - Must complete or exceed food goal
; Endgame: Sell slave to inn-keeper.
; 2 - Horny - Must complete or exceed sex goal
; Endgame: Sell slave to soldier barracks.
; 3 - Sadistic - Must complete or exceed punishment goals
; Endgame: Kill slave or left for dead.
; 4 - Gambler - Must complete or exceed gold goals.
; Endgame: Sell slave to dog fighting ring.
; 5 - Caring - Seeks full compliance for one goal at least
; Endgame: Banish slave (get out of my sight).
; 6 - Perfectionist - Seeks full compliance for all goals
; Endgame: Hunt, Kill slave or left for dead.
If (!StorageUtil.HasIntValue(kMaster, "_SD_iPersonalityProfile"))
int profileChance = Utility.RandomInt(0,100)
if (profileChance >= 95)
StorageUtil.SetIntValue(kMaster, "_SD_iPersonalityProfile", 6 )
elseif (profileChance >= 80)
StorageUtil.SetIntValue(kMaster, "_SD_iPersonalityProfile", 5 )
elseif (profileChance >= 70)
StorageUtil.SetIntValue(kMaster, "_SD_iPersonalityProfile", 4 )
elseif (profileChance >= 60)
StorageUtil.SetIntValue(kMaster, "_SD_iPersonalityProfile", 3 )
elseif (profileChance >= 50)
StorageUtil.SetIntValue(kMaster, "_SD_iPersonalityProfile", 2 )
elseif (profileChance >= 40)
StorageUtil.SetIntValue(kMaster, "_SD_iPersonalityProfile", 1 )
else
StorageUtil.SetIntValue(kMaster, "_SD_iPersonalityProfile", 0 )
endif
EndIf
If (_SDGVP_config_min_days_before_master_travel.GetValue()>0)
StorageUtil.SetIntValue(kMaster, "_SD_iDaysBeforeTravel", Utility.RandomInt(1,5) )
_SDGVP_isMasterTraveller.SetValue(0)
endif
If (!StorageUtil.HasStringValue(kMaster, "_SD_sColorProfile"))
int colorChance = Utility.RandomInt(0,100)
if (colorChance >= 60)
StorageUtil.SetStringValue(kMaster, "_SD_sColorProfile", ",black" )
elseif (colorChance >= 40)
StorageUtil.SetStringValue(kMaster, "_SD_sColorProfile", ",red" )
elseif (colorChance >= 20)
StorageUtil.SetStringValue(kMaster, "_SD_sColorProfile", ",white" )
endif
EndIf
; Master satisfaction - negative = angry / positive = happy
StorageUtil.SetIntValue(kMaster, "_SD_iDisposition", Utility.RandomInt(-5,10) )
StorageUtil.SetIntValue(kMaster, "_SD_iTrust", Utility.RandomInt(-10,5) )
StorageUtil.HasIntValue(kMaster, "_SD_iNeedRange")
StorageUtil.HasIntValue(kMaster, "_SD_iTrustRange")
StorageUtil.SetIntValue(kMaster, "_SD_iGoalFood", Utility.RandomInt(2,6))
StorageUtil.SetIntValue(kMaster, "_SD_iGoalSex", Utility.RandomInt(1,10))
StorageUtil.SetIntValue(kMaster, "_SD_iGoalPunishment", Utility.RandomInt(1,10))
StorageUtil.SetIntValue(kMaster, "_SD_iGoalGold", Utility.RandomInt(10,50))
; Special needs based on faction
; Special items (firewood, ingredients)
; Blood feedings (Vampire)
; Slave daily progress
StorageUtil.SetIntValue(kSlave, "_SD_iGoalFood", 0)
StorageUtil.SetIntValue(kSlave, "_SD_iGoalSex", 0)
StorageUtil.SetIntValue(kSlave, "_SD_iGoalPunishment", 0)
StorageUtil.SetIntValue(kSlave, "_SD_iGoalGold", 0)
; Master trust - number of merit points necessary for master to trust slave
If (!StorageUtil.HasIntValue(kMaster, "_SD_iTrustThreshold"))
StorageUtil.SetIntValue(kMaster, "_SD_iTrustThreshold", 20 )
else
StorageUtil.SetIntValue(kMaster, "_SD_iTrustThreshold", StorageUtil.GetIntValue(kMaster, "_SD_iTrustThreshold") + 10)
EndIf
; Slave privileges
StorageUtil.SetIntValue(kSlave, "_SD_iTrustPoints", 0) ; Trust earned by slave
; Slave constraints
; Leash
; Stand
; Move
; Action
; Fight
; Inventory
; Sprint
; Ride Horse
; Fast Travel
; Wait
; Spell Equip
; Shout Equip
; Clothing Equip
; Armor Equip
; Weapon Equip
; Money
; StorageUtil.SetIntValue(kSlave, "_SD_iEnableLeash", 1)
; StorageUtil.SetIntValue(kSlave, "_SD_iEnableStand", 0)
; StorageUtil.SetIntValue(kSlave, "_SD_iEnableMovement", 0)
; StorageUtil.SetIntValue(kSlave, "_SD_iEnableAction", 0)
; StorageUtil.SetIntValue(kSlave, "_SD_iEnableFight", 0)
; StorageUtil.SetIntValue(kSlave, "_SD_iEnableInventory", 0)
; StorageUtil.SetIntValue(kSlave, "_SD_iEnableSprint", 0)
; StorageUtil.SetIntValue(kSlave, "_SD_iEnableRideHorse", 0)
; StorageUtil.SetIntValue(kSlave, "_SD_iEnableFastTravel", 0)
; StorageUtil.SetIntValue(kSlave, "_SD_iEnableWait", 0)
; StorageUtil.SetIntValue(kSlave, "_SD_iEnableSpellEquip", 0)
; StorageUtil.SetIntValue(kSlave, "_SD_iEnableShoutEquip", 0)
; StorageUtil.SetIntValue(kSlave, "_SD_iEnableClothingEquip", 0)
; StorageUtil.SetIntValue(kSlave, "_SD_iEnableArmorEquip", 0)
; StorageUtil.SetIntValue(kSlave, "_SD_iEnableWeaponEquip", 0)
; StorageUtil.SetIntValue(kSlave, "_SD_iEnableMoney", 0)
StorageUtil.SetIntValue(kSlave, "_SD_iTimeBuffer", 20) ; number of seconds allowed away from Master
; Compatibility with other mods
StorageUtil.StringListAdd(kMaster, "_DDR_DialogExclude", "SD+:Master")
Variables set when enslavement stops
; API variables
StorageUtil.SetFormValue(kSlave, "_SD_LastOwner", kMaster)
StorageUtil.SetFloatValue(kSlave, "_SD_fLastReleasedGameTime", _SDGVP_gametime.GetValue())
StorageUtil.SetFloatValue(kSlave, "_SD_fPunishmentGameTime", 0.0)
StorageUtil.SetFloatValue(kSlave, "_SD_fPunishmentDuration", 0.0)
; Restore original relationship rank with slave
kMaster.SetRelationshipRank(kSlave, StorageUtil.GetIntValue(kMaster, "_SD_iOriginalRelationshipRank") )
StorageUtil.SetFormValue(kSlave, "_SD_LeashCenter", kMaster)
StorageUtil.SetIntValue(kSlave, "_SD_iLeashLength", 0)
StorageUtil.SetIntValue(kSlave, "_SD_iEnslaved", 0)
_SDGVP_enslaved.SetValue( 0 )
Mixing storageUtil variables and mod events
An example of code to send the player to Dreamworld:
; check for the storageUtil value of 'sanguineBlessings' (visits to Dreamworld)
If (StorageUtil.GetIntValue( Game.GetPlayer() , "_SD_iSanguineBlessings") <1 )
SendModEvent(“SDDreamworldPull", 10)
else
SendModEvent(“SDDreamworldPull", 15)
Endif
Customizing slavery gear
Slavery gear can be customized using racial or NPC overrides.
If kForm is a form ID for a race or an NPC, adding overrides requires the following:
1- To add a new race as a potential slaver (kForm = newRace as Form)
This is needed for a new race, or for an NPC of a race not currently covered by SD+.
if (StorageUtil.FormListFind( none, "_SD_lRaceMastersList", kForm) <0) StorageUtil.FormListAdd( none, "_SD_lRaceMastersList", kForm) StorageUtil.SetIntValue(kForm, "_SD_iSlaveryRace", 1) StorageUtil.SetStringValue( kForm, "_SD_sRaceType", "Beast") ; or "humanoid" if race members can speak StorageUtil.SetStringValue( kForm, "_SD_sRaceName", kForm.GetName()) StorageUtil.SetFormValue( thisRace, "_SD_sRaceFaction", racialFaction) endif
2- Define preferences for race or NPC as a slaver (kForm is a form ID for a race or NPC).
StorageUtil.SetIntValue(kForm, "_SD_iSlaveryCollarOn", allowCollar as Int) ; 0 or 1 StorageUtil.SetIntValue(kForm, "_SD_iSlaveryBindingsOn", allowArmbinders as Int) ; 0 or 1 StorageUtil.SetIntValue(kForm, "_SD_iSlaveryPunishmentOn", allowPunishmentDevice as Int) ; 0 or 1 StorageUtil.SetIntValue(kForm, "_SD_iSlaveryPunishmentSceneOn", allowPunishmentDevice as Int) ; 0 or 1 StorageUtil.SetIntValue(kForm, "_SD_iSlaveryWhippingSceneOn", allowPunishmentDevice as Int) ; 0 or 1 StorageUtil.SetStringValue(kForm, "_SD_sSlaveryDefaultStance", defaultStance) ; "Crawling", "Kneeling" or "Standing" StorageUtil.SetStringValue(kForm, "_SD_sSlaveryTat", raceSlaveTat) ; Name of Tattoo as defined in a slavetat json file StorageUtil.SetStringValue(kForm, "_SD_sSlaveryTatType", "SD+") ; name of the section as defined in a slavetat json file StorageUtil.SetIntValue(kForm, "_SD_iSlaveryTatDuration", raceSlaveTatDuration ) ; Int, in number of days StorageUtil.SetIntValue(kForm, "_SD_iSlaveryTatColor", raceSlaveTatColor ) ; color of tat StorageUtil.SetIntValue(kForm, "_SD_iSlaveryTatGlow", raceSlaveTatGlow ) ; 0 or 1
3- Register devious device override for that race or NPC (SD+ will apply generic devices defaults for devices that do not have a device override)
; deviceString is one of "Collar", "Armbinders", "LegCuffs", "Belt", "PlugVaginal", "PlugAnal", "Gag", "Blindfold" StorageUtil.SetFormValue(kForm, "_SD_" + deviceString + "_keyword", deviceKeyword as Form) ; required StorageUtil.SetFormValue(kForm, "_SD_" + deviceString + "_inventory", deviceInventory as Form) ; optional if genericDeviceTags used StorageUtil.SetFormValue(kForm, "_SD_" + deviceString + "_rendered", deviceRendered as Form) ; optional if genericDeviceTags used StorageUtil.SetStringValue(kForm, "_SD_" + deviceString + "_tags", genericDeviceTags) ; optional if deviceInventory used
Tune attacks and enslavement events
SexLab Dialogues v2.9 include a new mod event and storageUtil variables to set the values of the 3 sliders for comments, attacks and begging probabilities:
StorageUtil.SetIntValue( PlayerActor, "_SLD_iCommentProbability", <value 0-100> )
StorageUtil.SetIntValue( PlayerActor, "_SLD_iAttackProbability", <value 0-100> )
StorageUtil.SetIntValue( PlayerActor, "_SLD_iBeggingProbability", <value 0-100> )
SendModEvent("SLDRefreshGlobals")
You need to first set the value in storageUtil and then call the mod event to refresh the global variables used by SexLab Dialogues.
If you don't call the mod event, the values will be updated next time you reload.