Lately I had to keep a low profile due to various issues, probably all related to me spending to much energy into our all most famous hobby, modding. But now that my wife isn't home, I think it's a good opportunity to fulfill a promise and make this tutorial by popular demant. This tutorial will, more or less, teach you how to create a basic widget with Flash tools. Prepare for a long, long journey So let's begin:
1. Setting up the necessary tools
You will need Adobe Flash tools, this is inevitable. Tools like Trilix, SWiX or Sothink are good for basic 'code hacking', but not for serious development of Flash elements. You can download Sothink Decompiler to speed up decompilation and do basic stuff on .swf/.gfx files though. To create Widgets from scratch, I recommend using Flash CS6, to modifie existing .swf/.gfx I recommend, by proposal of SkyUI team and due to personal experience, using Flash CS4. You will need to keep in mind, that if you compiled/decompiled a file with either CS6 or CS4, you will need to recompile it with the same tool. If you, for example, decompile CS4 files and recompile them CS6 (which is perfectly feasible if you're upgrading, but not downgrading), they will create bugs in game, like weird symbols and messed up UI elements. You will get to notice anyways during the compilation process, because usually compiling with the wrong tool version, will spit out tons of compilation errors. Flash tools are free as trial for about 4 weeks, from there it will cost 24, 95€ a month to furtherly use flash tools. Also, as far as I understood it, you can ONLY buy a license for a year, you can't have the tools for just a month, or 3, or half a year, which is a bit of a disapointment. I'm just lucky I'm currently working on other Flash projects so I was allowed to buy the license.
http://de.sothink.com/product/flashdecompiler/index.htm
http://helpx.adobe.com/de/x-productkb/policy-pricing/cs6-product-downloads.html
http://helpx.adobe.com/de/creative-suite/kb/cs4-product-downloads.html
2. Setting up the necessary sources files
You will need source files, which are granted to us by SkyUI team. To create widgets from scratch I recommend using @Schlangster's source files, to modifie existing Skyrim UI elements, I recommend using @Mardoxx's source files. It's good practice to use CS6 for Schlangster's source and use CS4 for Mardoxx's source. You will want to use CS4 for Mardoxx's files anyways, because compiling them with CS6 will cause previously mentioned errors in game. Optionally you can do as Schlangster proposes and set up Github on your computer, to easily push files to the website. I did so previously, but since the loss of all of my source files, I don't feel the nerv to do it again, unless SkyUI-Team asks for. Instructions on how to interact with the web based part of Github is to be found on their website. ALWAYS make sure, to give proper credits, because as far as I can tell, with the exception of maybe Alex J. Velicky on his Falskaar project and the SKSE-Team, there's no community member even remotely having done so much for the community then Schlangster, Mardoxx and team did.
https://github.com/schlangster/skyui
https://github.com/Mardoxx/skyrimui
3. Setting up the necessary file structure
Now let's get to the setup of files. Let's concentrate on making new widgtes this time, we'll get to more experienced stuff another day. I assume you've already set up Adobe Flash CS6 and downloaded the zipped source files by Schlangster? Good. Now copy the source folder somewhere you can easily back it up, whenever you feel something went wrong. The structure you need to make should look something like this:
The only relevant folder inside this structure for you is the src folder. As the name suggest it has all the source files inside. For now we will concentrate on creating widgets, which will be achieved from inside the HUDWidgets Folder. To create a widget we do not make one from scratch, but use an already exisiting widget. Those widgets exist as .fla (Flash Movie) files. And the particular one you're searching for is the one labeled arrowcount.fla. So, opening your CS6 programm open the arrowcount.fla. Then follow the next steps:
Use this picture as help:
http://www.nexusmods.com/skyrim/Images/467230/?
So, if you now take a look at the top of the arrowcount.as file, you should see the following, green notes are made by me:
So, now that you've made sure that both files have the same file path set up, memorize this information to always do this again whenever you set up a new file. The easiest way to set up a new file, for example, if you would like to create a basic weight widget, is by duplicating the arrowcount.fla and .as files and change the file path, names and all relevant data. You can start creating files from scratch once you're more familiar with developing Flash elements. Remember, the first thing you always want to do, is sycronizing file path structure inside .as and .fla files. Also, it's probably best practice to learn by simple copypasta, but do read what the variables tell you and try to understand it. Copypasta has limits, for more experienced code you'll actually need to learn the code.
4. Learning how .as script files work
Now I will describe how variables inside .as files will be used in .fla and then be transported to Papyrus code using SKSE functions. This seems to be a very complicated task, and believe me, for a beginner it is. So first I will roughly describe how the structure looks, then I will give you a visual impression with screens, and then we care about the actual code. There's various relevant variables to be found in other .as files, primarly inside StatusWidget.as, Meter.as and ActiveEffect.as, use those variables with copypasta to start experimenting. Not all variables can be used on every flash element. Some variables are ONLY for counting widgets, others are only for meter widgets, you'll need to fiddle to figure. Go into the arrowcount.as file and read:
import skyui.widgets.WidgetBase /* <-- mentioned before, this imports 'mother' code from widgetbase.as */class skyui.widgets.arrowcount.ArrowCountWidget extends WidgetBase /* <-- defines this .as file and the corresponding .fla as ArrowCountWidget and extends on the 'mother' file */{ /* STAGE ELEMENTS */ public var countText: TextField /* <-- this is comparable to Papyrus propertys, here you actually define a public variable that will be used in .fla files as text counter using integral numbers. The term 'public' is comparable to Papyrus Auto, if you' want to have it 'hidden' you'd set it to privat. Public says this variable will be 'seen' by all other files. */ /* INITIALIZATION */ public function ArrowCountWidget() /* <-- a function, just as in Papyrus, with the difference that you actually define the widget as function */ { super(); _visible = false; /* <-- this makes the widget visible on your Hud when set to true but you later need to define it as function as well*/ countText.text = "0"; /* <-- this will define the integral counter and set its count to 0 */ } /* PUBLIC FUNCTIONS */ // @overrides WidgetBase public function getWidth(): Number /* <-- a function that's been refred to directly from WidgetBase.as, see the WidgetBase.as to find this variable, hence the notification 'overrides'. This function gets the width of you flash element. */ { return _width; } // @overrides WidgetBase public function getHeight(): Number { return _height; /* <-- yes, gets the height */ } // @Papyrus public function setVisible(a_visible: Boolean): Void { _visible = a_visible; /* <-- visibility code your .fla file, respectively SKSE invoking code will use */ } // @Papyrus public function setCount(a_count: Number): Void { countText.text = String(a_count); /* count code your .fla file, respectively SKSE invoking code will use */ }}
So basically the above code will define various functions you can interact with from inside Papyrus code by invoking said variables. This code will allow you set the arrow count visible and define the integral count. You're probably getting confused by the string, which usually referes to letters rather then numbers. But the int that gets counted inside Papyrus, will be displayed as string inside the flash element, so this is perfectly good, irritating but good. Now let's take this further to the code I actually tinkered for my arrow counter...
import skyui.widgets.WidgetBase;import skyui.widgets.status.StatusWidget;class skyui.widgets.arrowcount.ArrowCountWidget extends WidgetBase{ /* STAGE ELEMENTS */ var _xscale, _yscale; public var countText: TextField; public var countText2: TextField; public var _labelTextField: TextField; private var _labelText: String; public var _iconSize: Number; /* INITIALIZATION */ public function ArrowCountWidget() { super(); _visible = false; countText.text = "0"; countText2.text = "0"; } /* PUBLIC FUNCTIONS */ // @overrides WidgetBase public function getWidth(): Number { return _width; } // @overrides WidgetBase public function getHeight(): Number { return _height; } // @Papyrus public function setVisible(a_visible: Boolean): Void { _visible = a_visible; } // @Papyrus public function setCount(a_count: Number): Void { countText.text = String(a_count); } // @Papyrus public function setCount2(a_count: Number): Void { countText2.text = String(a_count); } // @Papyrus public function setLabelText(a_val: String): Void { if (_labelText == a_val) return _labelTextField.text = _labelText = a_val; } function get Scale() { return (_xscale); } function set Scale(scale) { _xscale = scale; _yscale = scale; this.invalidateSize(); // null; } }
Not only does this code look much more 'tidy', it also made copypasta use by various functions from other .as files. It has two integral counts, one text field, is allowed to be turned off and on, its scale can be set, as well as its position and its transparency changed, either by usage of extended code from inside the WidgetBase.as or directly from inside this file. I figure this all looks complicated, probably also because I'm describing it extremely complicated, which I usually don't. But there's nothing I can do about it, developing flash elements IS complicated...
5. Learning how .fla movie files work
Ok, so now that you got yourself familiar with .as files, we're now going to make changes inside the arrowcount.fla, to make use of the newly imported code. Remember, always synchronize the file path structure, can't stop repeating to remind you of that. The original arrowcount.fla has a simple arrow icon and a global counter telling you how many arrows are inside your inventory. We're going to enhance this arrow count widget, by also displaying the currently equipped arrow name, and the numbers of currently equipped arrows. So basically we will duplicate the integral counter, import a string field, and as bonus, will also change the appearance and color of the arrow count widget. First have a look at this screenshot:
http://www.nexusmods.com/skyrim/Images/469436/?
You will notice it has a whole different look from the original arrow counter. To see how the arrow counter looks inside game, I recommend taking a peek at my http://www.nexusmods.com/skyrim/mods/59361/?. On the right sight you will recognize that there's also changes made to the library. The library basically contains everything that is used by the .fla file. This could be fonts, pictures, text and various other items. What you want to do now, is importing a small arrow icon made by @Psychosteve, which is the icon developer inside SkyUI-Team I assume. The new arrow icon will reflect bolts from DLC's, as well as spears and other ranged weapon ammo. Make it so:
This is one way how to import new icons and combine them. You can also use this to replace icons, so for example if you want to make a basic weight counter, you'd just replace the arrow icon with something that reflects weight. So now, since were learning here how to replace icons, let's teach us how to customize them. I like my UI colorful, in tradition of old RPG games. If this is not your cup of tea, and you simply want to use the icons as they are, then you're better off to skip the next lesson. So now we have a arrow icon symbol that has a bolt icon added, let's recolor it. To customize the single icons you will want to right click and edit it in the library. On some occasions, and based on how you've structured your customization (for example, you could also make this customized arrow icon outside of Flash and then have it imported), you can also furtherly customize the elements isnide the icon holder or the widget directly. You'll need to fiddle around to figure. Use CTRL-Z extensivley during trial and fail and only save if you're certain your changes are appropriate. Ok, now let's cusotmize the weapon bolt, right click it in the library and select edit.
Now it's probably best practice to get familiar with the right side customization bar. Basically it's the same as in programs like Paint, Photoshop or Gimp. The important information here is, a icon can have several layers which you will need to sometimes select seperately to customize them. It's all dependend on the icon and they're are not always the same. If you're lucky the icon has a single layer which you can modifie, if you're unlucky, then there's a miriad of layers which you will someimes have to split and glue back together later. If you need to do this, it's important that you do it correctly. It's basically the same as inside the CK, if you do not work carefully, you will create a lot of 'dirty edits'. You will notice if you made bad edits once your in game. Flash will not always necessarily inform you, if you did something wrong. Now, what you want to try is giving the bolt icon another base color and edge color.
There's tons of customization options available, so start playing with them and later see the results in game. The last thing we want to do now is setting up the functions that are used inside the .as file. So you will learn now how to import .fla counter and text elements.
Stop, now before we continue, just for reference, go into the arrowcount.as file and search for 'countText', found it? Good, you probably see what I'm up to?
Notice that you can also customize those counter/text elements. For example you could recolor them to adapt them to the recolorization of the icons. You probably ask yourself, what the heck was I doing? Well, you've made a copy of the already existing counter to later display the currently equipped arrows, and made another copy to later display the name of the currently equipped arrows type. Exchanging flash elements to show text instead of numbers is simply done by replacing numbers with letters. So if you want to show the arrow name, you just need to change it to show strings instead of integers. If you want to display floats, you will need to put a dot somehwere inside the number. Integers = 10000, floats = 10000.0, strings = xxx. The original counter will be used for what Schlangster intended it to do.Iit will display the global number of arrows inside your inventory. So ok, now that you've learned how to modifie .as and .fla files, it's time to learn how to connect both files in order to make them do what they're supposed to by compiling them.
6. Compile the fla. file into a format useable for the game
Before I'll explain how to compile, I want you to again read through the .as file and figure all the connections to the .fla file. I can't emphasize and encourage you enough to do so. It's important that you did not simply copypastaed what I presented you inside this tutorial. Learn all the diverse variables please. If you do so, you, and respectively the mod user community will benefit greatly. Capable Flash Modders are extremely rare, and I understand this is due to the degree of difficulty. With this tutorial you will scratch the surface of UI modding, rendering you an apprentice, but if you happen to have mastered this 'art', you will be amongst the finest of modders the community has to offer (I haven't even remotely mastered it yet). I want to honorably note @LordConti2 from the Nexus here. Go and have a look at his Mods, it's amazing what this guy achieved with UI modding, specially because it was way ahead in time of every other effort. However, let's continue with compiling:
Ok, now, this is something I can barely adress. If you happen to have compile erros, there's not a lot I can do, then telling you that something went wrong. Usually this happens to wrong file structure mentioned in part 3. of this tutorial. If you get a high number of compile errors, this is likely due to this reason. I fyou maybe have like 5 or 6 errors only, then you maybe have some typos inside your .as file, or you forgot to import information from other .as files, or you haven't correctly syncronized file structure and variables inside the .as and .fla file. All errors I ever experienced, were always related to me using the wrong tool version, or not having the correct file structure set up. Flash will search for .as and .fla files that are used by your widget in the correct folders and pack them inside the compiled file. If those files can't be found by Flash, then this will likely create said compile errors. Files compiled errors will NOT work in game, even if there's only one error. If everything works during the compilation process, you will have your newly created .swf file on your desktop. Please copy this file into your Skyrim folder:
Data/Interface/Exported/Widgets/YourWidgetFolderName
If you can't find those folders, please create them. Name your Widget Folder to something that reflects your Mod. For example my Folder is simply named 'WM' for 'Widget Mod'.
7. Build your actual Mod inside the Creation Kit
Ok, puhh...now that's done, now let's continue with the most important part. Make use of the .swf file from inside Papyrus script. The way it works, is by using various SKSE 'invoking' functions. You will now want to start the Creation Kit, and before, make sure that the SkyUI source files are copied to your Skyrim folder. I'm refering to the .pex and .psc files, NOT the flash files. Usually you can find the SkyUI SDK files https://github.com/schlangster/skyui/wiki, BUT, and that's the recommended way of getting the source files, they're also inside the .bsa that comes with the http://www.nexusmods.com/skyrim/mods/3863/?. Unpack those script files and copy them to your Data folder. Some files are missing from the Github download. Make sure to build your new plugin with Update and all DCLs as master enabled, IF you want to cover assets imported by this master plugins. For example, an arrow counter widget also wants to display bolts and spears from Dragonborn and Dawnguard.
So ok, pretty much the only thing needed to enable a widget is by creating a new quest. So head on:
Basic setup done, now let's ge to the funny part. Basically Widget Mods make use of three script types. The actual Widget Script, the Update script and the MCM script, if you want to be able to customize your widget from inside the ingame MCM menu. The update script will update information on a given interval for your widgets to display. Usually it does that by simply calling a function inside the widget script OnUpdate(). So please make three new quest scripts with appropriate names. Examples, where XXX resamples your Mods name:
1. XXX_ArrowCountScript2. XXX_MasterUpdateScript3. XXX_MCMScript
I will not describe how you actually build scripts inside the CK. Being capable of scripting with Papyrus is a prerequisite to even remotely think about creating UI related Mods. I will post the scripts of my Widget Mod instead, and let you figure how to do it. However, I will give you some hints on what actually happens inside those scripts. So let's continue:
Arrow Count Script:
Actor Property PlayerREF Auto
FormList Property WM_ArrowFormList Auto
Ammo Property boundArrow Auto
Ammo Property DLC1BoltDwarven Auto
Ammo Property DLC1BoltDwarvenExplodingFire Auto
Ammo Property DLC1BoltDwarvenExplodingIce Auto
Ammo Property DLC1BoltDwarvenExplodingShock Auto
Ammo Property DLC1BoltSteel Auto
Ammo Property DLC1BoltSteelExplodingFire Auto
Ammo Property DLC1BoltSteelExplodingIce Auto
Ammo Property DLC1BoltSteelExplodingShock Auto
Ammo Property DLC1DragonboneArrow Auto
Ammo Property DLC2NordicArrow Auto
Ammo Property DLC2RieklingSpearThrown Auto
Ammo Property DLC2StalhrimArrow Auto
Ammo Property DraugrArrow Auto
Ammo Property DwarvenArrow Auto
Ammo Property EbonyArrow Auto
Ammo Property ElvenArrow Auto
Ammo Property FalmerArrow Auto
Ammo Property ForswornArrow Auto
Ammo Property GlassArrow Auto
Ammo Property IronArrow Auto
Ammo Property NordHeroArrow Auto
Ammo Property OrcishArrow Auto
Ammo Property SteelArrow Auto
Bool ArrowVisible = false
Int ArrowCount = 0
Int ArrowCount2 = 0; <--- this section is were to define your variables to call on the .swf file
String ArrowName = ""
Int ArrowSize = 100
Bool Property Visible
Bool Function Get()
Return ArrowVisible
EndFunction
Function Set(bool a_val)
ArrowVisible = a_val
If (Ready)
UI.InvokeBool(HUD_MENU, WidgetRoot + ".setVisible", ArrowVisible); <-- find me the .setVisible inside your .as file please, you can't? Your .as files extends WidgetBase.as, search there. Nothing found? Good. The .setVisble is actually called from inside the MovieClip.as that the WidgetBase.as extends. As far as I understand MovieClip.as source is somewhere inside the Flash tool.
EndIf
EndFunction
EndProperty
Int Property Count
Int Function Get()
Return ArrowCount
EndFunction
Function Set(int a_val)
ArrowCount = a_val
If (Ready)
UI.InvokeInt(HUD_MENU, WidgetRoot + ".setCount", ArrowCount); <-- please find me the .setCount inside the .as file, found it? Good, head on.
EndIf
EndFunction
EndProperty
Int Property Count2
Int Function Get()
Return ArrowCount2
EndFunction
Function Set(int a_val)
ArrowCount2 = a_val
If (Ready)
UI.InvokeInt(HUD_MENU, WidgetRoot + ".setCount2", ArrowCount2); <-- please find me the .setCount2 inside the .as file, found it? Good, see what happens here? I show, you learn...
EndIf
EndFunction
EndProperty
String Property MessageText
String Function Get()
Return ArrowName
EndFunction
Function Set(String a_val)
ArrowName = a_val
If (Ready)
UI.InvokeString(HUD_MENU, WidgetRoot + ".setLabelText", ArrowName); <-- you remember the setLabelText, do you?
EndIf
EndFunction
EndProperty
Int Property Size
Int Function Get()
Return ArrowSize
EndFunction
Function Set(int a_val)
ArrowSize = a_val
If (Ready)
UpdateScale()
EndIf
EndFunction
EndProperty
; now note there's a change in how the variables are called inside the .swf file, previously you had propertys defined, now you will use functions. To figure what is appropriate, you will need to look through the SkyUI Papyrus source files. They will teach you what's right.
Function SetX(Float afX); <-- horizontal position
If (Ready)
X = afX
EndIf
EndFunction
Function SetY(Float afY); <-- vertical position
If (Ready)
Y = afY
EndIf
EndFunction
Function SetHorizontalAnchor(String asAnchor)
If (Ready)
HAnchor = asAnchor
EndIf
EndFunction
Function SetVerticalAnchor(String asAnchor)
If (Ready)
VAnchor = asAnchor
EndIf
EndFunction
Function SetTransparency(Float afAlpha); <-- transparency of the widget
If (Ready)
Alpha = afAlpha
EndIf
EndFunction
Event OnWidgetReset(); <-- this is where the actual code that drives the widget starts
UpdateScale(); <-- transports to scaling maintenance needs to be done before the widget resets!
Parent.OnWidgetReset()
If PlayerREF.IsEquipped(DLC1BoltDwarven)
ArrowName = DLC1BoltDwarven.GetName() as String; <-- see how I called the arrows name?
ArrowCount2 = PlayerRef.GetItemCount(DLC1BoltDwarven); <-- see how I called the current equipped arrow number?
ElseIf PlayerREF.IsEquipped(DLC1BoltDwarvenExplodingFire)
ArrowName = DLC1BoltDwarvenExplodingFire.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(DLC1BoltDwarvenExplodingFire)
ElseIf PlayerREF.IsEquipped(DLC1BoltDwarvenExplodingIce)
ArrowName = DLC1BoltDwarvenExplodingIce.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(DLC1BoltDwarvenExplodingIce)
ElseIf PlayerREF.IsEquipped(DLC1BoltDwarvenExplodingShock)
ArrowName = DLC1BoltDwarvenExplodingShock.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(DLC1BoltDwarvenExplodingShock)
ElseIf PlayerREF.IsEquipped(DLC1BoltSteel)
ArrowName = DLC1BoltSteel.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(DLC1BoltSteel)
ElseIf PlayerREF.IsEquipped(DLC1BoltSteelExplodingFire)
ArrowName = DLC1BoltSteelExplodingFire.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(DLC1BoltSteelExplodingFire)
ElseIf PlayerREF.IsEquipped(DLC1BoltSteelExplodingIce)
ArrowName = DLC1BoltSteelExplodingIce.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(DLC1BoltSteelExplodingIce)
ElseIf PlayerREF.IsEquipped(DLC1BoltSteelExplodingShock)
ArrowName = DLC1BoltSteelExplodingShock.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(DLC1BoltSteelExplodingShock)
ElseIf PlayerREF.IsEquipped(DLC1DragonboneArrow)
ArrowName = DLC1DragonboneArrow.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(DLC1DragonboneArrow)
ElseIf PlayerREF.IsEquipped(DLC2NordicArrow)
ArrowName = DLC2NordicArrow.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(DLC2NordicArrow)
ElseIf PlayerREF.IsEquipped(DLC2RieklingSpearThrown)
ArrowName = DLC2RieklingSpearThrown.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(DLC2RieklingSpearThrown)
ElseIf PlayerREF.IsEquipped(DLC2StalhrimArrow)
ArrowName = DLC2StalhrimArrow.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(DLC2StalhrimArrow)
ElseIf PlayerREF.IsEquipped(DraugrArrow)
ArrowName = DraugrArrow.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(DraugrArrow)
ElseIf PlayerREF.IsEquipped(DwarvenArrow)
ArrowName = DwarvenArrow.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(DwarvenArrow)
ElseIf PlayerREF.IsEquipped(EbonyArrow)
ArrowName = EbonyArrow.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(EbonyArrow)
ElseIf PlayerREF.IsEquipped(ElvenArrow)
ArrowName = ElvenArrow.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(ElvenArrow)
ElseIf PlayerREF.IsEquipped(FalmerArrow)
ArrowName = FalmerArrow.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(FalmerArrow)
ElseIf PlayerREF.IsEquipped(ForswornArrow)
ArrowName = ForswornArrow.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(ForswornArrow)
ElseIf PlayerREF.IsEquipped(GlassArrow)
ArrowName = GlassArrow.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(GlassArrow)
ElseIf PlayerREF.IsEquipped(IronArrow)
ArrowName = IronArrow.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(IronArrow)
ElseIf PlayerREF.IsEquipped(NordHeroArrow)
ArrowName = NordHeroArrow.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(NordHeroArrow)
ElseIf PlayerREF.IsEquipped(OrcishArrow)
ArrowName = OrcishArrow.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(OrcishArrow)
ElseIf PlayerREF.IsEquipped(SteelArrow)
ArrowName = SteelArrow.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(SteelArrow)
Else
ArrowName = "" as String; <-- makes sure no name gets displayed when no arrow equipped
ArrowCount2 = 0; <-- makes sure no number gets displayed when no arrow equipped
EndIf
; note this is the fun part, those four variables actually transport the information from your papyrus script to your .swf file
UI.InvokeBool(HUD_MENU, WidgetRoot + ".setVisible", ArrowVisible)
UI.InvokeInt(HUD_MENU, WidgetRoot + ".setCount", ArrowCount)
UI.InvokeInt(HUD_MENU, WidgetRoot + ".setCount2", ArrowCount2)
UI.InvokeString(HUD_MENU, WidgetRoot + ".setLabelText", ArrowName)
EndEvent
; this is the place where the script searchs for your widget, see how the root path is your widget folders name
String Function GetWidgetSource()
Return "WM/WM_ArrowCount.swf"
EndFunction
; your widget script, must be the same as this scripts name
String Function GetWidgetType()
Return "WM_ArrowCountQuestScript"
EndFunction
Function UpdateStatus(); <-- the update/maintenance code, will be called from inside the master update script, needs to have the same varaibles coded again or won't be transported through savegames!
If PlayerREF.IsEquipped(DLC1BoltDwarven)
ArrowName = DLC1BoltDwarven.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(DLC1BoltDwarven)
ElseIf PlayerREF.IsEquipped(DLC1BoltDwarvenExplodingFire)
ArrowName = DLC1BoltDwarvenExplodingFire.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(DLC1BoltDwarvenExplodingFire)
ElseIf PlayerREF.IsEquipped(DLC1BoltDwarvenExplodingIce)
ArrowName = DLC1BoltDwarvenExplodingIce.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(DLC1BoltDwarvenExplodingIce)
ElseIf PlayerREF.IsEquipped(DLC1BoltDwarvenExplodingShock)
ArrowName = DLC1BoltDwarvenExplodingShock.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(DLC1BoltDwarvenExplodingShock)
ElseIf PlayerREF.IsEquipped(DLC1BoltSteel)
ArrowName = DLC1BoltSteel.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(DLC1BoltSteel)
ElseIf PlayerREF.IsEquipped(DLC1BoltSteelExplodingFire)
ArrowName = DLC1BoltSteelExplodingFire.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(DLC1BoltSteelExplodingFire)
ElseIf PlayerREF.IsEquipped(DLC1BoltSteelExplodingIce)
ArrowName = DLC1BoltSteelExplodingIce.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(DLC1BoltSteelExplodingIce)
ElseIf PlayerREF.IsEquipped(DLC1BoltSteelExplodingShock)
ArrowName = DLC1BoltSteelExplodingShock.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(DLC1BoltSteelExplodingShock)
ElseIf PlayerREF.IsEquipped(DLC1DragonboneArrow)
ArrowName = DLC1DragonboneArrow.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(DLC1DragonboneArrow)
ElseIf PlayerREF.IsEquipped(DLC2NordicArrow)
ArrowName = DLC2NordicArrow.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(DLC2NordicArrow)
ElseIf PlayerREF.IsEquipped(DLC2RieklingSpearThrown)
ArrowName = DLC2RieklingSpearThrown.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(DLC2RieklingSpearThrown)
ElseIf PlayerREF.IsEquipped(DLC2StalhrimArrow)
ArrowName = DLC2StalhrimArrow.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(DLC2StalhrimArrow)
ElseIf PlayerREF.IsEquipped(DraugrArrow)
ArrowName = DraugrArrow.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(DraugrArrow)
ElseIf PlayerREF.IsEquipped(DwarvenArrow)
ArrowName = DwarvenArrow.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(DwarvenArrow)
ElseIf PlayerREF.IsEquipped(EbonyArrow)
ArrowName = EbonyArrow.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(EbonyArrow)
ElseIf PlayerREF.IsEquipped(ElvenArrow)
ArrowName = ElvenArrow.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(ElvenArrow)
ElseIf PlayerREF.IsEquipped(FalmerArrow)
ArrowName = FalmerArrow.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(FalmerArrow)
ElseIf PlayerREF.IsEquipped(ForswornArrow)
ArrowName = ForswornArrow.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(ForswornArrow)
ElseIf PlayerREF.IsEquipped(GlassArrow)
ArrowName = GlassArrow.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(GlassArrow)
ElseIf PlayerREF.IsEquipped(IronArrow)
ArrowName = IronArrow.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(IronArrow)
ElseIf PlayerREF.IsEquipped(NordHeroArrow)
ArrowName = NordHeroArrow.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(NordHeroArrow)
ElseIf PlayerREF.IsEquipped(OrcishArrow)
ArrowName = OrcishArrow.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(OrcishArrow)
ElseIf PlayerREF.IsEquipped(SteelArrow)
ArrowName = SteelArrow.GetName() as String
ArrowCount2 = PlayerRef.GetItemCount(SteelArrow)
Else
ArrowName = "" as String
ArrowCount2 = 0
EndIf
If (Ready)
UI.InvokeInt(HUD_MENU, WidgetRoot + ".setCount", PlayerRef.GetItemCount(WM_ArrowFormList)); <-- curious, are you? Why only here? I don't even remotely have an idea, but it does work like that. If I declare this on the WidgetReset, it will mess up the number. Haven't figured why...
UI.InvokeString(HUD_MENU, WidgetRoot + ".setLabelText", ArrowName)
UI.InvokeInt(HUD_MENU, WidgetRoot + ".setCount2", ArrowCount2)
EndIf
EndFunction
Function UpdateScale(); <-- the scale update code...took me like 4 hours to figure this had to be called BEFORE widget reset...-.-
UI.SetInt(HUD_MENU, WidgetRoot + ".Scale", ArrowSize)
EndFunction
Master Update Script:
WM_ArrowCountQuestScript Property ArrowScript Auto; <-- see how I defined a script property?
WM_WeightCountQuestScript Property WeightScript Auto
WM_GoldCountQuestScript Property GoldScript Auto
WM_BountyCountQuestScript Property BountyScript Auto
WM_SkillCountQuestScript Property SkillScript Auto
WM_AthleticCountQuestScript Property AthleticScript Auto
WM_LockpickCountQuestScript Property LockpickScript Auto
WM_LightCountQuestScript Property LightScript Auto
WM_HotkeyCountQuestScript Property HotkeyScript Auto
WM_HorseCountQuestScript Property HorseScript Auto
WM_FollowerCountQuestScript Property FollowerScript Auto
WM_AttributeCountQuestScript Property AttributeScript Auto
Float Property UpdateTimer Auto; <-- the update timer interval
Event OnInit()
RegisterForSingleUpdate(UpdateTimer)
EndEvent
Event OnUpdate()
ArrowScript.UpdateStatus(); <-- see how it calls the UpdateStatus() Function inside the Arrow Widget Script?
WeightScript.UpdateStatus()
GoldScript.UpdateStatus()
BountyScript.UpdateStatus()
SkillScript.UpdateStatus()
AthleticScript.UpdateStatus()
LockpickScript.UpdateStatus()
LightScript.UpdateStatus()
HotkeyScript.UpdateStatus()
HorseScript.UpdateStatus()
FollowerScript.UpdateStatus()
AttributeScript.UpdateStatus()
RegisterForSingleUpdate(UpdateTimer); <-- don't forget to reregister
EndEvent
MCM Script:
See second post, I've reached the post limit.
Things to remember:
1. you have to make a new script for every new widget
2. you have to call every new widget script from inside the update script
3. the .as, .fla and .psc variables are pretty much all available, for the moment there is no function that allow to modifie color via MCM or Papyrus code in general, I'm working to get this done
4. setting up the MCM menu is the most sophisticated part. You'll need to have done this before or you will certainly fail. All variables inside the MCM script have been described before.
Also, see this screenshot on how you have to fill propertys on the widget script, the update and mcm script will have all properties filled, the explicit widget script does not:
http://www.nexusmods.com/skyrim/Images/469622/?