Jump to content

[LE] MCM and shrine-menu problems


Recommended Posts

I have doubt that next is changing the option text inside the MCM menu you like. Why?

If you end the function VampireMenu() each temp array is thrown away.

 

 

 

Function VampireMenu() ; New version.

string[] VampireText = new string[6] ; Array with text labels for menu
VampireText[0] = ". Cancel"
VampireText[1] = ". Vampire Armor"
VampireText[2] = ". Vampire Armor without fighting"
VampireText[3] = ". Ancient Blood"
VampireText[4] = ". Cure Vampirism and remove all powers"
VampireText[5] = ". Cure Vampirism and Turn into a Lycan"

int c = 0        ; counting the number of rows for the array VampireMenu
int i = 1        ; adding mumbers to menu, starting with 1
int Index = 0    ; for array index and adding matching textlabels from array VampireText
string[] VampireMenu = new string [128]    ; Creating new menu array from bools who are True

While Index < RemoteMCM.VampireVal.Length
    Debug.Notification("VampireVal " + Index + " = " + RemoteMCM.VampireVal[Index])    ; debugging only !!!
    Index += 1
EndWhile

Index = 0
While Index < RemoteMCM.VampireVal.Length
    If    RemoteMCM.VampireVal[Index] == True    ; Check wich bools are True
        VampireMenu[Index] = i + VampireText[Index]; adding Textlabels + numbers to menu array

        ; adding actions to menu
        Debug.Notification("option " + i + VampireText[Index])    ; debugging only !!!
        functionSelect(Index)
        c += 1
    EndIf
    Index += 1
    i += 1
EndWhile
; At this point the new menu should be complete and stored in the array VampireMenu. Now i need to convert the array to a visible menu.

; The while loop below should display the array VampireMenu and all options in it. I only made this to see if everything works as intended.
Index = 0
Debug.Notification("You have seleted " + c + " Options")    ; debugging only !!!

While Index < c    
    Debug.Notification("VampireMenu " + Index + " = " + VampireMenu[Index])    ; debugging only !!!
    Index += 1
EndWhile
EndFunction

 

 

 

everything you made with

string[] VampireText
string[] VampireMenu

keeps in this function and will never get transfer to MCM script

 

The function VampireMenu() is not suppost to make changes to the mcm.

Inside VampireMenu() i collect info from the mcm, and with that info i create fill the array VampireMenu.

 

The mcm is only there to select wich options you want to see in the menu when you activate the shrine.

After the menu is made and presented to the player, it is ok if the temp arrays get thrown away.

 

It is true that i still need to figure out a way to convert the array to a menu, but giving the array back to the mcm was never my intention.

 

So maybe i am stupid, but i don't understand your post.

Link to comment
Share on other sites

 

 

That is not how OnOptionHighlight works. It will only display text when an option is highlighted. If you put the mouse over any non-option area, no text will display. Unfortunately, it is working as intended.

Thnx for explaining this, but in that case i just leave it as it is now.

My mcm is easy enough to understand as it is. The InfoText was just a litle extra.

 

If the code you showed is producing the message in screenshot 7/9 from your mod-page, then i don't understand why you made it. Isn't this the way all mcm menu's work?

First you need to exit all menu's before you can notice any changes.

 

I think i prefere to explain my mcm menu in the description of my mod page. That should be enough.

 

The reason I needed to add that message box was for the following reason:

When I made that MCM script I did not know that calling certain functions within the option select would cause the MCM menu to eventually cease functioning. It is not an issue if using just my mod's MCM. But it was causing an issue when going from my mod's MCM to another mod's MCM. I have since learned that it is better to utilize the OnConfigClose event to register a single update (which even with a short duration is safely delayed until the menu system is exited) to handle starting quests, setting variables etc depending upon user selections. My Inventory Management System Rebuilt mod uses this method.

 

At any rate, however you choose to inform your users of the mod's intentions is up to you.

Link to comment
Share on other sites

 

 

I'm not totally sure why there's the independent boolean variables at all. Why not the single array? Maybe another for reset-to-default information. Then you could just do

VampireVal[n] = !VampireVal[n]

The initial bools are there for when you load the mcm for the first time. The mcm should have some initial values to build the menu. I chose to make the initial values the same as the default values because i think that makes sense.

 

I don't know how to implement your suggestion into my script. I don't understand your comment enough.

 

 

You can set the initial bools in the Properties menu, since the boolean array is one. If you want a set to do the revert to default stuff, then you do need a second set of bools, but you can also make that a boolean array property and set them there.

 

So instead of a bunch of VampireValN variables for your defaults, you could use DefaultVampireVal[N] and only need to declare or manipulate one thing, just as you're doing with VampireVal[N] for your active booleans.

 

That way you can avoid hardcoding the defaults into the script and can replace the one-by-one copying into the active array in your OnInit block with a loop, which will be much more extensible should you decide to change the options in future.

 

As for the other piece:

 

Just as you can use ordinary arithmetic in an assignment (for example i = j + 1), you can use boolean arithmetic: EQUALS, NOT, AND, and OR, symbolically done as '==', '!', '&&', and '||'. Since all you're doing is flipping from one state to another you don't need an if-else-then sequence because you're always going to do the same operation: a NOT. This will turn trues into falses and falses into trues. You're doing this already with your operations ahead of the SetOptionToggle() call in your OnOptionSelect(), but you're then also doing explicit assignments of true and false to the boolean array, which you don't need to do.

 

A revision showing the implementation:

Scriptname VC_Script_MCM extends SKI_ConfigBase
{MCM menu script}

; For all code in this file i used the MCM video tutorials from DarkFox127 as starting point and started working from there.

bool bInitialized = false

string Property sVampireOptionName[] ;titles for the various options

bool Property bDefaultVampireVal[] ;fill this in the properties menu, replaces VampireValN below
;Bool VampireVal0 = True    ; Cancel button. This does not not show in mcm menu and therefore always is True.
;Bool VampireVal1 = True
;Bool VampireVal2 = False
;Bool VampireVal3 = True
;Bool VampireVal4 = False
;Bool VampireVal5 = False

int iVampireOption[] ;created & filled automatically
;int iVampire1
;int iVampire2
;int iVampire3
;int iVampire4
;int iVampire5

bool[] Property bVampireVal Auto    ; Make the array available for VC_Script_Shrine_MolagBal

Event OnConfigInit()
    ;Declare these in the property menu
    ;Pages = new string[1]
    ;Pages[0] = "Config"

    if !bInitialized
        int i = sVampireOptionName.Length
        int j = bDefaultVampireVal.Length
        iVampireOption = Utility.CreateIntArray(i)
        bVampireVal = Utility.CreateBoolArray(i)
        while i > 0
            i-=1
            if i < j ;precaution in case fewer defaults are specified than option names
                bVampireVal[i] = bDefaultVampireVal[i]
            endif
        endwhile
    endif
EndEvent

;Functionality moved to OnConfigInit()
;Event OnInit()
;    parent.OnInit()
;
;    VampireVal = new bool[6]    ; storing all bools in array
;
;    VampireVal[0] = VampireVal0
;    VampireVal[1] = VampireVal1
;    VampireVal[2] = VampireVal2
;    VampireVal[3] = VampireVal3
;    VampireVal[4] = VampireVal4
;    VampireVal[5] = VampireVal5
;EndEvent

Event OnPageReset(string page)
    If (Page == "")
        LoadCustomContent("Imaginary_Image")
        Return
    Else
        UnLoadCustomContent()
    EndIf

    If (Page == "Config")
        SetCursorFillMode(TOP_TO_BOTTOM)
        AddHeaderOption("Vampire Menu")

        int i = sVampireOptionName.Length
        while i > 1 ;because of hidden cancel button? I do not understand the purpose of that
            i-=1
            iVampireOption[i] = AddToggleOption(sVampireOptionName[i], bVampireOption[i])
        endwhile

        ;iVampire1 = AddToggleOption("Vampire Armor", VampireVal1)
        ;iVampire2 = AddToggleOption("Vampire Armor without fighting", VampireVal2)
        ;iVampire3 = AddToggleOption("Ancient Blood", VampireVal3)
        ;iVampire4 = AddToggleOption("Cure Vampirism", VampireVal4)
        ;iVampire5 = AddToggleOption("Turn into a Lycan", VampireVal5)
    EndIf
EndEvent

Event OnOptionSelect(int option)
    If (CurrentPage == "Config")

        int iIndex = iVampireOption.Find(option)
        if iIndex < 0
            return
        endif

        bVampireVal[iIndex] = !bVampireVal[iIndex]
        SetToggleOptionValue(iVampireOption[iIndex], bVampireVal[iIndex])

        ;all of the below is now redundant        
        ;If        (option == iVampire1)
        ;    VampireVal1 = !VampireVal1
        ;       SetToggleOptionValue(iVampire1, VampireVal1)
        ;       If VampireVal1 == True
        ;        VampireVal[1] = True
        ;       Else
        ;        VampireVal[1] = False
        ;    EndIf
        ;ElseIf    (option == iVampire2)
        ;    VampireVal2 = !VampireVal2
        ;    SetToggleOptionValue(iVampire2, VampireVal2)
        ;    VampireVal2 = VampireVal2
        ;    If VampireVal2 == True
        ;        VampireVal[2] = True
        ;    Else
        ;        VampireVal[2] = False
        ;    EndIf
        ;ElseIf    (option == iVampire3)
        ;    VampireVal3 = !VampireVal3
        ;    SetToggleOptionValue(iVampire3, VampireVal3)
        ;    VampireVal3 = VampireVal3
        ;    If VampireVal3 == True
        ;        VampireVal[3] = True
        ;    Else
        ;        VampireVal[3] = False
        ;    EndIf
        ;ElseIf    (option == iVampire4)
        ;    VampireVal4 = !VampireVal4
        ;    SetToggleOptionValue(iVampire4, VampireVal4)
        ;    VampireVal4 = VampireVal4
        ;    If VampireVal4 == True
        ;        VampireVal[4] = True
        ;    Else
        ;        VampireVal[4] = False
        ;    EndIf
        ;ElseIf    (option == iVampire5)
        ;    VampireVal5 = !VampireVal5
        ;    SetToggleOptionValue(iVampire5, VampireVal5)
        ;    VampireVal5 = VampireVal5
        ;    If VampireVal5 == True
        ;        VampireVal[5] = True
        ;    Else
        ;        VampireVal[5] = False
        ;    EndIf
        ;EndIf
    EndIf
EndEvent

Event OnOptionDefault(int option)

    if (CurrentPage == "Config") ;this is a needed check that was missed in original code
        int iIndex = iVampireOption.Find(option)
        if iIndex < 0
            return
        endif

        bVampireVal[iIndex] = bDefaultVampireVal[iIndex]
        SetToggleOptionValue(iVampireOption[iIndex], bVampireVal[iIndex])
    endif

    ;all of the below is now redundant
    ;If        (option == iVampire1)
    ;    VampireVal1 = True
    ;    SetToggleOptionValue(iVampire1, VampireVal1)
    ;    VampireVal[1] = True
    ;ElseIf    (option == iVampire2)
    ;    VampireVal2 = False
    ;    SetToggleOptionValue(iVampire2, VampireVal2)
    ;    VampireVal[2] = False
    ;ElseIf    (option == iVampire3)
    ;    VampireVal3 = True
    ;    SetToggleOptionValue(iVampire3, VampireVal3)
    ;    VampireVal[3] = True
    ;ElseIf    (option == iVampire4)
    ;    VampireVal4 = False
    ;    SetToggleOptionValue(iVampire4, VampireVal4)
    ;    VampireVal[4] = False
    ;ElseIf    (option == iVampire5)
    ;    VampireVal5 = False
    ;    SetToggleOptionValue(iVampire5, VampireVal5)
    ;    VampireVal[5] = False
    ;EndIf
EndEvent

I'm not exactly sure what the purpose is behind the 'cancel button' because AFAICT you have no code whatsoever that implements it. Normally I'd just iterate the arrays all the way to zero, but it throws things out on actually adding the toggles, which is why that particular loop is set to stop at one instead.

 

Provided you set up the properties correctly this should have the same functionality, but be much easier to add or remove options; you just need to modify a title and, optionally, a default value. I also added a missing CurrentPage check to the OnOptionDefault() block.

Edited by foamyesque
Link to comment
Share on other sites

Your new version of the mcm script looks great, i like the idea of shrinking the wall of code, but don't forget:

    If (Page == "Config")
        SetCursorFillMode(TOP_TO_BOTTOM)
        AddHeaderOption("Vampire Menu")
        iVampire1 = AddToggleOption("Vampire Armor", VampireVal1)
        iVampire2 = AddToggleOption("Vampire Armor without fighting", VampireVal2)
        iVampire3 = AddToggleOption("Ancient Blood", VampireVal3)
        iVampire4 = AddToggleOption("Cure Vampirism", VampireVal4)
        iVampire5 = AddToggleOption("Turn into a Lycan", VampireVal5)
    EndIf

is only a part of the total mcm i want to make. I think i mentioned this inside the script for the shrine in the added comments, but i am not sure it was mentioned in one of the forum posts. If not, then sorry for that. The plan was to get the vampire part working first and then add the mortal and lycan stuff later. The total menu layout will look something like this:

    If (Page == "Config")
        SetCursorFillMode(LEFT_TO_RIGHT)
        AddHeaderOption("Vampire Menu")
        AddHeaderOption("Mortal Menu")
        iVampire1 = AddToggleOption("Vampire Armor", VampireVal1)
        AddToggleOption("Cure All Disseases", True)
        iVampire2 = AddToggleOption("Vampire Armor without fighting", VampireVal2)
        AddToggleOption("Sanguinare Vampiris", True)
        iVampire3 = AddToggleOption("Ancient Blood", VampireVal3)
        AddToggleOption("Turn into a Vampire", True)
        iVampire4 = AddToggleOption("Cure Vampirism", VampireVal4)
        AddToggleOption("Turn into a Lycan", False)
        iVampire5 = AddToggleOption("Turn into a Lycan", VampireVal5)
        AddEmptyOption()
        AddEmptyOption()
        AddEmptyOption()
        AddHeaderOption("Lycan Menu")
        AddEmptyOption()
        AddToggleOption("Lycans can't use the shrine", False)
        AddEmptyOption()
        AddToggleOption("Cure Lycantrophy", True)
        AddEmptyOption()
        AddToggleOption("Turn into a Vampire", True)        
    EndIf

As you can see i did not add any actions to the mortal and lycan options yet.
My thought was, once i get the vampire menu working, the other 2 are just more of the same and easy to add in.

Once i get the vampire stuff working and i completed the whole mcm menu, then it is a good idea to shrink the code with the code you suggested. But before i even start with the mortal and lycan stuff, i want to get the vampire stuff working first.

I see you like to add all you can to the properties-window in the CK, is that personal preference, or is there another reason for doing that?
I like to keep everything inside the script whenever possible because it's easier when you need to change/add something. If you store everything in the properties-window then you need to start CK for every change you want to make. If you keep everything inside the script, then you can just open notepad++ to edit and compile scripts. Or maybe i am doing something wrong, that is also possible.

About the cancel button:
I want to make sure the new menu always has a cancel button, this way you are not forced to choose one of the options if you activate the shrine by accident.
In the function VampireMenu() inside VC_Script_Shrine_MolagBal i check wich bools are true.
Only true bools are added to the new menu.
Because there is no option to disable the cancel button in the mcm, Bool VampireVal0 is always True.

I am sure this is not the best way to do this, but it works.
Here is the script VC_Script_Shrine_MolagBal

 

Scriptname VC_Script_Shrine_MolagBal extends ObjectReference
{Menu Script for Molag Bal Shrine}

VC_Script_addCoffin Property RemoteScript Auto ; All functions are stored in VC_Script_addCoffin. I call them when needed with RemoteScript.
VC_Script_MCM Property RemoteMCM Auto ; Link to MCM menu script

Event onActivate(ObjectReference akActionRef)
    CheckRace()
EndEvent

Function CheckRace()
    RemoteScript.VC_Player_Race()
    If        (RemoteScript.vcRace == 1)    ; Player is Vampire
            VampireMenu()
    ElseIf    (RemoteScript.vcRace == 2)    ; Player is Lycan
            LycanMenu()
    ElseIf    (RemoteScript.vcRace == 3)    ; Player is Mortal
            MortalMenu()
    EndIf
EndFunction

Function VampireMenu() ; New version.

string[] VampireText = new string[6] ; Array with text labels for menu
VampireText[0] = ". Cancel"
VampireText[1] = ". Vampire Armor"
VampireText[2] = ". Vampire Armor without fighting"
VampireText[3] = ". Ancient Blood"
VampireText[4] = ". Cure Vampirism and remove all powers"
VampireText[5] = ". Cure Vampirism and Turn into a Lycan"

int c = 0        ; counting the number of rows/buttons for the array VampireMenu
int i = 1        ; adding mumbers to menu, starting with 1
int Index = 0    ; for array index and adding matching textlabels from array VampireText
string[] VampireMenu = new string [128]    ; Creating new menu array from bools who are True

While Index < RemoteMCM.VampireVal.Length
    Debug.Notification("VampireVal " + Index + " = " + RemoteMCM.VampireVal[Index])    ; debugging only !!!
    Index += 1
EndWhile

Index = 0
While Index < RemoteMCM.VampireVal.Length
    If    RemoteMCM.VampireVal[Index] == True    ; Check wich bools are True
        VampireMenu[Index] = i + VampireText[Index]; adding Textlabels + numbers to menu array
        ; Debug.Notification("option " + i + VampireText[Index])    ; debugging only !!!
        c += 1
    EndIf
    Index += 1
    i += 1
EndWhile
; At this point the new menu should be complete and stored in the array VampireMenu. Now i need to convert the array to a visible menu.

; The while loop below should display the array VampireMenu and all options in it. I only made this to see if everything works as intended.
Debug.Notification("You have seleted " + c + " Options")    ; debugging only !!!

Index = 0
While Index < c    
    Debug.Notification("Index "+ Index + " : " + VampireMenu[Index])    ; debugging only !!!
    Index += 1
EndWhile

;/
    ; Disabled during testing. First i want to see the new menu, then i add the functions
    If        Index == 0
    ElseIf    Index == 1
            RemoteScript.VamipereArmor()
    ElseIf    Index == 2
            RemoteScript.VamipereArmorCoward()
    ElseIf    Index == 3
            RemoteScript.AncientBlood()
    ElseIf    Index == 4
            RemoteScript.CureVampire()
    ElseIf    Index == 5
            RemoteScript.CureVampire()
            RemoteScript.CreateLycan()
    EndIf
/;
EndFunction

; Old working versions for lycan and mortal menus. I don't update them until i get the new vampire menu to work.

; Messages for old menu version. In the new menu i should no longer need them.
Message Property VC_Msg_ShrineMenu_Vampire Auto
Message Property VC_Msg_ShrineMenu_Lycan Auto
Message Property VC_Msg_ShrineMenu_Mortal Auto

Function LycanMenu (int aiButton = 0)
aiButton = VC_Msg_ShrineMenu_Lycan.Show()
    If        aiButton == 0    ; 1. Cancel
    ElseIf    aiButton == 1    ; 2. Cure my Lycantrophy
            RemoteScript.CureLycan()
    ElseIf    aiButton == 2    ; 3. Cure my Lycantrophy and turn me into a Vampire
            RemoteScript.CureLycan()
            RemoteScript.CreateVampire()
    EndIf
EndFunction

Function MortalMenu (int aiButton = 0)
aiButton = VC_Msg_ShrineMenu_Mortal.Show()
    If        aiButton == 0    ; 1. Cancel
    ElseIf    aiButton == 1    ; 2. Cure all my disseases
            RemoteScript.CureAllDisseases()
    ElseIf    aiButton == 2    ; 3. Sanguinare Vampiris
            RemoteScript.DiseaseSV()
    ElseIf    aiButton == 3    ; 4. Turn me into a vampire
            RemoteScript.CreateVampire()
    ElseIf    aiButton == 4    ; 5. Turn me into a Lycan. This option is not in v1.1, but will be in next release. In the MCM menu i will add the option to toggle this option on or off.
            RemoteScript.CreateLycan()
    EndIf
EndFunction

 

 

 

Link to comment
Share on other sites

What I prefer to do is reduce the amount of repetition of stuff, particularly of magic numbers, and especially if there's chances I might want to change it in the future. Since I do pretty much all my coding and compiling in the CK anyway, kicking out to the property filling menus doesn't particularly impede the workflow, and the approach otherwise has a bunch of benefits in terms of flexibility, reuse, extension, and interaction with other scripts.

 

As much as I am able, I try to keep explicit constant use in my scripts limited to comparisons to zero, true, false, and none. Nearly everything else comes from a variable, property, or function in one way or another.

Link to comment
Share on other sites

  • Recently Browsing   0 members

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