Always snap to grid
The base class for the UT2004 Instant Action and Host Game menus.
I've seen quite a few questions regarding the correct way for implementing a custom gametype rules page in the UT2004 GUI. Recently I received an email from a mod author who was having trouble with getting his custom game rules tabpanel to appear in the game. The following was my response to his question - copied here for the benefit of anyone else having trouble understanding the new gametype rules menu system.
The rules page is dynamically generated in UT2004, and there are no longer custom rules panels for each gametype. I decided to go this route in UT2004 because of the sheer volume of new properties that were going to be added and exposed in the interface.
The rules page is now dynamically generated by the UT2K4PlayInfoPanel class, using data from PlayInfo. The exact implementation, however, was changed very early in the development cycle. Originally, the rules tab was UT2K4Tab_RulesBase, which contained its own GUITabControl with a single tab for each playinfo group. InstantActionRulesPanel was the class that was used in this internal tabcontrol for each of the PlayInfo groups. If you take a look at UT2K4Tab_RulesBase.Refresh(), you'll see where the panels are generated based on the PlayInfo groups.
Eventually, however, we decided that the instant action menu looked too cluttered this way, and decided to go with a single page for all PlayInfo properties, represented as a multicolumn list of GUIMenuOptions...thus IAMultiColumnRulesPanel was born. This is the reason why your subclass of InstantActionRulesPanel isn't showing up.
If you take a look at UT2K4GamePageBase, you'll notice that there is a bUseTabs variable. Since I had spent so much time developing and fine-tuning the multiple tab method of displaying the rules, I didn't want to just throw it all away. I left bUseTabs in as a hook for going back to the multi-tabs approach, if we wanted to do that later. Unless you set bUseTabs to true in your subclass of UT2K4GamePageBase, it will always use GUI2K4.IAMultiColumnRulesPanel as the class that manages all the PlayInfo rules (look at UT2K4GamePageBase.InitComponent()). Generally, you shouldn't need to replace the rules panel - you can manipulate PlayInfo from within your gametype to be able to do lots of things in the menu without the need to write any menu code whatsoever.
As far as figuring out what the heck is going on in this menu, the most important thing to remember is that the whole thing revolves around PlayInfo - so you definitely want to make sure you know how PlayInfo works. When the gametype is changed, the current PlayInfo's data is no longer relevant, so the game type page re-initializes the PlayInfo object with the data from the new gametype, then notifies all panels that care that PlayInfo has been re-initialized.
For the rules panel (IAMultiColumnRulesPanel), this means that it must go through each property in PlayInfo, and generate the corresponding control for that rule, which involves adding the component to its GUIMultiOptionList, setting up the appropriate delegate chains, setting the default values, etc. For the mutators panel, this means it must re-verify that mutators are allowed in this gametype, and remove any that are not allowed.
So here's a quick run-down:
- user changes gametype
- gametype selection panel calls its OnChangeGameType delegate, which is hooked to UT2K4GamePageBase.ChangeGameType
- ChangeGameType notifies the mutator panel, then calls SetRuleInfo()
- SetRuleInfo initializes PlayInfo with the new gametype, then calls Refresh on the rules panel, which is currently IAMultiColumnRulesPanel
- the rules panel clears its current list of components, then re-fills the list with new components ( AddRule() ) based on the properties now in playinfo ( LoadRules() )
- the rules panel then goes through all of the components it just added, and initializes their values with the values from PlayInfo ( UpdateRules() )
- when the value of any of the options is changed, the rules panel takes care of propagating the change to PlayInfo ( UpdateSetting() )
- when the user exits the page, either by clicking 'Play', or clicking 'Back', the values stored in playinfo are written out to disk, and the changes have been applied ( UT2K4GamePageBase.InternalOnClick() / PrepareToPlay() )
I hope that clears up some things for you and gives you an idea of where to start digging into this menu if you need to.
NickR: Just because this is the wiki and if you didn't know: To get your own game settings into the new gamerules tab, you add them inside you own version of the static function FillPlayInfo which is declared in the GameInfo class.
smattbac: And you can remove settings with by returning false in AcceptPlayInfoProperty(). I spent almost an hour looking for this. :( Also, this page should probably be cleaned up, or have this info put somewhere else.