# 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