#
# file:: room.rb
# author:: Jon A. Lambert
# version:: 2.10.0
# date:: 06/25/2006
#
# Additional Contributor: Craig Smith
#
# This source code copyright (C) 2005, 2006 by Jon A. Lambert
# All rights reserved.
#
# Released under the terms of the TeensyMUD Public License
# See LICENSE file for additional information.
#
$:.unshift "lib" if !$:.include? "lib"
$:.unshift "vendor" if !$:.include? "vendor"
require 'network/protocol/mxpcodes'
require 'core/gameobject'
require 'core/spawn'
require 'gettext'
# The Room class is the mother of all rooms.
#
class Room < GameObject
property :exits, :spawns
logger 'DEBUG'
include GetText
include MXPCodes
bindtextdomain("core")
# Create a new Room object
# [+name+] The displayed name of the room
# [+owner+] The owner id of this room
# [+return+] A handle to the new Room.
def initialize(name, owner)
super(name, owner)
self.exits=[] # The list of exits for this room.
self.spawns=[] # Objects to spawn here
end
# Resets a room
# Removes stale entries that can come from shutting down the server
def reset
# Remove any stale user accounts
contents.each do |oid|
o = get_object(oid)
if o.is_a? Character and not o.account and not o.kind_of? Mobile
log.info "Purging stale contents #{oid} from Room #{id}."
contents.delete oid
end
end
end
# Lists the characters in the room
# [+notid+] Optional id of who not to return
# [+return+] Array of character objects
def characters(notid=nil)
ppl = []
contents.each do |oid|
o = get_object(oid)
if o.kind_of? Character
if notid
ppl << o if not notid == oid
else
ppl << o
end
end
end
ppl
end
# Sends a message to all characters in a room
# [+msg+] Message to broadcast
# [+notid+] Optional person to leave out of the broadcast
def say(msg, notid=nil)
if not msg.is_a? Msg
msg = Msg.new(msg)
msg.broadcast = true
end
if notid
characters(notid).each do |x|
add_event(id,x.id,:show, msg) if x.account and x.cansee?
end
else
characters.each do |x|
add_event(id,x.id,:show, msg) if x.account and x.cansee?
end
end
end
# Sends a message to the "rest" of the players in the room except
# for notid1 and notid2
# [+msg+] Message to display
# [+notid1+] First person to skip
# [+notid2+] Second person to skip
def sayrest(msg, notid1, notid2)
characters(notid1).each do |x|
add_event(id,x.id,:show, msg) if x.account and x.cansee? and not x.id == notid2
end
end
# Get the MP cost to move through this room via the modifier
# [+return+] cost in MP to move through this room
def mpcost
cost = 1
cost += get_modifier("mp").abs
cost
end
# Searches current room for an object by name
# [+obj+] object name to serach for. Supports 2.obj, etc.
# [+return+] an array of objects that match that obj name
def find_objects(what)
objs = []
nth = 1
found = 0
if what=~/^(\d+)\.(.*)/
nth = $1.to_i
what = $2
elsif what=~/^all\.(.*)/
nth = nil
what = $1
end
objects.each do |o|
gotname = false
if o.name =~/^#{what}$/i
gotname = true
elsif o.aliases.size > 0
o.aliases.each do |a|
gotname = true if a=~/^#{what}$/
end
end
if gotname
found += 1
if not nth
objs << o
elsif found == nth
objs << o
end
end
end
objs
end
# Returns if the room is dark
# [+return+] true if room is dark
def is_dark?
return false if has_attribute? :bright
return true if has_attribute? :dark
return true if world.climate.night and not has_attribute? :inside
false
end
# Event :describe
# [+e+] The event
# [+return+] Undefined
def describe(e)
msg = "[COLOR Green]"
if world.can_build? e.from
msg << "(#{id.to_s})"
msg << "[#{mpcost}]" if mpcost > 1
msg << " "
if spawns
msg << "*" if spawns.size > 0
end
end
msg << mxptag("RName") + name + mxptag("/RName")
if attributes
msg << " #{attributes.inspect}" if world.can_build? e.from and attributes.size > 0
end
msg << "[/COLOR]\n"
if get_object(e.from).cansee? :dark
msg << mxptag("RDesc") + desc + mxptag("/RDesc") + "\n"
else
msg << _("It is dark.\n")
end
add_event(id,e.from,:show,msg)
end
# Event :describe_exits
# [+e+] The event
# [+return+] Undefined
def describe_exits(e)
msg = "[COLOR Red]" + _("Exits:") +"\n"
s = exits.size
if s == 0
msg << _("None.")+"[/COLOR]"
else
i = 0
exits.each do |exid|
ex = get_object(exid)
key = ex.name.split(/;/).first
msg << mxptag("Ex") + key + mxptag("/Ex")
i += 1
case s - i
when 1 then s > 2 ? msg << "," + _(" and ") : msg << _(" and ")
when 0 then msg << "."
else
msg << ", "
end
end
msg << "[/COLOR]"
end
add_event(id,e.from,:show,msg)
end
# Event :spawn
# [+e+] Event to spawn all pending objects
# [+return+] Undefined
def spawn(e)
spawns.each do |s|
spawnobj = get_object(s)
# Check to make sure you dont exceed the max_in_room value
in_room = 0
contents.each do |oid|
obj = get_object(oid)
in_room += 1 if obj.id == spawnobj.targetid
if obj.parentid
in_room += 1 if obj.parentid == spawnobj.targetid
end
end
if in_room < spawnobj.max_in_room
o = spawnobj.load
if o
o.location = id
case o
when Mobile
add_event(id, id, :arrive,o.id)
else
add_contents(o.id)
end
end
end
end
end
# Event :arrive
# [+e+] The event
# [+return+] Undefined
def arrive(e)
ch = get_object(e.msg)
# add character
add_contents(ch.id) if not contents.include? ch.id
ch.location = id
infectguard = nil
# While we are parsing through players check for special players
characters(e.msg).each do |x|
msg = Msg.new _("^p1 has arrived.")
msg.p1 = ch.name
msg.is_invisible = true if ch.has_attribute? :invisible
add_event(id,x.id,:show,msg)
infectguard = x if x.has_attribute? :infect_guard
end
# Check if the person is infected and it is an infect_guard location
if ch.has_attribute? :infected and infectguard
ch.sendroom _("%{guard} scans %{name}'s eye then a siren sounds, \"INFECTED! INFECTED!\"" % {:guard => infectguard.name, :name => ch.name})
ch.sendto _("%{guard}, at point blank range, blows off your head!!" % {:guard => infectguard.name})
ch.sendrest( _("%{guard} unloads his weapon and blows off %{name}'s head!" % {:guard => infectguard.name, :name => ch.name}), ch.id)
ch.make_corpse
return
end
# If player is holding a light that requires power use it.
light = ch.has_light?
if light
if light.has_val? :powered_from and light.respond_to? "use_power"
left = light.use_power
if left == 1
ch.sendto _("Your %{light} flickers." % {:light => light.name})
elsif left == 0
# Check to make sure there are not alternate fuels stored too
if not light.has_power?
# Nope, that was it...die
ch.sendto _("Your %{light} flickers and dies." % {:light => light.name})
msg = Msg.new("^p1 %{light} flickers and dies." % {:light => light.name})
msg.p1 = ch.name
add_event(ch.id, ch.id, :roomsay, msg)
end
end
end
end
ch.parse('look') if ch.account
end
# Event :dig
# [+e+] Event
# [+return+] Undefined
def dig(e)
ch = get_object(e.from)
dig_cost = 3
dig_cost = 0 if world.can_build? ch.id
if ch.stats[:mp]-dig_cost > 0
ch.stats[:mp] -= dig_cost
objects.each do |o|
if o.has_attribute? :buried
o.del_attribute(:buried)
chmsg = Msg.new _("You dig up ^o1!")
chmsg.o1 = o.shortname
add_event(id,e.from,:show,chmsg)
rmsg = Msg.new _("^p1 digs up ^o1!")
rmsg.p1 = ch.name
rmsg.o1 = o.shortname
add_event(e.from,e.from,:roomsay,rmsg)
end
end
else
add_event(id,e.from,:show, _("You are too exhausted to dig right now."))
end
end
end