Gamefic

Adventure Games and Interactive Fiction

Building Your Game World

Anything that has a physical presence in the game world—a player, another character, a tool that players can use, a room, etc.—is called an entity. The two primary ways of creating entities are construct and make.

Entities can be of various types; for example, a Room entity is a space that other entities can occupy, while an Item entity is something that players can pick up and carry. In Ruby parlance, entity types are subclasses of the Gamefic::Entity class. The Standard Library provides several useful types, including the aforementioned Room and Item. Authors can also make their own entity types by subclassing Gamefic::Entity or another of its subclasses.

construct

The construct method defines an attribute method that references an entity:

module Mygame
  class Plot < Gamefic::Plot
    # ...

    construct :kitchen, Room, name: 'kitchen'
    construct :plate, Item, name: 'plate', parent: kitchen

    introduction do |actor|
      actor.parent = kitchen # Put the actor in the kitchen
      plate.parent = actor   # Give the plate to the actor
    end
  end
end

make

The make method is similar to construct but does not create a corresponding instance method. These are sometimes called “anonymous” entities.

make Item, name: 'plate'
make Fixture, name: 'mirror'
make Supporter, name: 'table'

Authors can use make to define entities at scripting time or create them dynamically during runtime. In the following example, the player can use the SPAWN command to create arbitrary items:

respond :spawn, plaintext do |actor, text|
  item = make Item, name: text
  actor.parent = item
  actor.tell "You now have #{an item}."
end

Example gameplay:

> spawn magic wand

You now have a magic wand.

> spawn dog biscuit

You now have a dog biscuit.

construct vs. make

There are a few important differences between construct and make that authors should consider when creating entities.

The construct method is a class method. It’s only available when you’re defining your plot’s static rules.

module Mygame
  class Plot < Gamefic::Plot
    # ...

    construct :home, Room, name: 'your home'

    introduction do |actor|
      actor.parent = home # This works because `home` was constructed at the class level

      construct :yard, Room, name: 'yard' # This raises an error because the introduction gets executed at runtime,
                                          # after the class-level scripts have already been executed
    end
  end
end

The make method works at both the class and instance levels. At the class level, the entity will be created when the plot gets initialized. In blocks that get executed at the instance level—e.g., introduction or respond blocks—the entity will be created dynamically at runtime when the plot executes the block.

module Mygame
  class Plot < Gamefic::Plot
    # ...

    # These entities are defined at the class level, so they get created when the plot gets initialized
    construct :home, Room, name: 'your home' # The instance attribute is `home`
    make Supporter, enterable: true, name: 'couch', parent: home # Note that `make` does not create an instance attribute

    # The introduction block runs at the start of the game, after the plot's been initialized
    introduction do |actor|
      actor.parent = couch # Error: The `couch` attribute does not exist

      actor.parent = pick!('couch') # OK: The `couch` attribute doesn't exist, but an entity named 'couch' does

      construct :book, Item, name: 'book', parent: home # Error: You can't use `construct` while the game is running

      make Item, name: 'book', parent: home # OK: The book will be created dynamically during the introduction
    end
  end
end

As a general rule, authors will usually want to create entities at the class level, e.g., the home and couch in the above example. Using construct will give your script blocks (e.g., the code inside the introduction) access to it via the specified attribute name (e.g., home). Using make will create an anonymous entity that doesn’t have a corresponding attribute method.

How do you decide whether to create an entity with an instance attribute via construct or an anonymous entity via make? It depends on whether or not you need to reference the entity elsewhere, such as making it another entity’s parent or using it as a required argument in an action. Example:

construct :home, Room, name: 'your home'
make Supporter, name: 'couch', enterable: true, parent: home

introduction do |actor|
  actor.parent = home
end

# This response prepends a message to a LOOK HOME command before continuing to
# the next applicable response.
respond :look, home do |actor|
  actor.tell 'You take a moment to admire your domicile...'
  actor.proceed
end

Next: Scripting