How To: ZSCRIPT MENUS?

Ask about ACS, DECORATE, ZScript, or any other scripting questions here!

Moderator: GZDoom Developers

Forum rules
Before asking on how to use a ZDoom feature, read the ZDoom wiki first. If you still don't understand how to use a feature, then ask here.

Please bear in mind that the people helping you do not automatically know how much you know. You may be asked to upload your project file to look at. Don't be afraid to ask questions about what things mean, but also please be patient with the people trying to help you. (And helpers, please be patient with the person you're trying to help!)
User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
Posts: 48376
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

Re: How To: ZSCRIPT MENUS?

Post by Graf Zahl »

Funny, because you coded it that way that if the menu processes an event it won't get passed on to the event handler.
User avatar
ZZYZX
 
 
Posts: 1382
Joined: Sun Oct 14, 2012 1:43 am
Location: Ukraine

Re: How To: ZSCRIPT MENUS?

Post by ZZYZX »

Does "funny" mean "it's a bug"? Because I clearly try to catch all possible events in Input/Ui event callbacks on a Menu, yet it still somehow calls MenuEvent instead for certain events.
Just to clarify: I'm inheriting a ListMenu, I'm overriding OnUIEvent and OnInputEvent, and certain events get converted without any obvious way to prevent it.

If anything, here's the code used viewtopic.php?p=988297#p988297

Also, is it possible to force-enable mouse for a specific menu? Either UI or Input variant, I don't care.
Right now I don't know what to do if I want to reliably support mouse for my menu but also want to draw a custom cursor, and I want the mouse even when m_use_mouse is false.
The reason for this is because mouse support is really, REALLY lame for regular doom menus and like half of people disable it, and I'd like my custom menus (that were made mouse-aware from the start and aren't as awful) to have it enabled anyway.
User avatar
Major Cooke
Posts: 8095
Joined: Sun Jan 28, 2007 3:55 pm

Re: How To: ZSCRIPT MENUS?

Post by Major Cooke »

Graf, how do I draw images that are assured to be properly scaled? And do I have to manually set coordinates on them in order for the mouse to register them like buttons, or is there a dedicated function for checking to see if the mouse is over their region?
User avatar
ZZYZX
 
 
Posts: 1382
Joined: Sun Oct 14, 2012 1:43 am
Location: Ukraine

Re: How To: ZSCRIPT MENUS?

Post by ZZYZX »

Apr 02... Graf, can I has an answer to my last post here pls?
(Cooke's question is answered by my script somewhere around viewtopic.php?p=988297#p988297)
User avatar
Major Cooke
Posts: 8095
Joined: Sun Jan 28, 2007 3:55 pm

Re: How To: ZSCRIPT MENUS?

Post by Major Cooke »

Graf's probably referring to this:

Code: Select all

// this is magic and I have no idea where it runs from, just null it here
override bool MenuEvent(int mkey, bool fromcontroller)
{
	if (e && e.MenuEvent(mkey, fromcontroller))
		return true;
	return Menu.MenuEvent(mkey, fromcontroller);
}
User avatar
Major Cooke
Posts: 8095
Joined: Sun Jan 28, 2007 3:55 pm

Re: How To: ZSCRIPT MENUS?

Post by Major Cooke »

Now I'm still in the middle of changing some things around so I cannot exactly state my opinion on it fully, but ZZYZX, I must heavily recommend adding in a simple button and coordinate system for said buttons in your base ZGui menu. Trying to read through and decipher your example GUI is quite difficult.

I suggest for maximum customization, adding in a struct with defined parameters such as this:

Code: Select all

Struct ButtonState
{
    int mRenderStyle;
    Color mColor;
    double mAlpha;
    TextureID mTex;
    String text;
    int fontColor;
    double textAlpha;
    
    void Init()
    {
        mRenderStyle = STYLE_Normal;
        mColor = (255, 255, 255, 255);
        mAlpha = 1.0;
        mTex = null;
        text = "";
        fontColor = Font.CR_RED;
        textAlpha = 1.0;
    }
    
    bool SetProperties(TextureID tex, String tx = "", int style = -1, double ta = -1.0, int r = -1, int g = -1, int b = -1)
    {
        mTex = TexMan.CheckForTexture(tex, TexMan.Type_Any);
        if (ta >= 0.0) mAlpha = ta;
        if (r >= 0) mColor.r = Clamp(r, 0, 255);
        if (g >= 0) mColor.g = Clamp(g, 0, 255);
        if (b >= 0) mColor.b = Clamp(b, 0, 255);
        if (style >= 0)    mRenderStyle = style;
        text = tx;
        return mTex != null;
    }
} 
I replaced the textures with the structs.

Code: Select all

ButtonState mButtonUp;
ButtonState mButtonDown;
ButtonState mButtonHover;
ButtonState mButtonDisabled;
Then in the drawer I added this:

Code: Select all

void DrawButton(ButtonState b, bool animated, double x, double y)
{
	Screen.DrawTexture(b.mTex, animated, VirtualX+x, VirtualY+y,
	
		DTA_VirtualWidthF, VirtualWidth,
		DTA_VirtualHeightF, VirtualHeight,
		DTA_KeepRatio, true,
		DTA_ClipTop, int(ClipTop),
		DTA_ClipLeft, int(ClipLeft),
		DTA_ClipBottom, int(ClipBottom),
		DTA_ClipRight, int(ClipRight)
		//,
		//DTA_Alpha, b.mAlpha,
	);
	
	if (b.mAlpha <= 0.0)	return;
	Screen.DrawTexture(b.mTex, animated, VirtualX+x, VirtualY+y,
	
		DTA_VirtualWidthF, VirtualWidth,
		DTA_VirtualHeightF, VirtualHeight,
		DTA_KeepRatio, true,
		DTA_ClipTop, int(ClipTop),
		DTA_ClipLeft, int(ClipLeft),
		DTA_ClipBottom, int(ClipBottom),
		DTA_ClipRight, int(ClipRight),
		DTA_Alpha, b.mAlpha,
		DTA_RenderStyle, b.mRenderStyle,
		DTA_ColorOverlay, b.mColor
	);
}
But again, that's just an example -- I haven't even tested it yet as I'm still hacking it to pieces but it'd offer customization of the graphic's appearance, not to mention what text to draw and the color of it too.
User avatar
AFADoomer
Posts: 1275
Joined: Tue Jul 15, 2003 4:18 pm

Re: How To: ZSCRIPT MENUS?

Post by AFADoomer »

Anyone have any idea as to why this fails?

Error:

Code: Select all

Script error, "PlayerMenu.pk7:menudef.txt" line 6:
Tried to replace menu 'Playermenu' with a menu of different type
MenuDef:

Code: Select all

ListMenu "PlayerMenu"
{
	StaticTextCentered 160, 6, "This is a redefined player menu"

	Class "NewPlayerMenu"
}
ZScript:

Code: Select all

class NewPlayerMenu : PlayerMenu
{
	override void Drawer()
	{
		Super.Drawer();
		console.printf("New menu is being used!");
	}
}
It also fails if I try to make NewPlayerMenu inherit from ListMenu directly instead of PlayerMenu.

This is the same thing I've done to replace episode and skill menus, so I'm not sure what's going on.
You do not have the required permissions to view the files attached to this post.
User avatar
Major Cooke
Posts: 8095
Joined: Sun Jan 28, 2007 3:55 pm

Re: How To: ZSCRIPT MENUS?

Post by Major Cooke »

You probably can't replace it. You just have to make your own and inject it into the menu since it potentially still relies on internal code that's not exported (or exportable)
User avatar
AFADoomer
Posts: 1275
Joined: Tue Jul 15, 2003 4:18 pm

Re: How To: ZSCRIPT MENUS?

Post by AFADoomer »

Major Cooke wrote:You probably can't replace it. You just have to make your own and inject it into the menu since it potentially still relies on internal code that's not exported (or exportable)
That's the thing - there's not anything that doesn't work if I define a new menu in Menudef, then tell it to use my new class...

This (where the "Test" ZScript class just inherits from PlayerMenu) gives me a fully-functional Player menu when I enter 'openmenu test' in the console:
Spoiler: For size...
It only fails when I try to replace the "PlayerMenu" menu.
User avatar
Major Cooke
Posts: 8095
Joined: Sun Jan 28, 2007 3:55 pm

Re: How To: ZSCRIPT MENUS?

Post by Major Cooke »

PlayerMenu is built before GZDoom even parses ZScript via mods in order to get some essential things up and running at start, so you cannot replace it directly.

Partly related are things like these.

Code: Select all

// All write function for the player config are native to prevent abuse.
protected native void AutoaimChanged(float val);
protected native void TeamChanged(int val);
protected native void AlwaysRunChanged(int val);
protected native void GenderChanged(int val);
protected native void SwitchOnPickupChanged(int val);
protected native void ColorChanged(int red, int green, int blue);
protected native void ColorSetChanged(int red);
protected native void PlayerNameChanged(String name);
protected native void SkinChanged (int val);
protected native void ClassChanged(int sel, PlayerClass cls);
You can make a copy, sure, but you can't actually override it like the others. It will need another name instead of PlayerMenu. That's why the Test scenario worked, simply because you didn't name it PlayerMenu which is reserved.
User avatar
AFADoomer
Posts: 1275
Joined: Tue Jul 15, 2003 4:18 pm

Re: How To: ZSCRIPT MENUS?

Post by AFADoomer »

Can you show me where in the code that happens? Because I'm not seeing it.

Those are just the native functions used to write player config information (so that certain sensitive functions didn't have to be exported to ZScript)... And they are also literally the only thingthat is still defined in native code for the player menu.
User avatar
Major Cooke
Posts: 8095
Joined: Sun Jan 28, 2007 3:55 pm

Re: How To: ZSCRIPT MENUS?

Post by Major Cooke »

Actually it's in Menudef. See the bottom of this code.

Code: Select all

ListMenu "PlayerMenu"
{
	StaticTextCentered 160, 6, "$MNU_PLAYERSETUP"
	Font "SmallFont"
	Linespacing 14
	Position 48, 36

	IfGame (Doom, Strife, Chex)
	{
		PlayerNameBox "$PLYRMNU_NAME", 0, "Playerbox"
		Selector "-", -16, -1
	}
	IfGame(Heretic, Hexen)
	{
		PlayerNameBox "$PLYRMNU_NAME", 5, "Playerbox"
		Selector "-", -16, 1
	}
	IfGame(Doom, Heretic, Strife, Chex)
	{
		MouseWindow 0, 220
		PlayerDisplay 220, 80, "20 00 00", "80 00 40", 1, "PlayerDisplay"
	}
	IfGame(Hexen)
	{
		MouseWindow 0, 220
		PlayerDisplay 220, 80, "00 07 00", "40 53 40", 1, "PlayerDisplay"
	}
	
	ValueText "$PLYRMNU_TEAM", "Team"
	ValueText "$PLYRMNU_PLAYERCOLOR", "Color"
	Linespacing 10
	Slider "$PLYRMNU_RED", "Red", 0, 255, 16
	Slider "$PLYRMNU_GREEN", "Green", 0, 255, 16
	Linespacing 14
	Slider "$PLYRMNU_BLUE", "Blue", 0, 255, 16
	ValueText "$PLYRMNU_PLAYERCLASS", "Class"
	ValueText "$PLYRMNU_PLAYERSKIN", "Skin"
	ValueText "$PLYRMNU_PLAYERGENDER", "Gender", "Gender"
	Slider "$PLYRMNU_AUTOAIM", "Autoaim", 0, 35, 1
	ValueText "$PLYRMNU_SWITCHONPICKUP", "Switch", "OffOn"
	ValueText "$PLYRMNU_ALWAYSRUN", "AlwaysRun", "OnOff"
	Class "PlayerMenu"
}
See this right here? Also included in the above code:

Code: Select all

	Class "PlayerMenu"
Because the "Class" word is used, it therefor becomes reserved. Thus, you can't replace it with that same name because it's already defined.
User avatar
AFADoomer
Posts: 1275
Joined: Tue Jul 15, 2003 4:18 pm

Re: How To: ZSCRIPT MENUS?

Post by AFADoomer »

Yes you can. That's exactly what I've already done with the Episode and Skill menus. You change Class to another value, and define that class in ZScript.

See MENUDEF in Blade of Agony.
Last edited by AFADoomer on Sun May 28, 2017 3:11 pm, edited 1 time in total.
User avatar
Major Cooke
Posts: 8095
Joined: Sun Jan 28, 2007 3:55 pm

Re: How To: ZSCRIPT MENUS?

Post by Major Cooke »

Check the menudef of gzdoom.pk3 again.

Code: Select all

ListMenu "SkillMenu"
{

	IfGame(Doom, Chex)
	{
		StaticPatch 96, 14, "M_NEWG"
	}
	IfGame(Strife)
	{
		StaticPatch 96, 14, "M_NGAME"
	}
	IfGame(Doom, Strife, Chex)
	{
		StaticPatch 54, 38, "M_SKILL"
		Position 48, 63
	}
	IfGame (Heretic)
	{
		Position 38, 30
	}
	IfGame (Hexen)
	{
		StaticText 74, 16, "$MNU_CHOOSESKILL"
		Position 160, 44
		centermenu
	}
}

Code: Select all

ListMenu "EpisodeMenu"
{
	IfGame(Doom, Heretic, Hexen, Strife)
	{
		NetgameMessage "$NEWGAME"
	}
	IfGame(Chex)
	{
		NetgameMessage "$CNEWGAME"
	}

	IfGame(Doom, Chex)
	{
		Position 48, 63
		StaticPatch 54, 38, "M_EPISOD"
	}
	IfGame(Strife)
	{
		Position 48, 63
		StaticText 54, 38, "$MNU_EPISODE"
	}
	IfGame(Heretic, Hexen)
	{
		Position 80, 50
	}
	// items will be filled in by MAPINFO
}
I clearly see no CLASS keyword being used in there. That's why you can replace them.
User avatar
AFADoomer
Posts: 1275
Joined: Tue Jul 15, 2003 4:18 pm

Re: How To: ZSCRIPT MENUS?

Post by AFADoomer »

Ah.

Damnit, you're right. Sorry.

So what is the difference between me adding a new Class there and replacing the old class for PlayerMenu with a class that inherits from PlayerMenu? Besides "the engine won't let you"? Shouldn't the inherited class have all of the same underlying code as the parent class? Is this actually something that should not be done, or a holdover from the old system where everything was in compiled code?
Last edited by AFADoomer on Sun May 28, 2017 3:17 pm, edited 1 time in total.

Return to “Scripting”