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).
# 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