diff options
-rw-r--r-- | ChangeLog | 7 | ||||
-rw-r--r-- | data/test.lua | 6 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/defines.h | 5 | ||||
-rw-r--r-- | src/game-server/buysell.cpp | 114 | ||||
-rw-r--r-- | src/game-server/buysell.hpp | 78 | ||||
-rw-r--r-- | src/game-server/character.cpp | 53 | ||||
-rw-r--r-- | src/game-server/character.hpp | 39 | ||||
-rw-r--r-- | src/game-server/gamehandler.cpp | 16 | ||||
-rw-r--r-- | src/game-server/state.cpp | 3 | ||||
-rw-r--r-- | src/game-server/trade.cpp | 8 | ||||
-rw-r--r-- | src/game-server/trade.hpp | 41 | ||||
-rw-r--r-- | src/scripting/lua.cpp | 32 |
13 files changed, 364 insertions, 40 deletions
@@ -13,6 +13,13 @@ src/account-server/dalstoragesql.hpp, src/dal/dataproviderfactory.cpp, src/account-server/accounthandler.cpp: Cleaned configuration. Removed obsolete SQL tables. + * src/defines.h, src/Makefile.am, src/game-server/trade.cpp, + src/game-server/trade.hpp, src/game-server/state.cpp, + src/game-server/character.cpp, src/game-server/character.hpp, + src/game-server/gamehandler.cpp, src/game-server/buysell.cpp, + src/game-server/buysell.hpp: Implemented buy/sell handler. + * src/scripting/lua.cpp, data/test.lua: Added a bit of buy/sell testing + code. 2007-08-11 Guillaume Melquiond <guillaume.melquiond@gmail.com> diff --git a/data/test.lua b/data/test.lua index 6b914634..f9ffb8fe 100644 --- a/data/test.lua +++ b/data/test.lua @@ -107,7 +107,7 @@ function my_npc1(npc, ch) do_message(npc, ch, "Hello! I am the testing NPC") do_message(npc, ch, "This message is just here for testing intertwined connections.") do_message(npc, ch, "What do you want?") - local v = do_choice(npc, ch, "Guns! Lots of guns!", "A christmas party!", "Nothing.") + local v = do_choice(npc, ch, "Guns! Lots of guns!", "A christmas party!", "To buy.", "To sell.", "Nothing.") if v == 1 then do_message(npc, ch, "Sorry, this is a heroic-fantasy game, I do not have any gun.") elseif v == 2 then @@ -121,6 +121,10 @@ function my_npc1(npc, ch) tmw.chr_inv_change(ch, 524, -1, 511, 1) end end + elseif v == 3 then + tmw.test_npc_buy(npc, ch) + elseif v == 4 then + tmw.test_npc_sell(npc, ch) end end diff --git a/src/Makefile.am b/src/Makefile.am index 51087749..6ddc3a11 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -80,6 +80,8 @@ tmwserv_game_SOURCES = \ game-server/accountconnection.cpp \ game-server/being.hpp \ game-server/being.cpp \ + game-server/buysell.hpp \ + game-server/buysell.cpp \ game-server/character.hpp \ game-server/character.cpp \ game-server/collisiondetection.hpp \ diff --git a/src/defines.h b/src/defines.h index 3e172489..2f1fbd57 100644 --- a/src/defines.h +++ b/src/defines.h @@ -166,11 +166,14 @@ enum { GPMSG_BEING_ATTACK = 0x0291, // W being id, B direction PGMSG_SAY = 0x02A0, // S text GPMSG_SAY = 0x02A1, // W being id, S text - GPMSG_NPC_CHOICE = 0x02B0, // W being id, B* text + GPMSG_NPC_CHOICE = 0x02B0, // W being id, { S text }* GPMSG_NPC_MESSAGE = 0x02B1, // W being id, B* text PGMSG_NPC_TALK = 0x02B2, // W being id PGMSG_NPC_TALK_NEXT = 0x02B3, // W being id PGMSG_NPC_SELECT = 0x02B4, // W being id, B choice + GPMSG_NPC_BUY = 0x02B5, // W being id, { W item id, W amount, W cost }* + GPMSG_NPC_SELL = 0x02B6, // W being id, { W item id, W amount, W cost }* + PGMSG_NPC_BUYSELL = 0x02B7, // W item id, W amount PGMSG_TRADE_REQUEST = 0x02C0, // W being id GPMSG_TRADE_REQUEST = 0x02C1, // W being id GPMSG_TRADE_START = 0x02C2, // - diff --git a/src/game-server/buysell.cpp b/src/game-server/buysell.cpp new file mode 100644 index 00000000..e73141df --- /dev/null +++ b/src/game-server/buysell.cpp @@ -0,0 +1,114 @@ +/* + * The Mana World Server + * Copyright 2007 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#include <algorithm> + +#include "game-server/buysell.hpp" + +#include "defines.h" +#include "game-server/character.hpp" +#include "game-server/gamehandler.hpp" +#include "game-server/inventory.hpp" +#include "net/messageout.hpp" + +BuySell::BuySell(Character *c, bool sell): + mChar(c), mSell(sell) +{ + c->setBuySell(this); +} + +BuySell::~BuySell() +{ + mChar->cancelTransaction(); +} + +void BuySell::cancel() +{ + delete this; +} + +void BuySell::registerItem(int id, int amount, int cost) +{ + if (mSell) + { + int nb = Inventory(mChar).count(id); + if (nb == 0) return; + if (!amount || nb < amount) amount = nb; + } + + TradedItem it = { id, amount, cost }; + mItems.push_back(it); +} + +void BuySell::start(MovingObject *obj) +{ + if (mItems.empty()) + { + cancel(); + return; + } + + MessageOut msg(mSell ? GPMSG_NPC_SELL : GPMSG_NPC_BUY); + msg.writeShort(obj->getPublicID()); + for (TradedItems::const_iterator i = mItems.begin(), + i_end = mItems.end(); i != i_end; ++i) + { + msg.writeShort(i->itemId); + msg.writeShort(i->amount); + msg.writeShort(i->cost); + } + mChar->getClient()->send(msg); +} + +void BuySell::perform(int id, int amount) +{ + Inventory inv(mChar); + int money = mChar->getMoney(); + for (TradedItems::iterator i = mItems.begin(), + i_end = mItems.end(); i != i_end; ++i) + { + if (i->itemId != id) continue; + if (i->amount && i->amount <= amount) amount = i->amount; + if (mSell) + { + amount -= inv.remove(id, amount); + money += amount * i->cost; + } + else + { + amount = std::min(amount, money / i->cost); + amount -= inv.insert(id, amount); + money -= amount * i->cost; + } + if (i->amount) + { + i->amount -= amount; + if (!i->amount) + { + mItems.erase(i); + } + } + mChar->setMoney(money); + return; + } +} diff --git a/src/game-server/buysell.hpp b/src/game-server/buysell.hpp new file mode 100644 index 00000000..7a579271 --- /dev/null +++ b/src/game-server/buysell.hpp @@ -0,0 +1,78 @@ +/* + * The Mana World Server + * Copyright 2007 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#ifndef _TMWSERV_GAMESERVER_BUYSELL_HPP_ +#define _TMWSERV_GAMESERVER_BUYSELL_HPP_ + +#include <vector> + +class Character; +class MovingObject; + +class BuySell +{ + public: + + /** + * Sets up a trade between a character and an NPC. + */ + BuySell(Character *, bool sell); + + /** + * Cancels the trade. + */ + void cancel(); + + /** + * Registers an item and indicates how many the NPC is ready to trade + * and how much it will cost. + */ + void registerItem(int id, int amount, int cost); + + /** + * Sends the item list to player. + */ + void start(MovingObject *obj); + + /** + * Performs the trade. + */ + void perform(int id, int amount); + + private: + + ~BuySell(); + + struct TradedItem + { + unsigned short itemId, amount, cost; + }; + + typedef std::vector< TradedItem > TradedItems; + + Character *mChar; /**< Character involved. */ + TradedItems mItems; /**< Traded items. */ + bool mSell; /**< Are items sold? */ +}; + +#endif diff --git a/src/game-server/character.cpp b/src/game-server/character.cpp index 1fb9b2fe..7a9372fb 100644 --- a/src/game-server/character.cpp +++ b/src/game-server/character.cpp @@ -22,19 +22,22 @@ #include <cassert> -#include "defines.h" #include "game-server/character.hpp" + +#include "defines.h" +#include "game-server/buysell.hpp" #include "game-server/mapcomposite.hpp" #include "game-server/mapmanager.hpp" +#include "game-server/trade.hpp" #include "net/messagein.hpp" #include "net/messageout.hpp" #include "serialize/characterdata.hpp" Character::Character(MessageIn & msg): Being(OBJECT_CHARACTER, 65535), - mClient(NULL), mTrading(NULL), mDatabaseID(-1), + mClient(NULL), mTransactionHandler(NULL), mDatabaseID(-1), mMoney(0), mGender(0), mHairStyle(0), mHairColor(0), mLevel(0), - mAttributesChanged(true) + mTransaction(TRANS_NONE), mAttributesChanged(true) { // prepare attributes vector mAttributes.resize(NB_ATTRIBUTES_CHAR, 1); @@ -121,3 +124,47 @@ void Character::setMapId(int id) { setMap(MapManager::getMap(id)); } + +void Character::cancelTransaction() +{ + TransactionType t = mTransaction; + mTransaction = TRANS_NONE; + switch (t) + { + case TRANS_TRADE: + static_cast< Trade * >(mTransactionHandler)->cancel(this); + break; + case TRANS_BUYSELL: + static_cast< BuySell * >(mTransactionHandler)->cancel(); + break; + case TRANS_NONE: + return; + } +} + +Trade *Character::getTrading() const +{ + return mTransaction == TRANS_TRADE + ? static_cast< Trade * >(mTransactionHandler) : NULL; +} + +BuySell *Character::getBuySell() const +{ + return mTransaction == TRANS_BUYSELL + ? static_cast< BuySell * >(mTransactionHandler) : NULL; +} + +void Character::setTrading(Trade *t) +{ + cancelTransaction(); + mTransactionHandler = t; + mTransaction = TRANS_TRADE; +} + +void Character::setBuySell(BuySell *t) +{ + cancelTransaction(); + mTransactionHandler = t; + mTransaction = TRANS_BUYSELL; +} + diff --git a/src/game-server/character.hpp b/src/game-server/character.hpp index efb93e1e..ff59c8a9 100644 --- a/src/game-server/character.hpp +++ b/src/game-server/character.hpp @@ -29,6 +29,7 @@ #include "common/inventorydata.hpp" #include "game-server/being.hpp" +class BuySell; class GameClient; class MessageIn; class MessageOut; @@ -78,16 +79,37 @@ class Character : public Being { return mPossessions; } /** - * Gets the trade object the character is involved in. + * Gets the Trade object the character is involved in. */ - Trade *getTrading() const - { return mTrading; } + Trade *getTrading() const; + + /** + * Sets the Trade object the character is involved in. + * Cancels other transactions. + */ + void setTrading(Trade *t); + + /** + * Gets the BuySell object the character is involved in. + */ + BuySell *getBuySell() const; /** * Sets the trade object the character is involved in. + * Cancels other transactions. */ - void setTrading(Trade *t) - { mTrading = t; } + void setBuySell(BuySell *t); + + /** + * Cancels current transaction. + */ + void cancelTransaction(); + + /** + * Gets transaction status of the character. + */ + bool isBusy() const + { return mTransaction != TRANS_NONE; } /* * Character data: @@ -211,8 +233,12 @@ class Character : public Being Character(Character const &); Character &operator=(Character const &); + enum TransactionType + { TRANS_NONE, TRANS_TRADE, TRANS_BUYSELL }; + GameClient *mClient; /**< Client computer. */ - Trade *mTrading; /**< Trade object the character is involved in. */ + /** Handler of the transaction the character is involved in. */ + void *mTransactionHandler; /** Atributes as the client should currently know them. */ std::vector<unsigned short> mOldAttributes; @@ -226,6 +252,7 @@ class Character : public Being unsigned char mHairStyle; /**< Hair Style of the character. */ unsigned char mHairColor; /**< Hair Color of the character. */ unsigned char mLevel; /**< Level of the character. */ + TransactionType mTransaction; /**< Trade/buy/sell action the character is involved in. */ /** * true when one or more attributes might have changed since the diff --git a/src/game-server/gamehandler.cpp b/src/game-server/gamehandler.cpp index 17ce6dee..7e860ab1 100644 --- a/src/game-server/gamehandler.cpp +++ b/src/game-server/gamehandler.cpp @@ -21,12 +21,13 @@ * $Id$ */ -#include "game-server/gamehandler.hpp" - #include <cassert> #include <map> +#include "game-server/gamehandler.hpp" + #include "game-server/accountconnection.hpp" +#include "game-server/buysell.hpp" #include "game-server/inventory.hpp" #include "game-server/item.hpp" #include "game-server/itemmanager.hpp" @@ -335,7 +336,7 @@ void GameHandler::processMessage(NetComputer *comp, MessageIn &message) } Character *q = findCharacterNear(computer.character, id); - if (!q || q->getTrading()) + if (!q || q->isBusy()) { result.writeShort(GPMSG_TRADE_CANCEL); break; @@ -366,7 +367,14 @@ void GameHandler::processMessage(NetComputer *comp, MessageIn &message) } } break; - + case PGMSG_NPC_BUYSELL: + { + BuySell *t = computer.character->getBuySell(); + if (!t) break; + int id = message.readShort(); + int amount = message.readShort(); + t->perform(id, amount); + } break; // The following messages should be handled by the chat server, not the game server. #if 0 diff --git a/src/game-server/state.cpp b/src/game-server/state.cpp index 9262798f..f5dcf917 100644 --- a/src/game-server/state.cpp +++ b/src/game-server/state.cpp @@ -507,8 +507,7 @@ void GameState::remove(Thing *ptr) { if (ptr->getType() == OBJECT_CHARACTER) { - Character *ch = static_cast< Character * >(ptr); - if (Trade *t = ch->getTrading()) t->cancel(ch); + static_cast< Character * >(ptr)->cancelTransaction(); } MovingObject *obj = static_cast< MovingObject * >(ptr); diff --git a/src/game-server/trade.cpp b/src/game-server/trade.cpp index c6cd8425..3bb25b61 100644 --- a/src/game-server/trade.cpp +++ b/src/game-server/trade.cpp @@ -44,8 +44,8 @@ Trade::Trade(Character *c1, Character *c2): Trade::~Trade() { - mChar1->setTrading(NULL); - mChar2->setTrading(NULL); + mChar1->cancelTransaction(); + mChar2->cancelTransaction(); } void Trade::cancel(Character *c) @@ -74,7 +74,7 @@ bool Trade::request(Character *c, int id) return true; } -static bool performTrade(TradedItems items, Inventory &inv1, Inventory &inv2) +bool Trade::perform(TradedItems items, Inventory &inv1, Inventory &inv2) { for (TradedItems::const_iterator i = items.begin(), i_end = items.end(); i != i_end; ++i) @@ -113,7 +113,7 @@ void Trade::accept(Character *c) } Inventory v1(mChar1, true), v2(mChar2, true); - if (!performTrade(mItems1, v1, v2) || !performTrade(mItems2, v2, v1)) + if (!perform(mItems1, v1, v2) || !perform(mItems2, v2, v1)) { v1.cancel(); v2.cancel(); diff --git a/src/game-server/trade.hpp b/src/game-server/trade.hpp index ec5239d0..33662e73 100644 --- a/src/game-server/trade.hpp +++ b/src/game-server/trade.hpp @@ -21,27 +21,13 @@ * $Id$ */ -#ifndef _TMSERV_GAMESERVER_TRADE_HPP_ -#define _TMSERV_GAMESERVER_TRADE_HPP_ +#ifndef _TMWSERV_GAMESERVER_TRADE_HPP_ +#define _TMWSERV_GAMESERVER_TRADE_HPP_ #include <vector> class Character; - -enum TradeState -{ - TRADE_INIT = 0, /**< Waiting for an ack from player 2. */ - TRADE_RUN, /**< Currently trading. */ - TRADE_EXIT /**< Waiting for an ack from player 2. */ -}; - -struct TradedItem -{ - unsigned short id; - unsigned char slot, amount; -}; - -typedef std::vector< TradedItem > TradedItems; +class Inventory; class Trade { @@ -53,8 +39,6 @@ class Trade */ Trade(Character *, Character *); - ~Trade(); - /** * Cancels a trade by a given character (optional). * Warns the other character the trade is cancelled. @@ -82,6 +66,25 @@ class Trade private: + ~Trade(); + + struct TradedItem + { + unsigned short id; + unsigned char slot, amount; + }; + + typedef std::vector< TradedItem > TradedItems; + + enum TradeState + { + TRADE_INIT = 0, /**< Waiting for an ack from player 2. */ + TRADE_RUN, /**< Currently trading. */ + TRADE_EXIT /**< Waiting for an ack from player 2. */ + }; + + static bool perform(TradedItems items, Inventory &inv1, Inventory &inv2); + Character *mChar1, *mChar2; /**< Characters involved. */ TradedItems mItems1, mItems2; /**< Traded items. */ TradeState mState; diff --git a/src/scripting/lua.cpp b/src/scripting/lua.cpp index 1fdd90e4..636417f9 100644 --- a/src/scripting/lua.cpp +++ b/src/scripting/lua.cpp @@ -30,6 +30,7 @@ extern "C" { #include "defines.h" #include "resourcemanager.h" +#include "game-server/buysell.hpp" #include "game-server/character.hpp" #include "game-server/gamehandler.hpp" #include "game-server/inventory.hpp" @@ -299,6 +300,35 @@ static int LuaChr_InvCount(lua_State *s) return nb_items; } +// For testing purpose. +static int test_NpcBuy(lua_State *s) +{ + NPC *p = getNPC(s, 1); + Character *q = getCharacter(s, 2); + if (!p || !q) return 0; + BuySell *t = new BuySell(q, false); + t->registerItem(533, 10, 20); + t->registerItem(535, 10, 30); + t->registerItem(537, 10, 50); + t->start(p); + return 0; +} + +// For testing purpose. +static int test_NpcSell(lua_State *s) +{ + NPC *p = getNPC(s, 1); + Character *q = getCharacter(s, 2); + if (!p || !q) return 0; + BuySell *t = new BuySell(q, true); + t->registerItem(511, 10, 200); + t->registerItem(524, 10, 300); + t->registerItem(508, 10, 500); + t->registerItem(537, 10, 25); + t->start(p); + return 0; +} + LuaScript::LuaScript(lua_State *s): mState(s), nbArgs(-1) @@ -322,6 +352,8 @@ LuaScript::LuaScript(lua_State *s): { "chr_warp", &LuaChr_Warp }, { "chr_inv_change", &LuaChr_InvChange }, { "chr_inv_count", &LuaChr_InvCount }, + { "test_npc_buy", &test_NpcBuy }, + { "test_npc_sell", &test_NpcSell }, { NULL, NULL } }; luaL_register(mState, "tmw", callbacks); |