Problem with custom Gamebook mode

Strainer
14 Dec 2013, 02:53
Hello dear community!

I have just recently picked up Quest and mostly spent my time finding out about the scripting language and reading through the tutorials and wiki.

I am planning to write an engine to support character stats and random rolls on different traits of the character, similar to a pen&paper RPG. I want to implement these functions in a gamebook-like mode though, but I found that the native Gamebook mode lacks an important funciton for this project, object handling. (As it seems, rooms are just objects in a gamebook file, maybe that's why).

For this reason, I decided to write a simple function to take over the Linking of pages and go from there, unfortunately, I couldn't get my function to work.

I would appreciate any help on this, I also think I have done things a little complicated, any tips highly appreciated.

The function is called "ShowLinks" and reads like this


Choices.Choice1 = Choice1
Choices.Choice1Room = Choice1Room
Choices.Choice2 = Choice2
Choices.Choice2Room = Choice2Room
Choices.Choice3 = Choice3
Choices.Choice3Room = Choice3Room
Choices.Choice4 = Choice4
Choices.Choice4Room = Choice4Room
Choices = NewStringList ()
list add (Choices, Choice1)
if (not Choice2 = "") {
}
list add (Choices, Choice2)
if (not Choice3 = "") {
}
list add (Choices, Choice3)
if (not Choice4 = "") {
}
list add (Choices, Choice4)
msg ("")
ShowMenu (MenuCaption, Choices, false) {
msg (result)
msg (Choices.Choice1Room)
if (result = Choices.Choice1) {
ClearScreen
MoveObject (player, Choices.Choice1Room)
}
else if (result = "Choice2") {
ClearScreen
MoveObject (player, Choice2Room)
}
else if (result = "Choice3") {
ClearScreen
MoveObject (player, Choice3Room)
}
else if (result = "Choice4") {
ClearScreen
MoveObject (player, Choice4Room)
}
}


Edit: I have found the error, which wasn't actually in the function, but the code that called it:

ShowLinks ("Do you want to...", "do A.", room1, "do B.", room1, "", "", "", "")

I had room1 written as "room1" which was the whole error, seems like I have to store it as the object, not as a string.

Edit2: Another question I had: Could I define standard values for a function, so I don't have to declare "" for the choices I don't need? I would like to make this function as flexible as possible, so supporting a variable number of choices is probably the right way to go, but writing 10 choices would require me to write something like ShowLinks ("What you want...", "do A.", room1, "do B.", room2, "do C.", room3, "", "", "", "", "", "", "", "", "", "", "", "", "", ""). This kinda eliminiates the purpose of it being easy or user-friendly.

jaynabonne
14 Dec 2013, 19:29
Since you found the first problem, I won't go into that... :)

For the second question, I'd like to propose a solution. There is a fairly simple way to go using dictionaries. ShowMenu can take a dictionary instead of a list of strings. The name/value pairs correspond to the result and displayed text respectively. In this case, the key/result string is the name of the room, and the value/displayed text is whatever you want to display. You can then easily use GetObject to get the room from its name when an item is chosen.

It does mean that things will be more data-driven (you create dictionaries to hold choices instead of function parameters), but I think that's cleaner anyway, to be honest.

The function is called ChooseRoom, and it's quite simple:

  <function name="ChooseRoom" parameters="caption, choices">
ShowMenu (caption, choices, false) {
ClearScreen
MoveObject (player, GetObject(result))
}
</function>

You just need to pass in a dictionary with the choices. A full code example follows. I attached the dictionary to the current room to keep it encapsulated. It's up to you how you want to organize the data. :) Let me know if you have any questions.

<!--Saved by Quest 5.4.4873.16527-->
<asl version="540">
<include ref="English.aslx" />
<include ref="Core.aslx" />
<game name="EasyGamebook">
<gameid>4e12284d-c554-45d8-93b1-8e91d047f697</gameid>
<version>1.0</version>
<firstpublished>2013</firstpublished>
</game>
<object name="room">
<inherit name="editor_room" />
<choices type="stringdictionary">
<item>
<key>Room 1</key>
<value>Head to the kitchen</value>
</item>
<item>
<key>Room 2</key>
<value>Go downstairs</value>
</item>
</choices>
<enter type="script">
ChooseRoom ("What would you like to do?", player.parent.choices)
</enter>
<object name="player">
<inherit name="editor_object" />
<inherit name="editor_player" />
</object>
</object>
<object name="Room 1">
<inherit name="editor_room" />
<description type="string"></description>
<alias>the kitchen</alias>
<usedefaultprefix type="boolean">false</usedefaultprefix>
</object>
<object name="Room 2">
<inherit name="editor_room" />
<alias>the basement</alias>
<usedefaultprefix type="boolean">false</usedefaultprefix>
</object>
<function name="ChooseRoom" parameters="caption, choices">
ShowMenu (caption, choices, false) {
ClearScreen
MoveObject (player, GetObject(result))
}
</function>
</asl>

Strainer
15 Dec 2013, 15:24
Thank you very much, this is indeed very useful and I will use your method from now on. I will now also try to work on a randomizing function, similar to the one developed for gamebooks here: http://forum.textadventures.co.uk/viewtopic.php?f=18&t=4025

Thanks again for your insight, I would have probably never come up with such a nice solution, the need to define the links in the attributes is no problem for me, I think it just adds to the ease of reading the code.

Entropic Pen
15 Dec 2013, 17:06
All ya had to do was ask! I do have a function that can randomize items in a stringlist with a special delimiter that I'm sure we can adapt to Text Adventures. Though that can't happen anytime soon since I can't access the Internet with my laptop.

Entropic Pen
15 Dec 2013, 17:49
UPDATE 12/16/13: Now there is a fourth parameter which you can choose to randomize the options or not, which should save some coding on creating two different functions:


<function name="rand_pagemenu" parameters="choices, destinations, delimiter, randomizer">
game.return_list = NewStringList()
game.location_list = NewStringList()
link_list = Split(choices,delimiter)
room_list = Split(destinations,delimiter)
if (randomizer = true) {
for (o, 0, ListCount(link_list) -1, 1) {
rand_link = GetRandomInt(0,ListCount(link_list)-1)
choosen_link = ListItem(link_list,rand_link)
choosen_page = ListItem(room_list,rand_link)
list remove (link_list, choosen_link)
list remove (room_list, choosen_page)
list add (game.return_list, choosen_link)
list add (game.location_list, choosen_page)
}
}
else {
foreach (o, link_list) {
list add (game.return_list, o)
}
foreach (o, room_list) {
list add (game.location_list, o)
}
}
ShowMenu ("", game.return_list, false) {
intItem = 0
gotItem = 0
foreach (o, game.return_list) {
if (o = result) {
gotItem = intItem
}
intItem = intItem +1
}
location_in_question = ListItem(game.location_list,gotItem)
MoveObject (player, GetObject(location_in_question))
}
</function>


After that, you'll set up a "Call Function" at the end of a room script like:
rand_pagemenu ("(Page 2):(Page 3):(Page 4)", "room2:room3:room4", ":", true)

1st Parameter = Link display
2nd Parameter = list of room objects
3rd Parameter = Delimiter (what separates the items in the first and second parameters).
4th Parameter = Whether you want the page links to be randomized or not.
true = randomize
false = don't randomize