Jump to content

[LE] Question about MCM menu and SSE.


Recommended Posts

I want to make a MCM menu for my mod, but I'm not sure if there will be any issues when converting the mod to SSE.

Just curious I've never worked with it and I don't want to start messing with it if will break stuff for SSE.

Do I have to remove stuff or will it load in fine in SSE without changing anything?

Edited by EddieTheEagle
Link to comment
Share on other sites

At the moment, there is no MCM menu in Skyrim SE. For that, there needs to be an SKSE for Skyrim SE (SKSE64) and unfortunately, SKSE64 is not done yet and there is some speculation that it may never get finished, but there is no definite word yet one way or the other. The next thing needed for an MCM menu would be SkyUI, which requires SKSE, so basically, the TL;DR here is there is no MCM in Skyrim SE, and at the very least, it'll be a while before there is one. In the meantime, mod authors usually will add a power to the game that will bring up a configuration menu for the mods that need one, though I don't know how that is done. I don't know much about scripting at the moment.

Link to comment
Share on other sites

At the moment, there is no MCM menu in Skyrim SE. For that, there needs to be an SKSE for Skyrim SE (SKSE64) and unfortunately, SKSE64 is not done yet and there is some speculation that it may never get finished, but there is no definite word yet one way or the other. The next thing needed for an MCM menu would be SkyUI, which requires SKSE, so basically, the TL;DR here is there is no MCM in Skyrim SE, and at the very least, it'll be a while before there is one. In the meantime, mod authors usually will add a power to the game that will bring up a configuration menu for the mods that need one, though I don't know how that is done. I don't know much about scripting at the moment.

 

I know it requires SkyUI and SKSE. I also know they are not available for SSE.

 

I already have the power spell made with a working config but I also wanted to do the MCM menu for Classic.

I'm just wondering it would cause issues if you load in a mod that requires SkyUI and SKSE in SSE.

Link to comment
Share on other sites

If you've constructed your mod correctly there's no problem leaving the MCM quest and scripts in place when porting to SSE. The game will fail to load the MCM scripts and generate an error in the Papyrus log but nothing bad will happen. It's the same as trying to run the mod in the original game if you disable SkyUI (and that's the easiest way to test that everything is good).

 

Constructing the mod correctly means that nothing in your mod can depend on those MCM scripts. If you already have a mod working without the MCM (and configurable in some other way) then everything should be fine. Just make sure that the MCM is checking and setting global variables, properties from other scripts, or detecting other things from your mod instead of having the other scripts check properties in the MCM script.

 

Here's an example MCM showing how to do the sort of optional MCM configuration you're talking about.

 

 

ScriptName InigoMCMScriptDemo extends SKI_ConfigBase
{Example MCM menu based on InigoMCM mod code. Values set by the MCM are either ActorValues of Inigo
himself or properties in some script, could have been GlobalVariables or even local variables.}


; Properties to access various external objects and scripts.
WorldSpace Property Tamriel Auto
Actor Property PlayerRef Auto
Actor Property InigoRef Auto ; this is used enough to make it worth setting as its own property
InigoStatusQuestScript Property InigoStatus Auto
{The status script holds lots of useful properties and functions that can be tweaked from the MCM.}
InigoExtrasScript Property InigoExtras Auto
{A script holding extra features like whistle hotkey and Mr. Dragonfly options that are not in the main Inigo mod.}


; These dynamic values must be checked each time the MCM is opened amd unfortunately 
; the values are needed in multiple functions so they have to be declared here
Actor SteedRef  ; may be null
Form CurrentWorld  ; either a world or cell so never null
bool IsSteedAllowedHere ; based on current contents of the formlist and this location


; I do not need an OnConfigInit() function, but that works just like the basic version of the MCM tutorial.


Function OnPageReset(String a_page)
	; Gather some information before showing the page because somethings get disabled if they are not appropriate
	; Get current steed from its alias, if he has one.
	SteedRef = InigoStatus.SteedAlias.GetReference() as Actor
	CurrentWorld = PlayerRef.GetWorldSpace()
	if !CurrentWorld
		CurrentWorld = PlayerRef.GetParentCell()
	endif
	; There is a formlist with all of the places Inigo is allowed to ride, see if we are in it.
	IsSteedAllowedHere = CurrentWorld && InigoStatus.InigoSteedAllowed && InigoStatus.InigoSteedAllowed.HasForm(CurrentWorld)

	; Now show the menu (a_page variable is not used because all of the options fit on one page)
	SetCursorFillMode(TOP_TO_BOTTOM)
	; This one is a key remap that allows the key to be completely unmapped.
	AddKeyMapOptionST("Whistle", "Whistle Hotkey", InigoExtras.WhistleKeyCode, OPTION_FLAG_WITH_UNMAP)
	; This one is a multiple option toggle implemented with a TextOption field. There is another control specifically for that but I did not use it.
	AddTextOptionST("ShowMrD", "Show Mr Dragonfly", ShowMrDTxt(InigoExtras.MrDVisible.ShowMrD))
	SetCursorPosition(1)
	AddToggleOptionST("SteedAllowed", "Steed Allowed Here", IsSteedAllowedHere)
	if SteedRef 
		AddSliderOptionST("SteedSpeedMult", "Trusty Steed's Speed", SteedRef.GetActorValue("SpeedMult"), "{0}%")
	else   ; I think it looks nicer to show a disabled text box if he does not have a steed
		AddTextOptionST("SteedSpeedMult", "Trusty Steed's Speed", "", OPTION_FLAG_DISABLED)
	endif
	SetCursorPosition(6)
	AddHeaderOption("Advanced Options")
	; I wanted it to be clear that some of these are percentage values so they have custom formatting.
	; These in this group all modify actor values on Inigo himself.
	AddSliderOptionST("SpeedMult", "Inigo's Speed", InigoRef.GetActorValue("SpeedMult"), "{0}%")
	AddSliderOptionST("CarryWeight", "Inigo's Carry Capacity", InigoRef.GetActorValue("CarryWeight"), "{0}")
	AddSliderOptionST("AttackDamageMult", "Inigo's Attack Damage", InigoRef.GetActorValue("AttackDamageMult")*100.0, "{0}%")  ; real value is a simple multipler
	AddSliderOptionST("DamageResist", "Inigo's Damage Resistance", InigoRef.GetActorValue("DamageResist"), "{0}")
	SetCursorPosition(7)
	AddHeaderOption("Emergency Use Only")
	; These TextOptions are being used as buttons
	AddTextOptionST("SummonInigoNow", "Summon Inigo Now", "")
	AddTextOptionST("SummonMrD", "Summon Mr Dragonfly", "")
	AddTextOptionST("RecoverBow", "Recover Inigo's Bow", "")
	AddTextOptionST("RecoverBooks", "Recover Inigo's Books", "")
EndFunction


string Function ShowMrDTxt(int val)
{Simple utility function to translate the ShowMrD variable values into matching text for the button.}
	if val == 1
		return "Large Jar"
	elseif val == 2
		return "Small Jar"
	elseif val == 3
		return "Front Jar"
	else
		return "No"
	endif
EndFunction


;Here are the various states needed to implement everything above (in reverse order)

State RecoverBooks

	Event OnHighlightST()
		SetInfoText("Recover Inigo's missing books.\n(They'll be added to his inventory not yours.)")
	EndEvent

	; Implements a button to perform an action
	Event OnSelectST()
		SetOptionFlagsST(OPTION_FLAG_DISABLED)
		if InigoRef.GetItemCount(InigoExtras.InigoJournal) < 1 && PlayerRef.GetItemCount(InigoExtras.InigoJournal) < 1
			InigoRef.AddItem(InigoExtras.InigoJournal, 1)
		endif
		if InigoRef.GetItemCount(InigoExtras.InigoBrave) < 1 && PlayerRef.GetItemCount(InigoExtras.InigoBrave) < 1
			InigoRef.AddItem(InigoExtras.InigoBrave, 1)
		endif
		if PlayerRef.HasSpell(InigoExtras.WhistlePower)
			if InigoRef.GetItemCount(InigoExtras.WBook) < 1 && PlayerRef.GetItemCount(InigoExtras.WBook) < 1
				InigoRef.AddItem(InigoExtras.WBook, 1)
			endif
		endif
		if (InigoExtras.InigoBadVibrationsQuest.IsStageDone(180)
			if InigoRef.GetItemCount(InigoExtras.DVJournal) < 1 && PlayerRef.GetItemCount(InigoExtras.DVJournal) < 1
				InigoRef.AddItem(InigoExtras.DVJournal, 1)
			endif
			if InigoRef.GetItemCount(InigoExtras.Champion1) < 1 && PlayerRef.GetItemCount(InigoExtras.Champion1) < 1
				InigoRef.AddItem(InigoExtras.Champion1, 1)
			endif
			if InigoRef.GetItemCount(InigoExtras.Champion2) < 1 && PlayerRef.GetItemCount(InigoExtras.Champion1) < 1
				InigoRef.AddItem(InigoExtras.Champion2, 1)
			endif
		endif
	EndEvent

EndState


State RecoverBow

	Event OnHighlightST()
		SetInfoText("Recover Inigo's bow if you've lost it.\n(It will be added to his inventory not yours.)")
	EndEvent

	Event OnSelectST()
		SetOptionFlagsST(OPTION_FLAG_DISABLED)
		if InigoRef.GetItemCount(InigoExtras.Bow) < 1 && PlayerRef.GetItemCount(InigoExtras.Bow) < 1
			InigoRef.AddItem(InigoExtras.Bow, 1)
			InigoRef.EquipItem(InigoExtras.Bow) ; Equip it so the player knows this function worked.
		endif
	EndEvent

EndState


State SummonMrD

	Event OnHighlightST()
		SetInfoText("Summon Mr. Dragonfly to the player.")
	EndEvent

	Event OnSelectST()
		SetOptionFlagsST(OPTION_FLAG_DISABLED)
		InigoExtras.MrD.MoveTo(PlayerRef, 80.0*Math.sin(PlayerRef.GetAngleZ()),  80.0*Math.cos(PlayerRef.GetAngleZ()), 10.0, 0)
	EndEvent

EndState


State SummonInigoNow

	Event OnHighlightST()
		SetInfoText("Bring Inigo to the player. This could break his quests!")
	EndEvent

	Event OnSelectST()
		SetOptionFlagsST(OPTION_FLAG_DISABLED)
		; position him directly in front of the player and turn him to face the player.
		; enabling and disabling can fix many game glitches
		float az = PlayerRef.GetAngleZ()
		InigoRef.MoveTo(PlayerRef, 80.0*Math.sin(az),  80.0*Math.cos(az), 10.0, 0.0)
		InigoRef.Disable()
		InigoRef.SetAngle(0.0, 0.0, az + 180.0)
		InigoRef.Enable()
	EndEvent

EndState


State AttackDamageMult

	Event OnHighlightST()
		SetInfoText("Inigo's Attack Damage compared to other NPCs. [default = 100%]")
	EndEvent

	Event OnSliderAcceptST(float value)
		InigoRef.ForceActorValue("AttackDamageMult", value/100.0)  ; real value is a multipler, so convert percent back to decimal
		SetSliderOptionValueST(value)
	EndEvent

	Event OnSliderOpenST()
	SetSliderDialogStartValue(InigoRef.GetActorValue("AttackDamageMult")*100.0)  ; real value isn't a percent, so make it one
		SetSliderDialogDefaultValue(100.0)
		SetSliderDialogRange(10.0, 1000.0)
		SetSliderDialogInterval(10.0)
	EndEvent

EndState


State DamageResist

	Event OnHighlightST()
		SetInfoText("Inigo's Damage Resistance (including benefits from any armor he may be wearing). [default = 0]")
	EndEvent

	Event OnSliderAcceptST(float value)
		InigoRef.ForceActorValue("DamageResist", value)
		SetSliderOptionValueST(value)
	EndEvent

	Event OnSliderOpenST()
		SetSliderDialogStartValue(InigoRef.GetActorValue("DamageResist"))
		SetSliderDialogDefaultValue(0.0)
		SetSliderDialogRange(0.0, 1000.0)
		SetSliderDialogInterval(1.0)
	EndEvent

EndState


State CarryWeight

	Event OnHighlightST()
		SetInfoText("Inigo's current carry capcity (possibly modified by spells or enchantments). [default = 300]")
	EndEvent

	Event OnSliderAcceptST(float value)
		InigoRef.ForceActorValue("CarryWeight", value)
		SetSliderOptionValueST(value)
	EndEvent

	Event OnSliderOpenST()
		SetSliderDialogStartValue(InigoRef.GetActorValue("CarryWeight"))
		SetSliderDialogDefaultValue(300.0)
		SetSliderDialogRange(100.0, 900.0)
		SetSliderDialogInterval(5.0)
	EndEvent

EndState



State SpeedMult

	Event OnHighlightST()
		SetInfoText("Inigo's current speed compared to the game default speed for NPCs. [default = 115%]")
	EndEvent

	Event OnSliderAcceptST(float value)
		InigoRef.ForceActorValue("SpeedMult", value)
		SetSliderOptionValueST(value)
	EndEvent

	Event OnSliderOpenST()
		SetSliderDialogStartValue(InigoRef.GetActorValue("SpeedMult"))
		SetSliderDialogDefaultValue(115.0)
		SetSliderDialogRange(50.0, 200.0)
		SetSliderDialogInterval(5.0)
	EndEvent

EndState


State SteedSpeedMult

	Event OnHighlightST()
		SetInfoText("Inigo's steed's current speed compared to the game default speed for horses. [default = 100%]")
	EndEvent

	Event OnSliderAcceptST(float value)
		SteedRef.ForceActorValue("SpeedMult", value)
		SetSliderOptionValueST(value)
	EndEvent

	Event OnSliderOpenST()
		SetSliderDialogStartValue(SteedRef.GetActorValue("SpeedMult"))
		SetSliderDialogDefaultValue(100.0)
		SetSliderDialogRange(50.0, 200.0)
		SetSliderDialogInterval(5.0)
	EndEvent

EndState


State SteedAllowed

	Event OnHighlightST()
		SetInfoText("Should Inigo be allowed to ride his trusty steed in this location?\nThis also summons or dismisses his current steed if possible.")
	EndEvent

	Event OnDefaultST()
		IsSteedAllowedHere = true
		OnSelectST()
	EndEvent

	Event OnSelectST()
		SetOptionFlagsST(OPTION_FLAG_DISABLED)
		IsSteedAllowedHere = !IsSteedAllowedHere
		if CurrentWorld != Tamriel ; Riding is always allowed in Tamriel
			if IsSteedAllowedHere
				InigoStatus.Steed = "Allow"
			else
				InigoStatus.Steed = "Forbid"
			endif
		endif
		if SteedRef && !SteedRef.IsBeingRidden()
			if IsSteedAllowedHere || (CurrentWorld == Tamriel && PlayerRef.GetDistance(SteedRef) > 900)
				InigoStatus.Steed = "Summon"
			else
				InigoStatus.Steed = "Stable"
				InigoStatus.Steed = "Follow"
			endif
		endif
	EndEvent

EndState


State ShowMrD

	Event OnHighlightST()
		SetInfoText("Should Inigo wear Mr Dragonfly in a jar on his belt and if so how?\nOptions: No (the default), in a full-sized jar, in a small jar, and in a small jar in front")
	EndEvent

	Event OnSelectST()
		int pr = InigoExtras.MrDVisible.ShowMrD + 1  ; cycle to the next option
		InigoExtras.MrDVisible.ShowMrD = pr  ;the custom property ShowMrD handles everything important
		SetTextOptionValueST(ShowMrDTxt(pr))
	EndEvent

	Event OnDefaultST()
		InigoExtras.MrDVisible.ShowMrD = 0
		SetTextOptionValueST(ShowMrDTxt(0))
	EndEvent

EndState


State Whistle

	Event OnHighlightST()
		SetInfoText("After learning to Whistle to Inigo you can use this key instead of the power.")
	EndEvent

	Event OnDefaultST()
		OnKeyMapChangeST(45,"","") ; X is the default
	EndEvent

	Event OnKeyMapChangeST(int keyCode, string conflictControl, string conflictName)
		if keyCode == 1 || (keyCode > 255 && !Game.UsingGamepad())
			ShowMessage("$SKI_MSG1", false, "$OK", "$Cancel")
			return 
		endif
		InigoExtras.UnregisterForKey(InigoExtras.WhistleKeyCode)
		InigoExtras.WhistleKeyCode = keyCode
		if keyCode > 0
			InigoExtras.RegisterForKey(keyCode)
		endif
		SetKeyMapOptionValueST(InigoExtras.WhistleKeyCode, false, "")
	EndEvent

EndState

 

 

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...