Creating a Generic Menu

From the Oblivion ConstructionSet Wiki
Jump to navigation Jump to search


This guide will explain the different parts involved for making and interacting with a GenericMenu. It is highly recommended to learn how Oblivion's XML works and what the mostly-used traits and tricks are. Which can be done by looking at how some of the other, simple, menus work and look like.

Aim[edit | edit source]

The aim of our menu will be to display a single picture along with a small description. The image will be one of the birthsign pictures and the description explains some extra feature for that birthsign. It will be shown when the user clicks on the birthsign in the stats menu. To close the menu the user must click on the image.

Basics[edit | edit source]

There are a few things that are useful or important to keep in mind.

  • The <class> trait must be either &GenericMenu; or the number 1011.
    • The exact name of the menu does not matter and is only used within the menu itself.
  • The <stackingtype> trait must be either &no_click_past; or the number 102.
  • If an element has a <id> trait of above 0 the menu will be closed as soon as the user clicks on that element. Assuming it can be targeted.
  • There can only be one generic menu at a time, each time one gets opened the existing menu is closed.

Apart from these things everything is possible. Well, within the limits of Oblivion's XML syntax ofcourse.

Layout[edit | edit source]

To begin our generic menu we start with the bare minimum and save it at Data\Menus\Generic\Demo.xml; with the following content:

<!-- demo.xml, only here for easy reference -->
<menu name="DemoMenu">
	<class> &GenericMenu; </class>
	<stackingtype> &no_click_past; </stackingtype>
	<locus> &true; </locus>
	<explorefade> 0.25 </explorefade>
</menu>

But when it is used the result would be a menu that has no visible components nor any means of closing. So it needs some elements, starting with a standard background.

<menu name="DemoMenu">
	....
	<rect name="background">
<include src="generic_background.xml" /> <!-- one of many default prefabricated elements -->
		<visible> &true; </visible>
		<locus> &true; </locus>
		<target> &true; </target>
		<user0> 400 </user0> <!-- the width of the background, excluding the borders -->
		<user1> 320 </user1> <!-- the height of the background, excluding the borders -->
		<depth> 15 </depth>
		<x> <!-- this puts it nicely in the center of the screen -->
			<copy src="screen()" trait="width" />
			<sub src="me()" trait="width" />
			<div> 2 </div>
		</x>
		<y> <!-- this puts it nicely in the center of the screen -->
			<copy src="screen()" trait="height" />
			<sub src="me()" trait="height" />
			<div> 2 </div>
		</y>
	</rect>

And now we have a background, empty perhaps, but there nonetheless. Next step would be to add the image that is to be displayed and that serves as a means for closing the menu.

<menu name="DemoMenu">
	....
	<rect name="background">
		....
		<image name="icon">
			<id> 1 </id> <!-- this is what will cause the menu to be closed when it is clicked -->
			<locus> &true; </locus>
			<target> &true; </target>
			<filename> Menus\Birthsign\Birthsign_the warrior.dds </filename>
			<zoom> 75 </zoom>
			<depth> 3 </depth>
			<width>
				<copy> 500 </copy>
				<mul src="me()" trait="zoom" />
				<div> 100 </div>
			</width>
			<height>
				<copy> 400 </copy>
				<mul src="me()" trait="zoom" />
				<div> 100 </div>
			</height>
			<x> 30 </x>
			<y> 25 </y>
		</image>




Script[edit | edit source]

In order to know when to display our menu we need to monitor the player's mouse input while the stats menu is open. For that we use a simple quest with the following script attached.

scn DemoMenuScript

float fQuestDelayTime
ref birthsign
string_var text
string_var icon
string_var name

begin MenuMode 1003
	set fQuestDelayTime to 0.0001
	if OnKeyDown 256	;LeftMouseButton
		if GetActiveMenuComponentID == 14	;the ID of stat_p1_birthsign_layout
			PrintC "Clicked on the birthsign in the statsmenu"
			
			set birthsign to GetPlayerBirthsign
			set name to GetName birthsign
			set icon to GetTexturePath birthsign
			set text to sv_Construct "Your custom description based on what exact birthsign was found."
			ShowGenericMenu "demo.xml"
			SetMenuStringValue "user0|%z", icon, 1011
			SetMenuStringValue "user1|%z", text, 1011
			SetMenuStringValue "user2|%z", name, 1011
		endif
	endif
end

Final[edit | edit source]

The final menu will contain a few more elements to explain what and how the user should do.

<!-- demo.xml -->
<menu name="DemoMenu">
	<class> &GenericMenu; </class>
	<stackingtype> &no_click_past; </stackingtype>
	<locus> &true; </locus>
	<explorefade> 0.25 </explorefade>

	<user0> Menus\Birthsign\Birthsign_the warrior.dds</user0>
	<user1> Description </user1>
	<user2> Name </user2>
	<user3> Click on the image to close this menu... </user3>

	<rect name="background">
<include src="generic_background.xml" />
		<visible> &true; </visible>
		<depth> 15 </depth>
		<locus> &true; </locus>
		<target> &true; </target>
		<user0>
			<copy src="icon" trait="x" />
			<add src="icon" trait="width" />
			<add> 250 </add>
		</user0>
		<user1>
			<copy src="icon" trait="y" />
			<add src="icon" trait="height" />
			<add> 60 </add>
		</user1>
		<x>
			<copy src="screen()" trait="width" />
			<sub src="me()" trait="width" />
			<div> 2 </div>
		</x>
		<y>
			<copy src="screen()" trait="height" />
			<sub src="me()" trait="height" />
			<div> 2 </div>
		</y>

		<image name="icon">
			<id> 1 </id>
			<locus> &true; </locus>
			<target> &true; </target>
			<filename> <copy src="DemoMenu" trait="user0" /> </filename>
			<zoom> 75 </zoom>
			<depth> 3 </depth>
			<width>
				<copy> 510 </copy>
				<mul src="me()" trait="zoom" />
				<div> 100 </div>
			</width>
			<height>
				<copy> 400 </copy>
				<mul src="me()" trait="zoom" />
				<div> 100 </div>
			</height>
			<x> 30 </x>
			<y> 25 </y>
		</image>

		<text name="hint">
			<string> <copy src="DemoMenu" trait="user3" /> </string>
			<depth> 3 </depth>
			<font> 3 </font>
			<red> 0 </red>
			<green> 0 </green>
			<blue> 0 </blue>
			<alpha> 200 </alpha>
			<visible> &true; </visible>
			<locus> &true; </locus>
			<target> &true; </target>
			<wrapwidth> 500 </wrapwidth>
			<x>
				<copy src="icon" trait="x"/>
				<add> 10 </add>
			</x>
			<y>
				<copy src="icon" trait="y"/>
				<add src="icon" trait="height" />
				<add> 5 </add>
			</y>
		</text>

		<text name="description">
			<string> <copy src="DemoMenu" trait="user1"/> </string>
			<depth> 3 </depth>
			<font> 3 </font>
			<red> 0 </red>
			<green> 0 </green>
			<blue> 0 </blue>
			<alpha> 200 </alpha>
			<visible> &true; </visible>
			<locus> &true; </locus>
			<target> &true; </target>
			<clips> &true; </clips>
			<wrapwidth> 230 </wrapwidth>
			<x>
				<copy src="icon" trait="x"/>
				<add src="icon" trait="width"/>
				<add> 20 </add>
			</x>
			<y>
				<copy src="icon" trait="y"/>
				<add> 40 </add>
			</y>
		</text>

		<rect name="title">
			<locus> &true; </locus>
			<target> &true; </target>
			<x> <copy src="description" trait="x" /> </x>
			<y> <copy src="icon" trait="y" /> </y>
			<width> 240 </width>
			<height> 25 </height>
			<depth> 3 </depth>

			<text name="title_text">
				<locus> &true; </locus>
				<target> &true; </target>
				<depth> 3 </depth>
				<font> 3 </font>
				<alpha> 200 </alpha>
				<red> 0 </red>
				<green> 0 </green>
				<blue> 0 </blue>
				<string> <copy src="DemoMenu" trait="user2" /> </string>
				<wrapwidth> <copy src="parent()" trait="width"/> </wrapwidth>
			</text>
			<image name="line1">
				<depth> 1 </depth>
				<x> -8 </x>
				<y> <copy src="title_text" trait="height" /> <add> 6 </add> </y>
				<filename> Stats\stat_border_horizontal_1.dds </filename>
				<zoom> 50 </zoom>
				<width> <copy src="description" trait="wrapwidth" /> <sub> 25 </sub> </width>
				<height> 3 </height>
			</image>
		</rect>
	</rect>


</menu>