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/
# Mobile class
# Author: Craig Smith
# This class is the base class of NPCs.

# 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 'core/body'
require 'storage/properties'


class Mobile < Character
   include GetText
   bindtextdomain("core")
   property :gender

   logger 'DEBUG'
   def initialize(name, owner, location=nil)
	super(name, owner, location)
	self.gender = nil	# Non descript
   end

   # Parse wrapper.  Currently does nothing but useful for debugging
   def parse(args)
	#log.info "Mobile command: #{name} - #{args}"
	super(args)
   end

   # Call parent reset()
   def reset
	super(true)
	@body.wearing.each do |oid|
		@body.wearing.delete oid
		o = get_object(oid)
		o.unused = true
		o.location = nil
	end
	@body.wielding?.each do |oid|
		@body.unwield(oid)
		o = get_object(oid)
		o.unused = true
		o.location = nil
	end
	contents.clear
	if parentid
		self.stats.clear
		self.attributes.clear
		self.val.clear
		self.modifier.clear
		parent = get_object(parentid)
		parent.stats.each { |key, val| set_stat(key, val) }
		parent.attributes.each { |at| add_attribute(at) }
		parent.val.each { |key, val| add_val(key, val) }
		parent.modifier.each { |key, val| add_modifier(key, val) }
	end
   end

   # Very simple kill recorder
   def add_kill(id)
	self.stats[:kills] += 1
   end

   # :idle event
   # This is called by the world timer
   def idle(e)
	return if not location
	return if location == 0
	room = get_object(location)
	recoverHP
	recoverMP
	recoverStunned
	if has_attribute? :zombie
		add_attribute :aggressive if not has_attribute? :aggressive
		target = find_zombie_victim
	else
		target = attack_nearby
		manage_infections
	end
	# What to do when fighting
	if @position == :fighting
		if has_attribute? :wimpy and not has_attribute? :zombie
			min = (get_stat(:maxhp) * 0.1).to_i
			min = 10 if min < 10
			flee if health <= min
		end
		# No idle commands, focus on fighting
		return
	end
	# Looking for a fight?
	if target
		kill_id(target)
	else
		# Scavengers - junk stuff too
		if has_attribute? :scavenger and rand(3) == 0 and contents.size > 0
			items = []
			contents.each { |oid| items << oid if get_object(oid).cost == 0 }
			if items.size > 0
				itemid = items[rand(items.size)]
				item = get_object(itemid).name
				parse(_("junk %{obj}" % {:obj => item}))
			end
		end
		# Scavenge more
		if has_attribute? :scavenger and rand(3) == 0
			items = []
			room.contents.each { |oid| items << oid if not get_object(oid).has_attribute? :fixed }
			if items.size > 0
				itemid = items[rand(items.size)]
				item = get_object(itemid).name
				parse(_("get %{obj}" % {:obj => item}))
				return
			end
		end
		# 1 in 10 chance of trying to leave the room
		move if not has_attribute? :fixed and rand(10) > 8
	end
   end

   # Move in a random direction
   def move
	if dirhint
		ex = get_object(dirhint)
		self.dirhint = nil
		if ex
			parse(ex.name)
			return
		end
	end
	room = get_object(location)
	if room.exits.size > 0
		dir = room.exits[rand(room.exits.size)]
		parse(get_object(dir).name)
	end
   end

   # If mobile is aggressive it will attack somebody nearby that is not
   # of the same type
   # [+return+] id of person to attack if one is found
   def attack_nearby
	# Must have an aggressive attribute of some type
	return nil if not has_attribute? :aggressive and 
                      not has_attribute? :guard and 
                      not has_attribute? :infect_guard 
	return nil if @position == :fighting
	victim_needs_light = false
	victim_needs_light = true if not cansee? :dark
	get_object(location).characters(id).each do |ch|
           if not world.can_build? ch.id  # Never attack builders/admins
		if has_attribute? :aggressive
			if not ch.is_a? Mobile
				if not cansee? :dark
					return ch.id if ch.has_light?
				end
				if ch.has_attribute? :invisible
					return ch.id if cansee? :invisible
				end
				return ch.id
			end
		elsif has_attribute? :infect_guard
			return ch.id if ch.has_attribute? :infected
		elsif has_attribute? :guard
			return ch.id if ch.has_attribute? :PK or ch.position == :fighting
		end
            end # End never attack gods
	end
	nil
   end

   # Attack target id
   # [+tid+] Character id to attack
   def kill_id(tid)
	target = get_object(tid)
	# Infect guards vs. infected == instant kill
	if has_attribute?(:infect_guard) and target.has_attribute?(:infected)
		sendroom _("%{guard} scans %{name}'s eye then a siren sounds, \"INFECTED! INFECTED!\"" % {:guard => name, :name => target.name})
		target.sendto _("%{guard}, at point blank range, blows off your head!!" % {:guard => name})
		sendrest( _("%{guard} unloads his weapon and blows off %{name}'s head!" % {:guard => name, :name => target.name}), target.id)
		target.make_corpse
	else
		sendroom _("%{attacker} shouts, \"%{name} is a player killer!!\"" % {:attacker => name, :name => target.name}) if has_attribute?(:guard) and target.has_attribute? :PK
		sendroom _("%{attacker} shouts, \"Hey! No fighting!!\"" % {:attacker => name}) if has_attribute?(:guard) and target.position == :fighting
		parse(_("kill %{name}" % {:name => target.name}))
	end
   end

   # Flee from a fight
   def flee
	parse(_("flee"))
   end
end