# Merchant class
# 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 'core/body'
require 'storage/properties'
class Merchant < Mobile
include GetText
bindtextdomain("core")
logger 'DEBUG'
MAX_MERCHANT_INV = 10
property :forsale, :buytype, :buyattribute, :buydtype, :markup
def initialize(name, owner, location=nil)
super(name, owner, location)
self.forsale = [] # Oids that merchant will have an unlimited supply of
self.buytype = [] # Object types that merchant will only buy
self.buyattribute = [] # Only buy objects with specified attributes
self.buydtype = [] # Buy only weapons of these damage types
self.markup = 0.20 # Markup percentage
end
# Event :list
# List the items for sale
# e.from = person requesting list
def list(e)
return if has_attribute? :zombie
items = {}
msg = _("----[ %{name}'s Items for Sale ]-------------------\n" % {:name => name})
msg += sprintf("%-10s %-25s %s\n", _("Amount"),_("Item"), _("Cost"))
msg << mxptag("StoreList")
forsale.each do |oid|
obj = get_object(oid)
price = obj.cost + (obj.cost * markup).to_i
imsg = sprintf("%-10s %-25s $%d\n", _("unlimited"),obj.shortname, price)
msg += mxptag("Buy '#{obj.name}' '#{name}'") + imsg + mxptag("/Buy")
end
# Group items together
contents.each do |oid|
obj = get_object(oid)
if obj.parentid
haveid = obj.parentid
else
haveid = obj.id
end
if not forsale.include? haveid
if items.has_key? haveid
items[haveid] += 1
else
items[haveid] = 1
end
end
end
items.each do |oid, count|
obj = get_object(oid)
price = obj.cost + (obj.cost * markup).to_i
imsg = sprintf("%-10s %-25s $%d\n", "[#{count}]",obj.shortname, price)
msg += mxptag("Buy '#{obj.name}' '#{name}'") + imsg + mxptag("/Buy")
end
msg << mxptag("/StoreList")
msg << "--------------------------------[End of List]----\n"
add_event(id, e.from, :show, msg)
end
# Check if merchant would by that item
# [+oid+] Oid to check to see if merchant will buy
# [+return+] True if they will buy that item
def willbuy(oid)
return false if has_attribute? :no_buy
obj = get_object(oid)
# At least one of these must match
if buytype.size > 0
typematch = false
buytype.each do |btype|
typematch = true if obj.class.to_s == btype
end
else
typematch = true
end
if buyattribute.size > 0
attrmatch = false
buyattribute.each do |battr|
attrmatch = true if obj.has_attribute? battr
attrmatch = true if obj.has_val? battr
end
else
attrmatch = true
end
if buydtype.size > 0
dtypematch = false
buydtype.each do |dtype|
# If the dtype is specified as bludgeon then allow any
dtypematch = true if obj.has_attribute? dtype or dtype == "bludgeon"
end
else
dtypematch = true
end
typematch and attrmatch and dtypematch
end
# [+objid+] Object to see how many we are carrying
# [+return+] number of items fo that type
def totalobjs(objid)
o = get_object(objid)
objid = o.parentid if o.parentid
cnt = 0
contents.each do |oid|
cobj = get_object(oid)
cnt += 1 if cobj.id == objid
if cobj.parentid
cnt += 1 if cobj.parentid == objid
end
end
cnt
end
# Event :offer
# Ask merchant to make an offer on an item
# [+e+] e.from = requester, e.msg = oid to make offer on
def offer(e)
return if has_attribute? :zombie
obj = get_object(e.msg)
return if not obj
if not willbuy(obj.id)
msg = _("Sorry, but I won't buy that.")
add_event(id, e.from, :show, msg)
return
end
if totalobjs(obj.id) > MAX_MERCHANT_INV
msg = _("Sorry but I have too many of those.")
add_event(id, e.from, :show, msg)
return
end
price = obj.cost - (obj.cost * markup).to_i
if price > 0
msg = _("I will give you $%{price} for that." % {:price => price})
add_event(id, e.from, :show, msg)
else
msg = _("That's is not worth anything to me.")
add_event(id, e.from, :show, msg)
end
end
# Event :buy
# Seems backwards but this is when a merchant SELLS something and a player buys
# [+e+] e.from = buyer, e.msg = object name
def buy(e)
return if has_attribute? :zombie
ch = get_object(e.from)
oname = e.msg
if oname.size < 1
ch.sendto _("Buy what?")
return
end
# First we check out contents
tobuy = nil
have = false
contents.each do |oid|
obj = get_object(oid)
if obj.name =~/#{oname}/i
tobuy = obj
have = true
end
end
# Didn't find anything in contents see if it is something we always sell
if not have
forsale.each do |oid|
obj = get_object(oid)
if obj.name =~/#{oname}/i
tobuy = obj
end
end
end
if not tobuy
msg = _("I do not have that item for sale.")
add_event(id, ch.id, :show, msg)
else
price = tobuy.cost + (tobuy.cost * markup)
if ch.get_stat(:cash) < price
msg = _("You do not have enough money.")
add_event(id, ch.id, :show, msg)
else
ch.adjust_stat(:cash, -price.to_i)
msg = _("That will be $%{cost}." % {:cost => price.to_i})
add_event(id, ch.id, :show, msg)
if not have # We need to load a new object
tobuy = world.load_object(tobuy.id)
tobuy.location = id
tobuy.reset if tobuy.respond_to? "reset"
add_contents(tobuy.id)
end
add_event(id, ch.id, :give, tobuy.id)
end
end
end
# Event :sell
# Seems backwards but this is when a merchant BUYS something and the player sells it
# [+e+] e.from = seller, e.msg = oid of object to sell
def sell(e)
return if has_attribute? :zombie
ch = get_object(e.from)
obj = get_object(e.msg)
if willbuy(obj.id)
if totalobjs(obj.id) <= MAX_MERCHANT_INV
price = obj.cost - (obj.cost * markup)
ch.adjust_stat(:cash, price.to_i)
msg = _("%{name} gives you $%{cost}." % {:name => name, :cost => price.to_i})
add_event(id, ch.id, :show, msg)
add_event(ch.id, id, :give, obj.id)
else
msg = _("I have too many of those.")
add_event(id, ch.id, :show, msg)
end
else
msg = _("I do not want that.")
add_event(id, ch.id, :show, msg)
end
end
end