[ZSCRIPT, ZFORMS] Polyobject Locked Door Menu

Post your example zscripts/ACS scripts/etc here.
Forum rules
The Projects forums are only for projects. If you are asking questions about a project, either find that project's thread, or start a thread in the General section instead.

Got a cool project idea but nothing else? Put it in the project ideas thread instead!

Projects for any Doom-based engine (especially 3DGE) are perfectly acceptable here too.

Please read the full rules for more details.
User avatar
ramon.dexter
Posts: 1562
Joined: Tue Oct 20, 2015 12:50 pm
Graphics Processor: nVidia with Vulkan support
Location: Kozolupy, Bohemia

[ZSCRIPT, ZFORMS] Polyobject Locked Door Menu

Post by ramon.dexter »

Finally, with help of Gutawer nad Agent_Ash, I finally created a zforms zscript menu that allows player to easily create and control (polyobject) locked door menu. The menu has three buttons - unlock, break and exit. Unlock button calls the script to unlock the door, break button calls the script to break the door (basically the same action as break, but uses different condition) and exit closes the menu. The menu can be also closed by escape key. Menu is mouse controlled, only yet. The Menu can read arguments defined udb linedef special, when setting up acs call on linedef. This part was especially hard to make, as passing data to menus is not an easy task.

Prerequisities:
- your own zforms build
- your own menu background & button graphics ... maybe I'll make a proper pk3 containing some graphics ...

Usage:
Place the ACS scripts into the map's scripts.
The universalPolyDoor and universalPolyDoorBase are my main polydoor control scripts. You can freely use them, as the require only three arguments - poly is polyobject nukmber, right1left2 is to control swing direction and speed ...well..controls opening speed. It's nice addition.

To use the locked door menu, just call the "menu_lockedDoor" (int poly, int right1left2, int stats) from the door or polyobject door, just the speed argument is changed to stats argument, which is used as condition to unlock the door. You can set-up your own arguments to open the door, I'm, using just built-in strife stats, which perfectly fit my needs.

Code:

Code: Select all

////////////////////////////////////////////////////////////////////////////////
// zscript locked door menu ////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// credits: Agent_Ash, Gutawer, ramon.dexter
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// ZSCRIPT /////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

// menu code ///////////////////////////////////////////////////////////////////
class DoorController play {
	int playerNumber;
	int poly;
	int right1left2;
	int stats;
	
	static void OpenDoorMenu(Actor activator, int poly, int right1left2, int stats) {
		if (activator.player && activator.player == players[consoleplayer]) {
			let handler = argentEventHandler(EventHandler.Find("argentEventHandler"));
			if (handler) {
				let dc = New('DoorController');
				dc.playerNumber = activator.PlayerNumber();
				dc.poly = poly;
				dc.right1left2 = right1left2;
				dc.stats = stats;
				// store a pointer to an instane of this in an event handler:
				handler.d_controllers[dc.playerNumber] = dc;
				Menu.SetMenu("lockedDoorMenu");
			}
		}
	}
}
class lockedDoorHandler : soa_ZF_Handler {
	lockedDoorMenu menu;

	override void buttonClickCommand(soa_ZF_Button caller, string command) {
		if ( command == "cmd_ld_odemknout" ) {
			//Console.Printf("cmd: odemknout");
			// do things ///////////////////////////////////////////////////////
			let lockedhandler = argentEventHandler(EventHandler.Find("argentEventHandler"));
			let dc = lockedhandler.d_controllers[consoleplayer];
			argentEventHandler.SendNetworkEvent("unlockDoor", dc.poly, dc.right1left2, dc.stats);
			////////////////////////////////////////////////////////////////////
			// close menu //////////////////////////////////////////////////////
			let curmenu = Menu.GetCurrentMenu();
			if (curmenu != null) curmenu.Close();
			// close menu //////////////////////////////////////////////////////
		} else if ( command == "cmd_ld_vypacit" ) {
			//Console.Printf("cmd: vypacit");
			// do things ///////////////////////////////////////////////////////
			let lockedhandler = argentEventHandler(EventHandler.Find("argentEventHandler"));
			let dc = lockedhandler.d_controllers[consoleplayer];
			argentEventHandler.SendNetworkEvent("breakDoor", dc.poly, dc.right1left2, dc.stats);
			////////////////////////////////////////////////////////////////////
			// close menu //////////////////////////////////////////////////////
			let curmenu = Menu.GetCurrentMenu();
			if (curmenu != null) curmenu.Close();
			// close menu //////////////////////////////////////////////////////
		} else if ( command == "cmd_ld_exit" ) {
			//Console.Printf("cmd: exit");
			// close menu //////////////////////////////////////////////////////
			let curmenu = Menu.GetCurrentMenu();
			if (curmenu != null) curmenu.Close();
			// close menu //////////////////////////////////////////////////////
		}
	}
}
class lockedDoorMenu : soa_ZF_GenericMenu {
	lockedDoorHandler handler;
	DoorController d_controller;
	// vars definition /////////////////////////////////////////////////////////
	font smallfont;
	soa_ZF_Image img_background;
	soa_ZF_Label ldm_lbl_title;
	soa_ZF_Label ldm_lbl_odemknout;
	soa_ZF_Label ldm_lbl_vypacit;
	soa_ZF_Label ldm_lbl_exit;
	soa_ZF_Button ldm_btn_odemknout;
	soa_ZF_Button ldm_btn_vypacit;
	soa_ZF_Button ldm_btn_exit;
	////////////////////////////////////////////////////////////////////////////

	override void Init(menu parent) {

		////////////////////////////////////////////////////////////////////////
		// overall init ////////////////////////////////////////////////////////
		////////////////////////////////////////////////////////////////////////
		Vector2 baseRes = (320, 200); //set base resolution to work with
		Super.Init(parent); // Call GenericMenu's 'Init' function to do some required initialization.
		// doorcontroller //////////////////////////////////////////////////////
		let lockedhandler = argentEventHandler(EventHandler.Find("argentEventHandler"));
		if (lockedhandler)
		{
			let dc = lockedhandler.d_controllers[consoleplayer];
			if (dc)
			{
				d_controller = dc;
			}
		}
		////////////////////////////////////////////////////////////////////////
		SetBaseResolution(baseRes);
		smallfont = "smallfont";
		handler = new("lockedDoorHandler"); // Create an instance of the handler.
		handler.menu = self; // Set the handler's "link" pointer to us.
		////////////////////////////////////////////////////////////////////////

		// play sound on menu open /////////////////////////////////////////////
		Menu.MenuSound("sounds/journalUse");
		////////////////////////////////////////////////////////////////////////

		////////////////////////////////////////////////////////////////////////
		// create background ///////////////////////////////////////////////////
		////////////////////////////////////////////////////////////////////////
		img_background = soa_ZF_Image.Create ( // Add a background.
			(0, 0),//position
			(320, 200), //size
			"graphics/soaMenu/menuBack2.png",//image path/name
			soa_ZF_Image.AlignType_TopLeft
		);
		img_background.Pack(mainFrame); // Add the image element into the main frame.
		////////////////////////////////////////////////////////////////////////

		////////////////////////////////////////////////////////////////////////
		// add buttons /////////////////////////////////////////////////////////
		////////////////////////////////////////////////////////////////////////
		
		// create the button's textures ////////////////////////////////////////
		let smallbuttonIdle = soa_ZF_BoxTextures.CreateSingleTexture("graphics/soaMenu/smallButtonIdle.png", true);
		let smallbuttonHover = soa_ZF_BoxTextures.CreateSingleTexture("graphics/soaMenu/smallButtonHover.png", false);
		let smallbuttonClick = soa_ZF_BoxTextures.CreateSingleTexture("graphics/soaMenu/smallButtonClick.png", false);

		// odemknout ///////////////////////////////////////////////////////////
		ldm_btn_odemknout = soa_ZF_Button.Create(
			(((baseRes.X - 32.0) / 2.0) - 40, ((baseRes.Y - 16.0) / 2.0) + 0),//position
			(9, 9), //size
			cmdHandler : handler, //command handler
			command : "cmd_ld_odemknout", //command string for button
			inactive: smallbuttonIdle,
			hover: smallbuttonHover,
			click: smallbuttonClick
		);
		ldm_btn_odemknout.pack(mainframe);

		// vypacit /////////////////////////////////////////////////////////////
		ldm_btn_vypacit = soa_ZF_Button.Create(
			(((baseRes.X - 32.0) / 2.0) - 40, ((baseRes.Y - 16.0) / 2.0) + 15),//position
			(9, 9), //size
			cmdHandler : handler, //command handler
			command : "cmd_ld_vypacit", //command string for button
			inactive: smallbuttonIdle,
			hover: smallbuttonHover,
			click: smallbuttonClick
		);
		ldm_btn_vypacit.pack(mainframe);

		// exit ////////////////////////////////////////////////////////////////
		ldm_btn_exit = soa_ZF_Button.Create(
			(((baseRes.X - 32.0) / 2.0) - 40, ((baseRes.Y - 16.0) / 2.0) + 30),//position
			(9, 9), //size
			cmdHandler : handler, //command handler
			command : "cmd_ld_exit", //command string for button
			inactive: smallbuttonIdle,
			hover: smallbuttonHover,
			click: smallbuttonClick
		);
		ldm_btn_exit.pack(mainframe);
		////////////////////////////////////////////////////////////////////////

		////////////////////////////////////////////////////////////////////////
		// ADD LABELS //////////////////////////////////////////////////////////
		////////////////////////////////////////////////////////////////////////

		// title ///////////////////////////////////////////////////////////////
		ldm_lbl_title = soa_ZF_Label.Create(
			(0, ldm_btn_odemknout.GetPosY() + ldm_btn_odemknout.GetHeight() - 30),
			(0, smallFont.GetHeight()),
			text: "$M_lockeddoorMenu_title", //label's text: [ Bedroll Menu ]
			fnt: smallfont, //font !string! to use > if 'null', uses default smallfont
			wrap: false, //auto text wrap
			autoSize: true, //auto resize elements
			textColor: Font.CR_FIRE //text color
		);
		//soaLabel_nadpis.SetPosX(baseRes.X - smallFont.stringWidth (soaLabel_nadpis.GetText ()) / 2.0);
		ldm_lbl_title.SetPosX((baseRes.X / 2.0) - (smallFont.stringWidth(ldm_lbl_title.GetText ()) / 2.0));
		ldm_lbl_title.Pack(mainFrame); //add element to mainframe

		// odemknout ///////////////////////////////////////////////////////////
		ldm_lbl_odemknout = soa_ZF_Label.Create(
			(0, ldm_btn_odemknout.GetPosY() + ldm_btn_odemknout.GetHeight() - 10),
			(0, smallFont.GetHeight()),
			text: "$M_lockeddoorMenu_btn_odemknout", //label's text: [ Bedroll Menu ]
			fnt: smallfont, //font !string! to use > if 'null', uses default smallfont
			wrap: false, //auto text wrap
			autoSize: true, //auto resize elements
			textColor: Font.CR_FIRE //text color
		);
		ldm_lbl_odemknout.SetPosX((baseRes.X / 2.0) - (smallFont.stringWidth(ldm_lbl_odemknout.GetText ()) / 2.0));
		ldm_lbl_odemknout.Pack(mainFrame); //add element to mainframe
		// vypacit /////////////////////////////////////////////////////////////
		ldm_lbl_vypacit = soa_ZF_Label.Create(
			(0, ldm_btn_vypacit.GetPosY() + ldm_btn_vypacit.GetHeight() - 10),
			(0, smallFont.GetHeight()),
			text: "$M_lockeddoorMenu_btn_vypacit", //label's text: [ Bedroll Menu ]
			fnt: smallfont, //font !string! to use > if 'null', uses default smallfont
			wrap: false, //auto text wrap
			autoSize: true, //auto resize elements
			textColor: Font.CR_FIRE //text color
		);
		ldm_lbl_vypacit.SetPosX((baseRes.X / 2.0) - (smallFont.stringWidth(ldm_lbl_vypacit.GetText ()) / 2.0));
		ldm_lbl_vypacit.Pack(mainFrame); //add element to mainframe
		// exit ////////////////////////////////////////////////////////////////
		ldm_lbl_exit = soa_ZF_Label.Create(
			(0, ldm_btn_exit.GetPosY() + ldm_btn_exit.GetHeight() - 10),
			(0, smallFont.GetHeight()),
			text: "$M_lockeddoorMenu_btn_exit", //label's text: [ Bedroll Menu ]
			fnt: smallfont, //font !string! to use > if 'null', uses default smallfont
			wrap: false, //auto text wrap
			autoSize: true, //auto resize elements
			textColor: Font.CR_FIRE //text color
		);
		ldm_lbl_exit.SetPosX((baseRes.X / 2.0) - (smallFont.stringWidth(ldm_lbl_exit.GetText ()) / 2.0));
		ldm_lbl_exit.Pack(mainFrame); //add element to mainframe
	}
}
////////////////////////////////////////////////////////////////////////////////

// eventhandler ////////////////////////////////////////////////////////////////
class lockedDoorEventHandler : EventHandler {
    DoorController d_controllers[MAXPLAYERS];
    override void NetworkProcess(ConsoleEvent e) {
        let pawn = <YourPlayerClass>(players[e.Player].mo);
        if ( e.Name ~== "unlockDoor" ) {
			let dc = d_controllers[e.Player];
			if (dc) {
				// dc.tag is now your door tag
				pawn.ACS_NamedExecuteAlways("unlockDoor", 0, dc.poly, dc.right1left2, dc.stats);
			}
		} else if ( e.Name ~== "breakDoor" ) {
			let dc = d_controllers[e.Player];
			if (dc) {
				// dc.tag is now your door tag
				pawn.ACS_NamedExecuteAlways("breakDoor", 0, dc.poly, dc.right1left2, dc.stats);
			}
		}
    }
}
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// ACS /////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// polyobject door control scripts /////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
#define MAX_SWINGING_DOORS 1000
bool polyDoor[MAX_SWINGING_DOORS]; //'dynamic' variable = array
////////////////////////////////////////////////////////////////////////////////

// newest iteration, universal script for right/left opened doors //////////////
script "universalPolyDoorBase" (int poly, int spd, int right1Left2) {
	if ( right1Left2 == 1 ) { //right
		if ( !polyDoor[poly] ) {
			Polyobj_RotateRight(poly, spd, 64);
			if(spd  < 16) {
				AmbientSound("sounds/DoorCreak", 127);
			}
			else if(spd >= 16) {
				AmbientSound("sounds/officeDopen", 127);
			}
			PolyWait(poly);
			polyDoor[poly] = true;
		} else if ( polyDoor[poly] ) {
			Polyobj_RotateLeft(poly, spd, 64);
			if(spd  < 16) {
				AmbientSound("sounds/DoorCreak", 127);
			}
			else if(spd >= 16) {
				AmbientSound("sounds/officeDclose", 127);
			}
			PolyWait(poly);
			polyDoor[poly] = false;
		}
	} else if ( right1Left2 == 2 ) { //left
		if ( !polyDoor[poly] ) {
			Polyobj_RotateLeft(poly, spd, 64);
			if(spd  < 16) {
				AmbientSound("sounds/DoorCreak", 127);
			}
			else if(spd >= 16) {
				AmbientSound("sounds/officeDopen", 127);
			}
			PolyWait(poly);
			polyDoor[poly] = true;
		} else if ( polyDoor[poly] ) {
			Polyobj_RotateRight(poly, spd, 64);
			if(spd  < 16) {
				AmbientSound("sounds/DoorCreak", 127);
			}
			else if(spd >= 16) {
				AmbientSound("sounds/officeDclose", 127);
			}
			PolyWait(poly);
			polyDoor[poly] = false;
		}
	}
}
// to make it behave as a built in function > run the script in separate VM ////
script "universalPolyDoor" (int poly, int spd, int right1Left2) {
	ACS_NamedExecuteAlways("universalPolyDoorBase", 0, poly, spd, right1Left2);
}
/////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// zscript locked door menu ////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
#define MAX_LOCKEDDOORS 1000
bool lockedDoor[MAX_LOCKEDDOORS];
script "menu_lockedDoor" (int poly, int right1left2, int stats) {
	if ( !lockedDoor[poly] ) {
		ScriptCall("DoorController", "OpenDoorMenu", poly, right1left2, stats);
	} else {
		ACS_NamedExecute("universalPolyDoor", 0, poly, 16, right1left2);
	}
}
script "unlockDoor" (int poly, int right1left2, int stats) {
	if ( !lockedDoor[poly] ) {
        // here the condition should be ANYTHING, I'm using player's strife stats here, as they're built-in (==lazy)
		int playerAccuracy = ScriptCall("wielder", "getplayerAccuracy");
		int desiredAccuracy = stats*10;
		if ( playerAccuracy >= desiredAccuracy ) {
			Log(l:"$TXT_unlockeddoor");
			ACS_NamedExecute("universalPolyDoor", 0, poly, 16, right1left2);
			lockedDoor[poly] = true;
		} else {
			Log(l:"TXT_required", i:desiredAccuracy, l:"TXT_accuracy2unlock");
		}
	} else {
		ACS_NamedExecute("universalPolyDoor", 0, poly, 16, right1left2);
	}

}
script "breakDoor" (int poly, int right1left2, int stats) {
	if ( !lockedDoor[poly] ) {
        // here the condition should be ANYTHING, I'm using player's strife stats here, as they're built-in (==lazy)
		int playerStamina = ScriptCall("wielder", "getplayerStamina");
		int desiredStamina = stats*10;
		if ( playerStamina >= desiredStamina ) {
			Log(l:"$TXT_brokendoor");
			ACS_NamedExecute("universalPolyDoor", 0, poly, 16, right1left2);
			lockedDoor[poly] = true;
		} else {
			Log(l:"TXT_required", i:desiredStamina, l:"TXT_stamina2unlock");
		}
	} else {
		ACS_NamedExecute("universalPolyDoor", 0, poly, 16, right1left2);
	}
}
////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

Return to “Script Library”