1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "player_trade.h"
25 #include "interface_manager.h"
26 #include "dbctrl_sheet.h"
27 #include "dbgroup_list_sheet.h"
28 #include "nel/gui/action_handler.h"
29 #include "inventory_manager.h"
31 #include "game_share/inventories.h"
33 #include "../sheet_manager.h"
34 #include "../client_sheets/item_sheet.h"
37 using namespace NLMISC
;
44 CPlayerTrade PlayerTrade
;
47 extern void contextHelp (const std::string
&help
);
49 //////////////////////
50 // MEMBER FUNCTIONS //
51 //////////////////////
54 void CPlayerTrade::putItemInExchange(CDBCtrlSheet
*src
, CDBCtrlSheet
*dest
, uint quantityMove
)
59 src
->copyAspect(dest
);
62 sint quantitySrc
= src
->getQuantity();
63 if((sint
)quantityMove
<quantitySrc
)
65 dest
->setQuantity(quantityMove
);
66 src
->setQuantity(quantitySrc
-quantityMove
);
68 // no more item in inventaire
76 void CPlayerTrade::restoreItem(CDBCtrlSheet
*exchangeSlot
)
78 if (!exchangeSlot
) return;
79 if (exchangeSlot
->getSheetId() == 0) return; // not used
80 CInventoryManager
&im
= getInventory();
82 // *** If not an AMMO, try to 'auto-stack', as server does
83 bool canAutoStack
= false;
84 uint32 autoStackSheetId
= 0;
85 sint32 autoStackQuality
= 0;
86 sint32 autoStackMaxQuantity
= 0;
87 const CItemSheet
*itemSheet
= exchangeSlot
->asItemSheet();
88 // NB: cannot auto stack ammo because their full props (dammage etc...) are not sent to client
91 canAutoStack
= itemSheet
->Stackable
>1 && itemSheet
->Family
!=ITEMFAMILY::AMMO
;
92 autoStackSheetId
= itemSheet
->Id
.asInt();
93 autoStackQuality
= exchangeSlot
->getQuality();
94 autoStackMaxQuantity
= itemSheet
->Stackable
;
97 // *** find an empty place in the inventory, or if autoStack, distribute over existing slot
99 sint32 quantityLeft
= exchangeSlot
->getQuantity();
100 for(uint k
= 0; k
< MAX_BAGINV_ENTRIES
; ++k
)
102 if (im
.getBagItem(k
).getSheetID() == 0)
105 // if cannot auto stack, don't need to go further
109 // can auto stack on this slot?
110 else if(canAutoStack
)
112 sint32 dstQuantity
= im
.getBagItem(k
).getQuantity();
114 // if same sheet/quality, and if can put some stack in this slot
115 if( im
.getBagItem(k
).getSheetID()==autoStackSheetId
&&
116 im
.getBagItem(k
).getQuality()==autoStackQuality
&&
117 dstQuantity
<autoStackMaxQuantity
)
119 // if can put all left stack
120 if(autoStackMaxQuantity
-dstQuantity
>=quantityLeft
)
122 im
.getBagItem(k
).setQuantity((uint16
)(dstQuantity
+quantityLeft
));
128 im
.getBagItem(k
).setQuantity((uint16
)autoStackMaxQuantity
);
129 quantityLeft
-= autoStackMaxQuantity
-dstQuantity
;
135 // if some quantity not distributed, Move all the remaining exchange slot to the empty slot detected (if any)
136 if(quantityLeft
&& emptySlot
>=0)
138 im
.getBagItem(emptySlot
).setSheetID(exchangeSlot
->getSheetId());
139 im
.getBagItem(emptySlot
).setQuality((uint16
) exchangeSlot
->getQuality());
140 im
.getBagItem(emptySlot
).setQuantity((uint16
) quantityLeft
);
141 im
.getBagItem(emptySlot
).setUserColor((uint8
) exchangeSlot
->getItemColor());
142 im
.getBagItem(emptySlot
).setWeight((uint32
) exchangeSlot
->getItemWeight());
143 im
.getBagItem(emptySlot
).setNameId(exchangeSlot
->getItemNameId());
144 im
.getBagItem(emptySlot
).setInfoVersion(exchangeSlot
->getItemInfoVersion());
145 im
.getBagItem(emptySlot
).setResaleFlag(exchangeSlot
->getItemResaleFlag());
149 // clear item from exchange
150 exchangeSlot
->setSheetId(0);
151 exchangeSlot
->setQuality(0);
152 exchangeSlot
->setQuantity(0);
155 CDBCtrlSheet
*CPlayerTrade::getExchangeItem(uint index
)
157 CInterfaceManager
*im
= CInterfaceManager::getInstance();
158 return dynamic_cast<CDBCtrlSheet
*>(CWidgetManager::getInstance()->getElementFromId(NLMISC::toString("ui:interface:player_trade:header_opened:give:given_items:slot%d", (int) index
)));
162 void CPlayerTrade::restoreAllItems()
164 for(uint k
= 0; k
< NumTradeSlot
; ++k
)
166 restoreItem(getExchangeItem(k
));
171 /////////////////////
172 // ACTION HANDLERS //
173 /////////////////////
175 class CPlayerTradeStartHandler
: public IActionHandler
177 virtual void execute (CCtrlBase
* /* pCaller */, const string
&/* Params */)
179 CInterfaceManager
*im
= CInterfaceManager::getInstance();
180 if (NLGUI::CDBManager::getInstance()->getDbProp("LOCAL:EXCHANGE:BEGUN")->getValue8() != 0)
182 //PlayerTrade.reset();
185 contextHelp ("inventory");
189 REGISTER_ACTION_HANDLER(CPlayerTradeStartHandler
, "player_trade_start");
192 class CPlayerTradeLeftClickOnSlotHandler
: public IActionHandler
194 virtual void execute (CCtrlBase
*pCaller
, const string
&/* Params */)
196 CDBCtrlSheet
*sheet
= dynamic_cast<CDBCtrlSheet
*>(pCaller
);
198 if (sheet
->getSheetId() == 0)
200 CInventoryManager
*pInv
= CInventoryManager::getInstance();
201 // is there's no item that is not worn, can't choose any item)
202 bool isThereObjectNotWorn
= false;
203 for(uint k
= 0; k
< MAX_BAGINV_ENTRIES
; ++k
)
205 uint32 sheetid
= pInv
->getBagItem(k
).getSheetID();
208 if (!pInv
->isBagItemWeared(k
))
210 CEntitySheet
*pES
= SheetMngr
.get(CSheetId(sheetid
));
211 if (pES
&& pES
->type()== CEntitySheet::ITEM
)
213 CItemSheet
*pIS
= (CItemSheet
*)pES
;
214 if (pIS
->canExchangeOrGive(PlayerTrade
.BotChatGiftContext
))
216 isThereObjectNotWorn
= true;
224 if (!isThereObjectNotWorn
)
226 // every object are worn, so there's no use to display an empty list -> no-op
230 CInterfaceManager
*im
= CInterfaceManager::getInstance();
231 CWidgetManager::getInstance()->pushModalWindow(pCaller
, "ui:interface:exchange_choose_in_bag");
234 REGISTER_ACTION_HANDLER(CPlayerTradeLeftClickOnSlotHandler
, "exchange_left_click_on_slot");