A relevant article that create the theme
 

originally written by MAOLUO:Amuro(lolo) of Stepmania China Forums
E-mail:amuro1987 (at) sina (dot) com
Translation by Kakurady
Posted at http://www.stepmania.com/boards/viewtopic.php?p=4308

(Stepmania 3.9 Final Theme)

I am a Chinese, interested in emulators.
Not long ago I wrote an article about 3.9final theme system and wish to share it with others.
But limited to my level, there is also some mistake, please point out. 


Contents

  • Default Loading Mechanism
  • File Loading Mechanism
  • Screen Loading Mechanism
    • Interheritage and Overloading of Screen Classes
      • Random Insertion 1
      • Random Insertion 2
      • Random Insertion 3
    • Accessory Sections
  • Screen Displaying Mechanism
    • [BGAnimation] Section
    • [LayerXX] Section
      • Random Insertion 4
      • Random Insertion 5
    • [Scoller] Section
  • Font File Loading Mechanism
  • Language Packs
  • Playback of Music (in themes)
  • Examples
    • Conditioned Screen Branches
    • Displaying Time in the Title Screen
    • Automatic Switch of Game Modes Under Coin Mode
  • References

Under normal circumstances at most the following parts of any theme can be read by the program:

metrics.ini under the root folderis the overall controlling script, where most operations are defined here.

BGAnimations Folder saving graphics of all screens with background set as ScreenWithMenuElements.

Graphics Folder saving graphics taking lesser space on-screen.

Fonts Folder saving font library graphics and metrics data used in game.

Sounds Folder saving music and sound effects files needed in-game.

Languages Folder saving language packs.

Numbers Folder Saving number fontfaces and their indices used in most places of the game.

Others Folder Can be used to save scoring infomation and steps for How To Play.

Note: None of above are required to exist in a theme, for example, in extreme cases only a metrics.ini file under the root folder can be called as a theme. This comes to the theme loading mechanism.

Default Loading Mechanism

When the skin that the player has selected lacks necessary infomation for the execution of the program, it will search in the default theme, and loads it if it exists, otherwise the error reporting screen will be shown or StepMania crashes. That is to say, default skin has the function of providing the default values, and because of this mechanism, we can create such a skin: one that only contains a mertics.ini, with only two rows of content:

[Common]
DefaultModifiers=1256% dizzy

(All player defaults to a 12.56 timed dizzy mod)

This skin is executable, though it seems to lack a lot of things.

But notice the graphics and sounds of this theme, dosen't it just look like those of the default theme. This proves that the mechanism of using the default skin as a default applies not only the .ini file, but to other parts of the skin as well.

Still from the simple skin we have created above, we can discover that, this mechanism is detailed enough. It's not "if this ini exists then read it and discard what remains in the default file". Experiment shows that, under most situations, process of overloads in the script content is on a line-by-line basis.

Example: The following is an exempt from the .ini file of the default theme.

[Common]
ColorP1=0.4,1.0,0.8,1 // sea green
ColorP2=1.0,0.5,0.2,1 // orange
FirstRunInitialScreen=ScreenCompany
InitialScreen=ScreenCompany
WindowTitle=StepMania
DefaultModifiers=
DefaultCpuModifiers=
JoinPauseSeconds=0.8
DifficultiesToShow=beginner,easy,medium,hard,challenge
CourseDifficultiesToShow=easy,regular,difficult

Now we want to build a theme, in which we hope that the color for 1P is no longer orange, but sea green like 2P. We can do it by filling the .ini as below:

[Common]
ColorP1=1.0,0.5,0.2,1

For other statements in Common section, the program will load their defaults.

Someone may ask at this point, what are these //xxxxxx stuff at the end of each line in the original?

In StepMania metrics, // is used to mark comments, everything that appears between // and the end of the line is not loaded, it only offers a chance for a Theme Coder to describe their code.

This part also tells us that unless absolutely necessary there is no need to edit the default skin, try to create a new theme if you need to test something instead.

Comments are useful in two ways- a descriptive label for others, and a reminder for the creator(s) of the theme. Commenting will help you to remember what the code means in case you forget.

File Loading Mechanism

Disregarding irregular operations, file types that can be loaded by a Stepmania Theme are listed below:

  • redir
  • ini
  • actor
  • sprite
  • png
  • jpg
  • bmp
  • gif
  • avi
  • mpg
  • mpeg
  • txt
  • mp3
  • ogg
  • wav
  • sm

Here I'd like to explain the effect of redir type files.

As the name suggests, this type of file provides a file redirecting functionality. It is a plain text file.

For example, suppose that the program needs to load a sound file with the name ScreenSelectMusic difficulty easier (we can infer from the name that this sound is played when switching to an easier difficulty in the Select Music Screen), so it starts to search for a file maching this name. The first name to be tried would be ScreenSelectMusic difficulty easier.redir, as when loading a file, StepMania will first try to locate a redir file whenever applicable. If the file exists, the text inside will be read as the file path to the actual file to be read. Of course, the path can be relative, such as ../Stepmania.png.

If the .redir file does not exist, the system will then try loading ScreenSelectMusic difficulty easier.ogg.

Back to our example: say the .redir file exists with a content of "ScreenSelectMusic difficulty harder". StepMania will then look for a file with a matching name of "ScreenSelectMusic difficulty harder". In fact this is how the default theme got to have the same sound for the two kinds of change between difficulties.

Redir files plays the same role when it comes to loading graphics. 

Screen Loading Mechanism

Let's still take a look at the .ini file under the root folder.

In this kind of metrics format, what's between two [xxxxxxx] (headers) is called a section.

One type of the sections is the Screen sections; for the other, let's just call it supplementary sections.

It is not difficult to decide which sections are the screen sections. Most sections that start with ScreenXxxxxx are screen sections.

All screen sections controls a cooresponding screen, for example: the [ScreenBranchEnding] Section, with the following contents:

Class=ScreenBranch
Choices=Credits,MusicScroll
ConditionCredits=GetBestFinalGrade() <= Grade("AA")
ConditionMusicScroll=true
NextScreenCredits=screen,ScreenCredits
NextScreenMusicScroll=screen,ScreenMusicScroll

It controls the screen after the name input screen. Strictly, the "game logic" of the screen, since this so-called "screen" does not display anything. The reason:

  • We'll skip the first line for later analysis.
  • The second line of code means that there are two kinds of choices, Credits and MusicScroll. (Those are just aliases for two choices, they can be changed into "China" and "Chinese" and the code will still work.)
  • The third line says that if the final grade is not less than AA, then choice "Credits" is determined to be true.
  • The fourth line says that the choice MusicScroll is always true. (This does not conflict with the third line, as when one choice is true, the remainder will not be evaluated anymore. In fact always-true entries like the fourth line provides only a default path of the game logic.)
  • The fifth and the sixth line shows that, if Credits is true, then the game logic goes to ScreenCredits screen, if not to ScreenMusicScroll screen.

From the perspective of the player:

If the final grade is not less than AA, the credits screen is shown.
Otherwise, the screen with all music titles scrolling is shown.

In the above, we have gone through a particular instance of screen sections. Next, we will explain screen sections in general.

Interheritage and Overloading of Screen Classes

The StepMania developers have created several fixed type screen sections for theme designers. We'll call them Native Screen types. Theme creators may use them as a basis to create new screens to achieve their desired effects.

Take the above example, notice the first line we have skipped:Class=ScreenBranch. In fact ScreenBranchEnding is not one of the Native Screens, but a new screen section created by the theme author. The meaning of the line is that ScreenBranchEnding interheits the attributes and values of ScreenBranch.

From the meaning of the names, ScreenBranch means "Screen for controlling branching", and ScreenBranchEnding means "Screen for controlling the branch after the ending".

Likewise, we may create other branching screens to need, for example if we want StepMania to switch to Options screen if it's January, switch to course select screen with a 12.56 dizzy mod if it's Feburary, and breach to normal song select screen with solo style selected if otherwise, we can do it like this:

[ScreenBranchTest]
Class=ScreenBranch
Choices=System,Course,Song
ConditionSyetem=MonthOfYear() == 1
ConditionCourse=MonthOfYear() == 2
ConditionSong=true
NextScreenSyetem=screen,ScreenOptionsMenu
NextScreenCourse=mod,1256% dizzy;screen,ScreenSelectCourse
NextScreenSong=Style,solo;screen,ScreenSelectMusic

Some notes regarding this example:

  • Later we'll talk about how to have the game logic breach into this screen.
  • Newly created screen section names can be decided as you like, as long as you remember what this section does.
  • Strings like GetBestFinalGrade() and MonthOfYear() are to of some functions though which we can obtain infomation. Some functions are API functions exposed by the Main application to be called by theme coders via Lua scripting language. In the text below you may find a comperhensive list about these functions.
  • In screens with a class of ScreenBreach, following the NextScreenXXXXX= statement can not only be the name of the next screen, but also statements for execution of other 11 operations.

From those two examples we can see that Native Screen classes determines a code format, in fact every Native Screen have their own loadable statements and required statements.

In the end we'll analyze how the statement Class=XXXX really works. When this statement is executed, the section it is in is determined to have a certain type of apperance, for example the select music screen or the gameplay screen, so as to determine the resources to be loaded and the behavior of the game; at the same time, the section will first interheit all statements in section XXX as defaults, then use section-specific statements to override them. If the section required does not exist the default is read.

This time we'll take the Title Menu screen as an example. Note: for illustration purposes, irrelvant statements are discarded.

[ScreenTitleMenu]
Fallback=ScreenWithMenuElements
ChoiceNames=1,2,3,4,5,6,7
Choice1=screen,ScreenSelectStyle
Name1=GAME START
Choice2=screen,ScreenSelectGame
Name2=SELECT GAME
Choice3=screen,ScreenOptionsMenu
Name3=OPTIONS
Choice4=screen,ScreenEditMenu
Name4=EDIT/SYNC SONGS
Choice5=screen,ScreenEditCoursesMenu
Name5=EDIT COURSES
Choice6=screen,ScreenJukeboxMenu
Name6=JUKEBOX
Choice7=screen,ScreenExit
Name7=EXIT
Choice8=screen,ScreenTest
Name8=SANDBOX

ScreenTitleMenu is also a Native Screen, the above is to tell the program which options needs to be displayed in this screen, their game logic paths and the displayed names of the options.

Say because of certain needs, we need to create a screen that interheits the above screen, with the first choice displayed as DDR, and leave others unchanged. We'll just need to write the following:

[MaoLuoTest]
Class=ScreenTitleMenu
Fallback=ScreenTitleMenu
Name1=ddr

Some comments regarding this example:

  • Screen sections don't always have to start with "Screen", so you shouldn't determine whether a section is a screen section by looking at whether there's a "screen" in it. However it's not recommended to use a name like "MaoLuoTest".
  • After the execution of the first statement the cooresponding screen will be constructed as the title menu screen, and values in the ScreenTitleMenu Section will be loaded as default values. Statements other than Fallback= and Name1= will be provided by the defaults, and the aforementioned two are overloaded. Remember the default loading mechanism we have explained? In fact, if we are not working under the /default/ skin, then even if there's no ScreenTitleMenu in the current skin, it doesn't matter as the Program will load relevant statements from the default skin as a default, provided that the /default/ skin is not corrupted of course.

sOn why it is required to overload the statement Fallback=XXX, the reason is that it has something to do with the screen displaying mechanism outlined below. In short, Fallback=ScreenTitleMenu indicates that the screen for this section uses the same /image/ with ScreenTitleMenu. And the original line Fallback=ScreenWithMenuElements indicates that images required for the title screen should be searched for in the BGAnimations folder. If Fallback= ScreenTitleMenu is deleted from MaoLuoTest Section, in other words not to overload, then when the screen is displayed the game will also search in the BGAnimations folder, under current circumstances this is not necessary.

In the above we have illustrated some problems with two screen classes. Below is a list of all Native Screen classes:

ScreenAttract
ScreenCaution
ScreenEdit
ScreenEditMenu
ScreenEvaluation
ScreenEz2SelectPlayer
ScreenGameOver
ScreenGameplay
ScreenHowToPlay
ScreenMapControllers
ScreenMusicScroll
ScreenPlayerOptions
ScreenSandbox
ScreenSelectDifficulty
ScreenSelectGroup
ScreenSelectMusic
ScreenSelectStyle5th
ScreenSelectStyle
ScreenSelectMode
ScreenSongOptions
ScreenStage
ScreenTest
ScreenTestFonts
ScreenTestSound
ScreenTitleMenu
ScreenEz2SelectMusic
ScreenRanking
ScreenLogo
ScreenUnlock
ScreenDemonstration
ScreenInstructions
ScreenNameEntry
ScreenNameEntryTraditional
ScreenJukebox
ScreenJukeboxMenu
ScreenStyleSplash
ScreenCredits
ScreenSelectCharacter
ScreenSelectMaster
ScreenEditCoursesMenu
ScreenProfileOptions
ScreenExit
ScreenReloadSongs
ScreenOptionsMaster
ScreenCenterImage
ScreenTestInput
ScreenBookkeeping
ScreenBranch
ScreenEnding
ScreenDownloadMachineStats
ScreenSetTime
ScreenTestLights
ScreenClearMachineStats
ScreenResetToDefaults
ScreenClearBookkeepingData
ScreenInsertCredit

It would be a massive project to give a thourough explaination on grammar of the above screen, nor would it be necessary. For what's next we'll only introduce one Native Screen and some other miscllanious points necessary to be described, for issues on other screens not discussed here please download and analyze some skins from http://www.stepmaniathings.com/ or resolve them by a process of trial and error.

Introduction of Native Screens: [ScreenTitleMenu]

This is the screen section for the title menu screen of the game. When coin mode is set to PAY, the menu list will not be displayed, and the first option will be used as the default redirect value.

Format of statements specific to this section:

ChoiceNames=
Choice1=
Name1=
...
NumCodes=
Code1=
Code1Action=
...
LogoHomeOnCommand=
LogoOnCommand=
VersionOnCommand=
SongsOnCommand=
MaxStagesOnCommand=
MaxStagesText=
LifeDifficultyOnCommand=
ChoicesX=
ChoicesStartY=
ChoicesSpacingY=
ChoicesShadowLength=
HelpX=
HelpY=
ColorNotSelected=
ColorSelected=
ZoomNotSelected=
ZoomSelected=
MenuTextAlign= // 0=left, 1=center, 2=right
MenuCommandOnCreate=
MenuCommandSelectDelay=
SecondsBetweenComments=
SecondsBeforeAttract=

The meaning of most statements can be inferred from their names. For example, ZoomSelected=2 indicates that the currently chosen item should be displayed at twice its normal size.

A few notes:

  • ChoiceNames=
    Choice1=
    Name1=
    ...

    Obviously they come in groups, the first line to describe the options avalible, the second for the actions executed when the options are selected, and the third for the names of the options displayed on screen. As mentioned before, besides using the screen, xxx statement to enter a screen, 11 other kinds of operations can be executed in this way, more on the Random Insertion One later.

  • NumCodes=
    Code1=
    Code1Action=

    In most themes you will only find the line NumCodes=0, with latter statements nonexistant. In fact its a setup where player can unlock songs thru special key combinations. For example when Keys are entered in the order of Up, Up, Down, Down, then Left and Right at the same time at the title menu screen, unlock song MAX300 and play MAX300.ogg in the sounds folder, you can do it like this:

  • NumCodes=1
    Code1=Up,Up,Down,Down,Left+Right
    Code1Action=Unlock,MAX300;sound,MAX300

    Why write it as "Up,Up,Down,Down,Left+Right"?

    In the metrics, Up corresponds to the Up panel, MenuUp to the Menu Up button, Down to the Down panel, Start to the start button, and so forth. (The appearances of the menu button codes here are mainly for other control layouts such as PIU. The relations between the codes and input should be obvious with the exception of Menu buttons, which are buttons dedicated for menu navigation on arcade machines. )

    Use , (comma) to denote keys in sequential order. The code syntax for simultaneous button press is unclear, it seems that for two keys pressed at once use + (plus) to connect the two buttons, for three use - (dash).

  • Lines like XXXXXXXXCommand= are used for controlling effects of pre-set elements. Remember the loaded songs display on the title screen? Its appearance can be controlled with SongsOnCommand, for example, if we state that SongsOnCommand=zoom,2, the text will become twice as large. Obviously, zoom,x is a string which can be used to control the size of things. There are other Actor Commands similar to zoom, which are the primary method of implementing animations in themes. More about Actor commands coming later in Screen Displaying Mechanism...

  • ColorNotSelected=
    ColorSelected=

    They assign colors to selected and unselected entries. We'll explain how to represent colors in SM in the next section.

Random Insertion One

List of twelve navigation commands that can be executed in ScreenNextXXX of the [ScreenBranch] class and Choice X in others.

  • game, xxx
    This can be used to change the game being simulated.
    But there is a glitch: after the switch the game will not reload the control information, that is, the key layout will be messed up.
    Example: game,dance
  • style, xxx
    This can be used to select a particular style for a game. Dance game type has styles single, solo, double, etc.
    Example: style,single
  • Playmode, xxx
    This can be used to select the play mode when the above two are determined. When game is dance, style can be chosen from regular, nonstop, oni, endless, and rave.
    Example: playmode,regular
  • difficulty, xxx
    This can be used so select the difficulties of the songs. There are beginner, easy, medium, hard and challenge difficulties.
    Example: difficulty,challenge
  • announcer, xxx
    Had never used this command; it might be for playing a sound in the announcers.
  • name, xxx
    Give the current option a name; has something to do with announcers and languages.
  • mod, xxxx
    Select modifiers for the current player. For more infomation about mods, refer to Random Insertion Three.
    Example: mod, 1256% dizzy
  • song, xxx
    Select the song for the next stage. You'll need to write the parameter exactly as how the song's folder name appears.
    Example: song, MAX300
  • steps, xxx
    Had never used this command; perhaps it has something to do with choosing steps for a song.
  • screen, xxx
    Jump to the xxx screen.
    Example: screen, ScreenSelectMusic
  • setenv, name, value
    Theme coders can use this statement to set an enviroment variable for later use.
    Example: setenv, is_dance_single,1
    Description: after this statement gets executed, the value for is_dance_single is now 1. For the second step of passing a variable - how to reach this value later, see the parts about Lua below.
  • You can seperate multiple commands with ; (comma), like this:
    Example: game,pump;style,single;playmode,nonstop;screen,ScreenSelectCourse

Random Insertion Two

 

 

Translation Notes

Occurances of Skin is changed to Theme.

Several occurances of Scripts is changed into Metrics, since the metrics is not really a script.

“It seems that” was a popular meme in China in 2006. You may find the author "abusing" this word throughout the article. ^_^

Why OGG and PNG?

Because they are not properiary formats (i.e. not owned by someone or some ebil company).