[Gamefic] Varying the description of a room?

What’s the easiest way to vary the description of a room depending on some value? Do I change a

respond :look, Query.new ... 

…and if so, what does the query look like (assuming I don’t want to make a custom class for the room)?

I’m hacking away at a Gamefic implementation of the Cloak of Darkness, by the way, just to try out the basics.

Hmm… I think you found a hole in the way the basic library handles looking at rooms. Unlike other objects, there’s no way to shape the query to change what look returns based on which room you’re in. There’s just a bare :look action that returns a description for your current location. You could override it with something like this, though:

exceptional_room = make Room, :name => "a room with a changing description"

# ...

respond :look do |actor|
  if actor.parent == exceptional_room
    # Code to give the player a dynamic description
  else
    passthru
  end
end

The passthru command will drop down into the parent action and keep executing.

Awesome! I’ll do my best to answer any questions and help you with bugs or missing features.

Aha, yes, that’s almost verbatim what I did. It doesn’t seem to cover the case when you get the description of the room printed when you walk into the room though, only when the player does an explicit “look”.

In general, I have a feeling that what I’d want to do all over the place is use Ruby’s capacity for passing blocks of codes as arguments. So that I’d say something like for handling such an such a command on this particular instance of a class, use this block: {…}

In this case, maybe one way out could be having a default “printing the description” method that just does an actor.tell with the description field, but you can override the method in subclasses (or maybe even instances).

Maybe something like this?


# The Describable class has an @describe field that stores a string or a proc
class Describable 
	attr_writer :descriptor
	def initialize(descriptor)
		@descriptor = descriptor
	end
	def describe
		if (@descriptor.is_a?(Proc)) then
			return @descriptor.call
		else 
			return @descriptor # assume it's a string
		end
	end
end

myItem = Describable.new("This is a description string.")
puts myItem.describe

# but now I can change it, to another string, or a proc! 

myItem.descriptor = proc {
	if rand(1..6) == 6 then
		"Something unexpected happens."
	else
		"Just the ordinary."
	end
}

puts myItem.describe

Entering a room triggered the description because there’s another action, :itemize_room, which is only ever used for that specific purpose. A short term solution is to override it:

respond :itemize_room, Query.new(:string) do |actor, option|
  # Code for displaying room description upon entering a room
end

In the long term, however, I think :itemize_room should not exist. I committed some changes to the repo that eliminate :itemize_room and make it easier to override :look actions that target the room. Something like this should work:

respond :look, Query.new(:parent) do |actor, room|
  # This method overrides the default action for looking at rooms
end

dark_room = make Room
respond :look, Query.new(:parent, dark_room) do |actor, room|
  # This method only overrides previous :look actions if the actor's parent is dark_room
end

The default :go action will now trigger a :look :parent instead.

That would make dynamic descriptions much easier, but it introduces a couple of other caveats. Foremost, it makes game data less portable to different engines, which does not affect anything in the current version, but has some side effects in some of the other WIP I have.

Fortunately, you can experiment with the idea in local scripts instead of modifying the core lib. I just tested it by putting this code in a game’s main.rb:

import 'basics'

class Entity
  def description
    result = nil
    if @description.kind_of?(Proc)
      result = @description.call
    else
      result = @description.to_s
    end
    result
  end
end

room = make Room, :name => 'a room'
box = make Item, :name => 'cardboard box', :description => 'Just a cardboard box.', :parent => room
crate = make Item, :name => 'wooden crate', :parent => room

crate.description = proc {
  "This description came from a proc at #{Time.now}"
}

introduction do |player|
  player.parent = room
end