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::    container.rb
# Author:   Craig Smith

# This source code copyright (C) 2009 Craig Smith
# All rights reserved.
#
# Released under the terms of the TeensyMUD Public License
# See LICENSE file for additional information.
#

$:.unshift "lib" if !$:.include? "lib"

require 'gettext'
require 'core/gameobject'
require 'storage/properties'

# This is the base container class
#
class Container < GameObject
  include GetText
  bindtextdomain("core")
  logger 'DEBUG'

  CONT_DEFAULT_MAX_AMT=50
  CONT_DEFAULT_MAX_WEIGHT=200
  
  property :types, :liq_amt, :initial_weight

  # Create a new Container object
  # [+name+]    The displayed name of the Container.
  # [+return+]  A handle to the new Container.
  def initialize(name, owner, location=nil)
    super(name, owner, location)
    self.liq_amt = 0  # Amount of liquid stored
    self.types = []   # types of other Containers or objects
                      # this Container can hold (e.g
    self.initial_weight = 1
  end

  # Reset runs when object first loads
  def reset
	self.liq_amt = 0
	contents.each { |oid| get_object(oid).unused = true }
	self.contents.clear
	# Some items come pre-filled with liquid (Like drinks)
	if has_val? :filled_with
		liq = get_object(has_val?(:filled_with))
		if liq.is_a? Liquid
			if has_val? :max_amt
				self.liq_amt = has_val? :max_amt
			else
				self.liq_amt = CONT_DEFAULT_MAX_AMT
			end
			add_contents(liq.id)
		end
	end
  end

  # Adds an item type
  # [+type+] The string of the Class allowed
  def add_type(type)
	self.types << type if not types.include? type
  end

  # Deletes an item type
  # [+type+] The string of the class to delete
  def del_type(type)
	self.types.delete(type) if types.include? type
  end

  # Checks if container can hold this type
  # [+type+] Class as string.  If types is empty always returns true
  def has_type?(type)
	types.include? type
  end

  # No container can weigh 0..this prevent infinite recursion
  # [+return+] total weight of contents
  def weight
	# If an initial weight is specified add that
	if initial_weight
		amt = initial_weight
	else	
		amt = 1
	end
	contents.each do |oid|
		amt += get_object(oid).weight
	end
	amt
  end

  # If container has value of powered_from checks if cont has power src
  # [+amt+] Amount of power requested
  # [+return+] Returns true if object has power to operate
  def has_power?(amt=1)
	return true if not has_val? :powered_from
	power = get_object(has_val?(:powered_from))
	if power
		if power.is_a? Liquid
			has_proper_liquid = false
			contents.each do |oid|
				has_proper_liquid = true if oid == power.id
			end
			return false if not has_proper_liquid
			return true if liq_amt - amt >= 0
			return false
		elsif power.is_a? Battery
			battery = nil
			# Any battery will do
			contents.each do |oid|
				obj = get_object(oid)
				battery = obj if obj.is_a? Battery
			end
			return false if not battery
			return true if battery.has_val?(:current_charge) - amt >= 0
			return false
		else
			log.info "Unknown power source for #{power.name}"
			return false
		end
	end
	false
  end

  # Simple emthod to return the value of :powered_from
  # [+return+] Nil if no power requirement, else oid of power req.
  def power_requirement
	has_val? :powered_from
  end

  # Drains power
  # [+amt+] Amount to drain
  # [+return+] amount left
  def use_power(amt=1)
	return false if not has_power? amt
	req = get_object(power_requirement)
	return false if not req
	remaining = 0
	if req.is_a? Liquid
		self.liq_amt -= amt
		if liq_amt <= 0
			self.liq_amt = 0
			self.contents.clear
		end
		remaining = liq_amt
	elsif req.is_a? Battery
		battery = nil
		contents.each do |oid|
			obj = get_object(oid)
			# Any Battery will do
			battery = obj if obj.is_a? Battery
		end
		return 0 if not battery
		charge = battery.has_val? :current_charge
		charge -= amt
		if charge <= 0
			battery.add_val(:current_charge, 0)
			battery.unused = true
			self.contents.delete(battery.id)
		else
			battery.add_val(:current_charge, charge)
		end
		remaining = battery.has_val? :current_charge
	else
		log.info "use_power() called with unknown power requirment"
	end
	remaining
  end

  # Check the Container to see if it can contain
  # a specific type of item or anything at all
  # [+oid+] Object id to check if container can hold it
  # [+return+]  Boolean
  def can_hold? oid
  	o = get_object(oid)
	supported_type = false
	if types.size == 0
		supported_type = true
	else
		supported_type = has_type? o.class.to_s
	end
	if supported_type
		# This object can hold that type.
		maxamt = CONT_DEFAULT_MAX_AMT
		maxweight = CONT_DEFAULT_MAX_WEIGHT
		maxamt = val["max_amt"] if has_val? :max_amt
		maxweight = val["max_weight"] if has_val? :max_weight
		if has_type? "Liquid"
			container_size = liq_amt
		else
			container_size = contents.size
		end
		if container_size < maxamt and weight+o.weight < maxweight
			# Object is within amount and weight limits
			return true
		end
	end
	false
  end
  
  # Case insensitive search of inventory.  Supports 2.obj and all.obj syntax
  # [+what+] name of obj in inventory
  # [+return+] Array of matching objects
  def find(what)
	objs = []
	nth = 1
	found = 0
	if what=~/^(\d+)\.(.*)/
		nth = $1.to_i
		what = $2
	elsif what=~/^all\.(.*)/
		nth = nil
		what = $1
	end
	contents.each do |oid|
		o = get_object(oid)
		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

  # Event :describe_contents
  # [+e+] Event data
  # [+return+] Undefined
  def describe_contents(e)
	ch = get_object(e.from)
	if contents.size < 1
		add_event(id, ch.id, :show, "It is empty.")
	else
		if liq_amt > 0
			maxamt = CONT_DEFAULT_MAX_AMT
			maxamt = val["max_amt"] if has_val? :max_amt
			half = maxamt * 0.5
			liq = get_object(contents[0])
			if liq_amt == maxamt
				add_event(id, ch.id, :show, _("It is full of %{liq}"  % {:liq => liq.name}))
			elsif liq_amt >= half
				add_event(id, ch.id, :show, _("It is over half full of %{liq}" % {:liq => liq.name}))
			else
				add_event(id, ch.id, :show, _("It has some %{liq} in it." % {:liq => liq.name}))
			end
		else
			contents.each do |oid|
				obj = get_object(oid)
				if obj
					add_event(oid, ch.id, :show, "#{obj.shortname}")
				else
					log.error "Contents of #{id} contained oid of #{oid} that was not an object"
				end
			end
		end
	end
  end

  # Event :put
  # [+e+] Event data.  e.from == ch, e.msg == item to place
  # [+return+] undefined
  def put(e)
	ch = get_object(e.from)
	what = get_object(e.msg)
	if can_hold? what.id
		ch.delete_contents(what.id)
		self.add_contents(what.id)
		what.location = id
		add_event(id, ch.id, :show, "You put #{what.shortname} in the #{name}")
		add_event(id, ch.id, :roomsay, "#{ch.name} puts #{what.shortname} in #{shortname}")
	else
		add_event(id, ch.id, :show, "You can not fit that in there.")
	end
  end

end