Table of Contents for
Gaming Hacks

Version ebook / Retour

Cover image for bash Cookbook, 2nd Edition Gaming Hacks by Simon Carless Published by O'Reilly Media, Inc., 2004
  1. Cover
  2. Gaming Hacks
  3. Credits
  4. Contributors
  5. Acknowledgments
  6. Foreword
  7. Preface
  8. How to Use This Book
  9. How This Book Is Organized
  10. Conventions Used in This Book
  11. Using Code Examples
  12. Comments and Questions
  13. Got a Hack?
  14. 1. Playing Classic Games
  15. Legal Emulation
  16. Play Commodore 64 Games Without the C-64
  17. Play Atari ROMs Without the Atari
  18. Use Atari Paddles with Your PC
  19. Run Homebrew Games on the Atari 2600
  20. Create Your Own Atari 2600 Homebrew Games
  21. Play Classic PC Graphic Adventures
  22. Play Old Games Through DOSBox
  23. Play Reissued All-in-One Joystick Games
  24. Play Arcade Games Without the Arcade
  25. Add and Manipulate a MAME Frontend
  26. Keep Your ROMs Tidy and Organized
  27. Learn Game-Specific MAME Controls
  28. Filter Inappropriate MAME ROMs
  29. Autoboot into MAME Heaven
  30. Play Emulated Arcade Games Online
  31. Play Classic Pinball Without the Table
  32. Emulate the SNES on the Dreamcast
  33. 2. Playing Portably
  34. Play Games on Your iPod
  35. Mod Your Game Boy
  36. Take and Print Photos with Your Game Boy
  37. Compose Music on Your Game Boy
  38. Explore the GP32 Handheld Gaming System
  39. Take Your Console with You
  40. Explore the Bandai WonderSwan
  41. Play Real Games on Your PDA
  42. Install a PlayStation 2 in Your Car
  43. 3. Playing Well with Others
  44. Practice Proper MMORPG Etiquette
  45. Understand MMORPG Lingo
  46. Grind Without Going Crazy
  47. Make a Profit in Vana’diel
  48. Write MMORPG Macros
  49. Build an Effective Group
  50. Catch Half-Life FPS Cheaters Redhanded
  51. 4. Playing with Hardware
  52. Build a Quiet, Killer Gaming Rig
  53. Find and Configure the Best FPS Peripherals
  54. Adapt Old Video Game Controllers to the PC
  55. Choose the Right Audio/Video Receiver
  56. Place Your Speakers Properly
  57. Connect Your Console to Your Home Theater
  58. Tune Console Video Output
  59. Tune Your TV for Console Video
  60. PC Audio Hacking
  61. Optimize PC Video Performance
  62. Build a Dedicated Multimedia PC
  63. Use a Multimedia Projector for Gaming
  64. 5. Playing with Console and Arcade Hardware
  65. Play LAN-Only Console Games Online
  66. Hack the Nuon DVD Player/Gaming System
  67. Play Import Games on American Consoles
  68. Find a Hackable Dreamcast
  69. Play Movies and Music on Your Dreamcast
  70. Hack the Dreamcast Visual Memory Unit
  71. Unblur Your Dreamcast Video
  72. Use Your Dreamcast Online
  73. Host Dreamcast Games Online
  74. Burn Dreamcast-Compatible Discs on Your PC
  75. Burn Dreamcast Homebrew Discs
  76. Buy Your Own Arcade Hardware
  77. Configure Your Arcade Controls, Connectors, and Cartridges
  78. Reorient and Align Your Arcade Monitor
  79. Buy Cart-Based JAMMA Boards
  80. Programming Music for the Nintendo Entertainment System
  81. 6. Playing Around the Game Engine
  82. Explore Machinima
  83. Choose a Machinima Engine
  84. Film Your First Machinima Movie
  85. Improve Your Camera Control
  86. Record Game Footage to Video
  87. Speedrun Your Way Through Metroid Prime
  88. Sequence-Break Quake
  89. Run Classic Game ROM Translations
  90. Change Games with ROM Hacks
  91. Apply ROM Hacks and Patches
  92. Create PS2 Cheat Codes
  93. Hack Xbox Game Saves
  94. Cheat on Other Consoles
  95. Modify PC Game Saves and Settings
  96. Buff Your Saved Characters
  97. Create Console Game Levels
  98. 7. Playing Your Own Games
  99. Adventure Game Studio Editing Tips
  100. Create and Play Pinball Tables
  101. Put Your Face in DOOM
  102. Create a Vehicle Model for Unreal Tournament 2004
  103. Add a Vehicle to Unreal Tournament 2004
  104. Modify the Behavior of a UT2004 Model
  105. Download, Compile, and Create an Inform Adventure
  106. Decorate Your IF Rooms
  107. Add Puzzles to Your IF Games
  108. Add Nonplayer Characters to IF Adventures
  109. Make Your IF NPCs Move
  110. Make Your IF NPCs Talk
  111. Create Your Own Animations
  112. Add Interactivity to Your Animations
  113. Write a Game in an Afternoon
  114. 8. Playing Everything Else
  115. Tweak Your Tactics for FPS Glory
  116. Beat Any Shoot-Em-Up
  117. Drive a Physics-Crazed Motorcycle
  118. Play Japanese Games Without Speaking Japanese
  119. Back Up, Modify, and Restore PlayStation Saved Games
  120. Access Your Console’s Memory Card Offline
  121. Overclock Your Console
  122. Index
  123. Colophon

Add Puzzles to Your IF Games

Challenge, guide, and tease—but don’t frustrate—your players.

IF games are often also called adventure games. Ask Infocom aficionados about their favorite moments, and they might mention the diamond puzzle in Zork II or the Babelfish puzzle from The Hitchhiker’s Guide to the Galaxy. Conflict is the heart of drama. Unless you’re creating an experimental new form of interactive fiction, you need to introduce some sort of conflict for the player to experience and overcome.

The canonical way to do that is to add a puzzle.

Designing the Puzzle

Let’s add a puzzle to the Inform adventure created in [Hack #85] and decorated in [Hack #86] .

The meat of the puzzle lies in the Scanner room. Here, the player must adjust both the analysis nets and the eye catalog—the lock and the key—to match each other. The nets then open, releasing an identity token. The player can take the token, hand it to the access controller (back in the Router), and be on his way.

To support these actions, you’ll need an analysis nets object and a way to make it change color (as the catalog does). For variety’s sake, let’s implement this as two game objects: the nets and a separate selector that changes the color setting:

Object nets "analysis nets" Scanner,
  with
    name 'array' 'arrays' 'image' 'analysis' 'image-analysis' 'net' 'nets',
    description [;
        print "Arrays of image-analysis nets hang around the sensor
            fountain, ready to accept and identify eyeprint data, should
            any arrive. A ";
        selector.colorname( );
        " identity selector hangs off the nets.";
    ],
  has scenery container open pluralname;

Object selector "identity selector" Scanner,
  with
    name 'id' 'identity' 'selector',
    article "an",
    color 0,
    colorname [;
        switch (self.color) {
            0: print "chartreuse";
            1: print "crimson";
            2: print "topaz";
            3: print "copper";
            4: print "pink";
        }
    ],
    description [;
        print "The selector indicates which meat-person the retinal
            scanner is trying to identify. Normally it would
            adjust itself to the datastream coming through the
            scanner -- but you can probably move it yourself, from
            in here. The selector is currently ";
        self.colorname( );
        ".";
    ],
    before [;
        Turn:
            self.color++;
            if (self.color >= 5)
                self.color = 0;
            print "Click. The identity selector turns ";
            self.colorname( );
            ".";
        Push, Pull, Set:
            <<Turn self>>;
    ],
  has scenery;

Tip

Variety is not the sole reason to separate the objects. The nets, unlike the catalog, aren’t part of the spy’s toolkit. They are unfamiliar. You must still clue the player in on how to change the net’s color, but try to convey this information as an observation, not an ingrained habit. Therefore, the action must be straightforward. By bringing a distinct selector to the player’s attention, you invite experimentation. Any selector will have a way to select.

Most of this is familiar. The nets have the container and open attributes. The standard library can handle actions appropriate to a container (look in nets, put something in nets, take something from nets, and so on). The container attribute ordains these, and open indicates that the container is open, so you can see inside.

Tip

For once, you don’t need article "an" on the analysis nets. This is because the nets also have pluralname, and so the library refers to them as some analysis nets.

The selector has color and colorname properties, just like those of the catalog, though there are only five colors. (There are five authorized meat-people for this retinal scanner, no doubt.) Notice that the nets.description function invokes selector.colorname(); you can see the selector’s color no matter which of the two parts you examine.

The selector responds to a different action; you don’t Squeeze it, you Turn it. Let’s be generous about this, though, because you want your spy to realize how to use this device; you certainly don’t want the player fumbling around, trying to guess the right command. So you accept Push, Pull, and Set actions as well. These three cases execute <<Turn self>>. This statement begins a new action and then returns true so that the previous action ends. The preceding case catches the new Turn action, and so all four commands become synonyms.

Tip

The selector’s description hints that the player should move the selector. Shouldn’t you include that action also? Certainly—and you have. The standard Inform library interprets move as a Push action.

Restricted Treasure

It’s time to create the identity token, which is the goal of this whole scene. It’s a straightforward object:

Object token "identity token" nets,
  with
    name 'id' 'identity' 'token',
    article "an",
    description "This denotes an identity within the system, validated
        by biometric data. (Why can't meat-people just have built-in
        crypto-keys? You've never understood it.)";

The token begins inside the nets. The challenge is to remove it. However, the player won’t know there’s a challenge unless she sees the token. It’s not listed in the room description. It’s present: you can examine it and even try look in nets, but that’s not good enough. The situation must be clear, or the player won’t ever know that she’s missing an object.

Let’s do this the simplest possible way by adding code to the room description. Change the Scanner’s description:

Object Scanner "Scanner South-9",
  has light,
  with
    description [;
        print "The firmware here is tight and clean; this device, at
            least, is well-maintained. You can see image-analysis nets
            strung in their neat rows around the sensor fountain which
            dominates this space. The only exit is the serial line to the
            north.^";
        if (token in nets)
            print "^You see an identity token caught in the image nets.^";
        rtrue;
    ],
    n_to Router;

The first paragraph of text is the same, except that, because this is a print statement, you need an explicit line break. Then, if the token is still within the nets, you print an additional line. This has a line break before and after to conform to Inform’s formatting rules, which mandate a blank line between paragraphs.

Tip

This simple room description hack is sufficient, because in this game, the nets contain either the token or nothing. If there were several objects in there, you’d need a series of print statements—tedious to write and also hard for the player to read. In that case, it’s better to use the library’s WriteListFrom function to write an arbitrary list of contents as a nice grammatical sentence.

If you’ve compiled the current version of the code, you’ve probably noticed the next flaw: taking the identity token is easy! Nothing prevents the player from typing take token and walking away with it, without ever solving the color-matching lock-and-key puzzle at all.

You can fix this several ways. You could customize the token’s Take action, for example. However, that actually leaves loopholes open. There are several library actions that can extract an object from a container: Take is only the most common.

Conveniently, all these extraction actions check the container’s LetGo action first. (The container really is the best place for this code, anyway. If there were several identity tokens in the nets, you’d want to write a single LetGo test on the nets object, rather than having to modify the Take action of every token.)

So, add these two properties to the nets object:

accessed false,
before [;
    LetGo:
        if (self.accessed =  = false)
            "The nets have not validated a retinal pattern; they
                refuse to yield the token to you.";
],

The accessed property is another custom job, not defined by the library. You can define it however you like. It’s best, of course, as a logical value that tells whether the nets are open.

The LetGo action does not result directly from a player command, as do Take, Turn, and Squeeze. It is part of any action that removes something from a container. Nonetheless, you can customize it the same way: in this before property, check the accessed value; if it’s not true, print a grim refusal. As usual, the bare-string statement returns true, ending the entire action. If self.accessed is true, the LetGo case ends, returning the default false value, and you’ll see the default behavior: the game allows the player to take the token.

Now you just need the command with which the player actually opens the analysis net, using his handy eye catalog.

What command should this be? Several possibilities might make sense. You don’t want it to be too hard to guess, so let’s take a straightforward command: put catalog in nets. This captures the idea that you’re inserting false data into the analysis network.

Again, you can customize the Insert action of the token, but it’s cleaner to customize the Receive action of the nets instead. Receive is the converse of LetGo; it is part of any action that places an object in (or on) a container. (By putting the code in Receive, you’ll recognize put catalog on nets as well as put catalog in nets. That’s good.)

Extend the nets.before property:

before [;
    Receive:
        if (noun =  = catalog) {
            if (self.accessed) {
                "The nets have already validated your identity.
                    Well, not YOUR identity, but somebody's.";
            }
            print "A wave of ";
            catalog.colorname( );
            print " data flows into the analysis nets. They absorb
                it hungrily";
            if (catalog.color =  = 3 && selector.color =  = 1) {
                self.accessed = true;
                "... and then untangle themselves, unveiling
                    the identity token. It is now free for
                    the taking.";
            }
            else {
                "... and then tear it to monochrome
                    meaningless bits.";
            }
        }
        "The nets do not accept your offer.";
    LetGo:
        if (self.accessed =  = false)
            "The nets have not validated a retinal pattern; they
                refuse to yield the token to you.";
],

This is the longest block of code yet; it has a lot of work to do.

The only object the nets accept is the catalog. If the player tries to insert anything else, the Receive case skips down to its last line, rejecting the offer. The bare string prints and returns. Let’s take the opportunity to add some anthropomorphism; the net description makes them sound as if they’re sentient. Are they? Ambiguity is all part of the fun.

The Receive action has to discriminate what the nets receive. For this, check the noun global variable. During a before routine, noun holds the object of the action (and second holds the secondary object, if there is one).

Within the if (noun = = catalog) case, first check the code if the puzzle has already been solved. Once you open the nets (and accessed is true), you don’t want the player to repeat the action. Another bare string returns true.

Tip

If you allow repeats, you have to add even more code to print an appropriate message:

The nets untangle themselves again.

Note

Plus, what happens if the player enters a wrong combination after the right one? Does the net lock away the token again? The puzzle would have more solidity if you added all this code, but in the interest of brevity, let’s just block the player from even trying to repeat the action. This doesn’t feel unduly restrictive, because once the player has the token, she’ll be more eager to use it than to keep playing around with the retinal scanner.

Now you know the player really has used the catalog on the nets. Print the first part of the message:

A wave of bright gold data flows into the analysis nets. They absorb it hungrily.

Of course, you call catalog.colorname to discover the catalog’s current color; that’s the fraudulent data the player is inserting into the analysis stream.

The second print statement ends with hungrily, with no punctuation or space following it. This is handy, because you can follow it up with anything: a period, comma, ellipsis, or and.

There are two possible cases. Either the player has chosen the right colors or she hasn’t. The catalog’s list of six colors and the analysis nets’ list of five overlap just once, at crimson. If catalog.color is 3, and selector.color is 1, there’s a match. Set the accessed flag to true, and print a triumphant message. Otherwise, indicate failure. (The failure message slyly hints that color is significant.)

That covers everything. Note that every case ends with a bare-string statement, which implicitly returns true to stop the action.

Tip

If you see the game printing multiple cases in response to a single action, it means you forgot something; you used a print statement where you should have used a bare string.

On Sensor Fountains

The Scanner room needs one more feature. The room description mentions the sensor fountain, so you should certainly implement it. On the other hand, the fountain has no purpose in the game. Its purpose in the game world is to digitize an actual retinal print and transfer it to the analysis nets, but no actual humans will wander by during the scene.

Let’s add a description. Do you need to react to any commands? Yes. When the player decides to introduce his catalog’s data into the retinal scanner, he might type put sphere in fountain. That makes just as much sense as put sphere in nets; after all, the whole point of the fountain is to send data to the nets.

You can do this by duplicating the code from the Receive action of the nets, but it’s easier to generate a new action using the statement <<Insert catalog nets>>; this behaves just as if the player had typed put catalog in nets.

Object fountain "sensor fountain" Scanner,
  with
    name 'sensor' 'fountain',
    description
        "It's a common sensor interface -- a spot where data from
        meat-side gushes up into the world. This fountain
        is fed by the retinal scanner you're inhabiting. If a
        meatsider presses his squashy eyeball against it, a torrent
        of digitized eyeprint data will flow from the fountain
        into the waiting analysis nets.",
    before [;
        Receive:
            if (noun =  = catalog)
                <<Insert catalog nets>>;
    ],
  has scenery;