For Modders - SkyrimLL/SDPlus GitHub Wiki

[Draft]

SD+ provides integration with other mods in two ways:

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.