Buying
Buy(id, furnitureId, count) buys count pieces of one kind of furniture from a furniture shop for the player, the way the shop screen does.
BaseShops buying furniture from a shop
Call Buy to buy furniture for the player from a furniture shop, and listen to Bought to hear about purchases made through it.
public static class BaseShops
{
public static BaseShopBuyResult Buy(string id, string furnitureId, int count);
public static event Action<BaseShopBoughtArgs> Bought;
}
| Method | Returns | What it does |
|---|---|---|
Buy(id, furnitureId, count) | BaseShopBuyResult | Buys count pieces of one kind of furniture from a shop for the player. |
| Event | Gives you | When it fires |
|---|---|---|
Bought | BaseShopBoughtArgs | The player bought furniture through Buy. It fires once, after the stock and the shop’s money have changed. |
BaseShopBuyResult what happened when you tried to buy
Buy returns this. Ok means the purchase is complete, and the other values say why it was not.
public enum BaseShopBuyResult
{
Ok,
Busy,
NotFound,
Unsupported,
Refused,
OutOfStock,
NoMoney,
Unavailable,
Failed
}
| Value | Meaning |
|---|---|
Ok | The purchase is complete. |
Busy | Not now. A save is loading or being written, money handlers are nested too deep, or the shop screen is open. |
NotFound | No furniture shop has that id, or the shop has no such furniture. |
Unsupported | The shop is a train shop. |
Refused | The request is not allowed. count is below 1, furnitureId is empty, a piece that needs a custom picture has none, or the total is above 16 million in either currency. |
OutOfStock | The shop holds fewer pieces than you asked for. |
NoMoney | The player cannot pay. Nothing was taken. |
Unavailable | The player’s wallet or home building is not ready. |
Failed | A step went wrong. A charge was refused, the delivery failed, or an error was caught before delivery. Any money taken was given back. |
BaseShopBoughtArgs what Bought tells you
Bought hands you this after a purchase made with Buy. FurnitureId and Count say what was bought, and Oc and Rm what was paid.
public sealed class BaseShopBoughtArgs
{
public string Id { get; }
public string Kind { get; }
public string FurnitureId { get; }
public int Count { get; }
public int Oc { get; }
public int Rm { get; }
}
| Property | Type | What it means |
|---|---|---|
Id | string | The shop’s id, the same as BaseShopInfo.Id. |
Kind | string | The type of shop. It is always FurnitureShop. |
FurnitureId | string | The id of the furniture that was bought. |
Count | int | How many pieces were bought. |
Oc | int | The total OC paid. |
Rm | int | The total RM paid. |
Things to know
- You find the furniture by its furniture id, and the shop must hold at least
countpieces of it. There is no call that lists a shop’s stock yet, so for a piece your mod added, use the id the furniture registry gave you. (The stock entry is the first entry ofGetAvailableItems()whosefurniture.IdisfurnitureId, and itsamountmust be at leastcount.) - The price is the shop’s buying price for each piece, times
count. There is no haggling, discount or owner price. (It uses the game’sGetOcBuyPriceandGetRmBuyPrice, which usebuyPercent.) - The money comes from the player’s wallet only, and the bank is not used. OC is taken first, then RM. (It uses
Money.RemoveMoneythroughCash.TrySpend.) - The framework checks everything before it takes any money: the save must not be busy, the id and count must be valid, the shop must have the piece and enough of it, a piece that needs a custom picture must have one, and the wallet must hold both prices.
- Then it charges OC and RM, puts the piece in the player’s building stock, and only after that takes the piece out of the shop’s stock and adds the money to the shop. (A custom-image piece is one with
canPlaceCustomImage, which the game checks inShopBaseUI.InfoButtonPressed. The delivery isBuildingSystem.AddFurniture. The shop’s stock goes throughRemoveItemand its money through the game’sAddBuyMoney.) - If the RM charge fails, the OC charge is refunded. If the delivery fails, both charges are refunded and the shop’s stock and money are left as they were. (A refund adds the money back without the wallet-limit check and without the save and nesting refusals, so those can’t block it. If the game’s money add itself throws, the refund is logged as an error and the money is not returned. OC is a whole number in the wallet, so its refund is exact. RM is a decimal number, so a charge and its refund can differ by one step of the number type.)
- If the shop can’t remove its stock after the delivery, the piece is taken back out of the player’s building stock, both charges are refunded, and the result is
Failed. - If the piece can’t be taken back, the money is not refunded, an error goes to the log, and the result is
Failed. This means the player never keeps both the piece and the money. Boughtonly fires for purchases made withBuy. A purchase made on the game’s own shop screen does not raise it.- An
Okresult stands even when the shop’s till fails afterwards. That problem is written to the log, and the purchase is not undone. Busyalso covers the shop screen being open. The screen has to be closed, because its selected entry would otherwise point at stock that was just removed. (Busycomes fromCash.Refused, which is true while a save is loading or being written, while the player’s inventory is in the middle of a change (PlayerInventory.InTransaction), and whenMoneyChangedorReceivedhandlers are nested too deep. The 16 million limit isCash.MaxAmount. The shop screen isShopController.menuIsOpen.)Unsupportedcovers train shops. Buying a train places it on the track from the shop screen’s preview, and selling one removes it from the track. The framework does neither.- A shop has no opening hours, so
Buynever refuses because a shop is closed. Opening hours belong to trading with characters: see Shop hours. - The player can always hold more furniture. The game puts no limit on the building stock, so
Buyhas no “full” result. (AddFurniturereturnstrueevery time.) - A purchase does not count as a crime and does not mark anything as stolen. The shop’s money and stock are saved at the next game save. (The game’s buy sets no crime or stolen flag. The shop’s data is written by
BaseShop.OnSavingGame.)
Limits
Buytakes the first matching entry only. A piece with custom pictures can have several entries, and oneBuycan’t take pieces from two of them. It returnsOutOfStockinstead.Buydoes not refresh a shop screen that is open.- A purchase from a furniture display in the world goes a different way and is not covered. (The display purchase is
InteractableFurnitureDisplay.Purchase.)