Monday, September 24, 2007

Player to player trading - How littles things can be so complicated

I thought that doing player to player trading was gonna be an easy ride. Well, I couldn't be more wrong. Beside just building the mechanic, I was constantly adding more and more validation to prevent cheating. Most of mechanics I took from Magic The Gathering Online system.

So let's see what I needed. I wanted players to be able to trade items AND money (just addind a /tip command wasn't good enough since I wanted to make sure players can do fair trades without having to rely on trust that the other will pay them).

So the commands looks like this:
- trade (send trade request / accept trade request)
- add item
- remove item
- update money
- accept (true or false)
- cancel trade

The interface will basically have 3 lists:
- Character's inventory
- Current character's items offer
- Other character's items offer

There's a textbox to insert money and a checkbox allowing each characters to accept the trade.

The first "anti-cheat" mechanic I added was to make sure that if Character A accepted the trade and that Character B modify it before accepting, the "accept" status is reseted. That way, there's no last minute changes without leaving the other reconsider the trade.

When an item (or money) is added to the trade, there's another system to make sure the character actually possess the item or have enough money. If not, the other player won't even see the illegal action. I had to add this since the way the interface interact with the server would be pretty easy to "hack". Remember, all commands can be used in the chat window so someone digging in the javascript a bit could figure how to send each parameters and try to trade an item he doesn't even possess.

The exact same check is made in the SQL database when the trade is accepted by both players. The reason is that when 2 characters trade together, everything else is still running in the background. A character could put an item for trade and then remove it from his inventory (or maybe even trade it to an alt or something). When the stored procedure is executed, there's nothing that can be modified to the trade. If the items and money states aren't the same as before accepting the trade, everything is canceled and the trade instance is deleted.

Beside those points, there's a system to make sure a character is currently trading with only another one character, again to make sure no item is lost.

One thing that always fascinated me is how almost all games have/had bugs allowing items to be duplicated. I think I made a good job that at least the trading system won't allow this. In the data, the object is never "moved" or deleted/recreated. The link to the character remains on the item so when an item is traded, only the reference to the character is changed, avoiding leaving a ghost item somewhere.

I haven't build a fully operational interface for this system yet and I believe it will wait until I get seriously into the interface. All those interaction (drag and drop, lots of events received) made it complicated to find my way in my prototype that is beginning to look a bit ugly by pushing a little bit of not so well thought code. The good thing is that with that prototype, I get a good sense of what not to do once I'll start coding the real interface. So far I have a list full and I'm still learning new tricks about how to use script.aculo.us.

What's next? I really want at least a basic guild system with guild chat for the first version and I have yet to work on PVE. That one should be a nice challenge. After this, if I check my to-do list, it's pretty much just revisiting existing functions to polish them and make sure they're usable in a real case scenario.

I feel I need to hit the brakes a bit before getting into something too big. That also means that I need to rethink my first game idea. What I have in mind now wouldn't require much "game specific" mechanics so I think it's better. The only real big thing to add would be a crafting system. Enough said for now, need to do before.

0 Comments: