[Solution] Lisp Game #49

S

Sean O'Halpin

I wasn't going to finish this but somehow I couldn't stop myself.... :)

It's not tested & debugged but I had to post it before I spent way too
much time on it.

Now if I can integrate it with IFMapper...

---- CODE ---

#$DEBUG_GAME =3D true
def dbg(*args)
puts *args if $DEBUG_GAME
end

class Object
def in?(container)
container.include?(self)
end
end

module Attributes
def has(*names)
self.class_eval {
names.each do |name|
# with args =3D setter
# without =3D getter
define_method(name) {|*args|
if args.size > 0
instance_variable_set("@#{name}", *args)
else
instance_variable_get("@#{name}")
end
}
# also define traditional setter=3D
define_method("#{name}=3D") {|*args|
instance_variable_set("@#{name}", *args)
}
end
}
end

end

module Directions
def directions(*directions)
directions.each do |name|
self.class.class_eval {
define_method(name) {
go(name)
}
}
end
end
end

class GameObject
extend Attributes
has :identifier, :name, :description
def initialize(identifier, &block)
@identifier =3D identifier
instance_eval &block
end
end

class Thing < GameObject
has :location, :portable

def initialize(identifier, &block)
# put defaults before super - they will be overridden in block (if at a=
ll)
# e.g. light, dark, etc.
@portable =3D true
super
end

end

class Room < GameObject
has :exits
end

class Game
include Directions

attr_accessor :name, :rooms, :location, :things

def initialize(name, &block)
@name =3D name
@rooms =3D {}
@things =3D {}

# read game definition
instance_eval &block

end

def room(identifier, &block)
@rooms[symbol(identifier)] =3D Room.new(symbol(identifier), &block)
end

def thing(identifier, &block)
@things[symbol(identifier)] =3D Thing.new(symbol(identifier), &block)
end

def match_thing(*identifiers)
thing =3D nil
identifiers.each do |identifier|
if thing =3D @things[identifier]
break
end
end
thing
end

def symbol(s)
s.to_s.to_sym
end

def start(room_identifier)
@location =3D @rooms[room_identifier]
end

def display_list(things)
if things.size > 2
things[0..-2].join(", ") + " and " + things[-1]
else
things.join(" and ")
end
end

def describe_path(direction, path)
"a #{path} going #{direction}"
end

def describe_exits(location)
"There is " + display_list(location.exits.map {|direction, (path,
destination)|
describe_path(direction, path)
}) + "."
end

def describe_floor(location)
things =3D @things.select{|key, thing| thing.location =3D=3D location.i=
dentifier}
if things.size > 0
"You can also see " + display_list(things.map{|key, thing| "a
#{thing.name}"}) + "."
else
""
end
end

def main_loop
print "> "
while input =3D gets
input.chomp!
case input
when 'exit', 'quit'
break
when 'help'
puts "Sorry pal! You're on your own here :)"
else
begin
#puts "#{input}"
tokens =3D input.split
cmd =3D tokens[0]
rest =3D tokens[1..-1].map{|x| x.to_sym}.reject{|x| x.in?
[:the, :to, :eek:n, :in, :a, :with]}
instance_eval { send(cmd, *rest) }
rescue Exception =3D> e
dbg e.to_s
puts "Eh?"
end
end
print "> "
end
end

# commands taking symbols

def in_location(location_id, thing_id)
@things[thing_id].location =3D=3D location_id
end

def is_here(thing_id)
in_location(@location.identifier, thing_id)
end

def player_has(thing_id)
in_location:)player, thing_id)
end

def player_in(location_id)
@location.identifier =3D=3D location_id
end

def move_to(location_id, thing_id)
@things[thing_id].location =3D location_id
end

def move_here(thing_id)
move_to(@location.identifier, thing_id)
end

def destroy(thing_id)
move_to:)nowhere, thing_id)
end

def pick_up(thing_id)
move_to:)player, thing_id)
end

# verbs

def look
puts location.description
puts describe_exits(location)
puts describe_floor(location)
end

def go(direction)
dest =3D @location.exits[direction]
if dest
@location =3D @rooms[dest[1]]
look
else
puts "You can't move in that direction"
end
end
alias :walk :go

def inventory
carried =3D @things.select{|key, thing| player_has(thing.identifier)}
puts "You are carrying " +
if carried.size > 0
"a #{display_list(carried.map{|key, thing| thing.name})}"
else
"nothing"
end
end
alias :i :inventory

def get(*args)
if thing =3D match_thing(*args)
if is_here(thing.identifier)
if thing.portable
pick_up(thing.identifier)
puts "OK - you picked up the #{thing.name}"
else
puts "You try and you try but you just can't pick up the
#{thing.name}"
end
else
puts "You can't see a #{thing.name} here"
end
else
puts "Get what?"
end
end
alias :take :get

def drop(*args)
if thing =3D match_thing(*args)
if player_has(thing.identifier)
move_here(thing.identifier)
puts "OK - you dropped the #{thing.name}"
else
"You're not carrying a #{thing.name}"
end
else
puts "Drop what?"
end
end

def examine(*args)
if obj =3D match_thing(*args)
if is_here(obj.identifier)
puts "Looks like #{obj.description}"
else
puts "You can't see that here"
end
else
puts "Don't know what you're talking about"
end
end
alias :exam :examine

end

def game(name, &block)
puts "Welcome to #{name}\n\n"
g =3D Game.new(name, &block)
g.look
g.main_loop
end

# Game definition

game "Ruby Adventure" do

directions :east, :west, :north, :south, :upstairs, :downstairs
alias :up :upstairs
alias :down :downstairs

# rooms

room :living_room do
name 'Living Room'
description "You are in the living-room of a wizard's house. There
is a wizard snoring loudly on the couch."
exits :west =3D> [:door, :garden],
:upstairs =3D> [:stairway, :attic]
end

room :garden do
name 'Garden'
description "You are in a beautiful garden. There is a well in
front of you."
exits :east =3D> [:door, :living_room]
end

room :attic do
name "Attic"
description "You are in the attic of the wizard's house. There is
a giant welding torch in the corner."
exits :downstairs =3D> [:stairway, :living_room]
end

start :living_room

# things

thing :wizard do
name "wizard"
description "a typical wizard - pointy hat, wand, unkempt beard,
smelly feet"
location :living_room
portable false
end

thing :self do
name "Yourself"
description "your same ol' ugly self"
portable false
end

thing :bottle do
name 'whiskey bottle'
description 'a half-empty whiskey bottle'
location :living_room
end

thing :bucket do
name 'bucket'
description 'a rusty bucket'
location :living_room
end

thing :welded_bucket do
name "bucket"
description "a bucket with a chain welded to it"
location :nowhere
end

thing :filled_bucket do
name "bucket"
description "a bucket full of water with a chain welded to it"
location :nowhere
end

# chain
thing :chain do
name 'chain'
description 'a sturdy iron chain'
location :garden
end

thing :frog do
name 'frog'
description 'a wide-mouthed frog'
location :garden
end

# verbs

def splash(*args)
thing, *rest =3D *args
if thing =3D=3D :wizard and player_in:)living_room) and
player_has:)filled_bucket)
if player_has:)frog)
puts "The wizard awakens and sees that you stole his frog. He
is so upset he banishes you to the netherworlds - you lose! The end."
break
else
puts "The wizard awakens from his slumber and greets you
warmly. He hands you the magic low-carb donut - you win! The end."
break
end
elsif thing =3D=3D :bucket
puts "The bucket has nothing in it"
else
puts "With what?"
end
end

def attach(*args)
subject, object, *rest =3D *args
if [subject, object].in?([[:chain, :bucket], [:bucket, :chain]])
and player_in:)attic) and player_has:)bucket) and player_has:)chain)
destroy:)bucket)
destroy:)chain)
pick_up:)welded_bucket)
puts "The chain is now securely welded to the bucket."
else
puts "Interesting..."
end
end
alias :weld :attach

def fill(*args)
thing, *rest =3D *args
if thing =3D=3D :bucket and player_in:)garden) and player_has:)welded_b=
ucket)
destroy:)welded_bucket)
pick_up:)filled_bucket)
puts "You have filled the bucket with water"
elsif thing =3D=3D :bucket
if player_in:)garden)
puts "You can't reach the water in the well. You'll need
something to lower the bucket down"
elsif player_has:)bucket)
puts "Fill it with what?"
else
puts "You don't have the bucket!"
end
else
puts "Hmmmm...."
end
end
alias :dunk :fill

end

__END__
get bucket
go west
get chain
east
upstairs
weld chain to bucket
down
west
fill bucket
east
splash wizard

--- END CODE ---

Regards,

Sean
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,763
Messages
2,569,562
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top