summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/defines.h5
-rw-r--r--src/game-server/buysell.cpp114
-rw-r--r--src/game-server/buysell.hpp78
-rw-r--r--src/game-server/character.cpp53
-rw-r--r--src/game-server/character.hpp39
-rw-r--r--src/game-server/gamehandler.cpp16
-rw-r--r--src/game-server/state.cpp3
-rw-r--r--src/game-server/trade.cpp8
-rw-r--r--src/game-server/trade.hpp41
-rw-r--r--src/scripting/lua.cpp32
11 files changed, 352 insertions, 39 deletions
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);