\section{Adventure Game} \label{adventure} This text adventure game is an example of using Max to do something useful. As we develop Max, we will enhance the game to show new features. @ <>= <> <> @ \subsection{Types used in the game} These types are implemented as "structures" or classes in most languages. In Max, we create a new type for, and functions taking values in that type as an argument and returning the appropriate value. For instance, there will be a type of Locations, and a function that takes a Location and returns you its name. <>= ; Location: name desc items actors ; Item: name desc place ; Actor: name items location ; Owner: location | actor <> <> <> <> @ \subsubsection{Locations} A location consists of a name, a description, a set of items in it, a set of actors in it, and a set of paths leading out. Create a location type: <>= (defparameter *location-type* (make-type)) @ Create 4 rooms in the game: <>= (defparameter ROOM1 (make-address :key 'ROOM1 :type *location-type*)) (defparameter ROOM2 (make-address :key 'ROOM2 :type *location-type*)) (defparameter ROOM3 (make-address :key 'ROOM3 :type *location-type*)) (defparameter ROOM4 (make-address :key 'ROOM4 :type *location-type*)) @ Since there must be a connection going out from every location even when that's a wall you can't go through, we created the fake location DEADEND to indicate you can't go that way. <>= (defparameter DEADEND (make-address :key 'DEADEND :type *location-type*)) @ The location-name function takes a location and returns a string containing the location's name. <>= (defparameter location-name (make-function 'enumerated-function 'location 'string (function-values '(ROOM1 . (make-string-address "ROOM1")) '(ROOM2 . (make-string-address "ROOM2")) '(ROOM3 . (make-string-address "ROOM3")) '(ROOM4 . (make-string-address "ROOM4")) ) ) ) @ The location-desc function takes a location and returns a string containing the description of the location. <>= (defparameter location-desc (make-function 'enumerated-function 'location 'string (function-values '(ROOM1 . (make-string-address "A cold, dark room with a hallway going East and a hallway going South")) '(ROOM2 . (make-string-address "A warm, well-lit room with a hallway going West and a hallway going South")) '(ROOM3 . (make-string-address "A lukewarm, dim-lit room with a hallway going East and a hallway going North")) '(ROOM4 . (make-string-address "A neutral feeling and neutral looking room with a hallway going West and a hallway going North")) ) ) ) @ \subsubsection{Items} An item is a game object that doesn't move by itself, but can have actions performed on it. An item consists of a name, a description, and an owner which can be a location (if on the ground) or an actor (if being carried). <>= (defparameter *item-type* (make-type)) (defparameter SWORD (make-address :key 'SWORD :type *item-type*)) (defparameter NAPKIN (make-address :key 'NAPKIN :type *item-type*)) (defparameter WARCRAFT3 (make-address :key 'WARCRAFT3 :type *item-type*)) @ The item-name function takes an item and returns the string containing the item's name. <>= (defparameter item-name (make-function 'enumerated-function 'item 'string (function-values '(SWORD . (make-string-address "sword")) '(NAPKIN . (make-string-address "napkin")) '(WARCRAFT3 . (make-string-address "War3 CD")) ) ) ) @ The item-desc function takes an item and returns a string containing the item's description. <>= (defparameter item-desc (make-function 'enumerated-function 'item 'string (function-values '(SWORD . (make-string-address "A sharp, two-edged sword with a gold-plated hilt")) '(NAPKIN . (make-string-address "A folded paper napkin with some scrawled text and unrecognizable drawings")) '(WARCRAFT3 . (make-string-address "Warcraft III: Reign of Chaos^(tm) PC CD-ROM by Blizzard Entertainment")) ) ) ) @ The item-owner function takes an item and returns the actor that currently possesses the item. An owner (item only property) is either a location (if unowned) or an actor. This should use a union (sum) type, like: [[(type-sum *item-type* *location-type*)]] <>= (defparameter item-owner (make-function 'enumerated-function 'item 'owner (function-values '(SWORD . ROOM1) '(NAPKIN . ROOM2) '(WARCRAFT3 . ROOM3) ) ) ) @ \subsubsection{Actors} Actors are the agents that do things in the game world. Players and monsters are examples of game actors. An actor consists of a name, a set of items being carried, and a location. <>= (defparameter *actor-type* (make-type)) (defparameter PLAYER1 (make-address :key 'PLAYER1 :type *actor-type*)) @ The actor-name function takes an actor and returns the string containing the actor's name. <>= (defparameter actor-name (make-function 'enumerated-function 'actor 'string (function-values '(PLAYER1 . (make-string-address "Hero")) ) ) ) @ Actor-items would be a function taking an actor and returning a set of items the actor is currently carrying. It is not implemented, but could be by taking the quotient of the item-location function. <>= ; actor-items? @ The actor-location function takes an actor and returns the location where the actor is currently at. <>= (defparameter actor-location (make-function 'enumerated-function 'actor 'location (function-values '(PLAYER1 . ROOM1) ) ) ) @ \subsubsection{Directions} A direction is one of N,S,E, and W. <>= (defparameter *direction-type* (make-type)) (defparameter N (make-address :type *direction-type* :key 'north)) (defparameter S (make-address :type *direction-type* :key 'south)) (defparameter E (make-address :type *direction-type* :key 'east)) (defparameter W (make-address :type *direction-type* :key 'west)) @ \subsection{Game Map} The game map takes LOCATION x DIRECTION and returns a LOCATION. It is implemented using a function called PATH, below. A path is a function: given a location and a direction, it returns a location you can travel to. The rooms will be connected in a rectangle. \begin{verbatim} ROOM1 - ROOM2 | | ROOM3 - ROOM4 \end{verbatim} Path is a 2-argument function, in reality, but with location naturally dispatching before direction, Path will take a location and return a function taking a direction and returning a location. TODO: Add some nice metaprogramming here to allow easy definition of these functions. <>= (defparameter PATH (make-function 'enumerated-function 'location 'function (function-values '(ROOM1 . (make-function 'enumerated-function 'direction 'location (function-values '(E . ROOM2) '(S . ROOM3) '(N . DEADEND) '(W . DEADEND) ) ) ) '(ROOM2 . (make-function 'enumerated-function 'direction 'location (function-values '(W . ROOM1) '(S . ROOM4) '(N . DEADEND) '(E . DEADEND) ) ) ) '(ROOM3 . (make-function 'enumerated-function 'direction 'location (function-values '(E . ROOM4) '(N . ROOM1) '(S . DEADEND) '(W . DEADEND) ) ) ) '(ROOM4 . (make-function 'enumerated-function 'direction 'location (function-values '(N . ROOM2) '(W . ROOM3) '(S . DEADEND) '(E . DEADEND) ) ) ) ) ) ) @ \subsection{Playing the game} When the game starts, the player is placed in the starting location (defined by a thunk returning the starting location). From there, the player can perform a few actions such as moving and picking up items and dropping them. There are no monsters yet. \subsubsection{Actions the player can perform} The player can perform the following actions: \begin{itemize} \item[move] Given a direction, the player attempts to move that direction from his or her current location. There will be an error that the way is blocked, or the player's location will change. MOVE is a direction sink. \item[take] Given an item in the current location, the player picks it up and starts carrying it. TAKE is an item sink. \item[drop] Given an item the player is carrying, the player drops it in the current location. DROP is an item sink. \item[examine] Given an item the player is carrying or an item in the current location, the player carefully looks at the item. Th item's description is displayed. EXAMINE is a function that returns a string given an item. \item[look] The player looks around the current location. The location's description, items here, and other actors here are displayed. LOOK is a thunk that returns a string. \item[inventory] The player looks at what he or she is carrying. INVENTORY is a thunk that returns a set of items. \end{itemize} \subsection{Cheating} Of course, using introspection the player could easily read the internals of the game and cheat. There's nothing that can be done about it, or at least nothing that would be ultimately effective. Since it's the user's computer, any single player game running on their computer is technically available for introspection, even if it is obfuscated (compiled to binary code, encrypted, or whatever). Combined with a powerful introspection tool, cheating is a piece of cake. Game makers simply have to trust the user is not going to cheat, or if they do, that they are going to take responsibility for their own entertainment.