KicklerOfButts Posted April 21, 2018 Posted April 21, 2018 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~ 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.
Teutonic Posted April 21, 2018 Posted April 21, 2018 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.
KicklerOfButts Posted April 21, 2018 Author Posted April 21, 2018 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
Teutonic Posted April 21, 2018 Posted April 21, 2018 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.
KicklerOfButts Posted April 21, 2018 Author Posted April 21, 2018 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?
Teutonic Posted April 21, 2018 Posted April 21, 2018 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).
KicklerOfButts Posted April 22, 2018 Author Posted April 22, 2018 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~
Teutonic Posted April 22, 2018 Posted April 22, 2018 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] != ""))
KicklerOfButts Posted April 22, 2018 Author Posted April 22, 2018 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. Now if only I could understand how to do a proper multi-dimensional array so I didn't have to copy/paste so much...
Teutonic Posted April 22, 2018 Posted April 22, 2018 Glad it works. Spoiler There are no proper multi-dimensional arrays in Papyrus.
KicklerOfButts Posted April 22, 2018 Author Posted April 22, 2018 I know there's not. 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.
Teutonic Posted April 22, 2018 Posted April 22, 2018 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.
KicklerOfButts Posted April 24, 2018 Author Posted April 24, 2018 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?
Teutonic Posted April 24, 2018 Posted April 24, 2018 I am not an expert on this, but afaik there are scripts that have thousands of instances. Try it, I guess. (Although I wonder why you need to store this amount of data).
KicklerOfButts Posted April 24, 2018 Author Posted April 24, 2018 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.
marq Posted August 1, 2020 Posted August 1, 2020 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.
Recommended Posts
Archived
This topic is now archived and is closed to further replies.