The other day, I mentioned the inability to right-click in a Quest game, and Pertex pointed out the bit of code to change that.
A few minutes later, he said we should make a custom contextmenu with Quest commands. So, we did.
Davy B tested it out and found erratic behavior across various mobile browsers; hence the code in game.inituserinterface
that disables the game if it detects a mobile browser (this bit of code is new and has not yet been tested by Davy B).
NOTE: There is a time lapse between JS and Quest when determining which browser is running the game using JS.whereAmI()
. It seems to be anywhere between 500ms and 2 seconds.
Here's what Davy B recently noted concerning this:
What I seem to conclude is that when playing on a mobile device (i) there has to be a time gap between executing the command and checking the results and (ii) using the command in the initialisation of the userinterface doesn't work at all? So what I'm doing is issuing the command on entry to the first room for the first time and issuing a warning about the limitations of mobile use after the player has interacted with the game.
https://play.textadventures.co.uk/Play.aspx?id=editor/2db0cef6-7a0e-4e16-8d7b-dfb91ffb8d64%2fCustom+ContextmenuTester+-+Online+Editor+Edition.aslx
In this test game, I am not using JS.whereAmI()
at all. I'm directly checking the platform in JS.
I can only test the part concerning the mobile player on Android, and things seem to usually work a little differently in Safari.
I'm also sure there is room for improvement. Any comments or suggestions are much appreciated in advance!
<!--Saved by Quest 5.8.7753.35184-->
<asl version="580">
<include ref="English.aslx" />
<include ref="Core.aslx" />
<game name="Custom ContextmenuTester - Online Editor Edition">
<gameid>c50900c0-cd8e-49f4-9fc8-8a2ce95d707d</gameid>
<version>1.0.1</version>
<firstpublished>2024</firstpublished>
<subtitle>v{game.version}</subtitle>
<author>KV and Pertex (with help from Davy B)</author>
<description><![CDATA[This is only a test game.<br/><br/>You can right-click for a custom menu.<br/><br/>---<br/><br/>This feature was created by Pertex.]]></description>
<inituserinterface type="script"><![CDATA[
// First, let's (try to) disable the game if a mobile browser is detected
lt = Chr(60)
br = lt + "br/>"
textadventures = lt + "a href=\"https://textadventures.co.uk\">textadventures.co.uk" + lt + "/a>"
JS.eval ("if (isMobilePlayer()){$('#gameContent').hide(); document.writeln('This game is not available to play on mobile browsers." + br + br +"Return to " + textadventures + ".');}else{console.log('All is well! No mobile browser detected.');}")
//
// ---
// This is the list of options that will appear when the player right-clicks (or long-click if on mobile)
game.contextmenucommands = "look,save,help,inventory,clear the screen,test"
// This will change the menu options on the fly if game.contextmenucommands is altered during play
game.changedcontextmenucommands => {
CreateCustomContextmenu (game.contextmenucommands)
}
// This creates the menu using the stringlist attribute game.contextmenucommands
CreateCustomContextmenu (game.contextmenucommands)
]]></inituserinterface>
</game>
<command name="clearscreen_cmd">
<pattern>clear;clear screen;clear the screen</pattern>
<script>
JS.clearScreen ()
</script>
</command>
<object name="room">
<inherit name="editor_room" />
<isroom />
<object name="player">
<inherit name="editor_object" />
<inherit name="editor_player" />
</object>
</object>
<command name="test_cmd">
<pattern>test</pattern>
<script>
if (not GetBoolean(test_cmd, "done")) {
msg ("{color:green:SUCCESS}")
game.contextmenucommands = "jump,Z,XYZZY,quit,HELP"
test_cmd.done = true
}
else {
msg ("This test has already been completed.")
}
</script>
</command>
<function name="CreateCustomContextmenu" parameters="data"><![CDATA[
// For the parameter, you can use:
// - a string like this: "look/wait/help" or "look,wait,help" or "look;wait;help"
// - a string list
// - a string dictionary, which allows you to choose the text displayed for each command, like: QuickParams("look", "Look", "wait", "Take a break", "help", "HELP ME!") or the normal way to create a string dictionary -- the key is the command sent and the value is the text displayed for that command in the contextmenu
lt = Chr(60)
JS.eval ("$('#custom-contextmenu').remove(); function createCustomContextmenu(menu){overrideContextMenuClick = function(e) { if (!e) e = window.event; if (e.type && e.type == 'contextmenu') { $('div.jjmenu').hide(); if($('#gamePanesFinished').css('display') != 'block'){ customContextMenu(e);} else { return false; } } else if ((e.button && e.button == 2) || (e.which && e.which == 3)) { return false; } else { return true; }};window.document.oncontextmenu = overrideContextMenuClick; $('body').append($(menu)); var customContextMenu = function(e){ $('#custom-contextmenu').show().css('left',e.x).css('top',e.y); e.preventDefault(); return true;}; document.onclick = function(){ $('#custom-contextmenu').hide(); };}")
menu = lt + "div id=\"custom-contextmenu\" class=\"jjmenu bottomOriented\" style=\"display:none; cursor:pointer; position:fixed;\">" + lt + "span>" + lt + "!--PLACEHOLDER-->" + lt + "/span>" + lt + "/div>"
options = NewStringDictionary()
if (TypeOf(data) = "stringdictionary" or TypeOf(data) = "dictionary") {
foreach (k, data) {
DictionaryAdd (options, Replace(k, " ", "___SPACE___"), DictionaryItem(data,k))
}
}
else if (TypeOf(data) = "string") {
delimiters = Split("/_,_;","_")
delimiter = ","
foreach (d, delimiters) {
if (Instr(data, d) > 0) {
delimiter = d
}
}
cmds = Split(data, delimiter)
foreach (cmd, cmds) {
dictionary add (options, Replace(cmd, " ", "___SPACE___"), CapFirst(cmd))
}
}
else if (TypeOf(data) = "stringlist") {
foreach (cmd, data) {
dictionary add (options, Replace(cmd, " ", "___SPACE___"), CapFirst(cmd))
}
}
else {
CreateCustomContextmenu (game.contextmenucommands)
return ("start over and use default")
}
menuitems = NewStringList()
foreach (option, options) {
cmd = option
displayed_text = DictionaryItem(options, option)
menuitem = lt + "div class=\"jj_menu_item\" onmouseover=\"$(this).addClass("jj_menu_item_hover");\" onmouseout=\"$(this).removeClass("jj_menu_item_hover")\">" + lt + "span name=\"" + cmd + "\" onclick=\"$("#custom-contextmenu").hide(); $('#txtCommand').val($(this).attr("name").replace(/___SPACE___/g," ")); runCommand()\">" + displayed_text + lt + "/span>" + lt + "/div>"
list add (menuitems, menuitem)
}
custom_context_menu = Replace (menu, lt + "!--PLACEHOLDER-->", Join(menuitems, ""))
JS.createCustomContextmenu (custom_context_menu)
]]></function>
</asl>
PS
These scripts are web editor friendly thanks to Davy B.