My two penneth

The Pixie
After something of a hiatus, I have been dabbling with Quest again recently. I thought I would leave you a few suggestions and comments about Quest 5.2. From the development thread, I see Alex is working on a map and changing the POV, both of which will be excellent features for Quest.


1. "on ready" is not documented. Are any other functions not documented in the latest version?

2. I would like to see a way to add inventory verbs to types; it should be extendable too. For example, a clothing type should have Wear and Remove, so all garments get them automatically, but some might get other verbs as well. I was also unable to add inventory verb programmatically at start-up, by the way. To me, this is a bug, but others may disagree.

3. A FormatList method that takes an ObjectList as a parameter would be useful. Most of the code is already in the library, but inside FormatObjectList. Should be easy to break into two functions, with FormatObjectList calling FormatList (indeed, see library of my demo).

4. On the status bar "A " is prepended to the room name. Is there a way to stop that? Again, this looks like a bug to me.

5. Spinner for setting an integer attribute does not update properly. Another bug.

6. Quality testing functions: A spell checker, something that highlights rooms and objects without aliases, a way to check every room has "look", "smell" and "listen" implemented. These things will help raise the quality of Quest games, which in turn will help Quest's reputation.

7. Comments in the code should be preserved.

8. An easy way to have scenery objects that are common to a whole set of rooms (say a sky object for any room of type "outside"). I hacked this by moving objects around with the player, but it was not pretty, and likely to break with multiple POV.




I have created a demo with some further ideas. Run the walkthrough, and see what happens!



Featuring...
assertions
comments
variable text
showme/valueof
walkthough/about/help/commands
save/load/transcript
new dictionary functions (look at the code to see what these do)

I like to use black text for narrative text, and grey for meta-game text, by the way; that is deliberate. All the interesting stuff is in the file PixFuncLib, because I like to put comments in, and Quest just quietly erases them. Some of these could (and I think should) go straight into 5.3 though some would require modifying. The variable text and saving last line output might be better coded in the msg function in C#. Some things should be disabled in the published adventure, too.

Alex
Thank you very much :)

Lots of awesome stuff here which it's going to take me a little while to go through properly. I'll take a look and try to post a follow up today if I get some time.

sgreig
You can remove the "A" prefix to the rooms on the room tab. Just uncheck the box that says "Use default prefix/suffix".

The Pixie
Version 1.1 of the PixLib and Demo



Now with language support - uses templates (but not for debugging functionality). The walk-though has been expanded to make clearer what is going on. Also, I have pulled out the grey/black-and-indented text style into a separate library PrettyPrintLib, which is included in the zip. A demo, PrettyPrintDemo, is included which is exactly the same as PixDemo, except that it also includes this library.

I have also added more print options, this is the full list:

RANDOM chosen at random
NEAR_RANDOM chosen at random, but not repeating the one last time
PREVIOUS use the same random number as the previous one in this string
CYCLE cycle through the options in order, then back to the beginning
ITERATE cycle through the options in order, then stick on the last one
FIRST_ONLY show the first option the first time, nothing after that
FIRST_THEN show the first option the first time, the second option every time after that
STICKY one is chosen at random the first time, but this same one is used thereafter
NAME prints the alias for the player object
GAME prints the name of the game
VERSION prints the version of the game
ROOM prints the alias of the current room, if there is one, or otherwise the name
CHAR prints the alias of a character in the room (no guarantee who that is if more than one is present)
EVAL evaluates the expression after the vertical bar (eg an object's property or a function call; no guarantee complicated expressions will work)
TIME puts in the time (if clock_lib is included)
TIME_IN_WORDS puts in the time in words (if a new version clock_lib is included)

The last few options are useful if you want to store a string in a stringlist, but want to have values inserted into it when it gets displayed. If this was incorporated into msg, you could then use them in room and object descriptions too (just as you can in Inform), and in templates, default responses, etc. I would be prepared to code this in C# if that was helpful, just as a simple method that takes a string and returns a string.

ETA: Having thought about this more, and looked at the Ques source code, I am not so sure my meagre knowledge of C# is up to this (accessing attributes in particular). So here is a new idea...

Have msg as a function, rather than a script command, that calls some other script command, which does the same thing. The impact of this indirection would be negligable to any existing game, but it would allow creators (or the core library even) to over-write msg to do the stuff above. With room description and error returns and whatever all calling msg, they would now be calling the over-written version, to do whatever we want before invoking the script command.

Alex
I like the print options, and the idea of msg indirection is interesting. I'll have a think about this for Q5.3 (logged http://quest.codeplex.com/workitem/1122) - maybe I could include some of the code from this library?

Assertions to test the last printed string are a good idea. May be better to incorporate this into the existing assert functionality within a walkthrough (http://quest5.net/wiki/Walkthroughs#Assertions) - you can use "assert:expression", so maybe you could have


assert:LastPrint("some text")


By using the built-in walkthrough assert functionality you have the advantage that the walkthrough will stop if the assertion fails.

To answer your questions...

1. "on ready" is only needed by the Core library I think. It runs the nested script only if there are no callbacks pending. A callback will be pending if Quest is waiting for the user to press a key for example. With "on ready" it means the script for triggering the room description when the player moves will only be printed when all other scripts have finished running, which fixes some confusing behaviour caused by the move to asynchronous scripts in Quest 5.1. There is probably some other stuff undocumented from both the 5.1 and 5.2 releases - I will go through the documentation soon to ensure it's up to date before the 5.3 release.

2. You can do this the same way the Core library does, using a "listextend" type.

3. Yes this seems to be a sensible refactoring.

4. As sgreig says, this is just the prefix for the room which can be easily removed.

5. Yes I've noticed the spinner is occasionally dodgy. Can you reproduce anything consistently?

6. May be good to have a spell checker. I couldn't find a good free one the last time I looked. Less of an issue on the web version as most web browsers spell check text fields automatically. Not sure why rooms and objects without aliases should be highlighted though - surely that's perfectly legitimate?

7. Comments within scripts (using "//") are preserved. Comments in XML are ignored when loading a game in the Editor. But maybe internally they could be stored as meta-attributes of their parent elements, which would allow them to be saved out again. Logged http://quest.codeplex.com/workitem/1123

8. The best way to implement this would be to modify the Scope functions. If we can come up with some common usage patterns for this it could be turned into a Core library feature.

The Pixie
Hi Alex

Version 3


I like the print options, and the idea of msg indirection is interesting. I'll have a think about this for Q5.3 (logged http://quest.codeplex.com/workitem/1122) - maybe I could include some of the code from this library?


I would love to see it included in 5.3.

I have slightly modified the print options in version 3 so they can be extended later. If you want to add a new directive, say MY_OPTIONS, create a function BasePrintMyOptions.

Assertions to test the last printed string are a good idea. May be better to incorporate this into the existing assert functionality within a walkthrough (http://quest5.net/wiki/Walkthroughs#Assertions) - you can use "assert:expression", so maybe you could have

assert:LastPrint("some text")

By using the built-in walkthrough assert functionality you have the advantage that the walkthrough will stop if the assertion fails.


Okay, I had no idea assertions were already in Quest...

The new version now has a LastPrint function that does just that.

5. Yes I've noticed the spinner is occasionally dodgy. Can you reproduce anything consistently?


Sadly, no!

8. The best way to implement this would be to modify the Scope functions. If we can come up with some common usage patterns for this it could be turned into a Core library feature.


Yes, I think scope is the way to go.

This is something Inform does very easily, and in contrast is a nightmare for Quest. And really it is vital for a game going into a competition, as people will expect to be able to examine walls, look at the sky, etc.

The Pixie
Okay, this may well be the final version!



This version has a few changes in the code to make it more robust, but no new functionality. All functions in PixLib now have comments, and a file PixLib.txt has those collected together in a format for QuestWiki. I have also included a unit-test adventure for some of the functions in PixLib.

The zip file contains:

PixLib.aslx: A library with several useful functions and commands. All functions are documented (but not commands) and use templates for language support. Some functions are unit tested.

PixDemo.aslx: A game that demos of some of the functions and commands in PixLib. Run the walk-through to see it all.

PixTest.aslx: A game that unit tests some of the functions and commands in PixLib. Run the walk-through.

PrettyPrintLib.aslx: A library that builds on PixLib, to format output so that the narrative text is in black and indented, and room names appear as sub-headings, while meta-game text is grey. This will not be to everyone's taste, so I have made it separate.

PrettyPrintDemo.aslx: This file is exactly the same as PixDemo.aslx except that it also invokes the PrettyPrintLib library. Run the walk-though to see the effect of the additional library.

PixLib.txt: Documentation for all the functions in PixLib, hopefully formatted for QuestWiki.


I think the comment functionality could be done better another way. As it is, comments stumble over full stops, as (I assume) Quest uses the fullstop to break sentences when parsing input. Also, any commands added after the comment (which would be any added by the author if this is in a standard library) may get a match with text in the comment, which could be bad. A far better way would be like assert, but to do nothing (which I guess is in a C# code, and certainly at a more basic level than I know how to access), which I would guess was fairly easy. A think a reliable comment system is a must if Quest adventures are to compete successfully in competitions, as judges do like this facility, and take it for granted as it is built into Inform.

The Pixie
Quick additional function. This gives a method, ToWords, that will take an integer and return it as a string, with the number written in words if it is between -2000 and +2000 exclusive.

ToWords(101) -> "one hundred and one"
ToWords(2000) -> "2000"
etc.

 <function name="ToWords" parameters="number" type="string"><![CDATA[
if (not TypeOf(number) = "int") {
error ("NumberInWords can only handle ints")
}

s = ""
if (number < 0) {
s = "minus "
number = -number
}
if (number < 2000) {
hundreds = number / 100
number = number % 100
if (hundreds > 0) {
s = s + StringListItem(printer_struct.number_units, hundreds) + " hundred "
if (number > 0) {
s = s + "and "
}
}
if (number < 20) {
if (not number = 0 or s = "") {
s = s + StringListItem(printer_struct.number_units, number)
}
}
else {
units = number % 10
tens = (number / 10) % 10
s = s + StringListItem(printer_struct.number_tens, tens - 2)
if (not units = 0) {
s = s + StringListItem(printer_struct.number_units, units)
}
}
}
else {
s = ToString(number)
}
return (Trim(s))
]]></function>

<object name="number_struct">
<number_units type="list">zero;one;two;three;four;five;six;seven;eight;nine;ten;eleven;twelve;thirteen;fourteen;fifteen;sixteen;seventeen;eighteen;nineteen;twenty</number_units>
<number_tens type="list">twenty;thirty;forty;fifty;sixty;seventy;eighty;ninety</number_tens>
</object>

The Pixie



Another library and demo. This allows objects (especially characters) to have a life of their own to some degree. Set up a string dictionary on your object of turn numbers (as strings) for the keys and function names (as strings) for the values. On the turn, the function gets called. Each object can be paused and unpaused.

Responses giving meta-data (help, etc. ad error reports) do not count as a turn (requires Pixlib and PrettyPrintLib for this to work).

I have to admit that the creator input is not that slick; you need to create a function for every action (well, not necesssary, but...). I would be interested to hear of any ideas how this could be improved (even in general terms without looking at my efforts).

Pertex
Could you zip all necesary files in the correct filestructure and post it here? Thanks

The Pixie


Try this

jaynabonne
SInce you asked for feedback, here are a few thoughts I had looking at PathLib:

1) It's probably just my object-oriented background, but my preference for the code (if it were mine) would be to lean toward trying to encapsulate the actions into the objects somehow. Toward that end, I'd prefer to have the actions be scripts on the object itself (which are invoked with "do") rather than global functions. That puts the behavior in the same place as the object.

Now, in your demo, you actually share behavior among a couple of objects. If there were the need for such a thing in a game, then I'd assume they'd be instances of the same thing (e.g. robot1 and robot2) since they have the same behaviorial possibilities. Regardless, either way, you could solve that with a base type which holds the common scripts.

2) The way it's set up suffices for many applications, where you have fixed behaviors. If you ever wanted to vary the behavior, then it gets much harder, or the code wouldn't be usable as is. One possibiity would be to have different dictionaries for different sequences. Then when a path object is active, it would have a "current sequence" string attribute, which names the dictionary in effect. (In other words, not only would you start up an object, but you'd tell it what it's supposed to be doing.) That's a simple change that would expand the possibilities for the code a bit.

3) This one is more a heads-up than anything. I had a similar set up to yours (a list of objects doing things), and the straightforward "add, remove, foreach" paradigm didn't end up working in the end, in real world situations. There are problems if you ever have one of the objects try to start up or shut down another object (or itself). For example, let's say you want your button to be itself a path object. When you press it, it goes through several states before the robot starts up (e.g. a stupid example: "The button flickers", "The button blinks several times, with increasing speed", "The button glows solid", and then the button activates the robot on the last state), you'll find that you get these annoying messages about modifying the list being enumerated. The same happens if, say, on the last state of the robot movement, it wants to shut itself down and remove itself from the list. Again, list modified while enumerating.

The solution I came up with (and any better suggestions are appreciated!) was to have a main list which is enumerated and then have a "pending" list for new adds and a way to mark objects in the list that have been removed. Then on each cycle, before the foreach, I would add all the pending additions and remove all the marked removals.

It's possible you'd never run into that. But I bet if this is used (and used to its fullest potential), you will run into it, and the hoops you have to go through to work around it are a bit ugly. (Another possibility I toyed with was to use a while loop with a variable. That avoids the modified message and works well for additions - assuming they're added at the end, and that you check the list length each time in case it grows - but it doesn't work for removals. In the case where the object you're removing comes before the current object in the list, everything would shift down, and most likely you'd end up skipping an object on that turn. So I nixed that idea.)

Hope this all helps!

jaynabonne
Oh, and I really like your "ToWords" function! :)

The Pixie


Okay, second version.

Had not thought about using scripts, but it turns out to be neater as you can access the object through this, and no return type.

You can now start up new paths for an object, as you suggest. You can also set a path to wait until a script gives a true.

Finally, I have included a warning about not beginning or terminating a path from a path (unless you have large numbers of objects with paths, just pause them instead, I suggest).

The Pixie
Another library function that might be a useful addition to 5.3:

  <function name="MoveChildObjects" parameters="from, to">
foreach (obj, GetDirectChildren (from)) {
obj.parent = to
}
</function>


Also, a library for adding a lift (or elevator) to your game.


To implement, create a room that will be the lift, and in it put a number of objects that will be buttons. You will obviously need one button per floor. For each floor, create an exit that goes to the lift room (but not the other way), also create a single exit for the lift room (does not matter where to).

The library adds a new tab to the editor. On the lift tab, set all the exits from each floor to the lift to be "Lift Entance" (do not do this for the exit in the lift room). Still on the lift tab, set the buttons to be "Lift Button", assign a floor number and a destination for each. For the lift room itself, set it to be a "Lift", and type in messages the player will see when buttons are pressed. You can use ### in these strings and this will be replaced by the destination floor.

See the included demo for an example.

Note that as implemented the player does not have to press a button to call the lift - the lift is automatically at whatever floor the player wants to get on at. You might want to have the lift entrances locked, and require the player to press a button to call the lift, which then unlocks the exit. Have the exit lock when the player goes that way.

Floors must be numbers (so no "ground" and "basement" I am afraid), as the system compares the current floor to the destination floor to decide if it is going up or down. Feel free to modify this if you prefer it otherwise.

Should be able to handle multiple lifts in one game (but I have to admit not testing that!).

The Pixie
Here is another one, this time for a computer network.

(version 2, 1340 BST 20/Oct/12)

Using this library you can easily implement one or more computer terminals in your game. This is quite a specific implementation, and may not be suitable for all games. All terminals are connected to the same network, and the same data can be access from all. The player's character is assigned a security level (which can be changed during the game), and this determines what data is accessible. Optionally, the player can hack a terminal for a higher security level.

The player is not required to give a password or access code, but it is assumed the character uses this when logging on. What you can do is give the player object a security level when a password is found.

Instructions for setting up are included in the library file, and there is a demo too, but all setting up is through a new "Terminal" tab, so fairly straightforward.

Edit: Updated as I found a couple of issues, mainly about handling different settings on the game object. New version uses PixLib (because ultimately this is for my benefit, and I use it), but the library files has instructions for modfying it so it does not, just comment out one line, uncomment another.

The Pixie
I have decided to put some of my libraries on the Wiki, where they will be easier to find, and I can provide a proper tutorial in their use.

Only done two so far, as I am not sure how 5.3 will impact on the rest.

http://quest5.net/wiki/Dynamic_Menus_for_Conversations
http://quest5.net/wiki/Implement_a_Lift

dgparryuk
I know it's a year & .2 versions later...
and i've only just started trying to make a game
but this looks perfect for part of mine..
unfortionatly it doesn't work :-(

i get an error of

System.Exception: Unknown source list for dropdown
at TextAdventures.Quest.EditorControls.DropDownControl.m_helper_Initialise()
at TextAdventures.Quest.EditorControls.ControlDataHelper`1.DoInitialise(EditorController controller, IEditorControl definition)
at TextAdventures.Quest.EditorControls.ElementEditor.InitialiseEditorControl(IEditorControl ctl)
at TextAdventures.Quest.EditorControls.ElementEditor.AddControlToGrid(Grid grid, IEditorControl ctl, Boolean firstControl)
at TextAdventures.Quest.EditorControls.ElementEditor.InitialiseTab(IEditorTab tab)
at TextAdventures.Quest.EditorControls.ElementEditor.Initialise(EditorController controller, IEditorDefinition definition)
at TextAdventures.Quest.WPFElementEditor.Initialise(EditorController controller, IEditorDefinition definition)
at TextAdventures.Quest.Editor.AddEditor(String name)
at TextAdventures.Quest.Editor.SetUpEditors()
at TextAdventures.Quest.Editor._Closure$__1._Lambda$__4()


i saw a sugestion of "list" to "script list" but that didn't work...

HegemonKhan
due to v5.4 of quest, code syntax+format is different for some things

http://quest5.net/wiki/Stringlist

this is probably the case of the error, unles you made a simple mistake or typo with your code causing that large script block to be the (presuming) source of your error.

http://quest5.net/wiki/Using_Lists
http://quest5.net/wiki/List
http://quest5.net/wiki/Using_Dictionaries

------

it's not:

list -> script list

IT"S:

list -> simplestringlist

---------

there is no "scriptlist", but there is a "scriptdictionary"

Lists:

1. stringlist ~ list ~ simplestringlist
2. objectlist

Dictionaries:

1. stringdictionary ~ simplestringdictionary
2. objectdictionary
3. scriptdictionary

dgparryuk
Cheers i'll try that later...

I'm not a programmer but i can program (a little)
so it's just learning the syntax etc..

This topic is now closed. Topics are closed after 14 days of inactivity.

Support

Forums