Creating in-game Menus

Post » Wed Sep 18, 2013 6:37 pm

I would like to program an in game menu to control my follower. Not MCM, but the ones that preceded it, and still seen in mods such as nature of the beast, puppeteer, and more hotkeys please. Unfortunately, trying to reverse engineer these mods is breaking my brain. It's hard to make sense of it. Does anyone have any advice to offer to get me started? Do you know of a mods with simpler menus so I can get a basic understanding? I doubt there are videos on this, as I've been searching for tutorials.

Perhaps I can elaborate on the simplicity of what I'm looking to do for now. I want a single menu with 4 options corresponding to 4 different states of a different script. The player chooses the first option and it sets the other script to it's first state, etc. That's it!

User avatar
Taylor Thompson
 
Posts: 3350
Joined: Fri Nov 16, 2007 5:19 am

Post » Wed Sep 18, 2013 4:47 pm

The way these kind of menus are created is by using Message objects in the CK. You need to create a new message, set it up with the "Message Box" flag ticked, and then add some "Menu Buttons" to the list. You can give each button a custom name, and the names you enter here will be the names that show up as your clickable options in the menu in-game. The index of each button that you see will be the return value given to the script when that button is clicked.

So in order to reverse-engineer any mod, you'll want to look at its Message objects in particular, and then probably you will want to look at their script source if they've included it. To use them in an actual script, you usually just include a line like:

int menuChoice = myCustomMenu.show()

This will cause the menu to pop-up in game, and whatever choice the player selects will send its index number into the variable menuChoice (the same index number that each choice had listed next to it in the Message object you made in the CK). Thus, you'll be able to respond to the player's choice by doing whatever you like--you can show another Message box menu with more specific options related to the button they've clicked, for instance, or have your script make adjustments to the follower based on that option.

A simple, slightly longer example:

Spoiler

;this could be a referenceAlias script linked to your followerEvent onActivate()  int choice1 = message1.show()  if choice1 == 0    ;respond to button one by showing another menu    int first = sub1message.show()      if first == 0        ;do stuff      elseif first == 1        ;do other stuff      elseif first == 2        ;do more stuff      endif  elseif choice1 == 1    ;respond to button two by showing a second sub-menu    int second = sub2message.show()      if second == 0        ;do fancy stuff      elseif second == 1        ;do other fancy stuff      endif  endif;finished showing the menus!EndEvent
User avatar
Daniel Lozano
 
Posts: 3452
Joined: Fri Aug 24, 2007 7:42 am

Post » Wed Sep 18, 2013 10:34 pm

Thank you kindly; this is very helpful, and i've already begun work.

I am wondering, however, if you could elaborate on a slightly offtopic question. I've never fully understood how two different scripts interact with each other. Can I have a variable in one script carry over to another - in this case one attached to an actor. Even if I could do that, I assume I would have to have an event such as an recurring update check the value of that variable, so the commands via this menu to that actor would not be instant, unless i could somehow have that event that checks the variable trigger from the closing of the message box? ideas most welcome! maybe i'll try using global variables.

Here is my very simple script:

Scriptname _an_AndromedaMenu extends ActiveMagicEffect Message Property StanceOptions  Auto  int forms Event OnEffectStart(Actor Target, Actor Caster)forms = StanceOptions.Show()EndEvent
User avatar
Nicola
 
Posts: 3365
Joined: Wed Jul 19, 2006 7:57 am

Post » Wed Sep 18, 2013 10:38 am

Yes it's possible. Just make sure the variable(s) you want to access in the remote script are set up as a property. For instance, if the script attached to your actor was called _an_ActorScript, you could access its variables and functions from your activeMagicEffect script by defining the remote script as a property like so:

Spoiler
Scriptname _an_AndromedaMenu extends ActiveMagicEffect_an_ActorScript property aScript autoint forms;...;set variables in remote scriptaScript.variable1 = 5;access variables in remote scriptforms = aScript.variable2;call functions in remote scriptaScript.someFunction();etcetera

It's also possible to gain access to the remote actor script without setting up a property if you want, just by defining it like a normal variable. For instance, if you were casting this effect on the actor with the script, you could do the following:

Spoiler
Scriptname ... extends ActiveMagicEffectEvent onEffectStart(actor akTarget, actor akCaster)  ;make a variable of the type of your remote script, then cast the actor with that script AS that script type, like so:  _an_ActorScript aScript = akTarget as _an_ActorScript  aScript.variable1 = 5  myvariable = aScript.variable2  ;etceteraEndEvent

Edit: Oh, and no you wont have to run any recurring updates or anything, every time you access a variable from the remote script, it will return its current updated value. This also will work faster than using global variables (though a bit trickier perhaps, until you get the hang of it). It is also worth noting that it is harder to access scripts that are more fleeting--like ActiveMagicEffect scripts--since you can't fill them as a property (they don't exist until runtime). You -can- get access to them, but it's quite a bit trickier.

User avatar
Lisa Robb
 
Posts: 3542
Joined: Mon Nov 27, 2006 9:13 pm

Post » Thu Sep 19, 2013 12:56 am

Ah thanks, but what event would I run in the actor script to immediately act upon the menu choice? If you could answer this, I would not deserve it, as you've basically been doing my work for me, but I would be exceptionally grateful.

Currently I'm using an extends Actor script for the Actor.

Say that "int Forms" is a property in my Actor script _an_Andromeda. Would this work or is this backwards? Also, is "int Forms" correct for this case or should it be something like "int property forms auto"? I'm glad to hear this is all possible but it's still a tad over my head.

Scriptname _an_AndromedaMenu extends ActiveMagicEffect Message Property StanceOptions  Auto_an_Andromeda property aScript Auto Event OnEffectStart(Actor Target, Actor Caster)forms = StanceOptions.Show()EndEvent
User avatar
Samantha hulme
 
Posts: 3373
Joined: Wed Jun 21, 2006 4:22 pm

Post » Wed Sep 18, 2013 4:48 pm

In order to access it in the actor script, yes, "forms" would have to be set up as a property (int property forms auto). You could theoretically do:

aScript.forms = StanceOptions.Show()

However, if you want to do more than change the variable, you probably will want to call a function or something in the other script too (depends what you want to do with it of course).
Maybe something like:

aScript.forms = StanceOptions.show()aScript.doStuffBasedOnNewValue()   ;call a function to respond to this variable change

or even

aScript.someFunction(StanceOptions.show());... then in the actor script, have this function:Function someFunction(int iVar)  ;we just got sent a new int! let's do something with it!EndFunction

Hope those examples help.

User avatar
dav
 
Posts: 3338
Joined: Mon Jul 30, 2007 3:46 pm

Post » Wed Sep 18, 2013 7:01 pm

I have one more question, if you'll permit me. In the properties window in the CK for this script, how do I properly direct "aScript" to the _an_Andromeda script? I pointed it to the actor with the script and hoped that would suffice, but

The function would merely change the state of the other script. Does it get simpler than this script?

Spoiler
Scriptname _an_AndromedaMenu extends ActiveMagicEffect Message Property StanceOptions Auto_an_Andromeda property aScript Auto Event OnEffectStart(Actor Target, Actor Caster)aScript.forms = StanceOptions.Show()if aScript.forms=0aScript.GoToState("StarForm")elseif aScript.forms=1aScript.GoToState("SunForm")elseif aScript.forms=2aScript.GoToState("GalaxyForm")ElseaScript.GoToState("VoidForm")EndIfEndEvent
User avatar
Janette Segura
 
Posts: 3512
Joined: Wed Aug 22, 2007 12:36 am

Post » Wed Sep 18, 2013 11:48 pm

I haven't ever tried to fill an actor script property myself in the CK (I usually use referenceAlias scripts, and put the actors into a reference alias). What options did it give you in the dropdown? If you chose the right actor it should hopefully work.

I notice though that you are using '=' instead of '==' in your script in the if statements, this will cause unexpected behavior, as you are assigning values there instead of comparing them. Everything else looks good in the script though, you are doing things right besides that as far as interacting between the two scripts is concerned. Bedtime for me, but feel free to leave any other concerns and I'll get back to you in the morning if no one else has!

User avatar
herrade
 
Posts: 3469
Joined: Thu Apr 05, 2007 1:09 pm


Return to V - Skyrim