Skip to content

Vendors

An NPC vendor sells goods for gold, as in ModernUO. A player opens the shop window of a vendor, sees what it sells with the price of a piece, picks what to buy and gets the goods in the backpack. What each vendor sells is a shop, converted from ModernUO’s SBInfo classes. A player can also sell to a vendor, and the shelves fill again with time.

A player opens the window in one of two ways, from as far as the vendor can be reached:

  • Click the vendor and pick Buy or Sell in the context menu, within 8 tiles.
  • Say vendor buy or vendor sell within 4 tiles. The client turns the words into a speech keyword in any language of the client, so vendor buy works in an Italian client as well. When several vendors hear the words, one answers.

A template that inherits basevendor runs the script, but only those with a shop sell: the menu of a vendor offers Buy only when its shop sells something and Sell only when it buys something, as in ModernUO, and a vendor with no shop (a shipwright, a rancher, a guildmaster that has none in templates/shops) offers neither and does not answer the words. A vendor opens the window only when it has a shop with goods in stock, is in the world, is no more than 10 tiles away, is in sight, and the player is alive. A murderer in a guarded place is refused by the vendor’s voice (cliloc 501522).

The window lists the goods with their prices. The player chooses a number of pieces for each line and confirms. A purchase is everything or nothing among the lines the vendor’s script allowed (see For script authors): when a check fails, nothing is taken and nothing is given.

  • A purchase has 1 to 100 lines. A line chosen twice adds up. Each line is a line of the window, and its amount is at most the vendor’s stock.
  • The total is the price of a piece times the pieces of every line; a total over int.MaxValue is refused. A game master pays nothing.
  • The gold comes from the backpack and the bags inside it. When the backpack lacks it and the total is 2000 or more, the bank makes up the difference; under 2000 the vendor says thou canst not afford (cliloc 500192) and the bank is left alone. The bank pays straight from its box, coins first and then checks, with none of the limits of a withdrawal (its maximum, the weight of the backpack, room for a new pile). A bank that cannot make up the difference is answered by cliloc 500191. The check comes before any item is made, so a refused purchase costs nothing.
  • A stackable line gives one stack, any other line gives one item for each piece. The serials for all of them are reserved before anything is taken; an order that needs more than the server has ready is refused with cliloc 500187.
  • The goods go to the backpack. When they do not fit, they are put on the ground at the player’s feet.
  • The player reads the total paid: cliloc 1151639, or 1151638 when part of it came out of the bank.

The window closes after every answer, a purchase or a refusal. A reply that is not for the open window of that vendor, or that has more than 100 lines, is dropped.

Sell opens a list of what the player carries that the vendor’s shop buys, with the gold paid for one piece. The list has the items of the backpack and of the bags in it, 250 at most. An item that is worn, held on the cursor, not movable or a container with something inside is not offered. A vendor that buys nothing the player carries says you have nothing I would be interested in.

The price of a piece is the price of the shop for common items. A rarer item is paid more: the price is multiplied by a number that depends on the rarity of the item, cut to whole gold and never under 1. The defaults are 1.25 for uncommon, 1.5 for rare, 2 for epic and 3 for legendary, set in [ultima.vendors]. It is the same for every vendor and every item with a rarity, and the list and the payment use the same number.

The player chooses items and how many pieces of each, and confirms. A sale is everything or nothing among the lines the vendor’s script allowed, like a purchase:

  • The reply has fewer than 100 lines. Each item must be one that was offered and is still in the backpack, and a line chosen twice adds up. An amount over what the item holds is cut to it. The total is refused over int.MaxValue. Items that are not regular loot, such as the starting items of a new character, are not bought.
  • The vendor must be in reach and the player alive, and a murderer in a guarded place is refused, as for a purchase.
  • The gold is paid in piles of 60000 in the backpack, or in the bank box when the backpack has no room for them. When neither has the room, nothing is sold and the player is told the backpack is full.
  • The pieces are taken from the items, and an item sold whole is deleted. The vendor offers them again, see Resale.

Each vendor starts with the amount of each line of its shop. A purchase lowers it, and the next window shows what is left. The stock is kept in memory only: a restart gives every vendor its full shelves again, as in ModernUO.

A vendor restocks when a player opens its window and more than an hour has passed since the last restock; a vendor seen for the first time only starts the clock. Each line is then filled to its maximum, which changes with how the line sold:

  • A line that sold out has twice the maximum, up to 999.
  • A line that sold no more than half of its maximum has it cut to half, and 999 is cut to 640. A maximum of 20 or less is never cut.
  • A line that sold more than half of its maximum keeps it.

What a player sold to a vendor is offered again in its window, after the goods of the shop, at 1.9 times the price of the shop for a piece (cut to whole gold). A rarer item that was paid more is resold from the same price of the shop, not from what it earned. The vendor keeps it for an hour from the last time the same goods were sold to it, or until it sells out. The goods come back as new items of the same template and hue, shown with the client’s name for the graphic: what the item had on it, such as a name, charges or a rarity, is not kept: a gem takes the rarity the template rolls for it. A vendor remembers 250 kinds of goods at most. Like the stock, the resale shelf is kept in memory only.

The window is the client’s own, driven by these packets: 0x2E puts two virtual containers on the vendor (layers ShopBuy and ShopResale, which the client needs or it crashes), 0x3C fills the first with one virtual item for each line, 0x74 gives the price and the name of each line, and 0x24 opens the window with gump 0x30. The purchase comes back in 0x3B, and the server answers it with a 0x3B that closes the window. The serials of the virtual items count down from Serial.MaxVirtual and mean nothing outside the open window. The sell list goes out in 0x9E and the player’s choice comes back in 0x9F; its items are the player’s own, with their real serials. See Packets.

The vendor templates that inherit basevendor run scripts/mobiles/shopkeeper.lua, which offers Buy and Sell in the context menu to the vendors that vendor.sells(npc) and vendor.buys(npc), and listens for vendor buy. The script is called shopkeeper because vendor is the name of the Lua module that opens the window:

vendor.open_buy(npc, player)

The other functions of the vendor module: vendor.open_sell(npc, player) offers the list of what the player carries that the vendor buys; vendor.open_buy_once(npc, speaker) and vendor.open_sell_once(npc, speaker) are for words the player said: they do nothing when another vendor opened a window for that player within half a second, so several vendors side by side do not all answer.

The script of a vendor NPC may also take part in a transaction, with four optional functions, all of them (serial, actor, item, amount, price), where item is the template id of the goods and price the gold of the whole line: can_buy and can_sell are asked for each line, before any gold or goods move, and false refuses that line; on_bought and on_sold are told after the line was done. A refused line spends nothing and moves nothing: the vendor says I will not sell you that. or I do not want that. once, and the other lines go on; when none is left the window closes. A script that wants its own words says them from the hook. The functions are asked of NPC vendors only, and only when the script defines them. A game master pays nothing, and the price of a line is still what it would cost. The functions are in Script hooks.

can_buy and can_sell are asked while the window is open and before the transaction: they must not open or close a vendor window, move or consume goods, or move the player. The server checks again afterwards: a purchase whose window a hook replaced is dropped, leaving the new window, and a sale whose goods changed or whose player went out of reach pays nothing.

-- scripts/mobiles/fussy_baker.lua: a script of your own, the script_id of a baker's template
-- (the shipped shopkeeper.lua defines none of these four functions)
fussy_baker = {}
function fussy_baker.can_buy(serial, actor, item, amount, price)
if item == "sword" and not npc.get_prop(serial, "knows_" .. actor) then
return false
end
end

A script of a vendor that has its own, such as banker.lua or healer.lua, can call it too: the healers keep a shop this way, through scripts/common/shop.lua, which holds the Buy and Sell entries and the words for any script. See Lua modules.

Vendors also teach the skills they have: see Trainers. The jewelers engrave rings and wedding bands with a text: see Engraved rings.

  • Pets for sale, bulk order deeds, the price scalar of towns, player vendors and the gold a vendor holds are not built.
  • The shops shipped with the server hold the lines of ModernUO that have an item template. The converter reports the others: a few goods have no template yet, so some vendors sell less than in ModernUO.

Made with ❤️ by Tom

Buy me a coffee