znmud-0.0.1/benchmark/
znmud-0.0.1/cmd/
znmud-0.0.1/cmd/emotes/
znmud-0.0.1/cmd/objects/
znmud-0.0.1/cmd/tiny/
znmud-0.0.1/doc/
znmud-0.0.1/farts/
znmud-0.0.1/lib/
znmud-0.0.1/lib/combat/
znmud-0.0.1/lib/core/bodytypes/
znmud-0.0.1/lib/engine/
znmud-0.0.1/lib/farts/
znmud-0.0.1/logs/
#
# 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