00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <algorithm>
00023 #include <cassert>
00024
00025 #include "game-server/trade.hpp"
00026
00027 #include "defines.h"
00028 #include "game-server/character.hpp"
00029 #include "game-server/gamehandler.hpp"
00030 #include "game-server/inventory.hpp"
00031 #include "net/messageout.hpp"
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042 Trade::Trade(Character *c1, Character *c2):
00043 mChar1(c1), mChar2(c2), mMoney1(0), mMoney2(0), mState(TRADE_INIT)
00044 {
00045 MessageOut msg(GPMSG_TRADE_REQUEST);
00046 msg.writeShort(c1->getPublicID());
00047 c2->getClient()->send(msg);
00048 c1->setTrading(this);
00049 c2->setTrading(this);
00050 }
00051
00052 Trade::~Trade()
00053 {
00054 mChar1->setTrading(NULL);
00055 mChar2->setTrading(NULL);
00056 }
00057
00058 void Trade::cancel()
00059 {
00060 MessageOut msg(GPMSG_TRADE_CANCEL);
00061 mChar1->getClient()->send(msg);
00062 mChar2->getClient()->send(msg);
00063 delete this;
00064 }
00065
00066 bool Trade::request(Character *c, int id)
00067 {
00068
00069 if (mState != TRADE_INIT || c != mChar2 || mChar1->getPublicID() != id)
00070 {
00071
00072
00073 cancel();
00074 return false;
00075 }
00076
00077
00078
00079
00080 mState = TRADE_RUN;
00081
00082
00083 MessageOut msg(GPMSG_TRADE_START);
00084 mChar1->getClient()->send(msg);
00085 mChar2->getClient()->send(msg);
00086 return true;
00087 }
00088
00089 bool Trade::perform(TradedItems items, Inventory &inv1, Inventory &inv2)
00090 {
00091 for (TradedItems::const_iterator i = items.begin(),
00092 i_end = items.end(); i != i_end; ++i)
00093 {
00094 if (i->id != inv1.getItem(i->slot) ||
00095 inv1.removeFromSlot(i->slot, i->amount) != 0 ||
00096 inv2.insert(i->id, i->amount) != 0)
00097 {
00098 return false;
00099 }
00100 }
00101 return true;
00102 }
00103
00104 void Trade::agree(Character *c)
00105 {
00106
00107 if(mState == TRADE_CONFIRMED)
00108 {
00109
00110 if (c == mChar2)
00111 {
00112 std::swap(mChar1, mChar2);
00113 std::swap(mItems1, mItems2);
00114 std::swap(mMoney1, mMoney2);
00115 }
00116
00117 mState = TRADE_CONFIRM_WAIT;
00118
00119
00120 MessageOut msg(GPMSG_TRADE_AGREED);
00121 mChar2->getClient()->send(msg);
00122 return;
00123 }
00124
00125 if(mState == TRADE_AGREE_WAIT && c == mChar1)
00126 {
00127
00128 return;
00129 }
00130
00131
00132
00133
00134
00135 Inventory v1(mChar1, true), v2(mChar2, true);
00136 if (!perform(mItems1, v1, v2) ||
00137 !perform(mItems2, v2, v1) ||
00138 !v1.changeMoney(mMoney2 - mMoney1) ||
00139 !v2.changeMoney(mMoney1 - mMoney2))
00140 {
00141 v1.cancel();
00142 v2.cancel();
00143 cancel();
00144 return;
00145 }
00146
00147 MessageOut msg(GPMSG_TRADE_COMPLETE);
00148 mChar1->getClient()->send(msg);
00149 mChar2->getClient()->send(msg);
00150 delete this;
00151 }
00152
00153 void Trade::confirm(Character *c)
00154 {
00155 if(mState == TRADE_CONFIRMED || mState == TRADE_AGREE_WAIT) return;
00156
00157 if (mState == TRADE_RUN)
00158 {
00159
00160 if (c == mChar2)
00161 {
00162 std::swap(mChar1, mChar2);
00163 std::swap(mItems1, mItems2);
00164 std::swap(mMoney1, mMoney2);
00165 }
00166 assert(c == mChar1);
00167
00168 mState = TRADE_CONFIRM_WAIT;
00169
00170
00171 MessageOut msg(GPMSG_TRADE_CONFIRM);
00172 mChar2->getClient()->send(msg);
00173 return;
00174 }
00175
00176 if (mState != TRADE_CONFIRM_WAIT || c != mChar2)
00177 {
00178
00179 return;
00180 }
00181
00182 mState = TRADE_CONFIRMED;
00183 MessageOut msg(GPMSG_TRADE_BOTH_CONFIRM);
00184 mChar1->getClient()->send(msg);
00185 mChar2->getClient()->send(msg);
00186 }
00187
00188 void Trade::setMoney(Character *c, int amount)
00189 {
00190
00191 if ((mState != TRADE_RUN && (mState != TRADE_CONFIRM_WAIT || c != mChar1))
00192 || amount < 0) return;
00193
00194
00195
00196
00197
00198 MessageOut msg(GPMSG_TRADE_SET_MONEY);
00199 msg.writeLong(amount);
00200
00201 if (c == mChar1)
00202 {
00203 mMoney1 = amount;
00204 mChar2->getClient()->send(msg);
00205 }
00206 else
00207 {
00208 assert(c == mChar2);
00209 mMoney2 = amount;
00210 mChar1->getClient()->send(msg);
00211 }
00212
00213
00214 mState = TRADE_RUN;
00215 }
00216
00217 void Trade::addItem(Character *c, int slot, int amount)
00218 {
00219
00220 if ((mState != TRADE_RUN && (mState != TRADE_CONFIRM_WAIT || c != mChar1))
00221 || amount < 0) return;
00222
00223 Character *other;
00224 TradedItems *items;
00225 if (c == mChar1)
00226 {
00227 other = mChar2;
00228 items = &mItems1;
00229 }
00230 else
00231 {
00232 assert(c == mChar2);
00233 other = mChar1;
00234 items = &mItems2;
00235 }
00236
00237
00238 if (items->size() >= 50) return;
00239
00240 Inventory inv(c);
00241 int id = inv.getItem(slot);
00242 if (id == 0) return;
00243
00244
00245
00246
00247
00248 TradedItem ti = { id, slot, amount };
00249 items->push_back(ti);
00250
00251 MessageOut msg(GPMSG_TRADE_ADD_ITEM);
00252 msg.writeShort(id);
00253 msg.writeByte(amount);
00254 other->getClient()->send(msg);
00255 }