| | 1 | #charset "us-ascii" |
| | 2 | |
| | 3 | /* |
| | 4 | * Copyright (c) 1999, 2002 by Michael J. Roberts. Permission is |
| | 5 | * granted to anyone to copy and use this file for any purpose. |
| | 6 | * |
| | 7 | * This is a starter TADS 3 source file. This is a complete TADS game |
| | 8 | * that you can compile and run. |
| | 9 | * |
| | 10 | * To compile this game in TADS Workbench, open the "Build" menu and |
| | 11 | * select "Compile for Debugging." To run the game, after compiling it, |
| | 12 | * open the "Debug" menu and select "Go." |
| | 13 | * |
| | 14 | * Please note that this file contains considerably more than the |
| | 15 | * minimal set of definitions necessary to create a working game; this |
| | 16 | * file has numerous examples meant to help you start making progress on |
| | 17 | * your game more quickly, by giving you a few concrete examples that |
| | 18 | * you can copy and modify. As you flesh out your game, you should |
| | 19 | * modify the objects we define here, or simply remove them when you no |
| | 20 | * longer need them in your game. |
| | 21 | * |
| | 22 | * If you want a truly minimal set of definitions, create another new |
| | 23 | * game in TADS Workbench, and choose the "advanced" version when asked |
| | 24 | * for the type of starter game to create. |
| | 25 | */ |
| | 26 | |
| | 27 | /* |
| | 28 | * Include the main header for the standard TADS 3 adventure library. |
| | 29 | * Note that this does NOT include the entire source code for the |
| | 30 | * library; this merely includes some definitions for our use here. The |
| | 31 | * main library must be "linked" into the finished program by including |
| | 32 | * the file "adv3.tl" in the list of modules specified when compiling. |
| | 33 | * In TADS Workbench, simply include adv3.tl in the "Source Files" |
| | 34 | * section of the project. |
| | 35 | * |
| | 36 | * Also include the US English definitions, since this game is written |
| | 37 | * in English. |
| | 38 | */ |
| | 39 | #include <adv3.h> |
| | 40 | #include <en_us.h> |
| | 41 | |
| | 42 | /* |
| | 43 | * Our game credits and version information. This object isn't required |
| | 44 | * by the system, but our GameInfo initialization above needs this for |
| | 45 | * some of its information. |
| | 46 | * |
| | 47 | * IMPORTANT - You should customize some of the text below, as marked: |
| | 48 | * the name of your game, your byline, and so on. |
| | 49 | */ |
| | 50 | versionInfo: GameID |
| | 51 | IFID = '2e201e44-1da4-d9fb-b4b7-2b4db5bb9903' |
| | 52 | name = 'Your New Game Title' |
| | 53 | byline = 'by Your Name' |
| | 54 | htmlByline = 'by <a href="mailto:your-email@host.com"> |
| | 55 | Your Name</a>' |
| | 56 | version = '1' |
| | 57 | authorEmail = 'Your Name <your-email@host.com>' |
| | 58 | desc = 'Put a brief "blurb" about your game here.' |
| | 59 | htmlDesc = 'Put a brief "blurb" about your game here.' |
| | 60 | |
| | 61 | /* |
| | 62 | * other bibliographic tags you might want to set include: |
| | 63 | * |
| | 64 | *. headline = 'An Interactive Sample' |
| | 65 | *. seriesName = 'The Sample Trilogy' |
| | 66 | *. seriesNumber = 1 |
| | 67 | *. genreName = 'Sample Games' |
| | 68 | *. forgivenessLevel = 'Polite' |
| | 69 | *. gameUrl = 'http://mysite.com/mygame.htm' |
| | 70 | *. firstPublished = '2006' |
| | 71 | *. languageCode = 'en-US' |
| | 72 | *. licenseType = 'Freeware' |
| | 73 | *. copyingRules = 'Nominal cost only; compilations allowed' |
| | 74 | *. presentationProfile = 'Default' |
| | 75 | */ |
| | 76 | |
| | 77 | showCredit() |
| | 78 | { |
| | 79 | /* show our credits */ |
| | 80 | "Put credits for the game here. "; |
| | 81 | |
| | 82 | /* |
| | 83 | * The game credits are displayed first, but the library will |
| | 84 | * display additional credits for library modules. It's a good |
| | 85 | * idea to show a blank line after the game credits to separate |
| | 86 | * them visually from the (usually one-liner) library credits |
| | 87 | * that follow. |
| | 88 | */ |
| | 89 | "\b"; |
| | 90 | } |
| | 91 | showAbout() |
| | 92 | { |
| | 93 | "Put information for players here. Many authors like to mention |
| | 94 | any unusual commands here, along with background information on |
| | 95 | the game (for example, the author might mention that the game |
| | 96 | was created as an entry for a particular competition). "; |
| | 97 | } |
| | 98 | ; |
| | 99 | |
| | 100 | /* |
| | 101 | * Entryway location. |
| | 102 | * |
| | 103 | * We use the class "Room" to define the location. Room is a class, |
| | 104 | * defined in the library, that can be used for most of the locations in |
| | 105 | * the game. |
| | 106 | * |
| | 107 | * Our definition defines two strings. The first string, which must be |
| | 108 | * in single quotes, is the "name" of the room; the name is displayed on |
| | 109 | * the status line and each time the player enters the room. The second |
| | 110 | * string, which must be in double quotes, is the "description" of the |
| | 111 | * room, which is a full description of the room. This is displayed |
| | 112 | * when the player types "look around," when the player first enters the |
| | 113 | * room, and any time the player enters the room when playing in VERBOSE |
| | 114 | * mode. |
| | 115 | */ |
| | 116 | entryway: Room 'Entryway' |
| | 117 | "This large, formal entryway is slightly intimidating: |
| | 118 | the walls are lined with somber portraits of gray-haired |
| | 119 | men from decades past; a medieval suit of armor<<describeAxe>> |
| | 120 | towers over a single straight-backed wooden chair. The |
| | 121 | front door leads back outside to the south. A hallway leads |
| | 122 | north. " |
| | 123 | |
| | 124 | /* |
| | 125 | * In the description text above, we embedded the expression |
| | 126 | * "describeAxe". Whenever the description text is displayed, it |
| | 127 | * will call evaluate that expression, which will in turn call this |
| | 128 | * method, where we'll generate some additional text to describe the |
| | 129 | * axe if it's still part of the suit of armor. |
| | 130 | */ |
| | 131 | describeAxe |
| | 132 | { |
| | 133 | if (axe.isIn(suitOfArmor)) |
| | 134 | ", posed with a battle axe at the ready,"; |
| | 135 | } |
| | 136 | |
| | 137 | /* |
| | 138 | * To the north is the hallway. Set the "north" property to the |
| | 139 | * destination room object. Other direction properties that we |
| | 140 | * could set: east, west, north, up, down, plus the diagonals: |
| | 141 | * northeast, northwest, southeast, southwest. We can also set "in" |
| | 142 | * and "out", and the shipboard directions port, starboard, fore, |
| | 143 | * and aft. |
| | 144 | */ |
| | 145 | north = hallway |
| | 146 | |
| | 147 | /* |
| | 148 | * To the south is the front door. A travel direction link can |
| | 149 | * point directly to another room, but it can also point to |
| | 150 | * something like a door. |
| | 151 | */ |
| | 152 | south = frontDoor |
| | 153 | |
| | 154 | /* |
| | 155 | * The "out" direction is the same as south, since going south leads |
| | 156 | * outside |
| | 157 | */ |
| | 158 | out = frontDoor |
| | 159 | ; |
| | 160 | |
| | 161 | /* |
| | 162 | * Define the front door. The "+" sign in front of the definition means |
| | 163 | * that the object is located within the most recently defined room, |
| | 164 | * which in this case is 'entryway' as defined above. |
| | 165 | * |
| | 166 | * We start this object definition with two strings, both in single |
| | 167 | * quotes, and a third in double quotes. The first is the vocabulary |
| | 168 | * list for the object, which tells us how the player can refer to this |
| | 169 | * object. The second string is the name, which is how the game refers |
| | 170 | * to the object in generated messages. The third is the full |
| | 171 | * description of the object, which is displayed when the player |
| | 172 | * examines this object. |
| | 173 | * |
| | 174 | * The vocabulary list consists of any number of words separated by |
| | 175 | * spaces. Every word is an adjective except the last, which is a noun. |
| | 176 | * You can specify more than one noun by listing several nouns separated |
| | 177 | * by slash characters ("/"). The player can use any of the words |
| | 178 | * defined here to refer to the object - the player doesn't have to use |
| | 179 | * all of the words, or use them in the same order that we define them |
| | 180 | * here, except that adjectives and nouns must be in the grammatically |
| | 181 | * correct order (in English, this means that adjectives must precede |
| | 182 | * nouns). |
| | 183 | */ |
| | 184 | + frontDoor: Door 'front door' 'front door' |
| | 185 | "It's a heavy wooden door, currently closed. " |
| | 186 | |
| | 187 | /* the door is initially closed */ |
| | 188 | initiallyOpen = nil |
| | 189 | |
| | 190 | /* |
| | 191 | * Doors can usually be opened, but we don't want to allow this one |
| | 192 | * to be opened. The library by default allows a door to be opened |
| | 193 | * and closed at will. To change this, we must override the "direct |
| | 194 | * object" handler for the Open action on this object. Since we |
| | 195 | * don't want anything to happen when the player tries to open the |
| | 196 | * door, we can simply override the action handler and display a |
| | 197 | * message indicating why we can't open the door. |
| | 198 | */ |
| | 199 | dobjFor(Open) |
| | 200 | { |
| | 201 | action() { "You'd rather stay in the house for now. "; } |
| | 202 | } |
| | 203 | ; |
| | 204 | |
| | 205 | /* |
| | 206 | * Define the chair. We use the Chair class for this. Note that the |
| | 207 | * default Chair class defines a moveable object; we don't want our chair |
| | 208 | * going anywhere, so make it use the Immovable class as well. |
| | 209 | * |
| | 210 | * We don't need to refer to the chair anywhere, so we don't bother |
| | 211 | * giving it a name. This saves us a little typing and saves us the |
| | 212 | * trouble of thinking of a name for the object. |
| | 213 | */ |
| | 214 | + Chair, Immovable 'straight-backed wooden chair' 'wooden chair' |
| | 215 | "It looks like one of those formal chairs that looks elegant |
| | 216 | but is incredibly uncomfortable to sit on. " |
| | 217 | ; |
| | 218 | |
| | 219 | /* |
| | 220 | * Define the suit of armor. It can't be moved because it's very heavy, |
| | 221 | * so make it a Heavy object. Note that we do need to refer to this |
| | 222 | * object (in the 'entryway' object), so we need to give it an object |
| | 223 | * name. |
| | 224 | * |
| | 225 | * Note that we define both "suit" and "armor" as nouns in our vocabulary |
| | 226 | * list, because we want to be able to refer to it as "suit of armor"; in |
| | 227 | * the phrasing "x of y", both x and y are noun phrases. |
| | 228 | */ |
| | 229 | + suitOfArmor: Heavy 'medieval plate-mail suit/armor' 'suit of armor' |
| | 230 | "It's a suit of plate-mail armor that looks suitable for |
| | 231 | a very tall knight. <<describeAxe>> " |
| | 232 | |
| | 233 | /* |
| | 234 | * as we did in entryway's description, we've embedded a call to our |
| | 235 | * describeAxe method, so that we can add a description of the axe |
| | 236 | * if appropriate |
| | 237 | */ |
| | 238 | describeAxe |
| | 239 | { |
| | 240 | if (axe.isIn(self)) |
| | 241 | "The armor is posed with a huge battle-axe held |
| | 242 | at the ready. "; |
| | 243 | } |
| | 244 | ; |
| | 245 | |
| | 246 | /* |
| | 247 | * The battle axe, initially posed with the suit of armor. We make this |
| | 248 | * a Thing, because we want it to be something the player can pick up |
| | 249 | * and manipulate. |
| | 250 | * |
| | 251 | * This definition starts with two "+" signs, to indicate that it is |
| | 252 | * initially inside the last object defined with one "+" sign, which is |
| | 253 | * the suit of armor. |
| | 254 | * |
| | 255 | * Note that we define a bunch of vocabulary words that aren't really |
| | 256 | * synonyms for "axe," but are for things we describe as parts of the |
| | 257 | * axe (the blade, the dried blood on the blade). Those parts aren't |
| | 258 | * worth defining as separate objects, but we can at least recognize |
| | 259 | * them as vocabulary words that simply refer to the axe itself. |
| | 260 | */ |
| | 261 | ++ axe: Thing 'large steel battle dried ax/axe/blade/edge/blood' 'battle axe' |
| | 262 | "It's a large steel battle axe. A little bit of dried blood on |
| | 263 | the edge of the blade makes the authenticity of the equipment |
| | 264 | quite credible. " |
| | 265 | |
| | 266 | /* |
| | 267 | * When we're located in the suit of armor, the suit of armor and |
| | 268 | * the room containing the suit of armor describe us specially. |
| | 269 | * This means that we do not want to display our name among the |
| | 270 | * miscellaneous items listed in the room's description. To prevent |
| | 271 | * being listed in the ordinary description, indicate that we have a |
| | 272 | * "special" description any time we're located in the suit of |
| | 273 | * armor, and then make this special desription show nothing - it's |
| | 274 | * not necessary to show anything because the room and suit of armor |
| | 275 | * both already show something special for us. |
| | 276 | */ |
| | 277 | useSpecialDesc = (isIn(suitOfArmor)) |
| | 278 | specialDesc = "" |
| | 279 | ; |
| | 280 | |
| | 281 | /* |
| | 282 | * Define the portraits. We don't want to define several individual |
| | 283 | * portraits, because they're not important enough, so define a single |
| | 284 | * object that refers to the portraits collectively. |
| | 285 | * |
| | 286 | * Because the library normally allows the player to abbreviate any word |
| | 287 | * to its first six or more letters, note that we don't have to provide |
| | 288 | * separate vocabulary words for "portrait" and "portraits", or for |
| | 289 | * "picture" and "pictures" - "portrait" is an acceptable abbreviation |
| | 290 | * for "portraits". |
| | 291 | */ |
| | 292 | + Fixture 'somber gray-haired portraits/pictures/men/man' 'portraits' |
| | 293 | "The men in the portraits look like bankers or businessmen, all |
| | 294 | serious faces and old-fashioned suits. " |
| | 295 | |
| | 296 | /* |
| | 297 | * this object has a plural name, so we must set the isPlural flag |
| | 298 | * to let the library know how to use its name in messages |
| | 299 | */ |
| | 300 | isPlural = true |
| | 301 | ; |
| | 302 | |
| | 303 | /* |
| | 304 | * The hallway, north of the entryway. |
| | 305 | */ |
| | 306 | hallway: Room 'Hallway' |
| | 307 | "This broad, dimly-lit corridor runs north and south. " |
| | 308 | |
| | 309 | south = entryway |
| | 310 | north = kitchen |
| | 311 | ; |
| | 312 | |
| | 313 | /* |
| | 314 | * The kitchen. |
| | 315 | */ |
| | 316 | kitchen: Room 'Kitchen' |
| | 317 | "This is a surprisingly cramped kitchen, equipped with |
| | 318 | antique accoutrements: the stove is a huge black iron contraption, |
| | 319 | and in place of a refrigerator is an actual icebox. A hallway |
| | 320 | lies to the south. " |
| | 321 | |
| | 322 | south = hallway |
| | 323 | ; |
| | 324 | |
| | 325 | /* |
| | 326 | * The stove is a Fixture, since we don't want the player to be able to |
| | 327 | * move it. It's also an OpenableContainer, because we want the player |
| | 328 | * to be able to open and close it and put things in it. |
| | 329 | * |
| | 330 | * Note that we define 'stove' as both an adjective and as a noun, |
| | 331 | * because we want the player to be able to refer to it not only as a |
| | 332 | * "stove" but also as a "stove door". |
| | 333 | * |
| | 334 | * Because we're an OpenableContainer, the library will automatically add |
| | 335 | * to our description text an open/closed indication and a listing of any |
| | 336 | * contents when we're open. |
| | 337 | */ |
| | 338 | + Fixture, OpenableContainer |
| | 339 | 'huge black iron stove stove/oven/contraption/door' 'stove' |
| | 340 | "It's a huge black iron cube, with a front door that swings |
| | 341 | open sideways. " |
| | 342 | |
| | 343 | /* it's initially closed */ |
| | 344 | initiallyOpen = nil |
| | 345 | ; |
| | 346 | |
| | 347 | /* |
| | 348 | * Put a loaf of bread in the stove. It's edible, so use the library |
| | 349 | * class Food. |
| | 350 | */ |
| | 351 | ++ Food 'fresh golden-brown brown loaf/bread/crust' 'loaf of bread' |
| | 352 | "It's a fresh loaf with a golden-brown crust. " |
| | 353 | |
| | 354 | /* |
| | 355 | * we want to provide a special message when we eat the bread, so |
| | 356 | * override the direct object action handler for the Eat action; |
| | 357 | * inherit the default handling, but also display our special |
| | 358 | * message, which will automatically override the default message |
| | 359 | * that the base class produces |
| | 360 | */ |
| | 361 | dobjFor(Eat) |
| | 362 | { |
| | 363 | action() |
| | 364 | { |
| | 365 | /* inherit the default handling */ |
| | 366 | inherited(); |
| | 367 | |
| | 368 | /* show our special description */ |
| | 369 | "You tear off a piece and eat it; it's delicious. You tear off |
| | 370 | a little more, then a little more, and before long the whole loaf |
| | 371 | is gone. "; |
| | 372 | } |
| | 373 | } |
| | 374 | ; |
| | 375 | |
| | 376 | /* |
| | 377 | * The icebox is similar to the stove. |
| | 378 | */ |
| | 379 | + Fixture, OpenableContainer 'ice box/icebox' 'icebox' |
| | 380 | "Before there were refrigerators, people had these: it's just |
| | 381 | a big insulated box, into which one would put perishables |
| | 382 | along with enough ice to keep the perishables chilled for a few |
| | 383 | days. " |
| | 384 | |
| | 385 | /* |
| | 386 | * when looking in the icebox, explicitly point out that it contains |
| | 387 | * no ice; do this by overriding the LookIn action handler, |
| | 388 | * inheriting the default handling and adding our own message |
| | 389 | */ |
| | 390 | dobjFor(LookIn) |
| | 391 | { |
| | 392 | action() |
| | 393 | { |
| | 394 | /* show the default description */ |
| | 395 | inherited(); |
| | 396 | |
| | 397 | /* add a note that there's no ice, after a paragraph break */ |
| | 398 | "<.p>It's been a long time since any ice was in there. "; |
| | 399 | } |
| | 400 | } |
| | 401 | ; |
| | 402 | |
| | 403 | /* |
| | 404 | * Define the player character. The name of this object is not |
| | 405 | * important, but note that it has to match up with the name we use in |
| | 406 | * the main() routine to initialize the game, below. |
| | 407 | * |
| | 408 | * Note that we aren't required to define any vocabulary or description |
| | 409 | * for this object, because the class Actor, defined in the library, |
| | 410 | * automatically provides the appropriate definitions for an Actor when |
| | 411 | * the Actor is serving as the player character. Note also that we |
| | 412 | * don't have to do anything special in this object definition to make |
| | 413 | * the Actor the player character; any Actor can serve as the player |
| | 414 | * character, and we'll establish this one as the PC in main(), below. |
| | 415 | */ |
| | 416 | me: Actor |
| | 417 | /* the initial location is the entryway */ |
| | 418 | location = entryway |
| | 419 | ; |
| | 420 | |
| | 421 | /* |
| | 422 | * The "gameMain" object lets us set the initial player character and |
| | 423 | * control the game's startup procedure. Every game must define this |
| | 424 | * object. For convenience, we inherit from the library's GameMainDef |
| | 425 | * class, which defines suitable defaults for most of this object's |
| | 426 | * required methods and properties. |
| | 427 | */ |
| | 428 | gameMain: GameMainDef |
| | 429 | /* the initial player character is 'me' */ |
| | 430 | initialPlayerChar = me |
| | 431 | |
| | 432 | /* |
| | 433 | * Show our introductory message. This is displayed just before the |
| | 434 | * game starts. Most games will want to show a prologue here, |
| | 435 | * setting up the situation for the player, and show the title of the |
| | 436 | * game. |
| | 437 | */ |
| | 438 | showIntro() |
| | 439 | { |
| | 440 | "Welcome to the TADS 3 Starter Game!\b"; |
| | 441 | } |
| | 442 | |
| | 443 | /* |
| | 444 | * Show the "goodbye" message. This is displayed on our way out, |
| | 445 | * after the user quits the game. You don't have to display anything |
| | 446 | * here, but many games display something here to acknowledge that |
| | 447 | * the player is ending the session. |
| | 448 | */ |
| | 449 | showGoodbye() |
| | 450 | { |
| | 451 | "<.p>Thanks for playing!\b"; |
| | 452 | } |
| | 453 | ; |