Question about custom command pane
Skarnisk
25 Mar 2018, 08:11I added a custom command pane to my game interface and populated it with JS.SetCommands
; now I'd want it to have 2 behaviours:
a) It should pass everything I click to a function that will handle it instead of taking it as a direct command;
b) Commands should be enabled or disabled according to the situation: e. g., if there is nothing that can be opened "Open" should be disabled.
How could I make the custom command pane do so?
Thanks.

CheeseMyBaby
25 Mar 2018, 13:57Cool thing. I have absolutely no idea how, or even if, it's possible but I'll sure be popping in here every now and then to see if someone has answered!
mrangel
25 Mar 2018, 14:24a) It should pass everything I click to a function that will handle it instead of taking it as a direct command;
As far as I know, that's not what the custom command pane is for. I suspect that creating your own custom pane will be easier than modifying one of the built-in ones to behave in a completely different way.
I can see ways to do it, but that would be a pretty big modification.
Skarnisk
25 Mar 2018, 15:40As far as I know, that's not what the custom command pane is for. I suspect that creating your own custom pane will be easier than modifying one of the built-in ones to behave in a completely different way.
Humpf - I should have known that. Well, I found this tutorial by The Pixie about creating a custom button pane. Using the custom command pane provided by Quest would have required less fiddling with CSS and HTML, but I'll take it as it comes. So, after creating a custom button pane as shown in the tutorial, how can I disable or enable selectively its buttons?

K.V.
25 Mar 2018, 16:32I can show how to modify which commands are displayed in the Commands pane during play.
Why do you want it to behave differently when clicking a command from that pane?
Skarnisk
25 Mar 2018, 16:44I'm trying to build an interface like the SCUMM that was used in old LucasArts' adventures, where disabled commands appeared grayed out. I'm just wondering if Quest could give me the same look & feel.

K.V.
25 Mar 2018, 17:03In this example game, the JUMP command only shows up in the pane when you are in the second room.
You control what is displayed in the commands pane in this example my modifying the string attribute: game.pane_commands
.
I added the functions to make it easier while scripting. I try to do any complicated coding in functions, that way everything else is a breeze.
There are numerous ways to do this, too. This seemed to be the easiest overall.
<!--Saved by Quest 5.7.6606.27193-->
<asl version="550">
<include ref="English.aslx" />
<include ref="Core.aslx" />
<game name="Command Pane">
<gameid>17f0e962-ffb7-4afa-9206-6258b00ef646</gameid>
<version>1.0</version>
<firstpublished>2018</firstpublished>
<feature_advancedscripts />
<commandpane />
<start type="script">
</start>
<inituserinterface type="script">
if (not HasAttribute(game,"pane_commands")) {
game.pane_commands = "Look;Wait;Jump"
}
JS.setCommands (game.pane_commands)
</inituserinterface>
</game>
<object name="room">
<inherit name="editor_room" />
<beforeenter type="script">
</beforeenter>
<enter type="script">
RemovePaneCommand ("jump")
</enter>
<object name="player">
<inherit name="editor_object" />
<inherit name="editor_player" />
</object>
<exit alias="north" to="second room">
<inherit name="northdirection" />
</exit>
</object>
<object name="second room">
<inherit name="editor_room" />
<beforeenter type="script">
AddPaneCommand ("Jump")
</beforeenter>
<exit alias="south" to="room">
<inherit name="southdirection" />
</exit>
</object>
<function name="AddPaneCommand" parameters="cmd">
list = Split(game.pane_commands)
exists = false
foreach (c, list) {
if (LCase(c) = LCase(cmd)) {
exists = true
}
}
if (not exists) {
game.pane_commands = game.pane_commands + ";" + cmd
}
SetPaneCommands
</function>
<function name="RemovePaneCommand" parameters="cmd">
list = Split(game.pane_commands)
foreach (c, list) {
if (LCase(c) = LCase(cmd)) {
cmd = ";" + c
game.pane_commands = Replace(game.pane_commands, cmd,"")
}
}
SetPaneCommands
</function>
<function name="SetPaneCommands">
JS.setCommands (game.pane_commands)
</function>
</asl>
Greying out disabled commands wouldn't be very complicated, I don't think, but that depends on what you mean by "disabled".
If you mean commands that output, "I didn't understand your command."
... that could be done.
If you mean commands that output: "You can't do that."
...that sounds quite difficult.
mrangel
25 Mar 2018, 17:32I think I see what you mean.
I can't recall seeing greyed out buttons in SCUMM games. I think in those games, you click the command and then the object, the reverse of Quest's verb buttons.
Now I'm imagining you want to modify the verbs display under the inventory/objects panes, so that it shows a static set of commands, and greys out the ones that aren't valid for a given object. Have I got the right idea? I think that coild be done in pure javascript.
Skarnisk
25 Mar 2018, 18:21@K.V.
I mean commands that don't react to a click when they are disabled.
Removing and adding commands to a panel is a way to disable them - but when I add a new command it appears at the bottom of the list, if I'm not mistaken. I'd want commands to keep their order, so I'm asking for a way to disable them without removal.
@mrangel
I'll have to replay some old SCUMM game in order to be sure, but I seem to recall seeing some of the commands greyed out in games like "Maniac Mansion" or the first two "Monkey Island". Not all of them, though, but "Talk to" button was disabled when there wasn't any NPC to talk to. Anyway, I'm not cloning the old SCUMM interface; I'm building my own, taking elements here and there. And yes, my custom pane shows a static set of commands; I'm looking for a way to grey out and disable the ones that don't have any use in that situation, like it happens with buttons in the compass pane.

K.V.
25 Mar 2018, 18:29I mean commands that don't react to a click when they are disabled.
Please define "disabled". Do you mean out of scope (or currently unavailable)? Like a command that only works in a specific room?
Sort of like the compass buttons? (When exits aren't available, the button is disabled.)
Skarnisk
25 Mar 2018, 18:40Yes, something like that. Commands that only work in a specific room, or with specific objects, e. g., where in a room there are no doors, trunks, cabinets or other openable objects, the "Open" command has to be disabled.
mrangel
25 Mar 2018, 18:58I think there's three main ways to arrange the interface to let the user select a command and an object. You could pick the command then the object, or the object then the command (the way Quest does it), or have both active and a button to press when you've selected both the command and the item you want to use it on.
I assume you're wanting to pick the command first, as you talk about objects available in the room rather than the selected object.
I'm pretty sure I can see how I'd go about doing that now. And most of it could be done just by tweaking the updateList javascript function. You'd have it initially disable all commands, and then enable the ones corresponding to the verbs it sees as it's displaying the object lists.
Would I be right in assuming that the reason you want a custom function rather than executing the command is because you then want the player to choose an object to use the command on? If so, I suspect it doesn't need to be a Quest function at all. You could keep your code in Javascript, and fire the command when the object is chosen. It's just like the verbs panel, but the other way around.
Hope that makes sense; I'm kind of rushing to get some work done on time tonight, so don't have the time to throw together a mockup right now. I might try later.

K.V.
25 Mar 2018, 19:17How about this example:
Old Code
<!--Saved by Quest 5.7.6606.27193-->
<asl version="550">
<include ref="English.aslx" />
<include ref="Core.aslx" />
<game name="Commands Pane">
<gameid>17f0e962-ffb7-4afa-9206-6258b00ef646</gameid>
<version>1.0</version>
<firstpublished>2018</firstpublished>
<feature_advancedscripts />
<commandpane />
<inituserinterface type="script">
if (not HasAttribute(game,"pane_commands")) {
game.pane_commands = "Look;Wait;Jump"
}
JS.setCommands (game.pane_commands)
</inituserinterface>
</game>
<object name="room">
<inherit name="editor_room" />
<enter type="script">
DisablePaneCmd ("Wait")
</enter>
<description><![CDATA[<h1>THIS IS ONLY A TEST</h1><br/><br/>At game start, "Wait" is disabled.<br/><br/>Enter {command:TEST} to enable it.<br/><br/>Enter {command:DISABLE} to disable it.]]></description>
<object name="player">
<inherit name="editor_object" />
<inherit name="editor_player" />
</object>
</object>
<command name="test_cmd">
<pattern>test</pattern>
<script>
EnablePaneCmd ("Wait")
</script>
</command>
<command name="test_disable">
<pattern>disable</pattern>
<script>
DisablePaneCmd ("Wait")
</script>
</command>
<function name="DisablePaneCmd" parameters="cmd">
JS.eval ("$('.commandlink').each(function(){if($(this).html()=='" + cmd + "'){$(this).addClass('disabled').data('deactivated', true);}});")
</function>
<function name="EnablePaneCmd" parameters="cmd">
JS.eval ("$('.commandlink').each(function(){if($(this).html()=='" + cmd + "'){$(this).removeClass('disabled').data('deactivated', false);}});")
</function>
</asl>
The next post is more like what you're looking for, I think.

K.V.
25 Mar 2018, 20:01One way to disable unavailable commands:
If using the desktop editor, you could add these two functions in code view:
<function name="DisablePaneCommand" parameters="cmd">
JS.eval ("$('#commandPane .commandlink').each(function(){if($(this).html()=='" + cmd + "'){$(this).addClass('disabled').data('deactivated', true);}});")
</function>
<function name="EnablePaneCommand" parameters="cmd">
JS.eval ("$('#commandPane .commandlink').each(function(){if($(this).html()=='" + cmd + "'){$(this).removeClass('disabled').data('deactivated', false);}});")
</function>
Then, in User Interface Initialisation, a turn script, AND after entering each room, call this function:
<function name="UpdatePaneCommands">
pcmds = Split(game.pane_commands)
foreach (pc, pcmds) {
available = false
foreach (cmd, ScopeCommands()) {
if (LCase(pc) = LCase(cmd.name)) {
available = true
}
}
if (not available) {
DisablePaneCommand (pc)
}
else {
EnablePaneCommand (pc)
}
}
</function>
You'd have to be precise with your command's names, making sure they match what you add to the pane after both strings are converted to lower case.
Here's an example game:
<!--Saved by Quest 5.7.6606.27193-->
<asl version="550">
<include ref="English.aslx" />
<include ref="Core.aslx" />
<game name="Commands Pane">
<gameid>17f0e962-ffb7-4afa-9206-6258b00ef646</gameid>
<version>1.0</version>
<firstpublished>2018</firstpublished>
<feature_advancedscripts />
<commandpane />
<start type="script">
</start>
<inituserinterface type="script">
if (not HasAttribute(game,"pane_commands")) {
game.pane_commands = "Look;Wait;Jump;Disabled"
}
JS.setCommands (game.pane_commands)
</inituserinterface>
<roomenter type="script">
UpdatePaneCommands
</roomenter>
</game>
<object name="room">
<inherit name="editor_room" />
<description><![CDATA[<h1>THIS IS ONLY A TEST</h1><br/><br/>Enter {command:TEST} to enable "Wait".<br/><br/>Enter {command:DISABLE} to disable it.]]></description>
<beforeenter type="script">
this = GetObject("wait")
this.parent = command_jail
</beforeenter>
<object name="player">
<inherit name="editor_object" />
<inherit name="editor_player" />
</object>
</object>
<command name="test_cmd">
<pattern>test</pattern>
<script>
this = GetObject("wait")
this.parent = null
</script>
</command>
<command name="test_disable">
<pattern>disable</pattern>
<script>
this = GetObject("wait")
this.parent = command_jail
</script>
</command>
<object name="command_jail">
<inherit name="editor_object" />
<command name="disabled">
<pattern>disabled</pattern>
<script>
msg ("This should not work!")
</script>
</command>
</object>
<turnscript name="pane_cmd_turnscript">
<enabled />
<script>
UpdatePaneCommands
</script>
</turnscript>
<function name="DisablePaneCommand" parameters="cmd">
JS.eval ("$('#commandPane .commandlink').each(function(){if($(this).html()=='" + cmd + "'){$(this).addClass('disabled').data('deactivated', true);}});")
</function>
<function name="EnablePaneCommand" parameters="cmd">
JS.eval ("$('#commandPane .commandlink').each(function(){if($(this).html()=='" + cmd + "'){$(this).removeClass('disabled').data('deactivated', false);}});")
</function>
<function name="UpdatePaneCommands">
pcmds = Split(game.pane_commands)
foreach (pc, pcmds) {
available = false
foreach (cmd, ScopeCommands()) {
if (LCase(pc) = LCase(cmd.name)) {
available = true
}
}
if (not available) {
DisablePaneCommand (pc)
}
else {
EnablePaneCommand (pc)
}
}
</function>
</asl>
mrangel
25 Mar 2018, 21:11Modified based on KV's script above; if you don't want to be moving commands in and out of scope.
This enables and disables commands based on whether there are any objects in the room with the command in their displayverbs list. So for example "open" will be disabled if there are no openable containers in the current room.
<function name="UpdatePaneCommands">
disabledcmds = Split(game.pane_commands)
if (HasAttribute(game, "alwaysenabledcommands")) {
// I'm assuming some commands, like "look", will always be available because
// you don't need an object to use them on
disabledcmds = ListExclude(disabledcmds, game.alwaysenabledcommands)
}
foreach (obj, ScopeReachable()) {
foreach (verb, GetDisplayVerbs(obj)) {
if (ListContains (disabledcmds, verb)) {
list remove (disabledcmds, verb)
EnablePaneCommand (verb)
}
}
}
foreach (cmd, disabledcmds) {
DisablePaneCommand (verb)
}
</function>

K.V.
25 Mar 2018, 21:23Oh, I missed that verbs were going to be in the command pane. I assumed the verbs would be left out of the command pane, since they are displayed for each object upon clicking them in the other panes.
Good catch, mrangel!
Skarnisk
26 Mar 2018, 15:43Thank you very much. I'll try these suggestions in my game.
mrangel
26 Mar 2018, 15:43I assumed the intention is to reverse the UI, so you click on a verb and then choose the object to apply it to.
I would note that the code I posted above is inefficient; if that's really what you want, then it's better to do it in pure javascript. Because the JS already has a list of verbs for all the objects, passed to the updateList function. So in this case, you could make updateList enable/disable verbs in the command pane each time it's updated, without having to add extra code on the Quest side.

CheeseMyBaby
26 Mar 2018, 19:57Interesting thread this one!
I love the old SCUMM games!
Skarnisk
03 Apr 2018, 21:06I found a solution for visually disabling (i.e. graying out) or enabling buttons. It requires having fun with CSS. I followed (again) The Pixie's tutorial, but I added an id
property to each span
element (i.e. button), so I can simply change their style with some JS.setCss
commands. After doing that, handling disabled or enabled buttons in game is simply a matter of scripting. I created a function that calculates which buttons have to be enabled or disabled (by counting objects that can be taken, opened, closed and so on) and I put a call to it into a turn script and when entering a room. Buttons get disabled or enabled automatically now.