27 Sep, 2009, Erok wrote in the 1st comment:
Votes: 0
Ok, a topic to get us re-focused on MUD development…

I've recently worked on a method for selling items, and doing so in one step to avoid situations where the item is exchanged but not the gold. I came up with an offer/accept approach, where one player offers an item to another player (or anyone) for a set price, who can then choose to accept the offer, which exchanges the item and gold at the same time, or ignore it. Command syntax is along the following lines…

> offer                         - lists items you have on offer
> offer <item> - cancels the item you have on offer
> offer <item> <gold> [player] - offers item for x gold to player (or all)

> buy <player>                  - lists items on offer to you (or all) by player
> buy <player> <item> <gold> - accepts the item on offer by player for x gold

Having the buyer specify the same gold as the seller acts as validation criteria to ensure the seller can't jack-up the price just as the buyer accepts the offer.
In terms of implementation, I ended up storing the details of any offer (i.e., the price and to whom the offer was made) on the item itself. This seems ok, but wastes memory since only a fraction of items are on offer at any given point in time. Maybe an explicit offer list on the player would be better. Any thoughts on this approach and ways to improve it, or alternate approaches that may work better?

Edit: Note that shopkeepers offer items to anyone, and will accept offered items (if the price is right) as well.
27 Sep, 2009, Idealiad wrote in the 2nd comment:
Votes: 0
I feel like the offer/buy syntax is a little awkward. It seems like it's mashing together two concepts, giving and receiving, and buying and selling, which are related but usually not the same thing. Do you have a separate give command that transfers items automatically? If you want a more generalized system, maybe just use give and accept. For example:

give <item> <player> [gold]

To cancel a give:
keep <item> [player]

To see a list:
offers [player]


You can have multiple offers out on an item, but if you do and 'keep <item>', the game will ask you to disambiguate, and you need to add the optional player argument.

The 'offers' command lists both items you're offering and items offered to you (organized by player) and you can limit the report by players (or even a player list if you want), like 'offers biff buffy'.

Then to accept:

accept <item> <gold> [player]


You could allow for a shorthand here with just 'accept <item>' which accepts the item regardless. Also you can set up a friends list so 'give <item> <player>' automatically transfers items like a normal DIKU give.

As to the programming implementation, not sure what you're writing this with but maybe create a new object that has the offer details on it. That way you can easily have multiple offers out on a single item if you wish. Something like the offers command would then iterate through the list of offer details objects filtering for the ones you want.
27 Sep, 2009, KaVir wrote in the 3rd comment:
Votes: 0
I do something very similar, and support the following syntax:

sell <object> for <amount>
sell <object> <creature> for <amount>
sell <object> to <creature> for <amount>
sell <creature> <object> for <amount>
sell to <creature> <object> for <amount>

buy/view <object>
buy/view <object> <creature>
buy/view <object> from <creature>
buy/view <creature> <object>
buy/view from <creature> <object>


Erok said:
Having the buyer specify the same gold as the seller acts as validation criteria to ensure the seller can't jack-up the price just as the buyer accepts the offer.

But what if they offer a different item with the same keywords just as the buyer accepts the offer?

My solution was that the purchase cannot be made within 3 seconds of the offer (likewise, it cannot be made after 30 seconds). I also store the price on the item itself, along with the timer and the recipient. I don't find the memory overhead to be a problem.

My shopkeepers use the same system, and make offers on request. This works for me as shopkeepers in my mud are rare, only have a few items, and aren't used much.

My 'give' command works much the same way, although players may choose to autoaccept via a config option.
27 Sep, 2009, Scandum wrote in the 4th comment:
Votes: 0
KaVir said:
But what if they offer a different item with the same keywords just as the buyer accepts the offer?

My solution was that the purchase cannot be made within 3 seconds of the offer (likewise, it cannot be made after 30 seconds). I also store the price on the item itself, along with the timer and the recipient.

That sounds rather annoying. Wouldn't it be easier to only allow one offer per player at a time, and require canceling the current offer before making another offer? I guess a 5 second wait should be added after a cancellation before you can offer again to prevent people from swapping unnoticed.

The most memory efficient approach is probably to use a global list of offers, with each node containing the seller, buyer, the object, and the price.
27 Sep, 2009, ghasatta wrote in the 5th comment:
Votes: 0
Hmm, I think I would need a little clarification on just what you are intending (i.e., what problem are you trying to solve?). I first read the OP to mean a way to codify a trade between two players. But now I am not so sure
Erok said:
where one player offers an item to another player (or anyone)


(emphasis added).

I foresee a few problems to be addressed if the approach described is used. Here are some critical questions:

What if a shopkeeper wanted to offer the item at different prices to different people?

What if you wanted to have a complex transaction? E.g., I offer you 10 sand dollars for a blue widget AND a red widget. Or if I offered you 3 sand dollars and a red widget for your blue widget?

What if you wanted to counter-offer?

What if you wanted to allow an item-for-item trade?

If I were starting from scratch, I would have an offer structure and either allow each character to have only 1 offer going at a time, or put a list of offers on the character. I don't think storing price on the object itself is so costly in terms of overhead to be impossible, but it probably will restrict you from doing more complex things.

HTH.
27 Sep, 2009, KaVir wrote in the 6th comment:
Votes: 0
Scandum said:
That sounds rather annoying. Wouldn't it be easier to only allow one offer per player at a time, and require canceling the current offer before making another offer?

I think that would be even more annoying, as it's not uncommon for players to offer several items at a time.
27 Sep, 2009, Erok wrote in the 7th comment:
Votes: 0
ghasatta said:
Erok said:
where one player offers an item to another player (or anyone)

Yes, specifying a player/creature in the offer is optional. When not specified, you are offering the item to any and all (this is what shopkeepers do).

ghasatta said:
What if a shopkeeper wanted to offer the item at different prices to different people?
What if you wanted to have a complex transaction? E.g., I offer you 10 sand dollars for a blue widget AND a red widget. Or if I offered you 3 sand dollars and a red widget for your blue widget?
What if you wanted to counter-offer?
What if you wanted to allow an item-for-item trade?

Can't do these currently, but I'm not sure supporting selling/trading at this level of complexity is worth it, at least via a text-based interface. Just my opinion, as I'm sure others would like to see this.

On the subject of security/validation, Kavir makes a good point and I can see how the timer solution alleviates the issue better than matching the purchase price, and also how it may annoy some players. What about a randomized alpha-numeric transaction ID, say just 2 or 3 characters in length? It could be generated when the offer is made, listed with the items when all the seller's offers are viewed, and used by the buyer to reference a specific item to view/purchase.
27 Sep, 2009, KaVir wrote in the 8th comment:
Votes: 0
Erok said:
On the subject of security/validation, Kavir makes a good point and I can see how the timer solution alleviates the issue better than matching the purchase price, and also how it may annoy some players.

It was actually added to address player complaints (about people who would switch the item at the last second), and I've never had any complaints about the 3 second delay. I doubt many people can type "view <object> <creature>", decide if it's worth buying, and then type "buy <object> <creature>", all in under 3 seconds.

Erok said:
What about a randomized alpha-numeric transaction ID, say just 2 or 3 characters in length? It could be generated when the offer is made, listed with the items when all the seller's offers are viewed, and used by the buyer to reference a specific item to view/purchase.

I wouldn't randomise it (on the off-chance that you get two the same). One particularly nice thing about such an approach is that if each transaction ID is unique, players wouldn't even need to specify who they were buying from.
28 Sep, 2009, Scandum wrote in the 9th comment:
Votes: 0
KaVir said:
I think that would be even more annoying, as it's not uncommon for players to offer several items at a time.

I was more thinking of buying items in bulk from shopkeepers being annoying, buying 20 items of the same type would take over a minute, unless the delay doesn't go for NPCs.
28 Sep, 2009, ghasatta wrote in the 10th comment:
Votes: 0
Erok said:
Can't do these currently, but I'm not sure supporting selling/trading at this level of complexity is worth it, at least via a text-based interface. Just my opinion, as I'm sure others would like to see this.
I offered the questions more in the spirit of stimulating your thinking. The implementation you decide to go with is going to be a product of the decisions you make re. what you do and don't want to make possible. So, consider yourself stimulated. :lol:
28 Sep, 2009, KaVir wrote in the 11th comment:
Votes: 0
Scandum said:
I was more thinking of buying items in bulk from shopkeepers being annoying, buying 20 items of the same type would take over a minute, unless the delay doesn't go for NPCs.

The 3 second delay is per-item, so you could request all the items up front and then spam 'buy' 3 seconds later. Of course that's not particularly nice for buying in bulk either, but as I said earlier, shopkeepers in my mud are rare, only have a few items, and aren't used much.

If shopkeepers were more widely used I'd probably just provide them a way to offer everything to everyone with no timer. But currently I've only got two shopkeeper mobs, and one of those is mostly a curiousity - so I decided to make their AI reuse the standard buy/sell code.
28 Sep, 2009, David Haley wrote in the 12th comment:
Votes: 0
To avoid the switching issues, I would suggest a transaction freeze of some kind. The transaction is only completed when both sides agree to it. Any modification by either party cancels any agreements. This generalizes very well to a full barter table, incidentally. I put this on the table, you put that on the table, we both agree, and stuff changes hands. If I agree, and then you remove something, my agreement is automatically withheld and I need to approve the new transaction again. Finally, one could use commands of some kind to indicate that you request a particular item from the other's inventory to be added to the table.

Implementation wise, I think it would be easy enough to create a transaction table item between any pair of characters engaged in a transaction. You would implement shopkeepers by having players request items from the shop's inventory; the shopkeeper would then expect some amount of cash (or item(s) worth something to the shopkeeper).
28 Sep, 2009, Grimble wrote in the 13th comment:
Votes: 0
Interesting thread.

David Haley said:
To avoid the switching issues, I would suggest a transaction freeze of some kind. The transaction is only completed when both sides agree to it. Any modification by either party cancels any agreements.

Hmmm…

1) seller puts a sword on the table
2) buyer puts 50gp on the table
3) seller agrees
4) seller switches a rusty fork for the sword
5) seller agrees
6) buyer agrees (and just paid 50gp for a rusty fork)

Maybe if any offer by the buyer has an implicit agree with it, giving

1) seller puts a sword on the table
2) buyer puts 50gp on the table (implicit agree)
3) seller agrees (transaction done)

and

1) seller puts a sword on the table
2) buyer puts 50gp on the table (implicit agree)
3) seller switches a rusty fork for the sword (buyer's offer canceled)

Actually, this can still be a problem because the seller can do a switch between step 1 and 2 in this last example sequence, and agree in step 3. I'm not sure your solution works David, at least as I understand it. Maybe you could provide a sequence of steps like the ones above to illustrate it.
28 Sep, 2009, David Haley wrote in the 14th comment:
Votes: 0
Well, I was thinking that once you agreed, you couldn't remove that agreement unless the transaction was changed. So, steps 4+5 would not be allowed. But, I suppose that there can still be some timing game, where something like this might happen:

1- Bob puts down a sword
2- John puts down 50 gp
(both wait a second or two)
3- Bob removes the sword and puts down a fork, agreeing
and immediately after, without seeing the change,
4- John agrees and spends 50 on a fork.

What I would propose then is modifying the trade table to work by not being able to remove particular items, but having to clear the entire table: this means that if you clear the table to put the fork, John's 50 goes away.

I don't like the delayed solutions, even if they help remove these timing games, because they make it difficult for good-faith business transactions. Of course, this table-clearing can be annoying too, if you're trying to negotiate a complex transaction and need to add/remove things several times as you discuss the terms. Perhaps the solution would be to have a modal interface, where you can request a timed delay on demand. (You would presumably only do this with people you don't trust.)

Basically, I want the simple transactions to be very simple. The common case of exchanging one item for another or one item for money should be easy to handle, while allowing complex transactions of several items/money for items items/money.

Besides, even with a timed delay, factors such as lag can get in the way of a timing solution unless you make the delay long enough that it's actually quite annoying.
28 Sep, 2009, Grimble wrote in the 15th comment:
Votes: 0
I think the short transaction key mentioned earlier could work reasonably well as a security mechanism. Whenever objects on the table change, the transaction key does as well. To agree to the transaction, the buyer and seller enter the matching transaction key as part of agreeing. There's no bait-n-switch to worry about because it would require a different key than the previous one, and no need for timers either.

The security mechanism could be optional, as you suggested, and disabled when you initiate a transaction with someone you already know and trust.
28 Sep, 2009, Erok wrote in the 16th comment:
Votes: 0
KaVir said:
I wouldn't randomise it (on the off-chance that you get two the same). One particularly nice thing about such an approach is that if each transaction ID is unique, players wouldn't even need to specify who they were buying from.


Good points. I think I'd like to make it so the transaction IDs are not consecutive though, to avoid, for example, "a2" being fat-fingered as "a3" and potentially getting the wrong item.
29 Sep, 2009, ATT_Turan wrote in the 17th comment:
Votes: 0
The whole table concept is very similar to how trading functions in Diablo II. You drag items into a shared window and check a box to signal your acceptance of the current deal - any change on either side causes both people to lose their checkboxes, making it impossible to trick your trading partner. If one presumes the worst possible faith on the part of one's players, I think the easiest way to replicate this functionality is to enforce a slight delay between any change to the table and either player being able to accept (or re-accept). Just a second would be sufficient to make sure the other person sees it when you change the table, even if they're in the middle of typing, and would take less time than reading and typing out a transaction ID. Of course, the latter notion has its own benefits, as mentioned above, but the table/acceptance idea could work quite well for regular person-on-person trading.
29 Sep, 2009, David Haley wrote in the 18th comment:
Votes: 0
ATT_Turan said:
You drag items into a shared window and check a box to signal your acceptance of the current deal - any change on either side causes both people to lose their checkboxes, making it impossible to trick your trading partner.

I think you can still trick the counterparty with careful timing, if you can anticipate when the trading partner will accept the deal. Grimble gave examples of this. Basically, you put a deal down, and then as they're about to accept you swap something and re-accept; they'll click accept before realizing that they aren't accepting what they thought they were.

The idea of transaction IDs isn't too bad, actually. I think you could probably just have linear numbers for the state of the table. I don't think you need fully unique IDs across all players, but that would be useful if you're trading with several people and don't want to track what's going on with each. (One wonders how often a player would be conducting transactions simultaneously, though: maybe just disallow more than one transaction? Allow an exception for NPCs, if they implement the same trading interface for shopkeepers.)
29 Sep, 2009, kiasyn wrote in the 19th comment:
Votes: 0
>trade testdummy

You begin trading with testdummy.

>offer sword
You offer a sword.
>offer mushrooms
You offer 2 mushrooms.
>offer glass
You offer a glass.

testdummy offers 100 gold.
testdummy accepts deal.

> accept
You accept the deal.

You are trading:
a sword
2 mushrooms
1 glass

You will recieve:
100 gold

Both players accepted deal, confirm and proceed with trade
testdummy confirmed trade.
> confirm
You confirmed the trade

Both players confirmed trade, trade complete.
29 Sep, 2009, KaVir wrote in the 20th comment:
Votes: 0
kiasyn, your approach might be nice for trading multiple items at a time, but in most cases transactions are fairly straightforward - and your proposal requires a lot of back-and-forth effort. Compare it to Erok's transaction ID proposal:

Testdummy offers to sell you a vorpal longsword for 100 gold (transaction ID #G78)

Testdummy offers to sell you a rusty longsword for 1000000 gold (transaction ID #M12)

> buy #G78
You buy a vorpal longsword from Testdummy for 100 gold.


Come to think of it, the lack of an explicit target would also make this approach ideal for an anonymous global auction system.
0.0/25