Skip to main content

State File Modification

State files control certain functions of UI screens in games using the Luxor 2 engine. They have an extension of sm and can be found in data/state.

For Luxor 2 (not HD), you may want to use a pre-fixed plaintext version of the state folder that should work with all versions HERE.

General Ideas

Here's some basic ideas you could do with state files:

  • Simple screen additions, such as a credits screen without the need for replacing something else for it, such as the Enable Cheats dialog
  • "Are you sure you wish to quit?"
  • Being able to assign MORE Map IDs in the Achievements screen, which might give way for mods with 26+ maps that properly function in Survival/Challenge/Gauntlet modes

    Remark: I noticed that it seems like Luxor AR HD (or Luxor 1 HD?) used to be a 2-in-one pack of sorts, you can check and notice how there's "Luxor Completion" stuff commented out and the map counts starting from 26, this is obvious when playing a map in Survival/Practice mode.

    Remark 2: It might be already possible to have 26+ maps in the Survival/Challenge/Gauntlet maps, due to the fact that these levels start from the index of 26.

  • Splitting achievements screen into two (achievements and personal stats), but I dunno why would you do that.
  • Set music playlists for each screen (without the need for hacky workarounds, such as playing an eiSound in the "Danger" track and setting "Normal" track volume to 0)

But before you get too excited, know that you can't do these:

  • An actual cutscene system (damn, I wish)
  • Conditional statements
  • A fix for 15+ stages (see: DRTPIAB's Epic Wins/Fails counter attempt, ask anyone lol)
  • Implement things from other Luxor 2-based engine games (LXE, NCQ, MM, etc)
  • Per-level tracks

    Remark: It seems like Luxor Evolved-specific features are in Luxor Amun Rising HD, and possibly other HD remasters. While looking at it's memory allocation in HxD, I noticed Luxor Evolved specific things like uiSpectrumFrame and Song are in the game. Sadly, it is not possible to assign level tracks this way. It just seems like those were just sitting in the code, and the devs only worked on those when Evolved was next to be developed.

    It only makes sense considering Luxor HD remasters and Evolved were released during 2012, and the other HD releases never needed such functionality.

Basic State File Modification

Creating Simple Screens

Let's say we'd like to create a simple confirmation screen for when the player wants to exit. We don't need to worry much about it - the UI system takes care of our UI elements, and the state system takes care of the "programming".

First we need to look at vars_pc.gvf (Don't mind the iOS and x360 files, unless you're over your head and want to create a Luxor AR HD mod for Android devices, then yes, go ahead).

   7  global TOPLEVEL_UI = ~data/scripts/interface/toplevel.ui
   8  global TRANSITION_UI = ~data/scripts/interface/transition.ui
   9  global GAME_UI = ~data/scripts/interface/game.ui
  10  global DIALOG_OPTIONS_UI = ~data/scripts/interface/dialog_options.ui
  11  global DIALOG_MODE_SELECT_UI = ~data/scripts/interface/dialog_mode_select.

As you can see, the vars pretty much define UI files for state machine files. We want to define a new UI here, as shown:

   7  global TOPLEVEL_UI = ~data/scripts/interface/toplevel.ui
   8  global TRANSITION_UI = ~data/scripts/interface/transition.ui
   9  global GAME_UI = ~data/scripts/interface/game.ui
+ 10  global DIALOG_CONFIRM_EXIT = ~data/scripts/interface/dialog_confirm_exit.ui
  11  global DIALOG_OPTIONS_UI = ~data/scripts/interface/dialog_options.ui

We're going to the ui files now. I'm not going to talk much about it, but we're mostly interested in the Command property.

  ..   uiButton Button_ActuallyQuit
  ..   {
  ..      Position = [ 108.000000, 390.000000, 0.000000 ]
  ..      AnchorHorz = CENTER
+ ..      Command = "QuitForReal"
  ..      uiTextWidget Text
  ..      {
  ..         Text = T( "Yes" )
  ..      }
  ..      uiSprite Icon
  ..      {
  ..         Style = "Icon"
  ..         Position = [ 48.000000, 48.000000, 0.000000 ]
  ..         Color = [ 1.000000, 1.000000, 1.000000, 0.908038 ]
  ..         AnchorHorz = CENTER
  ..         AnchorVert = CENTER
  ..         Sprite = ~data/scripts/interface/styles/dialog/button_ipad/sprites/icons/quit_game.png
  ..         BlendMode = ADD
  ..      }
  ..   }

The command name does not matter as long as it's readable and it's the exact same name you'll be using in the state file.

The state machine file we're interested in is

  37   Command "Profiles"     StateMachine::csPushState "Profile_Manage"
  38   Command "Play"         StateMachine::csPushState "ModeSelect"
  39   Command "Options"      StateMachine::csPushState "Options"
  40   Command "HighScores"   StateMachine::setState "HighScores"
  41   Command "Instructions" StateMachine::setState "Instructions"
  42   Command "Achievements" StateMachine::setState "Achievements"
  43   Command "MoreGames"    enClientLocal::invoke_3rdPartyMoreGamesURL
  44   Command "QuitMenu"     StateMachine::setState "MainMenuQuit"

The string after the keyword "Command" is what triggers the function/callback/whatever in the right. We want to change line 44 to something like:

  37   Command "Profiles"     StateMachine::csPushState "Profile_Manage"
  38   Command "Play"         StateMachine::csPushState "ModeSelect"
  39   Command "Options"      StateMachine::csPushState "Options"
  40   Command "HighScores"   StateMachine::setState "HighScores"
  41   Command "Instructions" StateMachine::setState "Instructions"
  42   Command "Achievements" StateMachine::setState "Achievements"
  43   Command "MoreGames"    enClientLocal::invoke_3rdPartyMoreGamesURL
! 44   Command "QuitMenu"     StateMachine::csPushState "ConfirmExit"

We want to "push" the state and not "set" it, because our exit confirmation dialog is a pop-up, not full-screen. All we need to do now is to create the new state!

+ ..   StateDialog ConfirmExit : BaseState
+ ..   {
+ ..      Dialog = DIALOG_CONFIRM_EXIT
+ ..   
+ ..      Command "Cancel"          StateMachine::popState
+ ..      Command "QuitForReal"     StateMachine::setState "MainMenuQuit"
+ ..   }

You might be able to understand quickly how this works now. The "Cancel" command just "pops" the state and goes back to the previous state (which is the main menu). The "QuitForReal" command sets the state to "MainMenuQuit", which is already defined, which well... exits the game!

Think of the "Command" property as an alias to a function, with the state file providing the "link" to the function.

Assigning Music to Screens

Let's say we want to change the adventure Stage Map to play something else instead of the same old boring main menu theme. First we need to modify data\game\music.gvf.

We just need to add a new objEffectMap, like so:

   1  objEffectMap Menu
   2   {
   3      Effect = ~data/scripts/effects/sound/music/menu.ofx
   4   }
+  6   objEffectMap Map
+  7   {
+  8      Effect = ~data/scripts/effects/sound/music/map.ofx
+  9   }
  11  objEffectMap Level
  12  {
  13     Effect = ~data/scripts/effects/sound/music/level.ofx
  14  }

The OFX file handles the actual music track, we just need to create one, like so:

   1  objEffect MapMusic
   2  {
   3     Loop = true
   4     ObjectOffset = "Normal"
   6     eiSound Song
   7     {
!  8        File = ~data/music/sparkleunleashed-map.ogg
   9        HandleGroup = "Music"
  10     }
  11  }

Then we edit data\state\common\ like so:

  31   StateDialog StageMap_Adventure : BaseState
  32   {
  34      TrTransInDone = gameClientLocal_Luxor::trigger_advanceLevelCb
  36      Init   = gameClientLocal_Luxor::init_stageMapAdventureCb
+ 37      Init   = enClientLocal::setMusicPlaylist "Map"
  39      Command "Cancel"   gameClientLocal_Luxor::command_quitGame "StageMap_QuitGame"
  40      Command "Start"    gameClientLocal_Luxor::command_startGameCb
  41      Command "SignOut"  StateMachine::setState "TransToMainMenu"
  42   }

And now when you enter the stage map (not the Challenge of Horus stage map), the new map music track should play. It should also stop playing when you return to the Main Menu.

Documentation, So Far

Common Properties


Init = namespace::Function

A function is called on state initialization.


Term = namespace::Function

A function is called on state termination.




StateMachine::csPushState "StateLabel"

Pushes a state into the current stack. Used for modal dialogs (such as confirmations).



Pops the current state pushed by csPushState and returns to the previous state.


StateMachine::csPopPushState "StateLabel"

Pops the current state, then pushes a state into the current stack.


StateMachine::setState "StateLabel"

Sets the state. Used for screens, like the High Scores screen or the Achievements screen.



enClientLocal::setMusicPlaylist "Label"

Sets the currently playing music to the objEffectMap defined in music.gvf.



Stops any playing music.



gameClientLocal_Luxor::command_newGameOrContinueGameCb "Pause" | "Menu"
  • "Pause" will pause the game with the "Paused: Press Spacebar to Continue" dialog.
  • "Menu" will pause the game and open the pause menu that allows you to quit/exit/change options.


⚠️ Luxor Evolved-specific.

gameClientLocal_Luxor::command_newGameOrContinueGameCb "DifficultySelect"

Checks if there's a currently running game. Else, show the difficulty selector.

State Types


Represents a dialog UI.

StateDialog Label : BaseState



NAME_OF_DIALOG must be defined in the target vars file (usually vars_pc.gvf).

DialogTransIn  = true
DialogTransOut = false

Both properties are boolean. Tells the game if the dialog should transition in or out.

EffectTransIn  = "LabelOfObjEffectMap"
EffectTransOut = "AnotherObjEffectMap"

Both properties take a string. Uses these effects as transin/out effects.

Command "Label"  namespace::Function

A function is called when the command is invoked. Must be defined in the ui file.


Used in gsv_*.sm files. I don't recommend you poking around gsv_*.sm and gcl_*.sm files, since they pretty much handle the game itself.

StateServer_Luxor Label : Server_Common



⚠️ Luxor Evolved-specific.

MusicState = "NameOfMusicState"

Sets the music state of the level.