Quest is a free, modular system for creating computer based role-playing games. This is the documentation and background of the Quest project.
Writing free software takes a lot of effort and to get anything done cooperation is necessary. The thing I've found to pose the greatest problem when adding to free software is discovering how to communicate with the already existing software. To overcome this problem the goal of Quest is to be as modular and simple as possible and not to invent new systems where standards already exist so that outsiders will not have to struggle with arbitrary internal standards.
FIXME: add short story about how Quest is inspired by POSIX processes.
I plan to use XML for all communication, because many types of data Quest will need to communicate are structured and I want to use one format for all data. XML parsers already exist in many languages, so that will save time.
The Quest client is really a collection of clients each dedicated to a separate task, examples of such tasks are network communication, data administration, user input/output in a certain game situation, etc. The server is set up in a similar way and can start its own clients to get specific tasks done, for example create a client to control a pack of goblins attacking the player.
specific client <-> meta client <-> client comm. <-> server comm. <-> meta server <-> specific server
The idea is that every such client should have the same set of functions that the meta server can call, so that the meta server won't have to know what kind of specific client it's talking to. The set of functions will have to be determined as we go, adding to the specification when needed. Currently these functions are in use:
This function triggers the specific client to send user input to the meta client, a text client would do something like this:
sub get_command { print "command? "; my $input = readline(STDIN); return '' if $input =~ /hello/; return ' ' if $input =~ /quit/; return "" # default }
This function sends a string from the meta client to the specific client, so that the specific client can decide for itsself how that string should be displayed. A graphical client will treat the string completely different than a text client.
A simplistic example in Perl of text_io::display is
sub display { print shift }
This function takes two references from the meta client, one reference to the `world', the other to the `room' where the player currently is, and stores them locally, so that the specific client can access the world directly without having to send an XML request to the meta client.
Communication from the specific client to the meta client works through the return value of get_command(), which is an XML string.
My immediate reaction in the past was to change the entire program to use the GUI's main loop as its main loop, thus making all other tasks of the program subservient to the GUI, but that is exactly what I don't want. So this makes communication between the meta client and the io client a bit more complicated.
like checking which information should become available to the player and if certain quests the player is participating in have been completed.
like random encounters and room triggers.
Here is a piece of example Perl code, to give an idea of the main loop of the meta client:
unless ($quit) { $_ = text_io::get_command; chomp; my $command = XMLin($_); if ($command->{"CLIENT"}) { my $cmd = $command->{"CLIENT"}->{"command"}; text_io::display("Hello World!") if ($cmd eq "hello"); $quit = 1 if ($cmd eq "quit") } }
Example: Here's an example data file.
<ROOM name="start"> <DESCRIPTION>The first room of the game</DESCRIPTION> <DOOR name="blue door" target="blue room" file="blue_room.xml"/> <DOOR name="big tree" target="tree trunk" file="start.xml"/> </ROOM> <ROOM name="tree top"> <DESCRIPTION>The top of the big tree</DESCRIPTION> <DOOR name="down" target="tree" file="start.xml"/> </ROOM> <ROOM name="tree"> <DESCRIPTION>Near the top of the big tree</DESCRIPTION> <DOOR name="up" target="tree top" file="start.xml"/> <DOOR name="down" target="tree trunk" file="start.xml"/> </ROOM> <ROOM name="tree trunk"> <DESCRIPTION>At the base of a big tree</DESCRIPTION> <DOOR name="up" target="tree" file="start.xml"/> <DOOR name="down" target="start" file="start.xml"/> </ROOM>
Example: Here's some example communication records.
<CLIENT command="move" target="tree top"/> <CLIENT command="trigger" target="look in mirror"/> <REQUEST><FILE name="blue_room.xml" path="./data"/></REQUEST> <ERROR info="blue_room.xml doesn't exist"/>