The Basics
The Skyrim GUI uses Adobe Flash and Scaleform. The format is SWF 10 and the scripts are written in ActionScript 2.0.
The GUI files can be found in the 'Skyrim - Interfaces.bsa' file in your game's Data directory. You can use Fallout Mod Manager to extract the files from the BSA.
There are two major types of files used, SWF and GFX. The SWF files can be modified using any standard Flash tool. The GFX files are created with the Adobe Scaleform product. Right now, we don't have any good way to manipulate GFX files. Important things like the HUD are in GFX format.
Information directly from the GUI developers
- You will need Flash to mod the menus. Or, I guess, any program that outputs an SWF file, since that's what the menu system uses now.
- You don't need to use any of the Scaleform APIs to make a menu. The menu system should (theoretically) be able to handle any Flash 8-compatible menu you make. Code-data communication is done via Flash's native ExternalInterface calls.
- Concerning the GFX files, an SWF file in the Data/Interface folder will take precedence over a GFX file in the Data/Interface/Exported folder. E.g. If you have both Interface/Exported/HUDMenu.gfx and Interface/HUDMenu.swf, the SWF is the file that'll be used. This should allow you to circumvent the GFX files that are currently in-place.
- In regards to errors like the following:SpoilerThis was said:
G:\MyDocuments\FD Trillix\Converted on 2011-11-14\inventorylists.swf_as\Shared\CenteredScrollingList.as, Line 265 There is no method with the name 'getTopMostEntity'.
G:\MyDocuments\FD Trillix\Converted on 2011-11-14\inventorylists.swf_as\Shared\CenteredScrollingList.as, Line 182 There is no method with the name 'getTopMostEntity'.
G:\MyDocuments\FD Trillix\Converted on 2011-11-14\inventorylists.swf_as\Shared\BSScrollingList.as, Line 142 There is no method with the name 'getTopMostEntity'.
G:\MyDocuments\FD Trillix\Converted on 2011-11-14\inventorylists.swf_as\gfx\core\UIComponent.as, Line 289 There is no method with the name 'getTopMostEntity'.
G:\MyDocuments\FD Trillix\Converted on 2011-11-14\inventorylists.swf_as\gfx\core\UIComponent.as, Line 187 There is no property with the name 'numControllers'.
G:\MyDocuments\FD Trillix\Converted on 2011-11-14\inventorylists.swf_as\gfx\core\UIComponent.as, Line 185 There is no method with the name 'getControllerMaskByFocusGroup'.
G:\MyDocuments\FD Trillix\Converted on 2011-11-14\inventorylists.swf_as\gfx\core\UIComponent.as, Line 173 There is no property with the name 'numControllers'.
G:\MyDocuments\FD Trillix\Converted on 2011-11-14\inventorylists.swf_as\gfx\core\UIComponent.as, Line 171 There is no method with the name 'getControllerMaskByFocusGroup'.
G:\MyDocuments\FD Trillix\Converted on 2011-11-14\inventorylists.swf_as\gfx\core\UIComponent.as, Line 166 There is no property with the name 'numFocusGroups'.
G:\MyDocuments\FD Trillix\Converted on 2011-11-14\inventorylists.swf_as\gfx\core\UIComponent.as, Line 69 There is no property with the name 'numControllers'.
G:\MyDocuments\FD Trillix\Converted on 2011-11-14\inventorylists.swf_as\gfx\core\UIComponent.as, Line 67 There is no method with the name 'getControllerMaskByFocusGroup'.
G:\MyDocuments\FD Trillix\Converted on 2011-11-14\inventorylists.swf_as\gfx\core\UIComponent.as, Line 60 There is no property with the name 'numFocusGroups'.
G:\MyDocuments\FD Trillix\Converted on 2011-11-14\inventorylists.swf_as\gfx\core\UIComponent.as, Line 55 There is no method with the name 'getFocusBitmask'.
G:\MyDocuments\FD Trillix\Converted on 2011-11-14\inventorylists.swf_as\gfx\core\UIComponent.as, Line 7 A class's instance variables may only be initialized to compile-time constant expressions.
G:\MyDocuments\FD Trillix\Converted on 2011-11-14\inventorylists.swf_as\gfx\core\UIComponent.as, Line 6 A class's instance variables may only be initialized to compile-time constant expressions.
G:\MyDocuments\FD Trillix\Converted on 2011-11-14\inventorylists.swf_as\Shared\GlobalFunc.as, Line 79 There is no property with the name 'safeRect'.
G:\MyDocuments\FD Trillix\Converted on 2011-11-14\inventorylists.swf_as\Shared\GlobalFunc.as, Line 78 There is no property with the name 'visibleRect'.
G:\MyDocuments\FD Trillix\Converted on 2011-11-14\inventorylists.swf_as\gfx\managers\FocusHandler.as, Line 175 There is no method with the name 'getControllerFocusGroup'.
G:\MyDocuments\FD Trillix\Converted on 2011-11-14\inventorylists.swf_as\gfx\managers\FocusHandler.as, Line 157 There is no method with the name 'getControllerFocusGroup'.
G:\MyDocuments\FD Trillix\Converted on 2011-11-14\inventorylists.swf_as\gfx\managers\FocusHandler.as, Line 121 There is no method with the name 'findFocus'.
G:\MyDocuments\FD Trillix\Converted on 2011-11-14\inventorylists.swf_as\gfx\managers\FocusHandler.as, Line 85 There is no method with the name 'getControllerFocusGroup'.
G:\MyDocuments\FD Trillix\Converted on 2011-11-14\inventorylists.swf_as\gfx\managers\FocusHandler.as, Line 68 There is no property with the name 'numControllers'.
G:\MyDocuments\FD Trillix\Converted on 2011-11-14\inventorylists.swf_as\gfx\managers\FocusHandler.as, Line 64 There is no method with the name 'getControllerMaskByFocusGroup'.
G:\MyDocuments\FD Trillix\Converted on 2011-11-14\inventorylists.swf_as\gfx\managers\FocusHandler.as, Line 16 There is no property with the name 'disableFocusRolloverEvent'.
G:\MyDocuments\FD Trillix\Converted on 2011-11-14\inventorylists.swf_as\gfx\managers\FocusHandler.as, Line 15 There is no property with the name 'disableFocusAutoRelease'.
G:\MyDocuments\FD Trillix\Converted on 2011-11-14\inventorylists.swf_as\gfx\managers\FocusHandler.as, Line 14 There is no property with the name 'disableFocusKeys'.
G:\MyDocuments\FD Trillix\Converted on 2011-11-14\inventorylists.swf_as\gfx\managers\FocusHandler.as, Line 13 There is no property with the name 'alwaysEnableArrowKeys'.
ERROR: GlobalFunc.as, Line 111: Syntax error.
MovieClip
ERROR: FocusHandler.as, Line 182: Syntax error.
return (_loc3 < (TextField)(
ERROR: inputDelegate.as, Line 2: The class name is different from The Class file name.
ERROR: scrollbar.as, Line 2: The class name is different from The Class file name.
ERROR: Button.as, Line 118: Syntax error.
var _loc2 = (gfx.controls.ButtonGroup)(
ERROR: constraints.as, Line 2: The class name is different from The Class file name.
WARNING: BSScrollingList.as, Line 109: There is no method with the name 'getTopMostEntity'.
WARNING: CenteredScrollingList.as, Line 145: There is no method with the name 'getTopMostEntity'.
WARNING: CenteredScrollingList.as, Line 219: There is no method with the name 'getTopMostEntity'.
WARNING: UIComponent.as, Line 34: There is no method with the name 'getFocusBitmask'.
WARNING: UIComponent.as, Line 36: The property being referenced does not have the static attribute 'numFocusGroups'.
WARNING: UIComponent.as, Line 41: There is no method with the name 'getControllerMaskByFocusGroup'.
WARNING: UIComponent.as, Line 42: The property being referenced does not have the static attribute 'capabilities'.
WARNING: UIComponent.as, Line 135: The property being referenced does not have the static attribute 'numFocusGroups'.
WARNING: UIComponent.as, Line 140: There is no method with the name 'getControllerMaskByFocusGroup'.
WARNING: UIComponent.as, Line 141: The property being referenced does not have the static attribute 'capabilities'.
WARNING: UIComponent.as, Line 151: There is no method with the name 'getControllerMaskByFocusGroup'.
WARNING: UIComponent.as, Line 152: The property being referenced does not have the static attribute 'capabilities'.
WARNING: UIComponent.as, Line 241: There is no method with the name 'getTopMostEntity'.
Those errors are calls to the Scaleform Flash API that don't exist on your machine. Methods like "Mouse.getTopMostEntity" and "Selection.disableFocusKeys" were added by Scaleform to Flash's native Mouse and Selection objects using the 'intrinsic class' keywords. I believe there's just, say, a Mouse.as file that's on the FLA's classpath that declares "getTopMostEntity" as a method in the Mouse class, and then the actual implementation is provided by the Scaleform VM when running the game.
So the modding challenge here is either to write your own overriding of the Mouse class (and others) and get the FLA to recognize it, or rewrite the menu so it doesn't depend on Scaleform, i.e. doesn't use those functions. - The HUD, in theory, should be re-creatable without Scaleform.
- All the intrinsic Flash class overrides are from Scaleform; we didn't have occasion to add anything ourselves. I'm not sure how available those intrinsic AS class definitions are. Looking through the docs I have on hand, the only addition I see that Scaleform made to the System class is a way to determine how many controllers you have plugged in, which is mainly for Wii titles. You can probably craft PC mods without needing that additional method, i.e. with the vanilla System class.
To which, LineaPhobic replied:
You can create your own intrinsic class to solve the numControllers error. Just save the next code as "capabilities.as" and put it in a folder named "System". Put the "System" folder in the clik folder or in your project root folder.
And provided the following code:Spoiler
intrinsic class System.capabilities
{
static var hasAudio:Boolean;
static var hasMP3:Boolean;
static var hasAudioEncoder:Boolean;
static var hasVideoEncoder:Boolean;
static var screenResolutionX:Number;
static var screenResolutionY:Number;
static var screenDPI:Number;
static var screenColor:String;
static var pixelAspectRatio:Number;
static var hasAccessibility:Boolean;
static var input:String;
static var isDebugger:Boolean;
static var language:String;
static var manufacturer:String;
static var os:String;
static var serverString:String;
static var version:String;
static var hasPrinting:Boolean;
static var playerType:String;
static var hasStreamingAudio:Boolean;
static var hasScreenBroadcast:Boolean;
static var hasScreenPlayback:Boolean;
static var hasStreamingVideo:Boolean;
static var hasEmbeddedVideo:Boolean;
static var avHardwareDisable:Boolean;
static var localFileReadDisable:Boolean;
static var windowlessDisable:Boolean;
static var numControllers:Number;
// Flash Lite 2.x
static var audioMIMETypes:Array;
static var has4WayKeyAS:Boolean;
static var hasCMIDI:Boolean;
static var hasCompoundSound:Boolean;
static var hasDataLoading:Boolean;
static var hasEmail:Boolean;
static var hasMappableSoftKeys:Boolean;
static var hasMFI:Boolean;
static var hasMIDI:Boolean;
static var hasMMS:Boolean;
static var hasMouse:Boolean;
static var hasQWERTYKeyboard:Boolean;
static var hasSharedObjects:Boolean;
static var hasSMAF:Boolean;
static var hasSMS:Number;
static var hasStylus:Boolean;
static var hasXMLSocket:Boolean; // added in Flash Lite 2.1
static var imageMIMETypes:Array;
static var MIMETypes:Array;
static var screenOrientation:String;
static var softKeyCount:Number;
static var videoMIMETypes:Array;
} - The following questions were asked and answered:
Q: If I edit fontconfig.txt to match the format from the UDK ScaleForm, (add the [FontConfig] label), I can generate a gfxfontlib.swf that uses the game fonts by copying in their libraries to my working folder. The .swf looks fine when I launch it with the ScaleForm launcher, but ingame the font is replaced with the system default. Is there a way to circumvent this? Do I have to embed the fonts rather than use gfxfontlib?
A: If 'gfxfontlib.swf' is what I think it is, then our equivalent of that is going to be 'Data/Interface/fonts_en.swf', which you should see referenced in FontConfig.txt. That SWF does contain all the characters from all the fonts that we use in the game embedded into the file itself. The Skyrim Flash VM will search this file for the embedded glyphs that it needs, and if it doesn't find them, will try to grab the system defaults off of your machine.
Q: I use the CS 5.5. If I decompile a .swf, load the generated .fla file, save it as a new .fla file (CS4 format, Flash player 10.2, no text remapping), the resulting .fla file is nearly twice as large as the original. Do I have to get the CS4 in order to save projects properly?
A: Not sure about this. Some of our files use external SWFs. For example, the Item Card in all of the inventory menus comes from the external library ItemCard.swf, the dual-lists come from InventoryLists.swf, etc. Since they're external, the MovieClips in those SWFs aren't saved in InventoryMenu.fla itself; they're just referenced and the VM knows to load the external SWFs with InventoryMenu.swf. It could be that by decompiling the SWF, the FLA grabs all the MovieClip info and saves it into the FLA. If you double-click on a MovieClip in your Library that should be imported from an external SWF and you don't get a "this is an imported MovieClip" warning, then you've copied over the MovieClip info into your FLA. It shouldn't break anything, but it will balloon up your file size. At least, that's my best guess.
Tools you might find useful
- http://www.wxhexeditor.org/home.php -A free hex editor that will allows you to edit very large files. You'll need a hex editor for converting GFX files into SWF files.
- http://swftools.org - A collection of Open Source command line utilities to modify SWF files. These can be used to compress and decompress SWF files. These are for more advanced users.
- http://www.sothink.com/ - Sothink makes various tools you might find useful. They typically have a 30 trail period on their products. The make a SWF decompiler as we'll as a SWF editing tool (SWF Quicker).
- http://www.eltima.com/ - Eltima makes various tools you might find useful, particularly their SWF decompiler, Trillix.
- http://www.udk.com/ - The Unreal engine development kit supports Scaleform and comes with some tools. http://gameware.autodesk.com/scaleform/support/documentation
- http://www.swixkit.com/ - This is a free (for personal use) tool that converts SWF files into XML and back. You'll need some experience with XML and an understanding the internal structure of SWF files to use this tool effectively.
Looking at the contents of a GFX file
A GFX file can be treated as a SWF file by doing the following:
- Change the extension on the GFX file to SWF.
- Open the file in a hex editor:
- If the first three bytes are CFX, change them to CWS. The C means compressed.
- If the first three bytes are GFX, change them to FWS. The lack of C means these are uncompressed.
- If the first three bytes are CFX, change them to CWS. The C means compressed.
Using SWiX to modify the GUI
The following information was taken from a post by Casiotone on how he/she managed to create the http://www.skyrimnexus.com/downloads/file.php?id=279 mod:
Here's what I've done with the mod that was mentioned:
- Unpacked the "Skyrim - Interface.bsa" file
- Copy out the hudmenu.gfx file, rename it to .swf, and used the hex editor in Notepad++ to edit the first three characters to "CWS".
- Decompile the swf with Trillix or similar. This is only to identify sprites and scripts so far - you won't be recompiling.
- Pore through the assets and determine which ones you want to alter. Note their shape numbers.
- Using SWiX, open the .swf file and manually remove the shapes in question
- I also edited the sprite that controls the fade in/fade out of the indicator text (hidden/detected) so that it remained at A=0 throughout the whole tween.
- Save in SWiX, hex edit the first three characters back to "CFX", and rename the file back to .gfx.
In order to start adding your own scripting, I imagine the process is something like this:
- Make your code adjustments in Flash, FlashDevelop, Trillix, etc. and publish with the CLIK framework in your classpath as a Flash Player 10 movie in AS2.0
- Use FLASM on the altered file to get the assembly for your changes
- Use FLASM on the original file to get something to compare it to
- Use a diff tool to compare the instructions between the two .flm files that FLASM generated
- Carefully copy over your changes from the newly published file to the "original" file
- Re-assemble into .swf using FLASM
Previous Discussions
http://www.gamesas.com/index.php?/topic/1256213-interface-change-pc/




