# # file:: gameobject.rb # author:: Jon A. Lambert # version:: 2.8.0 # date:: 01/19/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 'gettext' require 'network/protocol/mxpcodes' require 'utility/log' require 'core/root' # The GameObject class is no longer the mother of all objects. # class GameObject < Root property :location, :contents, :triggers, :msgfail, :msgsucc, :attributes, :val, :cost, :weight, :aliases, :modifier include MXPCodes include GetText bindtextdomain("core") logger 'DEBUG' # Create a new Object # [+name+] Every object needs a name # [+owner+] The owner id of this object # [+location+] The object id containing this object or nil. # [+return+] A handle to the new Object def initialize(name, owner, location=nil) super(name, owner) self.location = location # The location of this object or nil if none self.contents = [] self.triggers = {} self.msgfail = '' self.msgsucc = '' self.attributes = [] self.val = {} # VALues specific to this type of object self.cost = 0 self.weight = 0 self.aliases = [] self.modifier = {} end # add an attribute value # [+key+] Key for the value # [+value+] the actual value of that key def add_val(key, value) key = key.to_s if key.is_a? Symbol val[key] = value end # deletes an attribute value # [+key+] Key to delete def del_val(key) key = key.to_s if key.is_a? Symbol val.delete(key) if val.has_key? key end # has key. If so returns the value # [+key+] Key to check for # [+return+] returns the value if exists else nil def has_val? key key = key.to_s if key.is_a? Symbol return nil if val == nil return nil if not val.has_key? key val[key] end # Add an attribute # [+strattr+] String attribute to add def add_attribute(strattr) strattr = strattr.to_s if strattr.is_a? Symbol attributes << strattr if !attributes.include? strattr end # Delete an attribute # [+strattr+] String attribute to delete def del_attribute(strattr) strattr = strattr.to_s if strattr.is_a? Symbol attributes.delete(strattr) end # Checks if object has a set attribute # [+strattr+] String attribute to check for # [+return+] true or false def has_attribute? strattr return false if attributes == nil strattr = strattr.to_s if strattr.is_a? Symbol attributes.include? strattr end # Toggles attributes on and off # [+strattr+] String attribute to toggle # [+return+] Undefined def toggle_attribute(strattr) if has_attribute? strattr del_attribute(strattr) else add_attribute(strattr) end end # Adds a new modifier # [+key+] Key for modifier, Eg: MP, HP, etc. # [+value+] number of what to add/subtract # [+return+] Undefined def add_modifier(key,val) key = key.to_s if key.is_a? Symbol val = val.to_i if val.is_a? String self.modifier[key] = val end # Deletes a modifier # [+key+] key to delete, Eg: MP, HP, etc. # [+return+] Undefiened def del_modifier(key) key = key.to_s if key.is_a? Symbol self.modifier.delete(key) if has_modifier?(key) end # [+key+] Key to check for in modifier # [+return+] True of object has key in modifier def has_modifier?(key) return false if not self.modifier key = key.to_s if key.is_a? Symbol modifier.has_key? key end # Returns the given modifier # [+key+] To to retrieve, Eg: MP, HP, etc # [+return+] Numeric modifier or 0 if none def get_modifier(key) key = key.to_s if key.is_a? Symbol return modifier[key] if has_modifier? key 0 end # Add an object to the contents of this object # [+oid+] The object id to add def add_contents(oid) if contents.include? oid log.error "Object #{oid} already in contents of #{id}" else contents << oid end end # Deletes an object from the contents of this object # [+oid+] The object id to delete def delete_contents(oid) d = contents.delete(oid) if d.nil? log.error "Object #{oid} not in contents of #{id}" end d end # Returns the contents of the object # [+return+] An array of object ids def get_contents contents || [] end # Add a trigger script to this object # [+s+] The script to add def add_trigger(event, sid) event = event.intern if event.respond_to?(:to_str) triggers[event] = sid end # Deletes a trigger script from this object # [+event+] The trigger event type to delete def delete_trigger(event) event = event.intern if event.respond_to?(:to_str) triggers.delete(event) end # Returns a specific trigger script from the object # [+event+] The trigger event type to retrieve # [+return+] A trigger or nil def get_trigger(event) event = event.intern if event.respond_to?(:to_str) triggers[event] end # Returns the trigger scripts on the object # [+return+] An array of trigger scripts def get_triggers triggers.values end # Finds all objects contained in this object # [+return+] Handle to a array of the objects. def objects objs = [] contents.each do |oid| o = get_object(oid) case o when Spawn, Character, Account, Liquid nil when GameObject objs << o when nil, "" log.error "nil object found with oid of #{oid}. You might need to add the object to engine.rb" else nil end end objs end # Finds all the characters contained in this object except the passed character. # [+exempt+] The character id exempted from the list. # [+return+] Handle to a list of the Character objects. def characters(exempt=nil) ary = contents.collect do |oid| o = get_object(oid) (o.class == Character && oid != exempt && o.account) ? o : nil end ary.compact end # Find all mobiles contained in this object # [+return+] Handle to a list of mobile objects def mobiles ary = contents.collect do |oid| o = get_object(oid) (o.class == Mobile) ? o : nil end ary.compact end # Find players and NPCs mobiles alike # [+exempt+] The character id exempted from the list # [+return+] Handle to a list of the character objects def people(exempt=nil) chars = [] contents.each do |oid| o = get_object(oid) case o when Mobile chars << o if not o.id == exempt when Character chars << o if o.account and not o.id == exempt end end chars end # Generic object reset. Resets flags and attribute values if object is a clone def reset if isclone and parentid parent = get_object(parentid) attributes = parent.attributes.dup val = parent.val.dup modifier = parent.modifier.dup end end # All command input routed through here and parsed. # [+m+] The input message to be parsed # [+return+] false or true depending on whether command succeeded. def parse(m) # match legal command m=~/([A-Za-z0-9_@?"'#!]+)(.*)/ cmd=$1 arg=$2 arg.strip! if arg # look for a command from our table for objects c = world.ocmds.find(cmd) # there are three possibilities here case c.size when 0 # no commands found false when 1 # command found return self.send(c[0].cmd, arg) else # ambiguous command - tell luser about them. false end end # Returns a short name of an object # [+return+] a shortname of an object. (ex. ball == a ball) def shortname return name if self.is_a? Character # NOTE: This is very specific to english...maybe this should be redone return name if name=~/^a[n]*\s/i or name=~/^the\s/i return "an #{name}" if name=~ /^[aeiou]/i "a #{name}" end # Event :describe # [+e+] The event # [+return+] Undefined def describe(e) ch = get_object(e.from) msg = "" msg << "[COLOR Yellow]" msg << "(#{id}) " if ch.get_stat(:debugmode) == true if has_attribute? :buried if world.can_build? e.from msg << "*#{shortname.capitalize} " msg << _("is buried here.") msg << "[/COLOR]" else msg = _("A mound of dirt.") end else if has_val? :fountain msg << mxptag("Fountain '#{name}' '#{shortname}'") msg << _("%{item} is here." % {:item => shortname.ucfirst}) msg << mxptag("/Fountain") + "[/COLOR]" else msg << mxptag("GroundObj '#{name}' '#{shortname}'") msg << _("%{item} is here." % {:item => shortname.ucfirst}) msg << mxptag("/GroundObj") + "[/COLOR]" end end add_event(id,e.from,:show,msg) if msg end # Event :get # [+e+] The event # [+return+] Undefined def get(e) place = get_object(location) if has_attribute? :fixed and not world.is_admin? e.from if not place.owner == e.from or not world.can_build? e.from add_event(id,e.from,:show, _("You can not pick up the %{obj}" % {:obj => name})) return end end if has_attribute? :buried add_event(id,e.from,:show, _("You do not see that here.")) return end plyr = get_object(e.from) if not plyr.can_carry?(weight) add_event(id,e.from,:show, _("You are too encumbered to pick that up.")) return end from_cont = false from_cont = true if place.kind_of? Container if not place.kind_of? Room and not place.kind_of? Container place = get_object(plyr.location) end # remove it place.delete_contents(id) # add it plyr.add_contents(id) self.location = plyr.id if from_cont add_event(id,e.from,:show, _("You get the %{obj} from %{place}." % {:obj => name, :place => place.shortname})) add_event(e.from,e.from,:roomsay, _("%{person} gets %{obj} from %{place}" % {:person => plyr.name, :obj => shortname, :place => place.shortname})) else add_event(id,e.from,:show, _("You get the %{obj}" % {:obj => name})) add_event(e.from,e.from,:roomsay, _("%{person} picks up %{obj}" % {:person => plyr.name, :obj => shortname})) end end # Event :drop # [+e+] The event # [+return+] Undefined def drop(e) plyr = get_object(e.from) place = get_object(plyr.location) # remove it plyr.delete_contents(id) # add it place.add_contents(id) self.location = place.id add_event(id,e.from,:show, _("You drop the %{obj}." % {:obj => name})) add_event(e.from,e.from,:roomsay, _("%{person} drops %{obj}." % {:person => plyr.name, :obj => shortname})) end # Event :junk # [+e+] The event # [+return+] Undefined def junk(e) plyr = get_object(e.from) plyr.delete_contents(id) self.location = nil self.unused = true add_event(id,e.from,:show, _("You junk the %{obj}." % {:obj => name})) add_event(e.from,e.from,:roomsay, _("%{person} junks %{obj}." % {:person => plyr.name, :obj => shortname})) end # Event :timer # [+e+] The event # [+return+] Undefined def timer(e) end # Event :weathermsg (Called from world misc timer thread) # [+e+] The event # [+return+] Undefined def weathermsg(e) world.all_characters.each do |pid| char = get_object(pid) if char.account and char.cansee? if not get_object(char.location).has_attribute? :inside char.sendto("#{e.msg}") end end end end # Event :delete # [+e+] The event # [+return+] Undefined def delete(e) plyr = get_object(e.from) place = get_object(plyr.location) # remove it place.delete_contents(id) delete_object(id) self.location = nil add_event(id,e.from,:show, _("You delete the %{obj}." % {:obj => name})) end # Event :bury # [+e+] The event # [+return+] Undefined def bury(e) ch = get_object(e.from) bury_cost = 2 bury_cost = 0 if world.can_build? ch.id if ch.stats[:mp]-bury_cost > 0 ch.delete_contents(id) ch.stats[:mp] -= bury_cost add_event(id,e.from,:show, _("You bury the %{obj}." % {:obj => name})) add_event(e.from,e.from,:roomsay, _("%{person} buries %{obj}." % {:person => ch.name, :obj => shortname})) self.add_attribute(:buried) self.location = ch.location get_object(ch.location).add_contents(id) else add_event(id,e.from,:show, _("You are too exhausted to dig right now.")) end end end