Jump to content

MCM Menu Toggling [Solved]


Recommended Posts

THE ISSUE OF THIS TOPIC WAS:

I have a mod with an MCM menu, but the toggle buttons would not toggle when pressed.
It didn't work because I was asking papyrus to read a string as a bool incorrectly, in a way that always returns true.

Thanks to Teutonic for figuring out the issue~ :smiley:

SOLUTION and LESSON LEARNED:
If you tell papyrus to read a string as a bool, the string will always return bool=true unless the string contains nothing, like so: "". (IE: Absolutely nothing, not even a space.)

if !RandomString
	-DO STUFF-
else
	-DO OTHER STUFF-
endif

If RandomString holds anything at all, even just a blank space like so: " ", -DO STUFF- will happen.
If RandomString holds nothing at all, that is to say "", -DO OTHER STUFF- will happen.

Link to comment

Why even use an Int to store the toggle option value? Seems odd to cast back and forth. If you really need to store the value in an int, I would suggest something like 

 

event OnOptionSelect(int option)

	if option == mcm_ArmorList_1_OID_B[0]
		
		If (CMO_Array_OutfitEntry_1[3] == 1)
			CMO_Array_OutfitEntry_1[3] = 0
		Else
			CMO_Array_OutfitEntry_1[3] = 1
		EndIf
		
		SetToggleOptionValue(option, (CMO_Array_OutfitEntry_1[3] == 1))

	endif

Endevent

This is much neater code and there is no need to cast anything. If I understand bool <> int casting correctly, what you are doing should work though. From the top of my head, I would say the arrays you are using are not properly initialized. Forgetting that is one of those things that can drive you mad.

Link to comment

The following lines:

		mConverter = CMO_Array_OutfitEntry_1[3] as bool
		mConverter = !mConverter
		CMO_Array_OutfitEntry_1[3] = mConverter as int
		SetToggleOptionValue(mcm_ArmorList_1_OID_B[0], CMO_Array_OutfitEntry_1[3])

Would ideally just look like this: (the standard way of doing it when you're not using arrays, but I'm using arrays.)

		CMO_Array_OutfitEntry_1[3] = !CMO_Array_OutfitEntry_1[3]
		SetToggleOptionValue(mcm_ArmorList_1_OID_B[0], CMO_Array_OutfitEntry_1[3])

But I was having doubts about whether that actually works properly.

I broke out the value into an integer and manually flip it just to make certain it does work.
mConvert = !mConverter accomplishes the same thing as your entire if/then/else section at even less cost of performance. (Though it's a completely negligible performance level regardless.) It doesn't need to check what the current value is, it just needs to flip it.

My real trouble right now is that SetToggleOptionValue() seemingly isn't working and I can't for the life of me figure out why.

 

Here's the whole segment of the code that deals with establishing, initializing and using the arrays. In case it helps.
(I'm doing makeshift multi-dimensional array because I couldn't figure out how to do it according to the wiki)

string CMO_Array_SelectedArray

string[] CMO_Array_Index_0
string[] CMO_Array_Index_1
string[] CMO_Array_Index_2
int[] CMO_Array_Index_3
int[] CMO_Array_Index_4
int[] CMO_Array_Index_5
int[] CMO_Array_Index_6


string[] CMO_Array_OutfitEntry_1
string[] CMO_Array_OutfitEntry_2
string[] CMO_Array_OutfitEntry_3
string[] CMO_Array_OutfitEntry_4
string[] CMO_Array_OutfitEntry_5
string[] CMO_Array_OutfitEntry_6
string[] CMO_Array_OutfitEntry_7
string[] CMO_Array_OutfitEntry_8
string[] CMO_Array_OutfitEntry_9
string[] CMO_Array_OutfitEntry_10

Event OnConfigInit()
	Debug.Trace("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")

	int i = InitializeArrays(1)
	Debug.Trace("CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC")


	Pages = new string[2]
	Pages[0] = "Activate Mod"
	Pages[1] = "Vanilla Armors"
EndEvent

int Function InitializeArrays(int mInt)
	mcm_ArmorList_1_OID_B = new int[100]

	CMO_Array_SelectedArray = new string[16]

	CMO_Array_Index_0 = new string[100]
	int mLoop = 0
	while mLoop < 100

		CMO_Array_Index_0[mLoop] = "placeholder"
		mLoop += 1
	endwhile
    
	CMO_Array_Index_1 = new string[100]
	CMO_Array_Index_2 = new string[100]
	CMO_Array_Index_3 = new int[100]
	CMO_Array_Index_4 = new int[100]
	CMO_Array_Index_5 = new int[100]
	CMO_Array_Index_6 = new int[100]

	CMO_Array_OutfitEntry_1 = new string[7]
	CMO_Array_OutfitEntry_2 = new string[7]
	CMO_Array_OutfitEntry_3 = new string[7]
	CMO_Array_OutfitEntry_4 = new string[7]
	CMO_Array_OutfitEntry_5 = new string[7]
	CMO_Array_OutfitEntry_6 = new string[7]
	CMO_Array_OutfitEntry_7 = new string[7]
	CMO_Array_OutfitEntry_8 = new string[7]
	CMO_Array_OutfitEntry_9 = new string[7]
	CMO_Array_OutfitEntry_10 = new string[7]





	CMO_Array_OutfitEntry_1[0] = CMO_Array_Index_0[0]
	CMO_Array_OutfitEntry_1[1] = CMO_Array_Index_1[0]
	CMO_Array_OutfitEntry_1[2] = CMO_Array_Index_2[0]
	CMO_Array_OutfitEntry_1[3] = CMO_Array_Index_3[0] as string
	CMO_Array_OutfitEntry_1[4] = CMO_Array_Index_4[0] as string
	CMO_Array_OutfitEntry_1[5] = CMO_Array_Index_5[0] as string
	CMO_Array_OutfitEntry_1[6] = CMO_Array_Index_6[0] as string

	CMO_Array_OutfitEntry_2[0] = CMO_Array_Index_0[1]
	CMO_Array_OutfitEntry_2[1] = CMO_Array_Index_1[1]
	CMO_Array_OutfitEntry_2[2] = CMO_Array_Index_2[1]
	CMO_Array_OutfitEntry_2[3] = CMO_Array_Index_3[1] as string
	CMO_Array_OutfitEntry_2[4] = CMO_Array_Index_4[1] as string
	CMO_Array_OutfitEntry_2[5] = CMO_Array_Index_5[1] as string
	CMO_Array_OutfitEntry_2[6] = CMO_Array_Index_6[1] as string

	CMO_Array_OutfitEntry_3[0] = CMO_Array_Index_0[2]
	CMO_Array_OutfitEntry_3[1] = CMO_Array_Index_1[2]
	CMO_Array_OutfitEntry_3[2] = CMO_Array_Index_2[2]
	CMO_Array_OutfitEntry_3[3] = CMO_Array_Index_3[2] as string
	CMO_Array_OutfitEntry_3[4] = CMO_Array_Index_4[2] as string
	CMO_Array_OutfitEntry_3[5] = CMO_Array_Index_5[2] as string
	CMO_Array_OutfitEntry_3[6] = CMO_Array_Index_6[2] as string

	CMO_Array_OutfitEntry_4[0] = CMO_Array_Index_0[3]
	CMO_Array_OutfitEntry_4[1] = CMO_Array_Index_1[3]
	CMO_Array_OutfitEntry_4[2] = CMO_Array_Index_2[3]
	CMO_Array_OutfitEntry_4[3] = CMO_Array_Index_3[3] as string
	CMO_Array_OutfitEntry_4[4] = CMO_Array_Index_4[3] as string
	CMO_Array_OutfitEntry_4[5] = CMO_Array_Index_5[3] as string
	CMO_Array_OutfitEntry_4[6] = CMO_Array_Index_6[3] as string

	CMO_Array_OutfitEntry_5[0] = CMO_Array_Index_0[4]
	CMO_Array_OutfitEntry_5[1] = CMO_Array_Index_1[4]
	CMO_Array_OutfitEntry_5[2] = CMO_Array_Index_2[4]
	CMO_Array_OutfitEntry_5[3] = CMO_Array_Index_3[4] as string
	CMO_Array_OutfitEntry_5[4] = CMO_Array_Index_4[4] as string
	CMO_Array_OutfitEntry_5[5] = CMO_Array_Index_5[4] as string
	CMO_Array_OutfitEntry_5[6] = CMO_Array_Index_6[4] as string
	
	CMO_Array_OutfitEntry_6[0] = CMO_Array_Index_0[5]
	CMO_Array_OutfitEntry_6[1] = CMO_Array_Index_1[5]
	CMO_Array_OutfitEntry_6[2] = CMO_Array_Index_2[5]
	CMO_Array_OutfitEntry_6[3] = CMO_Array_Index_3[5] as string
	CMO_Array_OutfitEntry_6[4] = CMO_Array_Index_4[5] as string
	CMO_Array_OutfitEntry_6[5] = CMO_Array_Index_5[5] as string
	CMO_Array_OutfitEntry_6[6] = CMO_Array_Index_6[5] as string
	
	CMO_Array_OutfitEntry_7[0] = CMO_Array_Index_0[6]
	CMO_Array_OutfitEntry_7[1] = CMO_Array_Index_1[6]
	CMO_Array_OutfitEntry_7[2] = CMO_Array_Index_2[6]
	CMO_Array_OutfitEntry_7[3] = CMO_Array_Index_3[6] as string
	CMO_Array_OutfitEntry_7[4] = CMO_Array_Index_4[6] as string
	CMO_Array_OutfitEntry_7[5] = CMO_Array_Index_5[6] as string
	CMO_Array_OutfitEntry_7[6] = CMO_Array_Index_6[6] as string
	
	CMO_Array_OutfitEntry_8[0] = CMO_Array_Index_0[7]
	CMO_Array_OutfitEntry_8[1] = CMO_Array_Index_1[7]
	CMO_Array_OutfitEntry_8[2] = CMO_Array_Index_2[7]
	CMO_Array_OutfitEntry_8[3] = CMO_Array_Index_3[7] as string
	CMO_Array_OutfitEntry_8[4] = CMO_Array_Index_4[7] as string
	CMO_Array_OutfitEntry_8[5] = CMO_Array_Index_5[7] as string
	CMO_Array_OutfitEntry_8[6] = CMO_Array_Index_6[7] as string
	
	CMO_Array_OutfitEntry_9[0] = CMO_Array_Index_0[8]
	CMO_Array_OutfitEntry_9[1] = CMO_Array_Index_1[8]
	CMO_Array_OutfitEntry_9[2] = CMO_Array_Index_2[8]
	CMO_Array_OutfitEntry_9[3] = CMO_Array_Index_3[8] as string
	CMO_Array_OutfitEntry_9[4] = CMO_Array_Index_4[8] as string
	CMO_Array_OutfitEntry_9[5] = CMO_Array_Index_5[8] as string
	CMO_Array_OutfitEntry_9[6] = CMO_Array_Index_6[8] as string
	
	CMO_Array_OutfitEntry_10[0] = CMO_Array_Index_0[9]
	CMO_Array_OutfitEntry_10[1] = CMO_Array_Index_1[9]
	CMO_Array_OutfitEntry_10[2] = CMO_Array_Index_2[9]
	CMO_Array_OutfitEntry_10[3] = CMO_Array_Index_3[9] as string
	CMO_Array_OutfitEntry_10[4] = CMO_Array_Index_4[9] as string
	CMO_Array_OutfitEntry_10[5] = CMO_Array_Index_5[9] as string
	CMO_Array_OutfitEntry_10[6] = CMO_Array_Index_6[9] as string
	Debug.Trace("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB")


	return mInt
EndFunction


 

Link to comment

I don't see why var = !var would not work with bool array entries. 

 

The reason your toggle isn't working is that the array is not an int array, but a string array. No matter what you put into it, it will always evaluate to true. So flipping the value won't do anything. True will be cast as "TRUE" and false will be cast as "false" but both "TRUE" and "false" will be cast as true.

Link to comment

Can Papyrus not translate a string containing "0" into a bool if you tell it to read it as a bool?
Because logically, mConverter = CMO_Array_OutfitEntry_1[3] as bool should translate into mConverter == 0 because CMO_Array_OutfitEntry_1[3] == "0"

Will the string always return as true if I check it as a bool even when the string is "0" or "1" and the code says to read it as a bool?

Link to comment
48 minutes ago, JustSomeAnon said:

Can Papyrus not translate a string containing "0" into a bool if you tell it to read it as a bool?
Because logically, mConverter = CMO_Array_OutfitEntry_1[3] as bool should translate into mConverter == 0 because CMO_Array_OutfitEntry_1[3] == "0"

Will the string always return as true if I check it as a bool even when the string is "0" or "1" and the code says to read it as a bool?

A string will be cast as true if it is not empty. The only way to make it cast as false would be setting it to "" but since you are casting a bool to fill the string value, it contains either "TRUE" or "false" and is therefore not empty. So the solution would be to simply switch to using bool arrays to store the value of the option.

 

Btw you do not need to manually cast ints, bools, floats and strings as one another since the compiler does it automatically. (Although you could still do it manually to make it clear in the code of what type the variable is.) You only need to cast manually when casting objects as their children (e.g. Form as Quest).

Link to comment

Unfortunately it's absolutely not an option to have CMO_Array_OutfitEntry[] be any other type of array, it very much has to be strings for the rest of my mod to function.

That's very valuable knowledge though, that a string need to be empty like so: "" in order for papyrus to be able to return it as a bool set to false.
I would not have figured that out on my own, I just assumed it could translate "true" and "false" into bools just as it can translate true/false from them into strings.

I'll fiddle around with it and see if I can get it to work now that I know what would make papyrus read it properly.

I always cast variables that turn into other variable types manually for the sake of code clarity and because it's good coding practice to always make certain, minimizing any potential risk of compiler errors. (I've gotten compiler errors before in the creation kit because it wants the conversion to be explicit, may as well be on the safe side.)

Thanks for the help so far, I'll let you know if I get it to work or if I need to beg for more feedback~

Link to comment

You could take the If construct i suggested earlier, but instead of comparing it to 1, you compare it to "".

 

If (CMO_Array_OutfitEntry_1[3] != "")			;True
	CMO_Array_OutfitEntry_1[3] = ""				;set to False
Else											;False
	CMO_Array_OutfitEntry_1[3] = "something"	;set to True
EndIf
		
SetToggleOptionValue(option, (CMO_Array_OutfitEntry_1[3] != ""))

 

Link to comment

That's pretty much what I've ended up doing (Only I write it as if !CMO_Array_OutfitEntry_1[3] then instead. Cleaner code like that.)

Thanks for the help, I pretty much got it working.
Now my framework is actually getting close to having basic functionality. :blush:

Now if only I could understand how to do a proper multi-dimensional array so I didn't have to copy/paste so much... :bawling:

Link to comment

I know there's not. :tongue:
Currently I just have a bunch of arrays that I manually point to the specific indexes of other arrays, it's a solution that works but it's as basic as it could possibly get and requires a lot of manual if/then/else checking to use.

But there's a way of simulating one that gives you an array that automatically references other arrays without having to write a long line of if/then/else checks.

If I had one like that then I could use a while loop rather than manually typing out the 40+ scenarios for handling my outfit arrays, but I can't make enough sense of the CK wiki's instructions to make one. :bawling:

Link to comment

You might be able to create a script with multiple arrays as Properties and then create multiple instances of that script. Whenever you need the data, you add an array of those instances as a property.

 

Scriptname ArrayContainer extends Quest		;Just slap it on some quests 

String[] Property Array1 Auto 
String[] Property Array2 Auto 
Scriptname AwesomeScript 

ArrayContainer[] Property Container Auto 

Function AwesomeFunction()

	Container[0].Array1[0] = ""
	Container[1].Array1[3] = "stuff"
	Container[2].Array2[2] = "yay"

EndFunction

This would effectively give you a three-dimensional array. 

Link to comment

If the script is duplicated with each new container/3DArray and I need upwards of 200+ 3DArrays, wouldn't that take a massive toll on papyrus with 200+ copies of a script existing?

Even though the script only contains data and no functions or events, won't it still cause issues for the engine just by virtue of quantity?

Link to comment

I don't necessarily need to store "a lot" of information, I just need to store is in a very specific way so that I can use it effectively without having to copy/paste hundreds of if/then/else checks.
I'm creating a framework for "tagging" (without actual tags though) armors and outfits as more or less skimpy for other mods to make use of.

 

Event OnPageReset(string page)
	SetCursorFillMode(LEFT_TO_RIGHT)
	SetCursorPosition(0) ; Can be removed because it starts at 0 anyway
	int mMetaLoop = 0
	int mLoop = 1
	string mToggleName
	
	if (page == "Activate Mod")
	
	elseif (page == "Vanilla Armors 1")
	
						while mMetaLoop < 14
						
							AddHeaderOption(link_Container_Armors[mMetaLoop].VanillaArmor[0] as string)
							AddHeaderOption("")
							while mLoop < 5
							
								if mLoop == 1
									mToggleName = "Topless"
								elseif mLoop == 2
									mToggleName = "Skimpy Top"
								elseif mLoop == 3
									mToggleName = "Bottomless"
								elseif mLoop == 4
									mToggleName = "Skimpy Bottoms"
								elseif mLoop == 5
									mToggleName	= "Shared Name"
								endif
								mcm_ArmorList_1_OID_B[mMetaLoop] = AddToggleOption(mToggleName, link_Container_Armors[mMetaLoop].VanillaArmor[mLoop] as int)

							mLoop += 1
							endwhile

						AddEmptyOption()
						mMetaLoop += 1
						endwhile
	
	elseif (page == "Vanilla Armors 2")
	
	elseif (page == "Vanilla Armors 3")
	
	endIf

endEvent

This is how my MCM menu's pagereset function looks now compared to before.

Link to comment
  • 2 years later...

Hi! 

 

I am not a modder so I did not understand any of this. But I have a similar problem: that I cannot seem to toggle on and off options in mods in MCM.

 

I have a few adult mods that I have installed for Enderal. And I am trying to toggle off the more violent, rapey, anal simulations options etc.

 

Every time I toggle them off they reset when I exit mcm. (They reset because when I return to check on the mod options they have been re-toggled on.)

 

What can I do to ensure that I can toggle options of these mods in MCM in Enderal.

 

Cheers.

Link to comment

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

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

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. For more information, see our Privacy Policy & Terms of Use