Sample: One Way Door Check

From SkyCorp Global
Note - this entity is a modification for The Underworld. Visit the new Mods Portal for more mods, mods on the wiki are no longer maintained. You can put it in-game by visiting the Debug Mod Control Panel in the debug rooms and browse to this mod or copy/paste the JSON below into the program window.

Entity Details

This entity demonstrates how you could prevent the player from moving based on custom LUA code. Here, we have a one-way door, which prevents the player from entering the building from the outside, but otherwise allows them to leave the building or move in any other direction.

It is implemented as an invisible object outside the building, which checks moves as the player moves them. If they attempt to move into the building, the move is rejected.

When testing this, add the JSON for both the door and the map, then teleport to the map using the newly created map teleport object.

Author: SkyCorp

Entity JSON Code

{
	"type": "ENTITY",
	"name":
	{
		"literalString": "One Way Door Check Example"
	},
	"id": "One Way Door Check Example",
	"isExaminable":
	{
		"literalBoolean": false
	},
	"playerAttemptLeaveRoom":
	{
		"programBoolean": true
	},
	"notifyPlayerEnterRoom":
	{
		"programVoid": true
	},
	"luac": "G0x1YVEAAQQEBAgAFQAAAEBvbmVXYXlEb29yQ2hlY2subHVhAAAAAAAAAAAAAAACAgUAAAAkAAAABwAAACRAAAAHQAAAHgCAAAIAAAAEFwAAAHBsYXllckF0dGVtcHRMZWF2ZVJvb20ABBYAAABub3RpZnlQbGF5ZXJFbnRlclJvb20AAgAAAAAAAAAEAAAAGAAAAAADAAYQAAAAFwDAABaAAoDFQAAAxoDAAQHBAABBAQEAFUEBAtxAAAHFQAAAxkDBAdxAgADCAAAA3gAAAcIAgADeAAABHgCAAAYAAAAECQAAAEJ1aWxkaW5nAAQLAAAATWFpblNjcmVlbgAEDAAAAGFkZEdhbWVUZXh0AAQaAAAAVGhlIGRvb3Igb24gdGhlIGJ1aWxkaW5nIAAEKQAAAGFwcGVhcnMgdG8gYmUgbG9ja2VkIGZyb20gdGhlIG91dHNpZGUuCgoABBgAAABjb250aW51ZVNjZW5lVG9NYXBTY2VuZQAAAAAAEAAAAAgAAAAIAAAACgAAAAoAAAAKAAAACwAAAAsAAAAKAAAAEgAAABIAAAASAAAAEwAAABMAAAAXAAAAFwAAABgAAAADAAAADAAAAGN1cnJlbnRSb29tAAAAAAAPAAAAEAAAAGRlc3RpbmF0aW9uUm9vbQAAAAAADwAAABIAAABkZXN0aW5hdGlvblJvb21JRAAAAAAADwAAAAAAAAAAAAAAGwAAAB8AAAAAAgAHCQAAAIUAAACGQEABwYAAAAABAABBwQAAgAGAANWAgQGcQAABHgCAAAQAAAAECwAAAE1haW5TY3JlZW4ABAwAAABhZGRHYW1lVGV4dAAEFgAAAFlvdSdyZSBlbnRlcmluZyBmcm9tIAAEEwAAAC4gIEl0cyByb29tIElEIGlzIAAAAAAACQAAABwAAAAcAAAAHAAAAB0AAAAdAAAAHgAAAB4AAAAcAAAAHwAAAAIAAAARAAAAYXJyaXZpbmdGcm9tUm9vbQAAAAAACAAAABMAAABhcnJpdmluZ0Zyb21Sb29tSUQAAAAAAAgAAAAAAAAABQAAABgAAAAEAAAAHwAAABsAAAAfAAAAAAAAAAAAAAA="
}

Map JSON Code

{
	"type": "MAP",
	"mapID": "Sample Map",
	"startingRoomID": 1,	
	"map": "77u/PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjx0cml6Ym9ydCB2ZXJzaW9uPSIxLjUuOS45Ij4NCgk8aW5mbyAvPg0KCTxtYXA+DQoJCTxyb29tIGlkPSIxIiBuYW1lPSJSb2Fkd2F5IiBzdWJ0aXRsZT0iIiB4PSItNjQiIHk9Ii0zMiIgdz0iOTYiIGg9IjY0IiByZWdpb249Ik5vUmVnaW9uIiBoYW5kRHJhd249InllcyIgYWxsY29ybmVyc2VxdWFsPSJ5ZXMiIGVsbGlwc2U9Im5vIiByb3VuZGVkQ29ybmVycz0ibm8iIG9jdGFnb25hbD0ibm8iIGNvcm5lclRvcExlZnQ9IjE1IiBjb3JuZXJUb3BSaWdodD0iMTUiIGNvcm5lckJvdHRvbUxlZnQ9IjE1IiBjb3JuZXJCb3R0b21SaWdodD0iMTUiIGJvcmRlcnN0eWxlPSJTb2xpZCIgZGVzY3JpcHRpb249IkJlIHN1cmUgdG8gbG9hZCB0aGUgT25lIFdheSBEb29yIEV4YW1wbGUgb2JqZWN0ICpiZWZvcmUqIHByb2NlZWRpbmcgbm9ydGghIiByb29tRmlsbD0iIiBzZWNvbmRGaWxsPSIiIHNlY29uZEZpbGxMb2NhdGlvbj0iQm90dG9tIiByb29tQm9yZGVyPSIiIHJvb21MYXJnZVRleHQ9IiIgcm9vbVNtYWxsVGV4dD0iIiAvPg0KCQk8cm9vbSBpZD0iMiIgbmFtZT0iUGFya2luZyBMb3QiIHN1YnRpdGxlPSIiIHg9Ii02NCIgeT0iLTE2MCIgdz0iOTYiIGg9IjY0IiByZWdpb249Ik5vUmVnaW9uIiBoYW5kRHJhd249InllcyIgYWxsY29ybmVyc2VxdWFsPSJ5ZXMiIGVsbGlwc2U9Im5vIiByb3VuZGVkQ29ybmVycz0ibm8iIG9jdGFnb25hbD0ibm8iIGNvcm5lclRvcExlZnQ9IjE1IiBjb3JuZXJUb3BSaWdodD0iMTUiIGNvcm5lckJvdHRvbUxlZnQ9IjE1IiBjb3JuZXJCb3R0b21SaWdodD0iMTUiIGJvcmRlcnN0eWxlPSJTb2xpZCIgZGVzY3JpcHRpb249IlRvIHRoZSBub3J0aCBpcyBhIGRvb3IgdGhhdCBpcyBsb2NrZWQgZnJvbSB0aGUgb3V0c2lkZS4gIEl0IGNhbiBvbmx5IGJlIG9wZW5lZCBmcm9tIHRoZSBpbnNpZGUuIiByb29tRmlsbD0iIiBzZWNvbmRGaWxsPSIiIHNlY29uZEZpbGxMb2NhdGlvbj0iQm90dG9tIiByb29tQm9yZGVyPSIiIHJvb21MYXJnZVRleHQ9IiIgcm9vbVNtYWxsVGV4dD0iIj4NCgkJCTxvYmplY3RzPk9uZSBXYXkgRG9vciBDaGVjayBFeGFtcGxlPC9vYmplY3RzPg0KCQk8L3Jvb20+DQoJCTxyb29tIGlkPSIzIiBuYW1lPSJCdWlsZGluZyIgc3VidGl0bGU9IiIgeD0iLTE5MiIgeT0iLTM4NCIgdz0iMzUyIiBoPSIxNjAiIHJlZ2lvbj0iTm9SZWdpb24iIGhhbmREcmF3bj0ieWVzIiBhbGxjb3JuZXJzZXF1YWw9InllcyIgZWxsaXBzZT0ibm8iIHJvdW5kZWRDb3JuZXJzPSJubyIgb2N0YWdvbmFsPSJubyIgY29ybmVyVG9wTGVmdD0iMTUiIGNvcm5lclRvcFJpZ2h0PSIxNSIgY29ybmVyQm90dG9tTGVmdD0iMTUiIGNvcm5lckJvdHRvbVJpZ2h0PSIxNSIgYm9yZGVyc3R5bGU9IlNvbGlkIiBkZXNjcmlwdGlvbj0iIiByb29tRmlsbD0iIiBzZWNvbmRGaWxsPSIiIHNlY29uZEZpbGxMb2NhdGlvbj0iQm90dG9tIiByb29tQm9yZGVyPSIiIHJvb21MYXJnZVRleHQ9IiIgcm9vbVNtYWxsVGV4dD0iIiAvPg0KCQk8cm9vbSBpZD0iNCIgbmFtZT0iR2FyYWdlIiBzdWJ0aXRsZT0iIiB4PSIxOTIiIHk9Ii0zODQiIHc9Ijk2IiBoPSIxNjAiIHJlZ2lvbj0iTm9SZWdpb24iIGhhbmREcmF3bj0ieWVzIiBhbGxjb3JuZXJzZXF1YWw9InllcyIgZWxsaXBzZT0ibm8iIHJvdW5kZWRDb3JuZXJzPSJubyIgb2N0YWdvbmFsPSJubyIgY29ybmVyVG9wTGVmdD0iMTUiIGNvcm5lclRvcFJpZ2h0PSIxNSIgY29ybmVyQm90dG9tTGVmdD0iMTUiIGNvcm5lckJvdHRvbVJpZ2h0PSIxNSIgYm9yZGVyc3R5bGU9IlNvbGlkIiBkZXNjcmlwdGlvbj0iVGhlIGdhcmFnZSBpcyBvcGVuLiIgcm9vbUZpbGw9IiIgc2Vjb25kRmlsbD0iIiBzZWNvbmRGaWxsTG9jYXRpb249IkJvdHRvbSIgcm9vbUJvcmRlcj0iIiByb29tTGFyZ2VUZXh0PSIiIHJvb21TbWFsbFRleHQ9IiIgLz4NCgkJPHJvb20gaWQ9IjUiIG5hbWU9IlBhcmtpbmcgTG90IEVhc3QiIHN1YnRpdGxlPSIiIHg9IjE5MiIgeT0iLTE2MCIgdz0iOTYiIGg9IjY0IiByZWdpb249Ik5vUmVnaW9uIiBoYW5kRHJhd249InllcyIgYWxsY29ybmVyc2VxdWFsPSJ5ZXMiIGVsbGlwc2U9Im5vIiByb3VuZGVkQ29ybmVycz0ibm8iIG9jdGFnb25hbD0ibm8iIGNvcm5lclRvcExlZnQ9IjE1IiBjb3JuZXJUb3BSaWdodD0iMTUiIGNvcm5lckJvdHRvbUxlZnQ9IjE1IiBjb3JuZXJCb3R0b21SaWdodD0iMTUiIGJvcmRlcnN0eWxlPSJTb2xpZCIgZGVzY3JpcHRpb249IiIgcm9vbUZpbGw9IiIgc2Vjb25kRmlsbD0iIiBzZWNvbmRGaWxsTG9jYXRpb249IkJvdHRvbSIgcm9vbUJvcmRlcj0iIiByb29tTGFyZ2VUZXh0PSIiIHJvb21TbWFsbFRleHQ9IiIgLz4NCgkJPGxpbmUgaWQ9IjYiIG5hbWU9IiIgZGVzY3JpcHRpb249IiI+DQoJCQk8ZG9jayBpbmRleD0iMCIgaWQ9IjEiIHBvcnQ9Im4iIC8+DQoJCQk8ZG9jayBpbmRleD0iMSIgaWQ9IjIiIHBvcnQ9InMiIC8+DQoJCTwvbGluZT4NCgkJPGxpbmUgaWQ9IjciIG5hbWU9IiIgZGVzY3JpcHRpb249IiI+DQoJCQk8ZG9jayBpbmRleD0iMCIgaWQ9IjIiIHBvcnQ9Im4iIC8+DQoJCQk8ZG9jayBpbmRleD0iMSIgaWQ9IjMiIHBvcnQ9InMiIC8+DQoJCTwvbGluZT4NCgkJPGxpbmUgaWQ9IjgiIG5hbWU9IiIgZGVzY3JpcHRpb249IiI+DQoJCQk8ZG9jayBpbmRleD0iMCIgaWQ9IjMiIHBvcnQ9ImUiIC8+DQoJCQk8ZG9jayBpbmRleD0iMSIgaWQ9IjQiIHBvcnQ9InciIC8+DQoJCTwvbGluZT4NCgkJPGxpbmUgaWQ9IjkiIG5hbWU9IiIgZGVzY3JpcHRpb249IiI+DQoJCQk8ZG9jayBpbmRleD0iMCIgaWQ9IjQiIHBvcnQ9InMiIC8+DQoJCQk8ZG9jayBpbmRleD0iMSIgaWQ9IjUiIHBvcnQ9Im4iIC8+DQoJCTwvbGluZT4NCgkJPGxpbmUgaWQ9IjEwIiBuYW1lPSIiIGRlc2NyaXB0aW9uPSIiPg0KCQkJPGRvY2sgaW5kZXg9IjAiIGlkPSIyIiBwb3J0PSJlIiAvPg0KCQkJPGRvY2sgaW5kZXg9IjEiIGlkPSI1IiBwb3J0PSJ3IiAvPg0KCQk8L2xpbmU+DQoJPC9tYXA+DQoJPHNldHRpbmdzPg0KCQk8Y29sb3JzPg0KCQkJPGNhbnZhcz5XaGl0ZTwvY2FudmFzPg0KCQkJPGJvcmRlcj5NaWRuaWdodEJsdWU8L2JvcmRlcj4NCgkJCTxsaW5lPk1pZG5pZ2h0Qmx1ZTwvbGluZT4NCgkJCTxzZWxlY3RlZExpbmU+R29sZDwvc2VsZWN0ZWRMaW5lPg0KCQkJPGhvdmVyTGluZT5EYXJrT3JhbmdlPC9ob3ZlckxpbmU+DQoJCQk8bGFyZ2VUZXh0Pk1pZG5pZ2h0Qmx1ZTwvbGFyZ2VUZXh0Pg0KCQkJPHNtYWxsVGV4dD5NaWRuaWdodEJsdWU8L3NtYWxsVGV4dD4NCgkJCTxsaW5lVGV4dD5NaWRuaWdodEJsdWU8L2xpbmVUZXh0Pg0KCQkJPGdyaWQ+I0Y1RjVGNTwvZ3JpZD4NCgkJCTxzdGFydFJvb20+R3JlZW5ZZWxsb3c8L3N0YXJ0Um9vbT4NCgkJCTxlbmRSb29tPlJlZDwvZW5kUm9vbT4NCgkJPC9jb2xvcnM+DQoJCTxyZWdpb25zPg0KCQkJPE5vUmVnaW9uIE5hbWU9Ik5vUmVnaW9uIiBUZXh0Q29sb3I9IkJsdWUiPldoaXRlPC9Ob1JlZ2lvbj4NCgkJPC9yZWdpb25zPg0KCQk8Zm9udHM+DQoJCQk8cm9vbSBzaXplPSIxMyI+QXJpYWw8L3Jvb20+DQoJCQk8b2JqZWN0IHNpemU9IjExIj5BcmlhbDwvb2JqZWN0Pg0KCQkJPGxpbmUgc2l6ZT0iOSI+QXJpYWw8L2xpbmU+DQoJCTwvZm9udHM+DQoJCTxncmlkPg0KCQkJPHNuYXBUbz55ZXM8L3NuYXBUbz4NCgkJCTx2aXNpYmxlPnllczwvdmlzaWJsZT4NCgkJCTxzaG93T3JpZ2luPnllczwvc2hvd09yaWdpbj4NCgkJCTxzaXplPjMyPC9zaXplPg0KCQk8L2dyaWQ+DQoJCTxsaW5lcz4NCgkJCTx3aWR0aD4yPC93aWR0aD4NCgkJCTxhcnJvd1NpemU+MTI8L2Fycm93U2l6ZT4NCgkJCTx0ZXh0T2Zmc2V0PjQ8L3RleHRPZmZzZXQ+DQoJCTwvbGluZXM+DQoJCTxyb29tcz4NCgkJCTxkYXJrbmVzc1N0cmlwZVNpemU+MjQ8L2RhcmtuZXNzU3RyaXBlU2l6ZT4NCgkJCTxvYmplY3RMaXN0T2Zmc2V0PjQ8L29iamVjdExpc3RPZmZzZXQ+DQoJCQk8Y29ubmVjdGlvblN0YWxrTGVuZ3RoPjMyPC9jb25uZWN0aW9uU3RhbGtMZW5ndGg+DQoJCQk8cHJlZmVycmVkRGlzdGFuY2VCZXR3ZWVuUm9vbXM+NjQ8L3ByZWZlcnJlZERpc3RhbmNlQmV0d2VlblJvb21zPg0KCQkJPGRlZmF1bHRSb29tTmFtZT5DYXZlPC9kZWZhdWx0Um9vbU5hbWU+DQoJCTwvcm9vbXM+DQoJCTx1aT4NCgkJCTxoYW5kbGVTaXplPjEyPC9oYW5kbGVTaXplPg0KCQkJPHNuYXBUb0VsZW1lbnRTaXplPjE2PC9zbmFwVG9FbGVtZW50U2l6ZT4NCgkJPC91aT4NCgkJPG1hcmdpbnM+DQoJCQk8ZG9jdW1lbnRTcGVjaWZpYz5ubzwvZG9jdW1lbnRTcGVjaWZpYz4NCgkJCTxob3Jpem9udGFsPjA8L2hvcml6b250YWw+DQoJCQk8dmVydGljYWw+MDwvdmVydGljYWw+DQoJCTwvbWFyZ2lucz4NCgkJPGtleXBhZE5hdmlnYXRpb24+DQoJCQk8Y3JlYXRpb25Nb2RpZmllcj5jb250cm9sPC9jcmVhdGlvbk1vZGlmaWVyPg0KCQkJPHVuZXhwbG9yZWRNb2RpZmllcj5hbHQ8L3VuZXhwbG9yZWRNb2RpZmllcj4NCgkJPC9rZXlwYWROYXZpZ2F0aW9uPg0KCTwvc2V0dGluZ3M+DQo8L3RyaXpib3J0Pg=="
}

LUA Source Code

-- Called on all entities in the room that the player is leaving.
-- If any return false, the movement is denied.  A message should
-- be shown to the player explaining why the movement was denied.
function playerAttemptLeaveRoom(currentRoom, destinationRoom, 
	destinationRoomID)
	
	-- Check name of destination room.  (Could also check ID)
	if destinationRoom == "Building" then
		-- Display to the player why they can't continue
		MainScreen.addGameText("The door on the building " ..
				"appears to be locked from the outside.\n\n");
		
		-- This is absolutely essential or you will soft lock the
		-- game!  By default, no buttons are displayed, and this
		-- simply puts a 'continue' button that allows the player
		-- to read the text, and then continue back to the 
		-- main navigation of gameplay.
		MainScreen.continueSceneToMapScene();
		return false;
	end
	
	-- Player is allowed to go back south or east
	return true;	
end

-- Called when player enters same room as this entity.
function notifyPlayerEnterRoom(arrivingFromRoom, arrivingFromRoomID)
	MainScreen.addGameText("You're entering from " .. 
			arrivingFromRoom .. ".  Its room ID is " ..
			arrivingFromRoomID);
end

Map Source Code

<?xml version="1.0" encoding="utf-8"?>
<trizbort version="1.5.9.9">
	<info />
	<map>
		<room id="1" name="Roadway" subtitle="" x="-64" y="-32" w="96" h="64" region="NoRegion" handDrawn="yes" allcornersequal="yes" ellipse="no" roundedCorners="no" octagonal="no" cornerTopLeft="15" cornerTopRight="15" cornerBottomLeft="15" cornerBottomRight="15" borderstyle="Solid" description="Be sure to load the One Way Door Example object *before* proceeding north!" roomFill="" secondFill="" secondFillLocation="Bottom" roomBorder="" roomLargeText="" roomSmallText="" />
		<room id="2" name="Parking Lot" subtitle="" x="-64" y="-160" w="96" h="64" region="NoRegion" handDrawn="yes" allcornersequal="yes" ellipse="no" roundedCorners="no" octagonal="no" cornerTopLeft="15" cornerTopRight="15" cornerBottomLeft="15" cornerBottomRight="15" borderstyle="Solid" description="To the north is a door that is locked from the outside.  It can only be opened from the inside." roomFill="" secondFill="" secondFillLocation="Bottom" roomBorder="" roomLargeText="" roomSmallText="">
			<objects>One Way Door Check Example</objects>
		</room>
		<room id="3" name="Building" subtitle="" x="-192" y="-384" w="352" h="160" region="NoRegion" handDrawn="yes" allcornersequal="yes" ellipse="no" roundedCorners="no" octagonal="no" cornerTopLeft="15" cornerTopRight="15" cornerBottomLeft="15" cornerBottomRight="15" borderstyle="Solid" description="" roomFill="" secondFill="" secondFillLocation="Bottom" roomBorder="" roomLargeText="" roomSmallText="" />
		<room id="4" name="Garage" subtitle="" x="192" y="-384" w="96" h="160" region="NoRegion" handDrawn="yes" allcornersequal="yes" ellipse="no" roundedCorners="no" octagonal="no" cornerTopLeft="15" cornerTopRight="15" cornerBottomLeft="15" cornerBottomRight="15" borderstyle="Solid" description="The garage is open." roomFill="" secondFill="" secondFillLocation="Bottom" roomBorder="" roomLargeText="" roomSmallText="" />
		<room id="5" name="Parking Lot East" subtitle="" x="192" y="-160" w="96" h="64" region="NoRegion" handDrawn="yes" allcornersequal="yes" ellipse="no" roundedCorners="no" octagonal="no" cornerTopLeft="15" cornerTopRight="15" cornerBottomLeft="15" cornerBottomRight="15" borderstyle="Solid" description="" roomFill="" secondFill="" secondFillLocation="Bottom" roomBorder="" roomLargeText="" roomSmallText="" />
		<line id="6" name="" description="">
			<dock index="0" id="1" port="n" />
			<dock index="1" id="2" port="s" />
		</line>
		<line id="7" name="" description="">
			<dock index="0" id="2" port="n" />
			<dock index="1" id="3" port="s" />
		</line>
		<line id="8" name="" description="">
			<dock index="0" id="3" port="e" />
			<dock index="1" id="4" port="w" />
		</line>
		<line id="9" name="" description="">
			<dock index="0" id="4" port="s" />
			<dock index="1" id="5" port="n" />
		</line>
		<line id="10" name="" description="">
			<dock index="0" id="2" port="e" />
			<dock index="1" id="5" port="w" />
		</line>
	</map>
	<settings>
		<colors>
			<canvas>White</canvas>
			<border>MidnightBlue</border>
			<line>MidnightBlue</line>
			<selectedLine>Gold</selectedLine>
			<hoverLine>DarkOrange</hoverLine>
			<largeText>MidnightBlue</largeText>
			<smallText>MidnightBlue</smallText>
			<lineText>MidnightBlue</lineText>
			<grid>#F5F5F5</grid>
			<startRoom>GreenYellow</startRoom>
			<endRoom>Red</endRoom>
		</colors>
		<regions>
			<NoRegion Name="NoRegion" TextColor="Blue">White</NoRegion>
		</regions>
		<fonts>
			<room size="13">Arial</room>
			<object size="11">Arial</object>
			<line size="9">Arial</line>
		</fonts>
		<grid>
			<snapTo>yes</snapTo>
			<visible>yes</visible>
			<showOrigin>yes</showOrigin>
			<size>32</size>
		</grid>
		<lines>
			<width>2</width>
			<arrowSize>12</arrowSize>
			<textOffset>4</textOffset>
		</lines>
		<rooms>
			<darknessStripeSize>24</darknessStripeSize>
			<objectListOffset>4</objectListOffset>
			<connectionStalkLength>32</connectionStalkLength>
			<preferredDistanceBetweenRooms>64</preferredDistanceBetweenRooms>
			<defaultRoomName>Cave</defaultRoomName>
		</rooms>
		<ui>
			<handleSize>12</handleSize>
			<snapToElementSize>16</snapToElementSize>
		</ui>
		<margins>
			<documentSpecific>no</documentSpecific>
			<horizontal>0</horizontal>
			<vertical>0</vertical>
		</margins>
		<keypadNavigation>
			<creationModifier>control</creationModifier>
			<unexploredModifier>alt</unexploredModifier>
		</keypadNavigation>
	</settings>
</trizbort>