Linux multi-monitor fullscreen support
[ryzomcore.git] / ryzom / client / src / interface_v3 / action_phrase_faber.cpp
blob4fcf6b2fa96446adb412ab7e9d70d786d51308c0
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2014 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2012 Matt RAYKOWSKI (sfb) <matt.raykowski@gmail.com>
6 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
7 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
8 //
9 // This program is free software: you can redistribute it and/or modify
10 // it under the terms of the GNU Affero General Public License as
11 // published by the Free Software Foundation, either version 3 of the
12 // License, or (at your option) any later version.
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU Affero General Public License for more details.
19 // You should have received a copy of the GNU Affero General Public License
20 // along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "stdpch.h"
25 #include "action_phrase_faber.h"
26 #include "../client_sheets/sbrick_sheet.h"
27 #include "interface_manager.h"
28 #include "../sheet_manager.h"
29 #include "inventory_manager.h"
30 #include "nel/gui/action_handler.h"
31 #include "../client_cfg.h"
32 #include "nel/gui/ctrl_base_button.h"
33 #include "nel/gui/group_container.h"
34 #include "../string_manager_client.h"
35 #include "../net_manager.h"
36 #include "sbrick_manager.h"
37 #include "sphrase_manager.h"
38 #include "nel/gui/group_editbox.h"
39 #include "nel/gui/dbview_bar.h"
40 #include "skill_manager.h"
41 #include "game_share/bot_chat_types.h"
43 #ifdef DEBUG_NEW
44 #define new DEBUG_NEW
45 #endif
47 using namespace std;
48 using namespace NLMISC;
51 // ***************************************************************************
52 const std::string FaberPlanDB= "UI:PHRASE:FABER:FABER_PLAN:SHEET";
53 const std::string MPFaberDB= "UI:PHRASE:FABER:MP_BUILD";
54 const std::string MPSelectionDB= "UI:PHRASE:FABER:MP_SELECT";
55 const std::string MPQuantityDb= "UI:PHRASE:FABER:MP_QUANTITY";
56 const std::string MPQuantitySelectDb= "UI:PHRASE:FABER:STACK_SELECT";
57 const std::string ItemResultSheetDB= "UI:PHRASE:FABER:RESULT_ITEM:SHEET";
58 const std::string ItemResultQuantityDB= "UI:PHRASE:FABER:RESULT_ITEM:QUANTITY";
59 const std::string ItemResultSheetLevel= "UI:PHRASE:FABER:RESULT_ITEM:QUALITY";
60 const std::string ItemResultSheetColor= "UI:PHRASE:FABER:RESULT_ITEM:USER_COLOR";
61 const std::string ItemResultSheetClassType= "UI:PHRASE:FABER:RESULT_ITEM:RM_CLASS_TYPE";
62 const std::string ItemResultSheetStatType= "UI:PHRASE:FABER:RESULT_ITEM:RM_FABER_STAT_TYPE";
63 const std::string FaberPhraseWindow= "ui:interface:phrase_faber_execution";
64 const std::string FaberPhraseItemReqLine= FaberPhraseWindow + ":header_opened:item_reqs:item_req_%d";
65 const std::string FaberPhraseList= "list";
66 const std::string FaberPhraseText= "text";
67 const std::string FaberPhraseIcon= "icon";
68 const std::string FaberPhraseValidButton= FaberPhraseWindow + ":header_opened:ok_cancel:ok";
69 const std::string FaberPhraseFpCtrl= FaberPhraseWindow + ":header_opened:faber_plan";
70 const std::string FaberPhraseFpSuccessText= FaberPhraseWindow + ":header_opened:success_text";
71 const std::string FaberPhraseMpListModal= "ui:interface:phrase_faber_mp_selection";
72 const std::string FaberPhraseMpQuantityModal= "ui:interface:phrase_faber_mp_quantity";
73 const std::string FaberPhraseItemResultGroup= FaberPhraseWindow + ":header_opened:item_result";
76 #define MAX_MP_SELECTION_ENTRIES 256
78 // ***************************************************************************
79 CActionPhraseFaber::CActionPhraseFaber()
81 uint size = MAX_PLAYER_INV_ENTRIES + (MAX_ANIMALINV_ENTRIES * MAX_INVENTORY_ANIMAL) +
82 MAX_GUILDINV_ENTRIES + MAX_ROOMINV_ENTRIES;
83 _InventoryMirror.resize(size);
84 _InventoryObsSetup= false;
85 _ExecuteFromItemPlanBrick= NULL;
89 // ***************************************************************************
90 void CActionPhraseFaber::fillDBWithMP(const std::string &sheetBase, const CItem &item)
92 CInterfaceManager *pIM= CInterfaceManager::getInstance();
94 NLGUI::CDBManager::getInstance()->getDbProp(sheetBase + ":SHEET")->setValue32(item.Sheet.asInt());
95 NLGUI::CDBManager::getInstance()->getDbProp(sheetBase + ":QUALITY")->setValue32(item.Quality);
96 NLGUI::CDBManager::getInstance()->getDbProp(sheetBase + ":QUANTITY")->setValue32(item.Quantity);
97 NLGUI::CDBManager::getInstance()->getDbProp(sheetBase + ":USER_COLOR")->setValue32(item.UserColor);
98 NLGUI::CDBManager::getInstance()->getDbProp(sheetBase + ":WEIGHT")->setValue32(item.Weight);
102 // ***************************************************************************
103 void CActionPhraseFaber::launchFaberCastWindow(sint32 memoryLine, uint memoryIndex, CSBrickSheet *rootBrick)
105 // **** Get the ItemSheet for faber plan. NULL => no op.
106 if(!rootBrick)
107 return;
108 // Copy Execution launch
109 _ExecuteFromMemoryLine= memoryLine;
110 _ExecuteFromMemoryIndex= memoryIndex;
111 // no item plan setuped for now
112 _ExecuteFromItemPlanBrick= NULL;
115 // get the family of item plan (for selection) from the rootBrick. It is stored in the Property0.
116 _FaberPlanBrickFamilies.clear();
118 if (!rootBrick->Properties.empty())
120 string prop= NLMISC::toUpperAscii(rootBrick->Properties[0].Text);
121 vector<string> strList;
122 splitString(prop, " ", strList);
123 // The prop Id should be 'FPLAN:'
124 if(strList.size()>=2 && strList[0]=="FPLAN:")
126 for(uint i=1;i<strList.size();i++)
128 BRICK_FAMILIES::TBrickFamily bfam= BRICK_FAMILIES::toSBrickFamily(strList[i]);
129 if(bfam!=BRICK_FAMILIES::Unknown)
130 _FaberPlanBrickFamilies.push_back(bfam);
134 // if not found, error, cannot choose the faber plan
135 if(_FaberPlanBrickFamilies.empty())
137 nlwarning("ERROR: The Craft Root %s does not contain a valid FPLAN: property -> Can't select plan to craft",
138 rootBrick->Id.toString().c_str() );
139 return;
143 // **** Hide all widgets, MP Ctrls, and reset DB, until the Plan is not selected
144 CInterfaceManager *pIM= CInterfaceManager::getInstance();
145 // Hide the valid button
146 CCtrlBaseButton *validButton= dynamic_cast<CCtrlBaseButton*>(CWidgetManager::getInstance()->getElementFromId(FaberPhraseValidButton));
147 if(validButton)
148 validButton->setFrozen(true);
150 // reset DB, hide the Mps
151 uint itemReqLine;
152 for(itemReqLine=0;itemReqLine<MAX_ITEM_REQ_LINE;itemReqLine++)
154 // Reset All Mps slots.
155 for(uint mpSlot=0;mpSlot<MAX_MP_SLOT;mpSlot++)
157 CCDBNodeLeaf *node= NLGUI::CDBManager::getInstance()->getDbProp(toString("%s:%d:%d:SHEET", MPFaberDB.c_str(), itemReqLine, mpSlot), false);
158 if(node)
159 node->setValue32(0);
162 // Hide item requirements groups per default
163 CInterfaceGroup *itemReqLineGroup= dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId( toString(FaberPhraseItemReqLine.c_str(), itemReqLine) ));
164 if(itemReqLineGroup)
165 itemReqLineGroup->setActive(false);
168 // Reset the selected plan
169 CCDBNodeLeaf *node= NLGUI::CDBManager::getInstance()->getDbProp(FaberPlanDB, false);
170 if(node)
171 node->setValue32(0);
173 // Reset the result item
174 node= NLGUI::CDBManager::getInstance()->getDbProp(ItemResultSheetDB, false);
175 if(node)
176 node->setValue32(0);
178 // Hide the ItemResult group
179 CInterfaceGroup *groupMp= dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId(FaberPhraseItemResultGroup));
180 if(groupMp)
181 groupMp->setActive(false);
184 // **** Open the window!
185 CGroupContainer *window= dynamic_cast<CGroupContainer*>(CWidgetManager::getInstance()->getElementFromId(FaberPhraseWindow));
186 if(window)
188 window->setActive(true);
190 // Setup the Title with a default text
191 string title= CI18N::get("uiPhraseFaberExecuteNoPlan");
192 window->setTitle (title);
195 // **** setup DB observer!
196 // ensure remove (if setuped before), then add
197 CCDBNodeBranch *branch;
198 branch= NLGUI::CDBManager::getInstance()->getDbBranch("LOCAL:INVENTORY:BAG");
199 if(branch) NLGUI::CDBManager::getInstance()->removeBranchObserver( "LOCAL:INVENTORY:BAG",&_DBInventoryObs);
200 if(branch) NLGUI::CDBManager::getInstance()->addBranchObserver( "LOCAL:INVENTORY:BAG",&_DBInventoryObs);
202 // and for all pack animals
203 uint i;
204 for(i=0;i<MAX_INVENTORY_ANIMAL;i++)
206 branch= NLGUI::CDBManager::getInstance()->getDbBranch(toString("LOCAL:INVENTORY:PACK_ANIMAL%d", i));
207 if(branch) NLGUI::CDBManager::getInstance()->removeBranchObserver( toString("LOCAL:INVENTORY:PACK_ANIMAL%d", i).c_str(), &_DBInventoryObs);
208 if(branch) NLGUI::CDBManager::getInstance()->addBranchObserver( toString("LOCAL:INVENTORY:PACK_ANIMAL%d", i).c_str(), &_DBInventoryObs);
211 // Add observers on animal status, cause inventory may become unavailabe during the process
212 for(i=0;i<MAX_INVENTORY_ANIMAL;i++)
214 node= NLGUI::CDBManager::getInstance()->getDbProp(toString("SERVER:PACK_ANIMAL:BEAST%d:STATUS",i), false);
215 if(node)
217 ICDBNode::CTextId textId;
218 node->addObserver(&_DBAnimalObs, textId);
222 // Observe skill status change to update success rate
223 CSkillManager *pSM= CSkillManager::getInstance();
224 pSM->appendSkillChangeCallback(&_SkillObserver);
228 // ***************************************************************************
229 void CActionPhraseFaber::onCloseFaberCastWindow()
231 CInterfaceManager *pIM= CInterfaceManager::getInstance();
232 CSkillManager *pSM= CSkillManager::getInstance();
234 // No more need to listen inventory change
235 CCDBNodeBranch *branch;
236 branch= NLGUI::CDBManager::getInstance()->getDbBranch("LOCAL:INVENTORY:BAG");
237 if(branch) branch->removeBranchObserver(&_DBInventoryObs);
238 // and for all pack animals
239 for(uint i=0;i<MAX_INVENTORY_ANIMAL;i++)
241 branch= NLGUI::CDBManager::getInstance()->getDbBranch(toString("LOCAL:INVENTORY:PACK_ANIMAL%d", i));
242 if(branch) branch->removeBranchObserver(&_DBInventoryObs);
245 // remove observers on animal status, cause inventory may become unavailabe during the process
246 for(uint i=0;i<MAX_INVENTORY_ANIMAL;i++)
248 CCDBNodeLeaf *node= NLGUI::CDBManager::getInstance()->getDbProp(toString("SERVER:PACK_ANIMAL:BEAST%d:STATUS",i), false);
249 if(node)
251 ICDBNode::CTextId textId;
252 node->removeObserver(&_DBAnimalObs, textId);
256 pSM->removeSkillChangeCallback(&_SkillObserver);
260 // ***************************************************************************
261 void CActionPhraseFaber::fillFaberPlanSelection(const std::string &brickDB, uint maxSelection)
263 CInterfaceManager *pIM= CInterfaceManager::getInstance();
264 CSBrickManager *pBM= CSBrickManager::getInstance();
266 // fill selection with all bricks of the same family
267 uint i;
268 std::vector<CSheetId> bricks;
269 for(i=0;i<_FaberPlanBrickFamilies.size();i++)
271 const std::vector<NLMISC::CSheetId> &famBricks= pBM->getFamilyBricks(_FaberPlanBrickFamilies[i]);
272 bricks.insert(bricks.end(), famBricks.begin(), famBricks.end());
275 // get only ones known
276 pBM->filterKnownBricks(bricks);
278 // fill db
279 uint num= min(maxSelection, uint(bricks.size()));
280 for(i=0;i<maxSelection;i++)
282 if(i<num)
283 NLGUI::CDBManager::getInstance()->getDbProp(brickDB + ":" + toString(i) + ":SHEET")->setValue32(bricks[i].asInt());
284 else
285 NLGUI::CDBManager::getInstance()->getDbProp(brickDB + ":" + toString(i) + ":SHEET")->setValue32(0);
289 // ***************************************************************************
290 CItemImage *CActionPhraseFaber::getInvMirrorItemImage(uint slotIndex, uint& invId, uint& indexInInv)
292 if (slotIndex < MAX_PLAYER_INV_ENTRIES)
294 invId = INVENTORIES::bag;
295 indexInInv = slotIndex;
296 return &getInventory().getBagItem(slotIndex);
298 slotIndex -= MAX_PLAYER_INV_ENTRIES;
300 if (slotIndex < (MAX_ANIMALINV_ENTRIES * MAX_INVENTORY_ANIMAL))
302 uint animal = slotIndex / MAX_ANIMALINV_ENTRIES;
303 uint index = slotIndex % MAX_ANIMALINV_ENTRIES;
304 invId = INVENTORIES::pet_animal + animal;
305 indexInInv = index;
306 return &getInventory().getPAItem(animal, index);
308 slotIndex -= (MAX_ANIMALINV_ENTRIES * MAX_INVENTORY_ANIMAL);
310 if (slotIndex < MAX_GUILDINV_ENTRIES)
312 if (getInventory().isInventoryAvailable(INVENTORIES::guild))
314 CInterfaceManager *im = CInterfaceManager::getInstance();
315 CCDBNodeBranch *itemBranch = NLGUI::CDBManager::getInstance()->getDbBranch(SERVER_INVENTORY ":GUILD:" + toString(slotIndex));
316 static CItemImage image;
317 image.build(itemBranch);
318 invId = INVENTORIES::guild;
319 indexInInv = slotIndex;
320 return &image;
322 return NULL;
324 slotIndex -= MAX_GUILDINV_ENTRIES;
326 if (slotIndex < MAX_ROOMINV_ENTRIES)
328 if (getInventory().isInventoryAvailable(INVENTORIES::player_room))
330 CInterfaceManager *im = CInterfaceManager::getInstance();
331 CCDBNodeBranch *itemBranch = NLGUI::CDBManager::getInstance()->getDbBranch(SERVER_INVENTORY ":ROOM:" + toString(slotIndex));
332 static CItemImage image;
333 image.build(itemBranch);
334 invId = INVENTORIES::player_room;
335 indexInInv = slotIndex;
336 return &image;
338 return NULL;
341 return NULL;
345 // ***************************************************************************
346 bool CActionPhraseFaber::isMpAvailable(CItemSheet *mpSheet, uint invId, uint slotIndex) const
348 return mpSheet && mpSheet->Family==ITEMFAMILY::RAW_MATERIAL && getInventory().isInventoryAvailable((INVENTORIES::TInventory)invId);
351 // ***************************************************************************
352 void CActionPhraseFaber::validateFaberPlanSelection(CSBrickSheet *itemPlanBrick)
354 CInterfaceManager *pIM= CInterfaceManager::getInstance();
357 // **** Get the ItemSheet for faber plan. NULL => no op.
358 if(!itemPlanBrick)
359 return;
360 _ExecuteFromItemPlanBrick= itemPlanBrick;
363 // TestYoyo
364 /*for(uint tam=0;tam<_ExecuteFromItemPlanBrick->FaberPlan.ItemPartMps.size();tam++)
366 _ExecuteFromItemPlanBrick->FaberPlan.ItemPartMps[tam].Quantity= 20;
368 _ExecuteFromItemPlanBrick->FaberPlan.FormulaMps.resize(2);
369 _ExecuteFromItemPlanBrick->FaberPlan.FormulaMps[0].ItemRequired= CSheetId("m0152chdca01.sitem");
370 _ExecuteFromItemPlanBrick->FaberPlan.FormulaMps[0].Quantity= 13;
371 _ExecuteFromItemPlanBrick->FaberPlan.FormulaMps[1].ItemRequired= CSheetId("m0691chdca01.sitem");
372 _ExecuteFromItemPlanBrick->FaberPlan.FormulaMps[1].Quantity= 25;
376 // the num of itempPart/specific items to setup
377 _MPBuildNumItemPartReq= min((uint)MAX_ITEM_REQ_LINE, (uint)_ExecuteFromItemPlanBrick->FaberPlan.ItemPartMps.size());
378 _MPBuildNumSpecificItemReq= min(((uint)MAX_ITEM_REQ_LINE-_MPBuildNumItemPartReq), (uint)_ExecuteFromItemPlanBrick->FaberPlan.FormulaMps.size());
379 _MPBuildNumTotalItemReq= _MPBuildNumItemPartReq + _MPBuildNumSpecificItemReq;
382 // Setup the selected plan
383 CCDBNodeLeaf *node= NLGUI::CDBManager::getInstance()->getDbProp(FaberPlanDB, false);
384 if(node)
385 node->setValue32(_ExecuteFromItemPlanBrick->Id.asInt());
387 // Setup the result item
388 node= NLGUI::CDBManager::getInstance()->getDbProp(ItemResultSheetDB, false);
389 if(node)
390 node->setValue32(itemPlanBrick->FaberPlan.ItemBuilt.asInt());
392 // Setup the result quantity (for stacked items)
393 node= NLGUI::CDBManager::getInstance()->getDbProp(ItemResultQuantityDB, false);
394 if(node)
395 node->setValue32(itemPlanBrick->FaberPlan.NbItemBuilt);
397 // Show the ItemResult group
398 CInterfaceGroup *groupMp= dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId(FaberPhraseItemResultGroup));
399 if(groupMp)
400 groupMp->setActive(true);
403 // **** reset the mpBuild
404 // For all item required.
405 uint itemReqLine;
406 for(itemReqLine=0;itemReqLine<_MPBuildNumTotalItemReq;itemReqLine++)
408 CMPBuild &mpBuild= _MPBuild[itemReqLine];
410 // Type of requirement?
411 // First go the ItemPart reqs
412 if(itemReqLine<_MPBuildNumItemPartReq)
414 uint itemPartId= itemReqLine;
415 mpBuild.RequirementType= CMPBuild::ItemPartReq;
416 mpBuild.FaberTypeRequired= _ExecuteFromItemPlanBrick->FaberPlan.ItemPartMps[itemPartId].FaberTypeFilter;
417 mpBuild.QuantityReq= _ExecuteFromItemPlanBrick->FaberPlan.ItemPartMps[itemPartId].Quantity;
419 // Then go the Specific item reqs
420 else
422 uint itemSpecificId= itemReqLine - _MPBuildNumItemPartReq;
423 mpBuild.RequirementType= CMPBuild::SpecificItemReq;
424 mpBuild.SpecificItemRequired= _ExecuteFromItemPlanBrick->FaberPlan.FormulaMps[itemSpecificId].ItemRequired;
425 mpBuild.QuantityReq= _ExecuteFromItemPlanBrick->FaberPlan.FormulaMps[itemSpecificId].Quantity;
428 // Reset the quantity setuped for this line
429 mpBuild.NumMpSlot= 0;
430 for(uint mpSlot=0;mpSlot<MAX_MP_SLOT;mpSlot++)
432 mpBuild.Id[mpSlot]= 0; // useless, but for consistency
433 mpBuild.QuantitySelected[mpSlot]= 0;
436 // reset other to 0 also
437 for(;itemReqLine<MAX_ITEM_REQ_LINE;itemReqLine++)
439 _MPBuild[itemReqLine].reset();
443 // **** First clear and copy the inventory to local struct
444 uint i;
445 for(i=0;i<_InventoryMirror.size();i++)
447 _InventoryMirror[i].reset();
450 uint invId = 0;
451 uint indexInInv = 0;
452 // Run all the inventories.
453 for(i=0;i<_InventoryMirror.size();i++)
455 CItemImage *itemImage= getInvMirrorItemImage(i, invId, indexInInv);
456 bool bLockedByOwner = itemImage && itemImage->getLockedByOwner();
457 // item found and not locked?
458 if(itemImage)
460 // setup the origin
461 _InventoryMirror[i].InventoryId= invId;
462 _InventoryMirror[i].IdInInventory= indexInInv;
464 // The item must be a mp
465 CSheetId sheetId= CSheetId(itemImage->getSheetID());
466 CItemSheet *mpSheet= dynamic_cast<CItemSheet*>(SheetMngr.get(sheetId));
467 if( isMpAvailable(mpSheet, invId, i) && !bLockedByOwner)
469 _InventoryMirror[i].Sheet= sheetId;
470 _InventoryMirror[i].Quality= itemImage->getQuality();
471 _InventoryMirror[i].Quantity= itemImage->getQuantity();
472 _InventoryMirror[i].UserColor= itemImage->getUserColor();
473 _InventoryMirror[i].Weight= itemImage->getWeight();
474 // Bkup original quantity from inventory
475 _InventoryMirror[i].OriginalQuantity= _InventoryMirror[i].Quantity;
476 _InventoryMirror[i].LockedByOwner= bLockedByOwner;
482 // **** show ItemParts according to plan.
483 // Hide the valid button
484 CCtrlBaseButton *validButton= dynamic_cast<CCtrlBaseButton*>(CWidgetManager::getInstance()->getElementFromId(FaberPhraseValidButton));
485 if(validButton)
486 validButton->setFrozen(true);
488 // reset DB, show/hide the Mps
489 for(itemReqLine=0;itemReqLine<MAX_ITEM_REQ_LINE;itemReqLine++)
491 CMPBuild &mpBuild= _MPBuild[itemReqLine];
493 // Reset All Mps slots.
494 for(uint mpSlot=0;mpSlot<MAX_MP_SLOT;mpSlot++)
496 CCDBNodeLeaf *node= NLGUI::CDBManager::getInstance()->getDbProp(toString("%s:%d:%d:SHEET", MPFaberDB.c_str(), itemReqLine, mpSlot), false);
497 if(node)
498 node->setValue32(0);
501 // Setup item requirement groups
502 CInterfaceGroup *itemReqLineGroup= dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId( toString(FaberPhraseItemReqLine.c_str(), itemReqLine) ));
503 if(itemReqLineGroup)
505 if( itemReqLine<_MPBuildNumTotalItemReq )
507 itemReqLineGroup->setActive(true);
509 // Set as Text the required MP FaberType or Specific item
510 CViewText *viewText= dynamic_cast<CViewText*>(itemReqLineGroup->getView(FaberPhraseText));
511 if(viewText)
513 string text;
514 if(mpBuild.RequirementType==CMPBuild::ItemPartReq)
516 text= CI18N::get("uihelpFaberMpHeader");
517 strFindReplace(text, "%f", RM_FABER_TYPE::toLocalString(mpBuild.FaberTypeRequired) );
519 else if(mpBuild.RequirementType==CMPBuild::SpecificItemReq)
521 text= STRING_MANAGER::CStringManagerClient::getItemLocalizedName(mpBuild.SpecificItemRequired);
523 else
525 nlstop;
527 viewText->setText(text);
530 // Set as Icon the required MP FaberType / or Sheet Texture (directly...)
531 CViewBitmap *viewBmp= dynamic_cast<CViewBitmap*>(itemReqLineGroup->getView(FaberPhraseIcon));
532 if(viewBmp)
534 if(mpBuild.RequirementType==CMPBuild::ItemPartReq)
536 // texture name in config.xml
537 viewBmp->setTexture(CWidgetManager::getInstance()->getParser()->getDefine( RM_FABER_TYPE::toIconDefineString(mpBuild.FaberTypeRequired) ));
539 else if(mpBuild.RequirementType==CMPBuild::SpecificItemReq)
541 // NB: the texture is scaled, so it's ok to put the item 40x40 texture
542 const CItemSheet *itemSheet= dynamic_cast<const CItemSheet*>(SheetMngr.get(mpBuild.SpecificItemRequired));
543 if(itemSheet)
544 viewBmp->setTexture(itemSheet->getIconMain());
545 else
546 viewBmp->setTexture(std::string());
548 else
550 nlstop;
554 // update the EmptySlot
555 updateEmptySlot(itemReqLine, itemReqLineGroup);
557 // setup item required quantity view
558 updateQuantityView(itemReqLine);
560 else
562 itemReqLineGroup->setActive(false);
568 // **** Setup the new window title
569 CGroupContainer *window= dynamic_cast<CGroupContainer*>(CWidgetManager::getInstance()->getElementFromId(FaberPhraseWindow));
570 if(window)
572 // Setup the Title with the item built
573 string title= CI18N::get("uiPhraseFaberExecute");
574 strFindReplace(title, "%item", STRING_MANAGER::CStringManagerClient::getItemLocalizedName(_ExecuteFromItemPlanBrick->FaberPlan.ItemBuilt) );
575 window->setTitle (title);
579 // **** result view
580 updateItemResult();
583 // ***************************************************************************
584 void CActionPhraseFaber::resetSelection()
586 CInterfaceManager *pIM= CInterfaceManager::getInstance();
588 for(uint i=0;i<MAX_MP_SELECTION_ENTRIES;i++)
590 NLGUI::CDBManager::getInstance()->getDbProp(MPSelectionDB+ ":" + toString(i) + ":SHEET")->setValue32(0);
594 // ***************************************************************************
595 void CActionPhraseFaber::fillSelection(const std::vector<uint> &mps)
597 CInterfaceManager *pIM= CInterfaceManager::getInstance();
599 uint num= min(uint(MAX_MP_SELECTION_ENTRIES), uint(mps.size()));
600 for(uint i=0;i<MAX_MP_SELECTION_ENTRIES;i++)
602 if(i<num && mps[i]<_InventoryMirror.size())
604 CItem &item= _InventoryMirror[mps[i]];
605 fillDBWithMP(MPSelectionDB+ ":" + toString(i), item);
607 else
608 NLGUI::CDBManager::getInstance()->getDbProp(MPSelectionDB+ ":" + toString(i) + ":SHEET")->setValue32(0);
613 // ***************************************************************************
614 void CActionPhraseFaber::filterSelectionItemPart(std::vector<uint> &mps, RM_FABER_TYPE::TRMFType itemPartFilter, ITEM_ORIGIN::EItemOrigin originFilter)
616 // Unknown => no fitler
617 if(itemPartFilter==RM_FABER_TYPE::Unknown)
618 return;
620 std::vector<uint> res;
621 res.reserve(mps.size());
623 for(uint i=0;i<mps.size();i++)
625 // get the item sheet
626 const CItemSheet *itemSheet= dynamic_cast<const CItemSheet*>(SheetMngr.get(_InventoryMirror[mps[i]].Sheet));
627 // test itemPartFilter match.
628 if(itemSheet)
630 if(itemSheet->canBuildItemPart(itemPartFilter, originFilter))
632 res.push_back(mps[i]);
637 mps= res;
641 // ***************************************************************************
642 void CActionPhraseFaber::filterSelectionItemSpecific(std::vector<uint> &mps, NLMISC::CSheetId specificItemWanted)
644 std::vector<uint> res;
645 res.reserve(mps.size());
647 // if unknown sheetid, no match
648 if(specificItemWanted==NLMISC::CSheetId::Unknown)
650 mps.clear();
651 return;
654 for(uint i=0;i<mps.size();i++)
656 // get the item sheet
657 const CItemSheet *itemSheet= dynamic_cast<const CItemSheet*>(SheetMngr.get(_InventoryMirror[mps[i]].Sheet));
658 // test sheetid match.
659 if(itemSheet)
661 if(itemSheet->Id == specificItemWanted)
663 res.push_back(mps[i]);
668 mps= res;
672 // ***************************************************************************
673 void CActionPhraseFaber::startMpSelection(uint itemReqLine, uint mpSlot)
675 CInterfaceManager *pIM= CInterfaceManager::getInstance();
677 // get the ctrlSlot
678 CDBCtrlSheet *ctrlSlot= NULL;
679 CInterfaceGroup *itemReqLineGroup= dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId( toString(FaberPhraseItemReqLine.c_str(), itemReqLine) ));
680 if(itemReqLineGroup)
682 CDBGroupListSheet *listSheet= dynamic_cast<CDBGroupListSheet*>(itemReqLineGroup->getGroup(FaberPhraseList));
683 if(listSheet)
684 ctrlSlot= listSheet->getSheet(mpSlot);
686 if(!ctrlSlot)
687 return;
689 // get the mpBuild setup
690 nlassert(itemReqLine<MAX_ITEM_REQ_LINE);
691 CMPBuild &mpBuild= _MPBuild[itemReqLine];
693 // If the slot selected is already filled, Launch the MP Quantity selection modal
694 if(mpSlot<mpBuild.NumMpSlot)
696 // fill the sheet info
697 uint invSlot= mpBuild.Id[mpSlot];
698 CItem item= _InventoryMirror[invSlot];
699 fillDBWithMP(MPQuantitySelectDb, item);
701 // compute the maximum quantity possible to fill
702 uint maxQuantity= getMaxQuantityChange(itemReqLine, mpSlot);
704 // set the max quantity as the default quantity to set up.
705 CCDBNodeLeaf *node= NLGUI::CDBManager::getInstance()->getDbProp(MPQuantitySelectDb + ":CUR_QUANTITY", false);
706 if(node) node->setValue32(maxQuantity);
707 node= NLGUI::CDBManager::getInstance()->getDbProp(MPQuantitySelectDb + ":MAX_QUANTITY", false);
708 if(node) node->setValue32(maxQuantity);
710 // bkup for validation
711 _MpSelectionItemReqLine= itemReqLine;
712 _MpChangeQuantitySlot= mpSlot;
714 // Setup the text with value by default
715 CInterfaceGroup *quantityModal= dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId(FaberPhraseMpQuantityModal));
716 if(quantityModal)
718 CGroupEditBox *eb = dynamic_cast<CGroupEditBox *>(quantityModal->getGroup("eb"));
719 if (eb)
721 CWidgetManager::getInstance()->setCaptureKeyboard(eb);
722 eb->setInputString(toString(maxQuantity));
723 eb->setSelectionAll();
727 // launch the modal
728 CWidgetManager::getInstance()->enableModalWindow(ctrlSlot, quantityModal);
730 // else select new MP
731 else
733 // For All the inventory
734 vector<uint> selectMps;
735 for(uint i=0;i<_InventoryMirror.size();i++)
737 // If still some MP on this stack, and if not already selected, add to selection
738 if(_InventoryMirror[i].Quantity>0 && (_InventoryMirror[i].Selected&(1<<itemReqLine))==0 )
740 selectMps.push_back(i);
744 // Filter the selection whether it is an itemPart or specificItem reqiurement
745 if(mpBuild.RequirementType==CMPBuild::ItemPartReq)
747 CItemSheet *itemBuilt= dynamic_cast<CItemSheet*>(SheetMngr.get(_ExecuteFromItemPlanBrick->FaberPlan.ItemBuilt));
748 ITEM_ORIGIN::EItemOrigin itemOrigin= itemBuilt? itemBuilt->ItemOrigin : ITEM_ORIGIN::UNKNOWN;
749 filterSelectionItemPart(selectMps, mpBuild.FaberTypeRequired, itemOrigin);
751 else if(mpBuild.RequirementType==CMPBuild::SpecificItemReq)
753 filterSelectionItemSpecific(selectMps, mpBuild.SpecificItemRequired);
755 else
757 nlstop;
760 // Reset the DB selection
761 resetSelection();
762 fillSelection(selectMps);
764 // Bkup Selection for Validate later
765 _MpSelectionItemReqLine= itemReqLine;
766 _MpCurrentSelection= selectMps;
768 // Open the Selection Window.
769 CWidgetManager::getInstance()->enableModalWindow(ctrlSlot, FaberPhraseMpListModal);
773 // ***************************************************************************
774 void CActionPhraseFaber::validateMpSelection(uint selectId)
776 CInterfaceManager *pIM= CInterfaceManager::getInstance();
778 if(selectId>=_MpCurrentSelection.size())
780 CWidgetManager::getInstance()->disableModalWindow();
781 return;
784 // get which MP of the inventory we have selected
785 uint newInvSlot= _MpCurrentSelection[selectId];
787 // get the build
788 uint itemReqLine= _MpSelectionItemReqLine;
789 CMPBuild &mpBuild= _MPBuild[itemReqLine];
791 // Select the quantity to peek from this inventory slot: get max possible
792 sint quantity= mpBuild.QuantityReq - getTotalQuantitySetuped(itemReqLine);
793 nlassert(quantity>0);
794 quantity= min((sint32)quantity, _InventoryMirror[newInvSlot].Quantity);
796 // it may be possible (by update DB and error) that selected slot is no more usable => just quit
797 if(quantity<=0)
798 return;
800 // And Remove (virtually) item stack from this slot
801 _InventoryMirror[newInvSlot].Quantity-= quantity;
802 // mark as selected for this itemReqLine, so can no more select it
803 _InventoryMirror[newInvSlot].Selected|= 1<<itemReqLine;
805 // update the build
806 nlassert(mpBuild.NumMpSlot<MAX_MP_SLOT);
807 mpBuild.Id[mpBuild.NumMpSlot]= newInvSlot;
808 mpBuild.QuantitySelected[mpBuild.NumMpSlot]= quantity;
809 mpBuild.NumMpSlot++;
811 // Update The Execution View
812 CItem item= _InventoryMirror[newInvSlot];
813 item.Quantity= quantity;
814 fillDBWithMP(toString("%s:%d:%d", MPFaberDB.c_str(), itemReqLine, mpBuild.NumMpSlot-1), item);
816 // update the empty slot
817 updateEmptySlot(itemReqLine);
819 // update quantity view
820 updateQuantityView(itemReqLine);
822 // update the validateButton
823 updateValidButton();
825 // update the item result
826 updateItemResult();
828 // must hide the modal window which had open us. NB: must be done here because next,
829 // we'll open the MP quantity selection
830 CWidgetManager::getInstance()->disableModalWindow();
832 // **** when all is correctly ended, open the quantity selection
833 // NB: just enable this code, if you want this feature
834 //startMpSelection(itemReqLine, mpBuild.NumMpSlot-1);
837 // ***************************************************************************
838 void CActionPhraseFaber::validateMpSelectQuantity()
840 CInterfaceManager *pIM= CInterfaceManager::getInstance();
842 // get current execution context of the validate
843 uint itemReqLine= _MpSelectionItemReqLine;
844 nlassert(itemReqLine<MAX_ITEM_REQ_LINE);
845 CMPBuild &mpBuild= _MPBuild[itemReqLine];
846 uint mpSlot= _MpChangeQuantitySlot;
847 nlassert(mpSlot<mpBuild.NumMpSlot);
848 uint invSlot= mpBuild.Id[mpSlot];
849 nlassert(invSlot<_InventoryMirror.size());
850 nlassert(_InventoryMirror[invSlot].Selected & (1<<itemReqLine));
852 // get the quantity selected
853 uint quantitySelected= 0;
854 CCDBNodeLeaf *node= NLGUI::CDBManager::getInstance()->getDbProp(MPQuantitySelectDb + ":CUR_QUANTITY", false);
855 if(node) quantitySelected= node->getValue32();
857 // maximize (if error)
858 quantitySelected= min(quantitySelected, getMaxQuantityChange(itemReqLine, mpSlot));
860 // if the new quantity is 0
861 if(quantitySelected==0)
863 // special: remove the mp slot from list
864 deleteMpSlot(itemReqLine, mpSlot);
866 else
868 // restore old quantity into inventory
869 _InventoryMirror[invSlot].Quantity+= mpBuild.QuantitySelected[mpSlot];
870 // And then Remove (virtually) new item stack from this slot
871 _InventoryMirror[invSlot].Quantity-= quantitySelected;
873 // update the build
874 mpBuild.QuantitySelected[mpSlot]= quantitySelected;
876 // Update The Execution View
877 CItem item= _InventoryMirror[invSlot];
878 item.Quantity= quantitySelected;
879 fillDBWithMP(toString("%s:%d:%d", MPFaberDB.c_str(), itemReqLine, mpSlot), item);
882 // update the empty slot
883 updateEmptySlot(itemReqLine);
885 // update quantity view
886 updateQuantityView(itemReqLine);
888 // update the valid button
889 updateValidButton();
891 // update the item result
892 updateItemResult();
894 // hide the Modal Quantity selection
895 CWidgetManager::getInstance()->disableModalWindow();
898 // ***************************************************************************
899 void CActionPhraseFaber::validateExecution()
901 // the plan has must been selected
902 nlassert(_ExecuteFromItemPlanBrick);
904 // Build the list of MP in Bag.
905 vector<CFaberMsgItem> mpItemPartList;
906 vector<CFaberMsgItem> specificItemList;
908 // Run all the current Build execution
909 for(uint itemReqLine=0;itemReqLine<_MPBuildNumTotalItemReq;itemReqLine++)
911 CMPBuild &mpBuild= _MPBuild[itemReqLine];
912 // For all slot setuped.
913 for(uint mpSlot=0;mpSlot<mpBuild.NumMpSlot;mpSlot++)
915 CFaberMsgItem item;
917 uint invSlot= mpBuild.Id[mpSlot];
918 nlassert(invSlot<_InventoryMirror.size());
919 item.setInvId(INVENTORIES::TInventory(_InventoryMirror[invSlot].InventoryId));
920 item.IndexInInv= _InventoryMirror[invSlot].IdInInventory;
921 item.Quantity= mpBuild.QuantitySelected[mpSlot];
923 if(mpBuild.RequirementType==CMPBuild::ItemPartReq)
924 mpItemPartList.push_back(item);
925 else if(mpBuild.RequirementType==CMPBuild::SpecificItemReq)
926 specificItemList.push_back(item);
927 else
929 nlstop;
934 // display next craft action, and Send message to server
935 CSPhraseManager *pPM= CSPhraseManager::getInstance();
936 pPM->executeCraft(_ExecuteFromMemoryLine, _ExecuteFromMemoryIndex,
937 _ExecuteFromItemPlanBrick->Id.asInt(), mpItemPartList, specificItemList);
939 // Open the Interface to get the crafted item
940 CTempInvManager::getInstance()->open(TEMP_INV_MODE::Craft);
942 // NO more Close the Execution window (allow refaber quick)
943 /*CInterfaceManager *pIM= CInterfaceManager::getInstance();
944 CInterfaceElement *window= CWidgetManager::getInstance()->getElementFromId(FaberPhraseWindow);
945 if(window)
946 window->setActive(false);
952 // ***************************************************************************
953 uint CActionPhraseFaber::getTotalQuantitySetuped(uint itemReqLine) const
955 nlassert(itemReqLine<MAX_ITEM_REQ_LINE);
956 nlassert(_MPBuild[itemReqLine].NumMpSlot<=MAX_MP_SLOT);
958 uint ret= 0;
959 for(uint i=0;i<_MPBuild[itemReqLine].NumMpSlot;i++)
961 ret+= _MPBuild[itemReqLine].QuantitySelected[i];
964 return ret;
968 // ***************************************************************************
969 uint CActionPhraseFaber::getMaxQuantityChange(uint itemReqLine, uint mpSlot) const
971 nlassert(itemReqLine<MAX_ITEM_REQ_LINE);
972 nlassert(mpSlot<_MPBuild[itemReqLine].NumMpSlot);
974 uint invSlot= _MPBuild[itemReqLine].Id[mpSlot];
975 nlassert(invSlot<_InventoryMirror.size());
976 CItem item= _InventoryMirror[invSlot];
978 // This is the quantity already selected for this itemReqLine, + rest in inventory
979 uint maxQuantity= _MPBuild[itemReqLine].QuantitySelected[mpSlot] + item.Quantity;
980 // maximize with the rest of quantity with have to setup (remove us btw)
981 maxQuantity= min(maxQuantity, _MPBuild[itemReqLine].QuantityReq -
982 (getTotalQuantitySetuped(itemReqLine) - _MPBuild[itemReqLine].QuantitySelected[mpSlot]) );
984 return maxQuantity;
988 // ***************************************************************************
989 void CActionPhraseFaber::updateEmptySlot(uint itemReqLine, CInterfaceGroup *itemReqLineGroup)
991 CInterfaceManager *pIM= CInterfaceManager::getInstance();
993 if(!itemReqLineGroup)
994 itemReqLineGroup= dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId( toString(FaberPhraseItemReqLine.c_str(), itemReqLine) ));
995 if(!itemReqLineGroup)
996 return;
998 // get the list sheet and ctrlButton.
999 CDBGroupListSheet *listSheet= dynamic_cast<CDBGroupListSheet*>(itemReqLineGroup->getGroup(FaberPhraseList));
1000 if(!listSheet)
1001 return;
1003 // NB: forceValidity calls invalidateCoords() if state change => dont "clear then set".
1005 // All Setuped?
1006 bool allSetuped= getTotalQuantitySetuped(itemReqLine) >= _MPBuild[itemReqLine].QuantityReq;
1008 // button no more needed?
1009 if(allSetuped)
1011 // Reset all ForceValid
1012 for(uint i=0;i<MAX_MP_SLOT;i++)
1013 listSheet->forceValidity(i, false);
1015 else
1017 // Reset all ForceValid
1018 for(uint i=0;i<MAX_MP_SLOT;i++)
1020 listSheet->forceValidity(i, i==_MPBuild[itemReqLine].NumMpSlot);
1024 // Special for Specific Item requirement. Setup grayed item for the last empty slot
1025 for(uint i=0;i<MAX_MP_SLOT;i++)
1027 CMPBuild &mpBuild= _MPBuild[itemReqLine];
1029 // *** Fill the empty DB.
1030 if(i>=mpBuild.NumMpSlot)
1032 CItem item;
1033 // If Specfific requirement and just the last one, don't leave empty
1034 if(!allSetuped && i==mpBuild.NumMpSlot && mpBuild.RequirementType== CMPBuild::SpecificItemReq)
1036 item.Sheet= mpBuild.SpecificItemRequired;
1038 fillDBWithMP(toString("%s:%d:%d", MPFaberDB.c_str(), itemReqLine, i), item);
1041 // *** Grayed,NoQuantity,NoQuality for the last slot of a specific requirement
1042 CDBCtrlSheet *ctrl= listSheet->getSheet(i);
1043 if(ctrl)
1045 if(i==mpBuild.NumMpSlot && mpBuild.RequirementType== CMPBuild::SpecificItemReq)
1047 ctrl->setUseQuality(false);
1048 ctrl->setUseQuantity(false);
1049 ctrl->setGrayed(true);
1051 else
1053 ctrl->setUseQuality(true);
1054 ctrl->setUseQuantity(true);
1055 ctrl->setGrayed(false);
1062 // ***************************************************************************
1063 void CActionPhraseFaber::updateQuantityView(uint itemReqLine)
1065 nlassert(itemReqLine<MAX_ITEM_REQ_LINE);
1067 CInterfaceManager *pIM= CInterfaceManager::getInstance();
1069 CCDBNodeLeaf *node= NLGUI::CDBManager::getInstance()->getDbProp(toString("%s:%d:SELECTED", MPQuantityDb.c_str(), itemReqLine), false);
1070 if(node)
1071 node->setValue32(getTotalQuantitySetuped(itemReqLine));
1072 node= NLGUI::CDBManager::getInstance()->getDbProp(toString("%s:%d:REQUIRED", MPQuantityDb.c_str(), itemReqLine), false);
1073 if(node)
1074 node->setValue32(_MPBuild[itemReqLine].QuantityReq);
1078 // ***************************************************************************
1079 void CActionPhraseFaber::updateValidButton()
1081 // Check For All MPSlot: If All Ok, then can validate!
1082 bool canValid= true;
1084 // can validate only if the Plan has been selected
1085 if(_ExecuteFromItemPlanBrick)
1087 // Run all the current Build execution
1088 for(uint itemReqLine=0;itemReqLine<_MPBuildNumTotalItemReq;itemReqLine++)
1090 canValid= canValid && getTotalQuantitySetuped(itemReqLine)==_MPBuild[itemReqLine].QuantityReq;
1093 else
1094 canValid= false;
1096 // unfreeze if valid
1097 CInterfaceManager *pIM= CInterfaceManager::getInstance();
1098 CCtrlBaseButton *validButton= dynamic_cast<CCtrlBaseButton*>(CWidgetManager::getInstance()->getElementFromId(FaberPhraseValidButton));
1099 if(validButton) validButton->setFrozen(!canValid);
1103 // ***************************************************************************
1104 void CActionPhraseFaber::deleteMpSlot(uint itemReqLine, uint mpSlot)
1106 nlassert(itemReqLine<MAX_ITEM_REQ_LINE);
1107 CMPBuild &mpBuild= _MPBuild[itemReqLine];
1108 nlassert(mpSlot<mpBuild.NumMpSlot);
1109 uint invSlot= mpBuild.Id[mpSlot];
1110 nlassert(invSlot<_InventoryMirror.size());
1111 nlassert(_InventoryMirror[invSlot].Selected & (1<<itemReqLine));
1112 // NB: possible that mpBuild.QuantitySelected[mpSlot]==0 (call from removeMpSlotThatUseInvSlot())
1114 // restore quantity into inventory
1115 _InventoryMirror[invSlot].Quantity+= mpBuild.QuantitySelected[mpSlot];
1116 // no more selected for this itemReqLine, so can select it now
1117 _InventoryMirror[invSlot].Selected&= ~(1<<itemReqLine);
1119 // update the build by shifting in memory
1120 uint i;
1121 for(i=mpSlot;i<mpBuild.NumMpSlot-1;i++)
1123 mpBuild.Id[i]= mpBuild.Id[i+1];
1124 mpBuild.QuantitySelected[i]= mpBuild.QuantitySelected[i+1];
1126 mpBuild.NumMpSlot--;
1128 // update the execution view (just what needed)
1129 for(i=mpSlot;i<mpBuild.NumMpSlot;i++)
1131 CItem item= _InventoryMirror[mpBuild.Id[i]];
1132 item.Quantity= mpBuild.QuantitySelected[i];
1133 fillDBWithMP(toString("%s:%d:%d", MPFaberDB.c_str(), itemReqLine, i), item);
1136 // reset the empty slot!
1137 CItem item;
1138 fillDBWithMP(toString("%s:%d:%d", MPFaberDB.c_str(), itemReqLine, mpBuild.NumMpSlot), item);
1143 // ***************************************************************************
1144 // ***************************************************************************
1145 // Handlers
1146 // ***************************************************************************
1147 // ***************************************************************************
1150 static CActionPhraseFaber *ActionPhraseFaber = NULL;
1153 // ***************************************************************************
1154 // This expr is used only for define in phrase.xml.
1155 DECLARE_INTERFACE_CONSTANT(getPhraseMPSelectionMax, MAX_MP_SELECTION_ENTRIES)
1158 // ***************************************************************************
1159 class CHandlerPhraseFaberSelectMP : public IActionHandler
1161 public:
1162 virtual void execute (CCtrlBase *pCaller, const string &Params)
1164 CDBCtrlSheet *ctrl= dynamic_cast<CDBCtrlSheet*>(pCaller);
1165 if(!ctrl)
1166 return;
1168 // get itemReqLine to Modify
1169 uint itemReqLine;
1170 fromString(getParam(Params, "item_req"), itemReqLine);
1171 // get mpSlot edited
1172 uint mpSlot= ctrl->getIndexInDB();
1174 if (ActionPhraseFaber == NULL) ActionPhraseFaber = new CActionPhraseFaber;
1175 ActionPhraseFaber->startMpSelection(itemReqLine, mpSlot);
1178 REGISTER_ACTION_HANDLER( CHandlerPhraseFaberSelectMP, "phrase_faber_select_mp");
1181 // ***************************************************************************
1182 class CHandlerPhraseFaberValidateMP : public IActionHandler
1184 public:
1185 virtual void execute (CCtrlBase *pCaller, const string &/* Params */)
1187 CDBCtrlSheet *ctrl= dynamic_cast<CDBCtrlSheet*>(pCaller);
1188 if(!ctrl)
1190 CInterfaceManager *pIM= CInterfaceManager::getInstance();
1191 CWidgetManager::getInstance()->disableModalWindow();
1192 return;
1195 // get the selected MP.
1196 uint selectMP= ctrl->getIndexInDB();
1198 if (ActionPhraseFaber == NULL) ActionPhraseFaber = new CActionPhraseFaber;
1199 ActionPhraseFaber->validateMpSelection(selectMP);
1202 REGISTER_ACTION_HANDLER( CHandlerPhraseFaberValidateMP, "phrase_faber_validate_mp");
1205 // ***************************************************************************
1206 class CHandlerPhraseFaberValidate : public IActionHandler
1208 public:
1209 virtual void execute (CCtrlBase * /* pCaller */, const string &/* Params */)
1211 if (ActionPhraseFaber == NULL) ActionPhraseFaber = new CActionPhraseFaber;
1212 ActionPhraseFaber->validateExecution();
1215 REGISTER_ACTION_HANDLER( CHandlerPhraseFaberValidate, "phrase_faber_validate");
1218 // ***************************************************************************
1219 class CHandlerPhraseFaberValidateOnEnter : public IActionHandler
1221 public:
1222 virtual void execute (CCtrlBase * /* pCaller */, const string &/* Params */)
1224 // get the button
1225 CInterfaceManager *pIM= CInterfaceManager::getInstance();
1226 CCtrlBaseButton *button= dynamic_cast<CCtrlBaseButton*>(CWidgetManager::getInstance()->getElementFromId(FaberPhraseValidButton));
1228 // Ok, button found. test if active.
1229 if( button && !button->getFrozen() )
1231 // Act as if the player click on this button
1232 CAHManager::getInstance()->runActionHandler("phrase_faber_validate", button );
1236 REGISTER_ACTION_HANDLER( CHandlerPhraseFaberValidateOnEnter, "phrase_faber_validate_on_enter");
1239 // ***************************************************************************
1240 class CHandlerPhraseFaberSelectMpQuantity : public IActionHandler
1242 public:
1243 virtual void execute (CCtrlBase * /* pCaller */, const string &/* Params */)
1245 if (ActionPhraseFaber == NULL) ActionPhraseFaber = new CActionPhraseFaber;
1246 ActionPhraseFaber->validateMpSelectQuantity();
1249 REGISTER_ACTION_HANDLER( CHandlerPhraseFaberSelectMpQuantity, "phrase_faber_select_mp_quantity");
1253 // ***************************************************************************
1254 void launchFaberCastWindow(sint32 memoryLine, uint memoryIndex, CSBrickSheet *rootBrick)
1256 if (ActionPhraseFaber == NULL) ActionPhraseFaber = new CActionPhraseFaber;
1257 ActionPhraseFaber->launchFaberCastWindow(memoryLine, memoryIndex, rootBrick);
1260 // ***************************************************************************
1261 void fillFaberPlanSelection(const std::string &brickDB, uint maxSelection)
1263 if (ActionPhraseFaber == NULL) ActionPhraseFaber = new CActionPhraseFaber;
1264 ActionPhraseFaber->fillFaberPlanSelection(brickDB, maxSelection);
1267 // ***************************************************************************
1268 void validateFaberPlanSelection(CSBrickSheet *itemPlanBrick)
1270 if (ActionPhraseFaber == NULL) ActionPhraseFaber = new CActionPhraseFaber;
1271 ActionPhraseFaber->validateFaberPlanSelection(itemPlanBrick);
1274 // ***************************************************************************
1275 void closeFaberCastWindow()
1277 if (ActionPhraseFaber == NULL) return;
1278 CGroupContainer *window= dynamic_cast<CGroupContainer*>(CWidgetManager::getInstance()->getElementFromId(FaberPhraseWindow));
1279 if(window && window->getActive())
1280 window->setActive(false);
1284 // ***************************************************************************
1285 class CHandlerPhraseFaberOnClose : public IActionHandler
1287 public:
1288 virtual void execute (CCtrlBase * /* pCaller */, const string &/* Params */)
1290 if (ActionPhraseFaber == NULL) ActionPhraseFaber = new CActionPhraseFaber;
1291 ActionPhraseFaber->onCloseFaberCastWindow();
1294 REGISTER_ACTION_HANDLER( CHandlerPhraseFaberOnClose, "phrase_faber_on_close");
1297 // ***************************************************************************
1298 // ***************************************************************************
1299 // Management of Change in Inventory
1300 // ***************************************************************************
1301 // ***************************************************************************
1304 // ***************************************************************************
1305 void CActionPhraseFaber::removeMpSlotThatUseInvSlot(uint invSlot, uint quantityToRemove)
1307 if(quantityToRemove==0)
1308 return;
1310 // remove from all mpSlots
1311 for(uint itemReqLine=0;itemReqLine<_MPBuildNumTotalItemReq;itemReqLine++)
1313 CMPBuild &mpBuild= _MPBuild[itemReqLine];
1314 for(uint mpSlot=0;mpSlot<mpBuild.NumMpSlot;)
1316 // if this mpSlot use the invSlot.
1317 if(mpBuild.Id[mpSlot]==invSlot)
1319 // then remove stack mp. If slot not enough
1320 uint removeSlotQuantity;
1321 removeSlotQuantity= min(quantityToRemove, mpBuild.QuantitySelected[mpSlot]);
1322 mpBuild.QuantitySelected[mpSlot]-= removeSlotQuantity;
1323 quantityToRemove-= removeSlotQuantity;
1325 // if slot completely removed, then remove it totaly
1326 if(mpBuild.QuantitySelected[mpSlot]==0)
1328 // NB: nothing is restored to inventory since mpBuild.QuantitySelected[mpSlot] is reseted before
1329 deleteMpSlot(itemReqLine, mpSlot);
1331 else
1333 // just change this DB view
1334 CItem item= _InventoryMirror[invSlot];
1335 item.Quantity= mpBuild.QuantitySelected[mpSlot];
1336 fillDBWithMP(toString("%s:%d:%d", MPFaberDB.c_str(), itemReqLine, mpSlot), item);
1338 // go to next slot
1339 mpSlot++;
1342 // if ok, all req quantity removed, quit
1343 if(quantityToRemove==0)
1344 return;
1346 else
1347 mpSlot++;
1353 // ***************************************************************************
1354 void CActionPhraseFaber::onInventoryChange()
1356 CInterfaceManager *pIM= CInterfaceManager::getInstance();
1358 uint i;
1359 bool displayChange= false;
1361 // If the Faber Plan has not yet been selected, then must not check _InventoryMirror, since not initialized
1362 if(_ExecuteFromItemPlanBrick==NULL)
1363 return;
1365 // Run all the Bag
1366 uint invId = 0;
1367 uint indexInInv = 0;
1368 for(i=0;i<_InventoryMirror.size();i++)
1370 CItemImage *itemImage= getInvMirrorItemImage(i, invId, indexInInv);
1372 if(itemImage)
1374 CSheetId sheetId= CSheetId(itemImage->getSheetID());
1375 CItemSheet *mpSheet= dynamic_cast<CItemSheet*>(SheetMngr.get(sheetId));
1376 CItem newInvItem;
1378 bool bLockedByOwner = itemImage->getLockedByOwner();
1380 // The item must be a mp, and the item must be available and unlocked
1381 if( isMpAvailable(mpSheet, invId, i) && !bLockedByOwner)
1383 newInvItem.Sheet= sheetId;
1384 newInvItem.Quality= itemImage->getQuality();
1385 newInvItem.Quantity= itemImage->getQuantity();
1386 newInvItem.UserColor= itemImage->getUserColor();
1387 newInvItem.Weight= itemImage->getWeight();
1388 newInvItem.OriginalQuantity= newInvItem.Quantity;
1389 newInvItem.LockedByOwner = bLockedByOwner;
1392 /* There is 5 cases:
1393 - no changes => no op.
1394 - new/unlocked Mp on a empty or non Mp slot. Easy, just add.
1395 - old Mp removed (not same sheetId/quality/userColor/locked)
1396 - old Mp with quantity changed to be greater
1397 - old Mp with quantity changed to be smaller
1400 CItem &curInvItem= _InventoryMirror[i];
1402 // Bkup Id in newInvItem (for ope= correctness)
1403 newInvItem.InventoryId= curInvItem.InventoryId;
1404 newInvItem.IdInInventory= curInvItem.IdInInventory;
1406 // If the item was not a mp
1407 if(_InventoryMirror[i].Sheet==CSheetId::Unknown)
1409 // if now it is, easy, just add if not locked
1410 if(newInvItem.Sheet!=CSheetId::Unknown && !newInvItem.LockedByOwner)
1411 curInvItem= newInvItem;
1413 // else must test change or remove
1414 else
1416 bool sameMp;
1417 sameMp= curInvItem.Sheet == newInvItem.Sheet &&
1418 curInvItem.Quality == newInvItem.Quality &&
1419 curInvItem.UserColor == newInvItem.UserColor &&
1420 curInvItem.LockedByOwner == newInvItem.LockedByOwner;
1422 // if the Mp was deleted from this slot, delete it from all faber execution
1423 if(!sameMp)
1425 // remove all from current execution
1426 removeMpSlotThatUseInvSlot(i, curInvItem.OriginalQuantity);
1428 // replace (with nothing or new different Mp)
1429 curInvItem= newInvItem;
1431 // mpSlot may have been deleted
1432 displayChange= true;
1434 // test change of quantity
1435 else
1437 // if the quantity is the same, no op!
1438 if(curInvItem.OriginalQuantity!=newInvItem.OriginalQuantity)
1440 // if the quantity is now greater, its easy
1441 if(newInvItem.OriginalQuantity > curInvItem.OriginalQuantity)
1443 // just add the difference to the original and current setuped quantity
1444 uint32 diff= newInvItem.OriginalQuantity - curInvItem.OriginalQuantity;
1445 curInvItem.OriginalQuantity+= diff;
1446 curInvItem.Quantity+= diff;
1448 else
1450 // complex, must remove the quantity that has changed
1451 uint32 diff= curInvItem.OriginalQuantity - newInvItem.OriginalQuantity;
1452 // try first to remove it from remaining quantity
1453 if(curInvItem.Quantity>=(sint32)diff)
1455 // no change to current mpSlots!
1456 curInvItem.Quantity-= diff;
1458 // must close the selection modal if opened
1459 displayChange= true;
1461 // The remaining quantity is not enough, must also remove from mpSlot that use it!
1462 else
1464 uint32 toRemoveFromSlot= diff - curInvItem.Quantity;
1465 curInvItem.Quantity= 0;
1466 // remove all needed to current mp slot.
1467 removeMpSlotThatUseInvSlot(i, toRemoveFromSlot);
1469 // mpSlot may have been deleted
1470 displayChange= true;
1473 // bkup new original quantity
1474 curInvItem.OriginalQuantity= newInvItem.OriginalQuantity;
1482 // must update display?
1483 if(displayChange)
1485 for(uint itemReqLine= 0;itemReqLine<_MPBuildNumTotalItemReq;itemReqLine++)
1487 updateEmptySlot(itemReqLine);
1488 updateQuantityView(itemReqLine);
1490 updateValidButton();
1492 // close selection modals if they are opened
1493 CInterfaceGroup *quantityModal= dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId(FaberPhraseMpQuantityModal));
1494 if(quantityModal && CWidgetManager::getInstance()->getModalWindow()==quantityModal)
1495 CWidgetManager::getInstance()->disableModalWindow();
1496 CInterfaceGroup *listModal= dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId(FaberPhraseMpListModal));
1497 if(listModal && CWidgetManager::getInstance()->getModalWindow()==listModal)
1498 CWidgetManager::getInstance()->disableModalWindow();
1500 // update item result
1501 updateItemResult();
1505 // ***************************************************************************
1506 void CActionPhraseFaber::CDBInventoryObs::update(ICDBNode * /* node */)
1508 if (ActionPhraseFaber == NULL) ActionPhraseFaber = new CActionPhraseFaber;
1509 ActionPhraseFaber->onInventoryChange();
1512 // ***************************************************************************
1513 void CActionPhraseFaber::CDBAnimalObs::update(ICDBNode * /* node */)
1515 if (ActionPhraseFaber == NULL) ActionPhraseFaber = new CActionPhraseFaber;
1516 ActionPhraseFaber->onInventoryChange();
1521 // ***************************************************************************
1522 void CActionPhraseFaber::updateItemResult()
1524 CInterfaceManager *pIM= CInterfaceManager::getInstance();
1525 CSPhraseManager *pPM= CSPhraseManager::getInstance();
1526 CSBrickManager *pBM= CSBrickManager::getInstance();
1528 uint i;
1530 // level is the min level of MP
1531 sint32 minLevel= INT_MAX;
1532 // Stat is computed like server
1533 float statArray[RM_FABER_STAT_TYPE::NumRMStatType];
1534 float statCount[RM_FABER_STAT_TYPE::NumRMStatType];
1535 uint64 itemStatBF= 0;
1536 for(i=0;i<RM_FABER_STAT_TYPE::NumRMStatType;i++)
1538 statArray[i]= 0;
1539 statCount[i]= 0;
1541 // Color stat (for armour)
1542 uint32 bestItemColor[RM_COLOR::NumColors];
1543 for(i=0;i<RM_COLOR::NumColors;i++)
1544 bestItemColor[i]= 0;
1545 // Stat energy is computed like server
1546 float statEnergy= 0;
1549 // **** Parse all Bricks of the phrase executed, to get min level
1550 // take The brick with the lowest CR_RECOMMENDED
1551 uint phraseSlot= pPM->getMemorizedPhrase(_ExecuteFromMemoryLine, _ExecuteFromMemoryIndex);
1552 const CSPhraseCom &phrase= pPM->getPhrase(phraseSlot);
1553 uint32 recommendedPropId= pBM->getBrickPropId("cr_recommended");
1554 for(i=0;i<phrase.Bricks.size();i++)
1556 CSBrickSheet *brick= pBM->getBrick(phrase.Bricks[i]);
1557 if(brick)
1559 for(uint j=0;j<brick->Properties.size();j++)
1561 // if a CR_RECOMMENDED propId
1562 if(brick->Properties[j].PropId == recommendedPropId)
1564 // minimze the level
1565 minLevel= min(minLevel, sint32(brick->Properties[j].Value));
1572 // **** Parse all MPs setuped, to compute level and stats
1573 uint totalItemPartMPReq= 0;
1574 uint totalItemPartMPSetuped= 0;
1575 for(i=0;i<_MPBuildNumTotalItemReq;i++)
1577 CMPBuild &mpBuild= _MPBuild[i];
1579 // --- ItemPart requirement?
1580 if(mpBuild.RequirementType==CMPBuild::ItemPartReq)
1582 // For all slots setuped
1583 uint nSlot= min((uint)MAX_MP_SLOT, mpBuild.NumMpSlot);
1584 for(uint j=0;j<nSlot;j++)
1586 // Try to get the MP in this slot
1587 CItemSheet *mp= dynamic_cast<CItemSheet*>(SheetMngr.get(_InventoryMirror[mpBuild.Id[j]].Sheet));
1588 if(mp && mp->canBuildItemPart(mpBuild.FaberTypeRequired))
1590 // minimize level
1591 minLevel= min(_InventoryMirror[mpBuild.Id[j]].Quality, minLevel);
1593 // Increment stat for each of this MP selected
1594 const CItemSheet::CMpItemPart &mpIP= mp->getItemPart(mpBuild.FaberTypeRequired);
1596 // append to the stats
1597 uint numMps= mpBuild.QuantitySelected[j];
1598 for(uint k=0;k<RM_FABER_STAT_TYPE::NumRMStatType;k++)
1600 if(RM_FABER_STAT_TYPE::isStatRelevant(mpBuild.FaberTypeRequired, (RM_FABER_STAT_TYPE::TRMStatType)k))
1602 // %age to 0-1.
1603 statArray[k]+= numMps * (mpIP.Stats[k]/100.f);
1607 // Same for total energy
1608 statEnergy+= numMps * (mp->Mp.StatEnergy/100.f);
1610 // Increment color stat
1611 if(mp->Mp.MpColor>=0 && mp->Mp.MpColor<RM_COLOR::NumColors)
1613 bestItemColor[mp->Mp.MpColor]+= numMps;
1616 // Total MP setuped
1617 totalItemPartMPSetuped+= numMps;
1621 // get all stat for this item, and count MP req per stat
1622 for(uint k=0;k<RM_FABER_STAT_TYPE::NumRMStatType;k++)
1624 // if item part 'i' affect stat 'k'
1625 if(RM_FABER_STAT_TYPE::isStatRelevant(mpBuild.FaberTypeRequired, (RM_FABER_STAT_TYPE::TRMStatType)k))
1627 // StatPerItemPart ored in StatPerItem
1628 itemStatBF|= uint64(1)<<k;
1629 // Total Num MP per stat
1630 statCount[k]+= mpBuild.QuantityReq;
1634 // Total MP Req
1635 totalItemPartMPReq+= mpBuild.QuantityReq;
1638 // --- Specific Item requirement?
1639 else if(mpBuild.RequirementType==CMPBuild::SpecificItemReq)
1641 // For all slots setuped
1642 uint nSlot= min((uint)MAX_MP_SLOT, mpBuild.NumMpSlot);
1643 for(uint j=0;j<nSlot;j++)
1645 // Try to get the MP in this slot
1646 CItemSheet *mp= dynamic_cast<CItemSheet*>(SheetMngr.get(_InventoryMirror[mpBuild.Id[j]].Sheet));
1647 if(mp->Id == mpBuild.SpecificItemRequired)
1649 // minimize level
1650 minLevel= min(_InventoryMirror[mpBuild.Id[j]].Quality, minLevel);
1652 // Formula 's Specific MPs don't impact on stats.
1658 // Mean stat
1659 for(i=0;i<RM_FABER_STAT_TYPE::NumRMStatType;i++)
1661 if(statCount[i])
1662 statArray[i]/= statCount[i];
1663 clamp(statArray[i], 0.f, 1.f);
1666 // Mean stat energy
1667 if(totalItemPartMPReq)
1669 statEnergy/= totalItemPartMPReq;
1670 clamp(statEnergy, 0.f, 1.f);
1673 // As in server, stretch the stats.
1674 // Add the special bonus ONLY when all MPs are setuped, for clearness
1675 RM_FABER_STAT_TYPE::stretchItemStats(statArray, itemStatBF, totalItemPartMPSetuped>=totalItemPartMPReq);
1678 // **** setup Level
1679 if(minLevel==INT_MAX)
1680 minLevel= 0;
1681 CCDBNodeLeaf *node= NLGUI::CDBManager::getInstance()->getDbProp(ItemResultSheetLevel, false);
1682 if(node)
1683 node->setValue32(minLevel);
1686 // **** change success rate too
1687 CViewText *successView= dynamic_cast<CViewText*>(CWidgetManager::getInstance()->getElementFromId(FaberPhraseFpSuccessText));
1688 if(successView)
1690 string text= CI18N::get("uiPhraseFaberSuccessRate");
1691 // Get the success rate of the related phrase
1692 uint phraseSlot= pPM->getMemorizedPhrase(_ExecuteFromMemoryLine, _ExecuteFromMemoryIndex);
1694 sint32 craftSuccessModifier = 0;
1695 CCDBNodeLeaf *nodeCSM= NLGUI::CDBManager::getInstance()->getDbProp("SERVER:CHARACTER_INFO:SUCCESS_MODIFIER:CRAFT", false);
1696 if(nodeCSM)
1698 craftSuccessModifier = nodeCSM->getValue32();
1700 // With the faber plan skill
1701 sint success= pPM->getCraftPhraseSuccessRate(pPM->getPhrase(phraseSlot), _ExecuteFromItemPlanBrick->getSkill(), minLevel, 0);
1702 sint bonus = pPM->getCraftPhraseSuccessRate(pPM->getPhrase(phraseSlot), _ExecuteFromItemPlanBrick->getSkill(), minLevel, (sint) craftSuccessModifier) - success;
1703 string successStr;
1704 if( bonus == 0 )
1706 successStr = toString("@{FFFF}") + toString(success);
1708 else
1709 if( bonus > 0 ) // bonus
1711 successStr = "@{0F0F}" + toString(success + bonus)
1712 + "@{FFFF}("
1713 + toString( success )
1714 + "@{0F0F} + "
1715 + toString( bonus )
1716 + "@{FFFF})";
1718 else
1720 successStr = "@{E42F}" + toString(success + bonus)
1721 + "@{FFFF}("
1722 + toString( success )
1723 + "@{E42F} - "
1724 + toString( abs(bonus) )
1725 + "@{FFFF})";
1727 strFindReplace(text, "%success", successStr );
1728 successView->setTextFormatTaged(text);
1732 // **** setup Color
1733 // Same than server code (NB: beige==1 per default)
1734 uint maxNumColor = 0;
1735 uint dominanteColor = 1;
1736 for(i = 0; i < RM_COLOR::NumColors; ++i )
1738 if( bestItemColor[i] > maxNumColor )
1740 maxNumColor = bestItemColor[i];
1741 dominanteColor = i;
1744 node= NLGUI::CDBManager::getInstance()->getDbProp(ItemResultSheetColor, false);
1745 if(node)
1746 node->setValue32(dominanteColor);
1749 // **** Get Stat validity
1750 uint64 itemStatFinalUsageBF= 0;
1751 // Some stat (magic protection and magic resist) are finaly used in the item only for the best ones
1752 itemStatFinalUsageBF= RM_FABER_STAT_TYPE::getStatFinalValidity(statArray, itemStatBF);
1755 // **** Stats
1756 CInterfaceGroup *groupMp= dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId(FaberPhraseItemResultGroup));
1757 if(groupMp)
1759 // default: hide all
1760 for(i=0;i<RM_FABER_STAT_TYPE::NumRMStatType;i++)
1762 // get the stat group
1763 CInterfaceGroup *groupStat= dynamic_cast<CInterfaceGroup*>(groupMp->getElement(groupMp->getId()+toString(":stat%d",i) ));
1764 if(groupStat)
1765 groupStat->setActive(false);
1767 // enable only one that are relevant for this item
1768 uint groupIndex= 0;
1769 for(i=0;i<RM_FABER_STAT_TYPE::NumRMStatType;i++)
1771 RM_FABER_STAT_TYPE::TRMStatType statType= RM_FABER_STAT_TYPE::TRMStatType(i);
1773 // if this stat is not relevant for the item, don't display it!
1774 if( (itemStatBF&(uint64(1)<<i)) == 0)
1775 continue;
1777 // Is the stat finaly used? (magic protection for instance may not be)
1778 bool finalyUsed= (itemStatFinalUsageBF&(uint64(1)<<i)) != 0;
1779 CRGBA usageColor= finalyUsed?(CRGBA::White):CRGBA(128,128,128);
1781 // get the next stat group
1782 CInterfaceGroup *groupStat= dynamic_cast<CInterfaceGroup*>(groupMp->getElement(groupMp->getId()+toString(":stat%d",groupIndex) ));
1783 if(groupStat)
1785 groupStat->setActive(true);
1786 // fill text and bar according to stat
1787 CViewText *statTitle= dynamic_cast<CViewText*>(groupStat->getElement(groupStat->getId()+":text" ));
1788 CDBViewBar *statValueBar= dynamic_cast<CDBViewBar*>(groupStat->getElement(groupStat->getId()+":bar" ));
1789 CViewText *statValueText= dynamic_cast<CViewText*>(groupStat->getElement(groupStat->getId()+":textstat" ));
1790 CCtrlBase *statToolTip= dynamic_cast<CCtrlBase*>(groupStat->getElement(groupStat->getId()+":tt" ));
1791 uint sv= uint(statArray[i]*100);
1792 if(statTitle)
1794 statTitle->setText(RM_FABER_STAT_TYPE::toLocalString(statType));
1795 statTitle->setColor(usageColor);
1797 if(statValueBar)
1799 statValueBar->setValue(sv);
1800 statValueBar->setColor(usageColor);
1802 if(statValueText)
1804 statValueText->setText(toString(sv)+"/100");
1805 statValueText->setColor(usageColor);
1807 if(statToolTip)
1809 if(finalyUsed)
1811 // display something only for magic/protect stat
1812 if( RM_FABER_STAT_TYPE::isMagicResistStat(RM_FABER_STAT_TYPE::TRMStatType(i)) ||
1813 RM_FABER_STAT_TYPE::isMagicProtectStat(RM_FABER_STAT_TYPE::TRMStatType(i)) )
1814 statToolTip->setDefaultContextHelp(CI18N::get("uiFaberStatActive"));
1815 else
1816 statToolTip->setDefaultContextHelp(std::string());
1818 else
1819 statToolTip->setDefaultContextHelp(CI18N::get("uiFaberStatGrayed"));
1823 groupIndex++;
1828 // **** BestStat (for text over)
1829 node= NLGUI::CDBManager::getInstance()->getDbProp(ItemResultSheetStatType, false);
1830 if(node)
1832 float bestStatValue =-1.0f;
1833 RM_FABER_STAT_TYPE::TRMStatType bestStat = RM_FABER_STAT_TYPE::NumRMStatType;
1834 for( i = 0; i < RM_FABER_STAT_TYPE::NumRMStatType; ++i )
1836 // if this stat is not relevant for the item, don't use it!
1837 if( (itemStatBF&(uint64(1)<<i)) == 0)
1838 continue;
1839 float value = statArray[i];
1840 if( value > bestStatValue )
1842 bestStatValue = value;
1843 bestStat = (RM_FABER_STAT_TYPE::TRMStatType)i;
1846 // Setup DB
1847 node->setValue32(bestStat);
1851 // **** ClassType (for text over)
1852 node= NLGUI::CDBManager::getInstance()->getDbProp(ItemResultSheetClassType, false);
1853 if(node)
1855 // Setup DB
1856 node->setValue32(RM_CLASS_TYPE::getItemClass((uint32)(100.0f * statEnergy)));
1861 /* Handle change of skill -> recompute success rate */
1862 void CActionPhraseFaber::CSkillObserver::onSkillChange()
1864 if (ActionPhraseFaber == NULL) ActionPhraseFaber = new CActionPhraseFaber;
1865 // Dont update if the plan has not yet been selected
1866 if(ActionPhraseFaber->_ExecuteFromItemPlanBrick==NULL)
1867 return;
1868 ActionPhraseFaber->updateItemResult();