1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2020 Winch Gate Property Limited
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>
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/>.
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"
48 using namespace NLMISC
;
51 // ***************************************************************************
52 const std::string FaberPlanDB
= "UI:PHRASE:FABER:FABER_PLAN:SHEET";
53 const std::string FaberPlanHpBuffDB
= "UI:PHRASE:FABER:FABER_PLAN:HP_BUFF";
54 const std::string FaberPlanSapBuffDB
= "UI:PHRASE:FABER:FABER_PLAN:SAP_BUFF";
55 const std::string FaberPlanStaBuffDB
= "UI:PHRASE:FABER:FABER_PLAN:STA_BUFF";
56 const std::string FaberPlanFocusBuffDB
= "UI:PHRASE:FABER:FABER_PLAN:FOCUS_BUFF";
57 const std::string MPFaberDB
= "UI:PHRASE:FABER:MP_BUILD";
58 const std::string MPSelectionDB
= "UI:PHRASE:FABER:MP_SELECT";
59 const std::string MPQuantityDb
= "UI:PHRASE:FABER:MP_QUANTITY";
60 const std::string MPQuantitySelectDb
= "UI:PHRASE:FABER:STACK_SELECT";
61 const std::string ItemResultSheetDB
= "UI:PHRASE:FABER:RESULT_ITEM:SHEET";
62 const std::string ItemResultQuantityDB
= "UI:PHRASE:FABER:RESULT_ITEM:QUANTITY";
63 const std::string ItemResultSheetLevel
= "UI:PHRASE:FABER:RESULT_ITEM:QUALITY";
64 const std::string ItemResultSheetColor
= "UI:PHRASE:FABER:RESULT_ITEM:USER_COLOR";
65 const std::string ItemResultSheetClassType
= "UI:PHRASE:FABER:RESULT_ITEM:RM_CLASS_TYPE";
66 const std::string ItemResultSheetStatType
= "UI:PHRASE:FABER:RESULT_ITEM:RM_FABER_STAT_TYPE";
67 const std::string FaberPhraseWindow
= "ui:interface:phrase_faber_execution";
68 const std::string FaberPhraseItemReqLine
= FaberPhraseWindow
+ ":header_opened:item_reqs:item_req_%d";
69 const std::string FaberPhraseList
= "list";
70 const std::string FaberPhraseText
= "text";
71 const std::string FaberPhraseIcon
= "icon";
72 const std::string FaberPhraseValidButton
= FaberPhraseWindow
+ ":header_opened:ok_cancel:ok";
73 const std::string FaberPhraseFpCtrl
= FaberPhraseWindow
+ ":header_opened:faber_plan";
74 const std::string FaberPhraseFpSuccessText
= FaberPhraseWindow
+ ":header_opened:success_text";
75 const std::string FaberPhraseMpListModal
= "ui:interface:phrase_faber_mp_selection";
76 const std::string FaberPhraseMpQuantityModal
= "ui:interface:phrase_faber_mp_quantity";
77 const std::string FaberPhraseItemResultGroup
= FaberPhraseWindow
+ ":header_opened:item_result";
80 #define MAX_MP_SELECTION_ENTRIES 256
82 // ***************************************************************************
83 CActionPhraseFaber::CActionPhraseFaber()
85 uint size
= MAX_PLAYER_INV_ENTRIES
+ (MAX_ANIMALINV_ENTRIES
* MAX_INVENTORY_ANIMAL
) +
86 MAX_GUILDINV_ENTRIES
+ MAX_ROOMINV_ENTRIES
;
87 _InventoryMirror
.resize(size
);
88 _InventoryObsSetup
= false;
89 _ExecuteFromItemPlanBrick
= NULL
;
93 // ***************************************************************************
94 void CActionPhraseFaber::fillDBWithMP(const std::string
&sheetBase
, const CItem
&item
)
96 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
98 NLGUI::CDBManager::getInstance()->getDbProp(sheetBase
+ ":SHEET")->setValue32(item
.Sheet
.asInt());
99 NLGUI::CDBManager::getInstance()->getDbProp(sheetBase
+ ":QUALITY")->setValue32(item
.Quality
);
100 NLGUI::CDBManager::getInstance()->getDbProp(sheetBase
+ ":QUANTITY")->setValue32(item
.Quantity
);
101 NLGUI::CDBManager::getInstance()->getDbProp(sheetBase
+ ":USER_COLOR")->setValue32(item
.UserColor
);
102 NLGUI::CDBManager::getInstance()->getDbProp(sheetBase
+ ":WEIGHT")->setValue32(item
.Weight
);
106 // ***************************************************************************
107 void CActionPhraseFaber::launchFaberCastWindow(sint32 memoryLine
, uint memoryIndex
, CSBrickSheet
*rootBrick
)
109 // **** Get the ItemSheet for faber plan. NULL => no op.
112 // Copy Execution launch
113 _ExecuteFromMemoryLine
= memoryLine
;
114 _ExecuteFromMemoryIndex
= memoryIndex
;
115 // no item plan setuped for now
116 _ExecuteFromItemPlanBrick
= NULL
;
119 // get the family of item plan (for selection) from the rootBrick. It is stored in the Property0.
120 _FaberPlanBrickFamilies
.clear();
122 if (!rootBrick
->Properties
.empty())
124 string prop
= NLMISC::toUpperAscii(rootBrick
->Properties
[0].Text
);
125 vector
<string
> strList
;
126 splitString(prop
, " ", strList
);
127 // The prop Id should be 'FPLAN:'
128 if(strList
.size()>=2 && strList
[0]=="FPLAN:")
130 for(uint i
=1;i
<strList
.size();i
++)
132 BRICK_FAMILIES::TBrickFamily bfam
= BRICK_FAMILIES::toSBrickFamily(strList
[i
]);
133 if(bfam
!=BRICK_FAMILIES::Unknown
)
134 _FaberPlanBrickFamilies
.push_back(bfam
);
138 // if not found, error, cannot choose the faber plan
139 if(_FaberPlanBrickFamilies
.empty())
141 nlwarning("ERROR: The Craft Root %s does not contain a valid FPLAN: property -> Can't select plan to craft",
142 rootBrick
->Id
.toString().c_str() );
147 // **** Hide all widgets, MP Ctrls, and reset DB, until the Plan is not selected
148 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
149 // Hide the valid button
150 CCtrlBaseButton
*validButton
= dynamic_cast<CCtrlBaseButton
*>(CWidgetManager::getInstance()->getElementFromId(FaberPhraseValidButton
));
152 validButton
->setFrozen(true);
154 // reset DB, hide the Mps
156 for(itemReqLine
=0;itemReqLine
<MAX_ITEM_REQ_LINE
;itemReqLine
++)
158 // Reset All Mps slots.
159 for(uint mpSlot
=0;mpSlot
<MAX_MP_SLOT
;mpSlot
++)
161 CCDBNodeLeaf
*node
= NLGUI::CDBManager::getInstance()->getDbProp(toString("%s:%d:%d:SHEET", MPFaberDB
.c_str(), itemReqLine
, mpSlot
), false);
166 // Hide item requirements groups per default
167 CInterfaceGroup
*itemReqLineGroup
= dynamic_cast<CInterfaceGroup
*>(CWidgetManager::getInstance()->getElementFromId( toString(FaberPhraseItemReqLine
.c_str(), itemReqLine
) ));
169 itemReqLineGroup
->setActive(false);
172 // Reset the selected plan
173 CCDBNodeLeaf
*node
= NLGUI::CDBManager::getInstance()->getDbProp(FaberPlanDB
, false);
178 node
= NLGUI::CDBManager::getInstance()->getDbProp(FaberPlanHpBuffDB
, false);
179 if (node
) node
->setValue32(0);
180 node
= NLGUI::CDBManager::getInstance()->getDbProp(FaberPlanSapBuffDB
, false);
181 if (node
) node
->setValue32(0);
182 node
= NLGUI::CDBManager::getInstance()->getDbProp(FaberPlanStaBuffDB
, false);
183 if (node
) node
->setValue32(0);
184 node
= NLGUI::CDBManager::getInstance()->getDbProp(FaberPlanFocusBuffDB
, false);
185 if (node
) node
->setValue32(0);
187 // Reset the result item
188 node
= NLGUI::CDBManager::getInstance()->getDbProp(ItemResultSheetDB
, false);
192 // Hide the ItemResult group
193 CInterfaceGroup
*groupMp
= dynamic_cast<CInterfaceGroup
*>(CWidgetManager::getInstance()->getElementFromId(FaberPhraseItemResultGroup
));
195 groupMp
->setActive(false);
198 // **** Open the window!
199 CGroupContainer
*window
= dynamic_cast<CGroupContainer
*>(CWidgetManager::getInstance()->getElementFromId(FaberPhraseWindow
));
202 window
->setActive(true);
204 // Setup the Title with a default text
205 string title
= CI18N::get("uiPhraseFaberExecuteNoPlan");
206 window
->setTitle (title
);
209 // **** setup DB observer!
210 // ensure remove (if setuped before), then add
211 CCDBNodeBranch
*branch
;
212 branch
= NLGUI::CDBManager::getInstance()->getDbBranch("LOCAL:INVENTORY:BAG");
213 if(branch
) NLGUI::CDBManager::getInstance()->removeBranchObserver( "LOCAL:INVENTORY:BAG",&_DBInventoryObs
);
214 if(branch
) NLGUI::CDBManager::getInstance()->addBranchObserver( "LOCAL:INVENTORY:BAG",&_DBInventoryObs
);
216 // and for all pack animals
218 for(i
=0;i
<MAX_INVENTORY_ANIMAL
;i
++)
220 branch
= NLGUI::CDBManager::getInstance()->getDbBranch(toString("LOCAL:INVENTORY:PACK_ANIMAL%d", i
));
221 if(branch
) NLGUI::CDBManager::getInstance()->removeBranchObserver( toString("LOCAL:INVENTORY:PACK_ANIMAL%d", i
).c_str(), &_DBInventoryObs
);
222 if(branch
) NLGUI::CDBManager::getInstance()->addBranchObserver( toString("LOCAL:INVENTORY:PACK_ANIMAL%d", i
).c_str(), &_DBInventoryObs
);
225 // Add observers on animal status, cause inventory may become unavailabe during the process
226 for(i
=0;i
<MAX_INVENTORY_ANIMAL
;i
++)
228 node
= NLGUI::CDBManager::getInstance()->getDbProp(toString("SERVER:PACK_ANIMAL:BEAST%d:STATUS",i
), false);
231 ICDBNode::CTextId textId
;
232 node
->addObserver(&_DBAnimalObs
, textId
);
236 // Observe skill status change to update success rate
237 CSkillManager
*pSM
= CSkillManager::getInstance();
238 pSM
->appendSkillChangeCallback(&_SkillObserver
);
241 // add observer to mod_craft_success.sbrick
243 CCDBNodeLeaf
*node
= NLGUI::CDBManager::getInstance()->getDbProp("SERVER:CHARACTER_INFO:SUCCESS_MODIFIER:CRAFT", false);
246 ICDBNode::CTextId textId
;
247 node
->addObserver(&_DBModCraftObs
, textId
);
253 // ***************************************************************************
254 void CActionPhraseFaber::onCloseFaberCastWindow()
256 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
257 CSkillManager
*pSM
= CSkillManager::getInstance();
259 // No more need to listen inventory change
260 CCDBNodeBranch
*branch
;
261 branch
= NLGUI::CDBManager::getInstance()->getDbBranch("LOCAL:INVENTORY:BAG");
262 if(branch
) branch
->removeBranchObserver(&_DBInventoryObs
);
263 // and for all pack animals
264 for(uint i
=0;i
<MAX_INVENTORY_ANIMAL
;i
++)
266 branch
= NLGUI::CDBManager::getInstance()->getDbBranch(toString("LOCAL:INVENTORY:PACK_ANIMAL%d", i
));
267 if(branch
) branch
->removeBranchObserver(&_DBInventoryObs
);
270 // remove observers on animal status, cause inventory may become unavailabe during the process
271 for(uint i
=0;i
<MAX_INVENTORY_ANIMAL
;i
++)
273 CCDBNodeLeaf
*node
= NLGUI::CDBManager::getInstance()->getDbProp(toString("SERVER:PACK_ANIMAL:BEAST%d:STATUS",i
), false);
276 ICDBNode::CTextId textId
;
277 node
->removeObserver(&_DBAnimalObs
, textId
);
281 pSM
->removeSkillChangeCallback(&_SkillObserver
);
284 // remove mod_craft_success.sbrick observer
286 CCDBNodeLeaf
*node
= NLGUI::CDBManager::getInstance()->getDbProp("SERVER:CHARACTER_INFO:SUCCESS_MODIFIER:CRAFT", false);
289 ICDBNode::CTextId textId
;
290 node
->removeObserver(&_DBModCraftObs
, textId
);
296 // ***************************************************************************
297 void CActionPhraseFaber::fillFaberPlanSelection(const std::string
&brickDB
, uint maxSelection
, TOOL_TYPE::TCraftingToolType toolType
)
299 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
300 CSBrickManager
*pBM
= CSBrickManager::getInstance();
302 // fill selection with all bricks of the same family
304 std::vector
<CSheetId
> bricks
;
305 for(i
=0;i
<_FaberPlanBrickFamilies
.size();i
++)
307 const std::vector
<NLMISC::CSheetId
> &famBricks
= pBM
->getFamilyBricks(_FaberPlanBrickFamilies
[i
]);
308 if (toolType
== TOOL_TYPE::Unknown
)
310 bricks
.insert(bricks
.end(), famBricks
.begin(), famBricks
.end());
314 for(std::vector
<CSheetId
>::const_iterator it
= famBricks
.begin(); it
!= famBricks
.end(); ++it
)
316 CSBrickSheet
*brick
= pBM
->getBrick(*it
);
317 if (brick
&& brick
->FaberPlan
.ToolType
== toolType
)
319 bricks
.push_back(*it
);
325 // get only ones known
326 pBM
->filterKnownBricks(bricks
);
329 uint num
= min(maxSelection
, uint(bricks
.size()));
330 for(i
=0;i
<maxSelection
;i
++)
333 NLGUI::CDBManager::getInstance()->getDbProp(brickDB
+ ":" + toString(i
) + ":SHEET")->setValue32(bricks
[i
].asInt());
335 NLGUI::CDBManager::getInstance()->getDbProp(brickDB
+ ":" + toString(i
) + ":SHEET")->setValue32(0);
339 // ***************************************************************************
340 CItemImage
*CActionPhraseFaber::getInvMirrorItemImage(uint slotIndex
, uint
& invId
, uint
& indexInInv
)
342 if (slotIndex
< MAX_PLAYER_INV_ENTRIES
)
344 invId
= INVENTORIES::bag
;
345 indexInInv
= slotIndex
;
346 return &getInventory().getBagItem(slotIndex
);
348 slotIndex
-= MAX_PLAYER_INV_ENTRIES
;
350 if (slotIndex
< (MAX_ANIMALINV_ENTRIES
* MAX_INVENTORY_ANIMAL
))
352 uint animal
= slotIndex
/ MAX_ANIMALINV_ENTRIES
;
353 uint index
= slotIndex
% MAX_ANIMALINV_ENTRIES
;
354 invId
= INVENTORIES::pet_animal
+ animal
;
356 return &getInventory().getPAItem(animal
, index
);
358 slotIndex
-= (MAX_ANIMALINV_ENTRIES
* MAX_INVENTORY_ANIMAL
);
360 if (slotIndex
< MAX_GUILDINV_ENTRIES
)
362 if (getInventory().isInventoryAvailable(INVENTORIES::guild
))
364 CInterfaceManager
*im
= CInterfaceManager::getInstance();
365 CCDBNodeBranch
*itemBranch
= NLGUI::CDBManager::getInstance()->getDbBranch(SERVER_INVENTORY
":GUILD:" + toString(slotIndex
));
366 static CItemImage image
;
367 image
.build(itemBranch
);
368 invId
= INVENTORIES::guild
;
369 indexInInv
= slotIndex
;
374 slotIndex
-= MAX_GUILDINV_ENTRIES
;
376 if (slotIndex
< MAX_ROOMINV_ENTRIES
)
378 if (getInventory().isInventoryAvailable(INVENTORIES::player_room
))
380 CInterfaceManager
*im
= CInterfaceManager::getInstance();
381 CCDBNodeBranch
*itemBranch
= NLGUI::CDBManager::getInstance()->getDbBranch(SERVER_INVENTORY
":ROOM:" + toString(slotIndex
));
382 static CItemImage image
;
383 image
.build(itemBranch
);
384 invId
= INVENTORIES::player_room
;
385 indexInInv
= slotIndex
;
395 // ***************************************************************************
396 bool CActionPhraseFaber::isMpAvailable(CItemSheet
*mpSheet
, uint invId
, uint slotIndex
) const
398 return mpSheet
&& mpSheet
->Family
==ITEMFAMILY::RAW_MATERIAL
&& getInventory().isInventoryAvailable((INVENTORIES::TInventory
)invId
);
401 // ***************************************************************************
402 void CActionPhraseFaber::validateFaberPlanSelection(CSBrickSheet
*itemPlanBrick
)
404 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
407 // **** Get the ItemSheet for faber plan. NULL => no op.
410 _ExecuteFromItemPlanBrick
= itemPlanBrick
;
414 /*for(uint tam=0;tam<_ExecuteFromItemPlanBrick->FaberPlan.ItemPartMps.size();tam++)
416 _ExecuteFromItemPlanBrick->FaberPlan.ItemPartMps[tam].Quantity= 20;
418 _ExecuteFromItemPlanBrick->FaberPlan.FormulaMps.resize(2);
419 _ExecuteFromItemPlanBrick->FaberPlan.FormulaMps[0].ItemRequired= CSheetId("m0152chdca01.sitem");
420 _ExecuteFromItemPlanBrick->FaberPlan.FormulaMps[0].Quantity= 13;
421 _ExecuteFromItemPlanBrick->FaberPlan.FormulaMps[1].ItemRequired= CSheetId("m0691chdca01.sitem");
422 _ExecuteFromItemPlanBrick->FaberPlan.FormulaMps[1].Quantity= 25;
426 // the num of itempPart/specific items to setup
427 _MPBuildNumItemPartReq
= min((uint
)MAX_ITEM_REQ_LINE
, (uint
)_ExecuteFromItemPlanBrick
->FaberPlan
.ItemPartMps
.size());
428 _MPBuildNumSpecificItemReq
= min(((uint
)MAX_ITEM_REQ_LINE
-_MPBuildNumItemPartReq
), (uint
)_ExecuteFromItemPlanBrick
->FaberPlan
.FormulaMps
.size());
429 _MPBuildNumTotalItemReq
= _MPBuildNumItemPartReq
+ _MPBuildNumSpecificItemReq
;
432 // Setup the selected plan
433 CCDBNodeLeaf
*node
= NLGUI::CDBManager::getInstance()->getDbProp(FaberPlanDB
, false);
435 node
->setValue32(_ExecuteFromItemPlanBrick
->Id
.asInt());
437 // Setup the result item
438 node
= NLGUI::CDBManager::getInstance()->getDbProp(ItemResultSheetDB
, false);
440 node
->setValue32(itemPlanBrick
->FaberPlan
.ItemBuilt
.asInt());
442 // Setup the result quantity (for stacked items)
443 node
= NLGUI::CDBManager::getInstance()->getDbProp(ItemResultQuantityDB
, false);
445 node
->setValue32(itemPlanBrick
->FaberPlan
.NbItemBuilt
);
447 // Show the ItemResult group
448 CInterfaceGroup
*groupMp
= dynamic_cast<CInterfaceGroup
*>(CWidgetManager::getInstance()->getElementFromId(FaberPhraseItemResultGroup
));
450 groupMp
->setActive(true);
453 // **** reset the mpBuild
454 // For all item required.
456 for(itemReqLine
=0;itemReqLine
<_MPBuildNumTotalItemReq
;itemReqLine
++)
458 CMPBuild
&mpBuild
= _MPBuild
[itemReqLine
];
460 // Type of requirement?
461 // First go the ItemPart reqs
462 if(itemReqLine
<_MPBuildNumItemPartReq
)
464 uint itemPartId
= itemReqLine
;
465 mpBuild
.RequirementType
= CMPBuild::ItemPartReq
;
466 mpBuild
.FaberTypeRequired
= _ExecuteFromItemPlanBrick
->FaberPlan
.ItemPartMps
[itemPartId
].FaberTypeFilter
;
467 mpBuild
.QuantityReq
= _ExecuteFromItemPlanBrick
->FaberPlan
.ItemPartMps
[itemPartId
].Quantity
;
469 // Then go the Specific item reqs
472 uint itemSpecificId
= itemReqLine
- _MPBuildNumItemPartReq
;
473 mpBuild
.RequirementType
= CMPBuild::SpecificItemReq
;
474 mpBuild
.SpecificItemRequired
= _ExecuteFromItemPlanBrick
->FaberPlan
.FormulaMps
[itemSpecificId
].ItemRequired
;
475 mpBuild
.QuantityReq
= _ExecuteFromItemPlanBrick
->FaberPlan
.FormulaMps
[itemSpecificId
].Quantity
;
478 // Reset the quantity setuped for this line
479 mpBuild
.NumMpSlot
= 0;
480 for(uint mpSlot
=0;mpSlot
<MAX_MP_SLOT
;mpSlot
++)
482 mpBuild
.Id
[mpSlot
]= 0; // useless, but for consistency
483 mpBuild
.QuantitySelected
[mpSlot
]= 0;
486 // reset other to 0 also
487 for(;itemReqLine
<MAX_ITEM_REQ_LINE
;itemReqLine
++)
489 _MPBuild
[itemReqLine
].reset();
493 // **** First clear and copy the inventory to local struct
495 for(i
=0;i
<_InventoryMirror
.size();i
++)
497 _InventoryMirror
[i
].reset();
502 // Run all the inventories.
503 for(i
=0;i
<_InventoryMirror
.size();i
++)
505 CItemImage
*itemImage
= getInvMirrorItemImage(i
, invId
, indexInInv
);
506 bool bLockedByOwner
= itemImage
&& itemImage
->getLockedByOwner();
507 // item found and not locked?
511 _InventoryMirror
[i
].InventoryId
= invId
;
512 _InventoryMirror
[i
].IdInInventory
= indexInInv
;
514 // The item must be a mp
515 CSheetId sheetId
= CSheetId(itemImage
->getSheetID());
516 CItemSheet
*mpSheet
= dynamic_cast<CItemSheet
*>(SheetMngr
.get(sheetId
));
517 if( isMpAvailable(mpSheet
, invId
, i
) && !bLockedByOwner
)
519 _InventoryMirror
[i
].Sheet
= sheetId
;
520 _InventoryMirror
[i
].Quality
= itemImage
->getQuality();
521 _InventoryMirror
[i
].Quantity
= itemImage
->getQuantity();
522 _InventoryMirror
[i
].UserColor
= itemImage
->getUserColor();
523 _InventoryMirror
[i
].Weight
= itemImage
->getWeight();
524 // Bkup original quantity from inventory
525 _InventoryMirror
[i
].OriginalQuantity
= _InventoryMirror
[i
].Quantity
;
526 _InventoryMirror
[i
].LockedByOwner
= bLockedByOwner
;
527 // remember these for sorting
528 _InventoryMirror
[i
].MpFamily
= mpSheet
->Mp
.Family
;
529 _InventoryMirror
[i
].Ecosystem
= mpSheet
->Mp
.Ecosystem
;
530 _InventoryMirror
[i
].StatEnergy
= mpSheet
->Mp
.StatEnergy
;
536 // **** show ItemParts according to plan.
537 // Hide the valid button
538 CCtrlBaseButton
*validButton
= dynamic_cast<CCtrlBaseButton
*>(CWidgetManager::getInstance()->getElementFromId(FaberPhraseValidButton
));
540 validButton
->setFrozen(true);
542 // reset DB, show/hide the Mps
543 for(itemReqLine
=0;itemReqLine
<MAX_ITEM_REQ_LINE
;itemReqLine
++)
545 CMPBuild
&mpBuild
= _MPBuild
[itemReqLine
];
547 // Reset All Mps slots.
548 for(uint mpSlot
=0;mpSlot
<MAX_MP_SLOT
;mpSlot
++)
550 CCDBNodeLeaf
*node
= NLGUI::CDBManager::getInstance()->getDbProp(toString("%s:%d:%d:SHEET", MPFaberDB
.c_str(), itemReqLine
, mpSlot
), false);
555 // Setup item requirement groups
556 CInterfaceGroup
*itemReqLineGroup
= dynamic_cast<CInterfaceGroup
*>(CWidgetManager::getInstance()->getElementFromId( toString(FaberPhraseItemReqLine
.c_str(), itemReqLine
) ));
559 if( itemReqLine
<_MPBuildNumTotalItemReq
)
561 itemReqLineGroup
->setActive(true);
563 // Set as Text the required MP FaberType or Specific item
564 CViewText
*viewText
= dynamic_cast<CViewText
*>(itemReqLineGroup
->getView(FaberPhraseText
));
568 if(mpBuild
.RequirementType
==CMPBuild::ItemPartReq
)
570 text
= CI18N::get("uihelpFaberMpHeader");
571 strFindReplace(text
, "%f", RM_FABER_TYPE::toLocalString(mpBuild
.FaberTypeRequired
) );
573 else if(mpBuild
.RequirementType
==CMPBuild::SpecificItemReq
)
575 text
= STRING_MANAGER::CStringManagerClient::getItemLocalizedName(mpBuild
.SpecificItemRequired
);
581 viewText
->setText(text
);
584 // Set as Icon the required MP FaberType / or Sheet Texture (directly...)
585 CViewBitmap
*viewBmp
= dynamic_cast<CViewBitmap
*>(itemReqLineGroup
->getView(FaberPhraseIcon
));
588 if(mpBuild
.RequirementType
==CMPBuild::ItemPartReq
)
590 // texture name in config.xml
591 viewBmp
->setTexture(CWidgetManager::getInstance()->getParser()->getDefine( RM_FABER_TYPE::toIconDefineString(mpBuild
.FaberTypeRequired
) ));
593 else if(mpBuild
.RequirementType
==CMPBuild::SpecificItemReq
)
595 // NB: the texture is scaled, so it's ok to put the item 40x40 texture
596 const CItemSheet
*itemSheet
= dynamic_cast<const CItemSheet
*>(SheetMngr
.get(mpBuild
.SpecificItemRequired
));
598 viewBmp
->setTexture(itemSheet
->getIconMain());
600 viewBmp
->setTexture(std::string());
608 // update the EmptySlot
609 updateEmptySlot(itemReqLine
, itemReqLineGroup
);
611 // setup item required quantity view
612 updateQuantityView(itemReqLine
);
616 itemReqLineGroup
->setActive(false);
622 // **** Setup the new window title
623 CGroupContainer
*window
= dynamic_cast<CGroupContainer
*>(CWidgetManager::getInstance()->getElementFromId(FaberPhraseWindow
));
626 // Setup the Title with the item built
627 string title
= CI18N::get("uiPhraseFaberExecute");
628 strFindReplace(title
, "%item", STRING_MANAGER::CStringManagerClient::getItemLocalizedName(_ExecuteFromItemPlanBrick
->FaberPlan
.ItemBuilt
) );
629 window
->setTitle (title
);
637 // ***************************************************************************
638 void CActionPhraseFaber::resetSelection()
640 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
642 for(uint i
=0;i
<MAX_MP_SELECTION_ENTRIES
;i
++)
644 NLGUI::CDBManager::getInstance()->getDbProp(MPSelectionDB
+ ":" + toString(i
) + ":SHEET")->setValue32(0);
648 // ***************************************************************************
649 void CActionPhraseFaber::fillSelection(const std::vector
<uint
> &mps
)
651 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
653 uint num
= min(uint(MAX_MP_SELECTION_ENTRIES
), uint(mps
.size()));
654 for(uint i
=0;i
<MAX_MP_SELECTION_ENTRIES
;i
++)
656 if(i
<num
&& mps
[i
]<_InventoryMirror
.size())
658 CItem
&item
= _InventoryMirror
[mps
[i
]];
659 fillDBWithMP(MPSelectionDB
+ ":" + toString(i
), item
);
662 NLGUI::CDBManager::getInstance()->getDbProp(MPSelectionDB
+ ":" + toString(i
) + ":SHEET")->setValue32(0);
667 // ***************************************************************************
668 void CActionPhraseFaber::filterSelectionItemPart(std::vector
<uint
> &mps
, RM_FABER_TYPE::TRMFType itemPartFilter
, ITEM_ORIGIN::EItemOrigin originFilter
)
670 // Unknown => no fitler
671 if(itemPartFilter
==RM_FABER_TYPE::Unknown
)
674 std::vector
<uint
> res
;
675 res
.reserve(mps
.size());
677 for(uint i
=0;i
<mps
.size();i
++)
679 // get the item sheet
680 const CItemSheet
*itemSheet
= dynamic_cast<const CItemSheet
*>(SheetMngr
.get(_InventoryMirror
[mps
[i
]].Sheet
));
681 // test itemPartFilter match.
684 if(itemSheet
->canBuildItemPart(itemPartFilter
, originFilter
))
686 res
.push_back(mps
[i
]);
695 // ***************************************************************************
696 void CActionPhraseFaber::filterSelectionItemSpecific(std::vector
<uint
> &mps
, NLMISC::CSheetId specificItemWanted
)
698 std::vector
<uint
> res
;
699 res
.reserve(mps
.size());
701 // if unknown sheetid, no match
702 if(specificItemWanted
==NLMISC::CSheetId::Unknown
)
708 for(uint i
=0;i
<mps
.size();i
++)
710 // get the item sheet
711 const CItemSheet
*itemSheet
= dynamic_cast<const CItemSheet
*>(SheetMngr
.get(_InventoryMirror
[mps
[i
]].Sheet
));
712 // test sheetid match.
715 if(itemSheet
->Id
== specificItemWanted
)
717 res
.push_back(mps
[i
]);
725 // ***************************************************************************
729 RM_FAMILY::TRMFamily MpFamily
;
730 ECOSYSTEM::EECosystem Ecosystem
;
735 SItemSortData(uint i
, RM_FAMILY::TRMFamily mpfam
, ECOSYSTEM::EECosystem eco
, uint16 stat
, uint16 quality
, uint16 quantity
)
736 : Index(i
), MpFamily(mpfam
), Ecosystem(eco
), StatEnergy(stat
), Quality(quality
), Quantity(quantity
)
739 bool operator<(const SItemSortData
&other
) const
742 if (MpFamily
< other
.MpFamily
) return true;
743 if (MpFamily
> other
.MpFamily
) return false;
746 if (Ecosystem
< other
.Ecosystem
) return true;
747 if (Ecosystem
> other
.Ecosystem
) return false;
750 if (StatEnergy
< other
.StatEnergy
) return true;
751 if (StatEnergy
> other
.StatEnergy
) return false;
754 if (Quality
< other
.Quality
) return true;
755 if (Quality
> other
.Quality
) return false;
758 if (Quantity
< other
.Quantity
) return true;
759 if (Quantity
> other
.Quantity
) return false;
765 // ***************************************************************************
766 void CActionPhraseFaber::sortSelection(std::vector
<uint
> &mps
) const
768 std::vector
<SItemSortData
> items
;
769 items
.reserve(mps
.size());
770 for(uint i
= 0; i
< mps
.size(); i
++)
772 const CItem
&item
= _InventoryMirror
[mps
[i
]];
773 items
.push_back(SItemSortData(mps
[i
], item
.MpFamily
, item
.Ecosystem
, item
.StatEnergy
, item
.Quality
, item
.Quantity
));
776 std::sort(items
.begin(), items
.end());
778 // overwrite previous values
779 for(uint i
= 0; i
< items
.size(); i
++)
780 mps
[i
] = items
[i
].Index
;
783 // ***************************************************************************
784 void CActionPhraseFaber::startMpSelection(uint itemReqLine
, uint mpSlot
)
786 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
789 CDBCtrlSheet
*ctrlSlot
= NULL
;
790 CInterfaceGroup
*itemReqLineGroup
= dynamic_cast<CInterfaceGroup
*>(CWidgetManager::getInstance()->getElementFromId( toString(FaberPhraseItemReqLine
.c_str(), itemReqLine
) ));
793 CDBGroupListSheet
*listSheet
= dynamic_cast<CDBGroupListSheet
*>(itemReqLineGroup
->getGroup(FaberPhraseList
));
795 ctrlSlot
= listSheet
->getSheet(mpSlot
);
800 // get the mpBuild setup
801 nlassert(itemReqLine
<MAX_ITEM_REQ_LINE
);
802 CMPBuild
&mpBuild
= _MPBuild
[itemReqLine
];
804 // If the slot selected is already filled, Launch the MP Quantity selection modal
805 if(mpSlot
<mpBuild
.NumMpSlot
)
807 // fill the sheet info
808 uint invSlot
= mpBuild
.Id
[mpSlot
];
809 CItem item
= _InventoryMirror
[invSlot
];
810 fillDBWithMP(MPQuantitySelectDb
, item
);
812 // compute the maximum quantity possible to fill
813 uint maxQuantity
= getMaxQuantityChange(itemReqLine
, mpSlot
);
815 // set the max quantity as the default quantity to set up.
816 CCDBNodeLeaf
*node
= NLGUI::CDBManager::getInstance()->getDbProp(MPQuantitySelectDb
+ ":CUR_QUANTITY", false);
817 if(node
) node
->setValue32(maxQuantity
);
818 node
= NLGUI::CDBManager::getInstance()->getDbProp(MPQuantitySelectDb
+ ":MAX_QUANTITY", false);
819 if(node
) node
->setValue32(maxQuantity
);
821 // bkup for validation
822 _MpSelectionItemReqLine
= itemReqLine
;
823 _MpChangeQuantitySlot
= mpSlot
;
825 // Setup the text with value by default
826 CInterfaceGroup
*quantityModal
= dynamic_cast<CInterfaceGroup
*>(CWidgetManager::getInstance()->getElementFromId(FaberPhraseMpQuantityModal
));
829 CGroupEditBox
*eb
= dynamic_cast<CGroupEditBox
*>(quantityModal
->getGroup("eb"));
832 CWidgetManager::getInstance()->setCaptureKeyboard(eb
);
833 eb
->setInputString(toString(maxQuantity
));
834 eb
->setSelectionAll();
839 CWidgetManager::getInstance()->enableModalWindow(ctrlSlot
, quantityModal
);
841 // else select new MP
844 // For All the inventory
845 vector
<uint
> selectMps
;
846 for(uint i
=0;i
<_InventoryMirror
.size();i
++)
848 // If still some MP on this stack, and if not already selected, add to selection
849 if(_InventoryMirror
[i
].Quantity
>0 && (_InventoryMirror
[i
].Selected
&(1<<itemReqLine
))==0 )
851 selectMps
.push_back(i
);
855 // Filter the selection whether it is an itemPart or specificItem reqiurement
856 if(mpBuild
.RequirementType
==CMPBuild::ItemPartReq
)
858 CItemSheet
*itemBuilt
= dynamic_cast<CItemSheet
*>(SheetMngr
.get(_ExecuteFromItemPlanBrick
->FaberPlan
.ItemBuilt
));
859 ITEM_ORIGIN::EItemOrigin itemOrigin
= itemBuilt
? itemBuilt
->ItemOrigin
: ITEM_ORIGIN::UNKNOWN
;
860 filterSelectionItemPart(selectMps
, mpBuild
.FaberTypeRequired
, itemOrigin
);
862 else if(mpBuild
.RequirementType
==CMPBuild::SpecificItemReq
)
864 filterSelectionItemSpecific(selectMps
, mpBuild
.SpecificItemRequired
);
871 // Sort before displaying
872 sortSelection(selectMps
);
874 // Reset the DB selection
876 fillSelection(selectMps
);
878 // Bkup Selection for Validate later
879 _MpSelectionItemReqLine
= itemReqLine
;
880 _MpCurrentSelection
= selectMps
;
882 // Open the Selection Window.
883 CWidgetManager::getInstance()->enableModalWindow(ctrlSlot
, FaberPhraseMpListModal
);
887 // ***************************************************************************
888 void CActionPhraseFaber::validateMpSelection(uint selectId
)
890 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
892 if(selectId
>=_MpCurrentSelection
.size())
894 CWidgetManager::getInstance()->disableModalWindow();
898 // get which MP of the inventory we have selected
899 uint newInvSlot
= _MpCurrentSelection
[selectId
];
902 uint itemReqLine
= _MpSelectionItemReqLine
;
903 CMPBuild
&mpBuild
= _MPBuild
[itemReqLine
];
905 // Select the quantity to peek from this inventory slot: get max possible
906 sint quantity
= mpBuild
.QuantityReq
- getTotalQuantitySetuped(itemReqLine
);
907 nlassert(quantity
>0);
908 quantity
= min((sint32
)quantity
, _InventoryMirror
[newInvSlot
].Quantity
);
910 // it may be possible (by update DB and error) that selected slot is no more usable => just quit
914 // And Remove (virtually) item stack from this slot
915 _InventoryMirror
[newInvSlot
].Quantity
-= quantity
;
916 // mark as selected for this itemReqLine, so can no more select it
917 _InventoryMirror
[newInvSlot
].Selected
|= 1<<itemReqLine
;
920 nlassert(mpBuild
.NumMpSlot
<MAX_MP_SLOT
);
921 mpBuild
.Id
[mpBuild
.NumMpSlot
]= newInvSlot
;
922 mpBuild
.QuantitySelected
[mpBuild
.NumMpSlot
]= quantity
;
925 // Update The Execution View
926 CItem item
= _InventoryMirror
[newInvSlot
];
927 item
.Quantity
= quantity
;
928 fillDBWithMP(toString("%s:%d:%d", MPFaberDB
.c_str(), itemReqLine
, mpBuild
.NumMpSlot
-1), item
);
930 // update the empty slot
931 updateEmptySlot(itemReqLine
);
933 // update quantity view
934 updateQuantityView(itemReqLine
);
936 // update the validateButton
939 // update the item result
942 // must hide the modal window which had open us. NB: must be done here because next,
943 // we'll open the MP quantity selection
944 CWidgetManager::getInstance()->disableModalWindow();
946 // **** when all is correctly ended, open the quantity selection
947 // NB: just enable this code, if you want this feature
948 //startMpSelection(itemReqLine, mpBuild.NumMpSlot-1);
951 // ***************************************************************************
952 void CActionPhraseFaber::validateMpSelectQuantity()
954 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
956 // get current execution context of the validate
957 uint itemReqLine
= _MpSelectionItemReqLine
;
958 nlassert(itemReqLine
<MAX_ITEM_REQ_LINE
);
959 CMPBuild
&mpBuild
= _MPBuild
[itemReqLine
];
960 uint mpSlot
= _MpChangeQuantitySlot
;
961 nlassert(mpSlot
<mpBuild
.NumMpSlot
);
962 uint invSlot
= mpBuild
.Id
[mpSlot
];
963 nlassert(invSlot
<_InventoryMirror
.size());
964 nlassert(_InventoryMirror
[invSlot
].Selected
& (1<<itemReqLine
));
966 // get the quantity selected
967 uint quantitySelected
= 0;
968 CCDBNodeLeaf
*node
= NLGUI::CDBManager::getInstance()->getDbProp(MPQuantitySelectDb
+ ":CUR_QUANTITY", false);
969 if(node
) quantitySelected
= node
->getValue32();
971 // maximize (if error)
972 quantitySelected
= min(quantitySelected
, getMaxQuantityChange(itemReqLine
, mpSlot
));
974 // if the new quantity is 0
975 if(quantitySelected
==0)
977 // special: remove the mp slot from list
978 deleteMpSlot(itemReqLine
, mpSlot
);
982 // restore old quantity into inventory
983 _InventoryMirror
[invSlot
].Quantity
+= mpBuild
.QuantitySelected
[mpSlot
];
984 // And then Remove (virtually) new item stack from this slot
985 _InventoryMirror
[invSlot
].Quantity
-= quantitySelected
;
988 mpBuild
.QuantitySelected
[mpSlot
]= quantitySelected
;
990 // Update The Execution View
991 CItem item
= _InventoryMirror
[invSlot
];
992 item
.Quantity
= quantitySelected
;
993 fillDBWithMP(toString("%s:%d:%d", MPFaberDB
.c_str(), itemReqLine
, mpSlot
), item
);
996 // update the empty slot
997 updateEmptySlot(itemReqLine
);
999 // update quantity view
1000 updateQuantityView(itemReqLine
);
1002 // update the valid button
1003 updateValidButton();
1005 // update the item result
1008 // hide the Modal Quantity selection
1009 CWidgetManager::getInstance()->disableModalWindow();
1012 // ***************************************************************************
1013 void CActionPhraseFaber::validateExecution()
1015 // the plan has must been selected
1016 nlassert(_ExecuteFromItemPlanBrick
);
1018 // Build the list of MP in Bag.
1019 vector
<CFaberMsgItem
> mpItemPartList
;
1020 vector
<CFaberMsgItem
> specificItemList
;
1022 // Run all the current Build execution
1023 for(uint itemReqLine
=0;itemReqLine
<_MPBuildNumTotalItemReq
;itemReqLine
++)
1025 CMPBuild
&mpBuild
= _MPBuild
[itemReqLine
];
1026 // For all slot setuped.
1027 for(uint mpSlot
=0;mpSlot
<mpBuild
.NumMpSlot
;mpSlot
++)
1031 uint invSlot
= mpBuild
.Id
[mpSlot
];
1032 nlassert(invSlot
<_InventoryMirror
.size());
1033 item
.setInvId(INVENTORIES::TInventory(_InventoryMirror
[invSlot
].InventoryId
));
1034 item
.IndexInInv
= _InventoryMirror
[invSlot
].IdInInventory
;
1035 item
.Quantity
= mpBuild
.QuantitySelected
[mpSlot
];
1037 if(mpBuild
.RequirementType
==CMPBuild::ItemPartReq
)
1038 mpItemPartList
.push_back(item
);
1039 else if(mpBuild
.RequirementType
==CMPBuild::SpecificItemReq
)
1040 specificItemList
.push_back(item
);
1048 // display next craft action, and Send message to server
1049 CSPhraseManager
*pPM
= CSPhraseManager::getInstance();
1050 pPM
->executeCraft(_ExecuteFromMemoryLine
, _ExecuteFromMemoryIndex
,
1051 _ExecuteFromItemPlanBrick
->Id
.asInt(), mpItemPartList
, specificItemList
);
1053 // Open the Interface to get the crafted item
1054 CTempInvManager::getInstance()->open(TEMP_INV_MODE::Craft
);
1056 // NO more Close the Execution window (allow refaber quick)
1057 /*CInterfaceManager *pIM= CInterfaceManager::getInstance();
1058 CInterfaceElement *window= CWidgetManager::getInstance()->getElementFromId(FaberPhraseWindow);
1060 window->setActive(false);
1066 // ***************************************************************************
1067 uint
CActionPhraseFaber::getTotalQuantitySetuped(uint itemReqLine
) const
1069 nlassert(itemReqLine
<MAX_ITEM_REQ_LINE
);
1070 nlassert(_MPBuild
[itemReqLine
].NumMpSlot
<=MAX_MP_SLOT
);
1073 for(uint i
=0;i
<_MPBuild
[itemReqLine
].NumMpSlot
;i
++)
1075 ret
+= _MPBuild
[itemReqLine
].QuantitySelected
[i
];
1082 // ***************************************************************************
1083 uint
CActionPhraseFaber::getMaxQuantityChange(uint itemReqLine
, uint mpSlot
) const
1085 nlassert(itemReqLine
<MAX_ITEM_REQ_LINE
);
1086 nlassert(mpSlot
<_MPBuild
[itemReqLine
].NumMpSlot
);
1088 uint invSlot
= _MPBuild
[itemReqLine
].Id
[mpSlot
];
1089 nlassert(invSlot
<_InventoryMirror
.size());
1090 CItem item
= _InventoryMirror
[invSlot
];
1092 // This is the quantity already selected for this itemReqLine, + rest in inventory
1093 uint maxQuantity
= _MPBuild
[itemReqLine
].QuantitySelected
[mpSlot
] + item
.Quantity
;
1094 // maximize with the rest of quantity with have to setup (remove us btw)
1095 maxQuantity
= min(maxQuantity
, _MPBuild
[itemReqLine
].QuantityReq
-
1096 (getTotalQuantitySetuped(itemReqLine
) - _MPBuild
[itemReqLine
].QuantitySelected
[mpSlot
]) );
1102 // ***************************************************************************
1103 void CActionPhraseFaber::updateEmptySlot(uint itemReqLine
, CInterfaceGroup
*itemReqLineGroup
)
1105 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
1107 if(!itemReqLineGroup
)
1108 itemReqLineGroup
= dynamic_cast<CInterfaceGroup
*>(CWidgetManager::getInstance()->getElementFromId( toString(FaberPhraseItemReqLine
.c_str(), itemReqLine
) ));
1109 if(!itemReqLineGroup
)
1112 // get the list sheet and ctrlButton.
1113 CDBGroupListSheet
*listSheet
= dynamic_cast<CDBGroupListSheet
*>(itemReqLineGroup
->getGroup(FaberPhraseList
));
1117 // NB: forceValidity calls invalidateCoords() if state change => dont "clear then set".
1120 bool allSetuped
= getTotalQuantitySetuped(itemReqLine
) >= _MPBuild
[itemReqLine
].QuantityReq
;
1122 // button no more needed?
1125 // Reset all ForceValid
1126 for(uint i
=0;i
<MAX_MP_SLOT
;i
++)
1127 listSheet
->forceValidity(i
, false);
1131 // Reset all ForceValid
1132 for(uint i
=0;i
<MAX_MP_SLOT
;i
++)
1134 listSheet
->forceValidity(i
, i
==_MPBuild
[itemReqLine
].NumMpSlot
);
1138 // Special for Specific Item requirement. Setup grayed item for the last empty slot
1139 for(uint i
=0;i
<MAX_MP_SLOT
;i
++)
1141 CMPBuild
&mpBuild
= _MPBuild
[itemReqLine
];
1143 // *** Fill the empty DB.
1144 if(i
>=mpBuild
.NumMpSlot
)
1147 // If Specfific requirement and just the last one, don't leave empty
1148 if(!allSetuped
&& i
==mpBuild
.NumMpSlot
&& mpBuild
.RequirementType
== CMPBuild::SpecificItemReq
)
1150 item
.Sheet
= mpBuild
.SpecificItemRequired
;
1152 fillDBWithMP(toString("%s:%d:%d", MPFaberDB
.c_str(), itemReqLine
, i
), item
);
1155 // *** Grayed,NoQuantity,NoQuality for the last slot of a specific requirement
1156 CDBCtrlSheet
*ctrl
= listSheet
->getSheet(i
);
1159 if(i
==mpBuild
.NumMpSlot
&& mpBuild
.RequirementType
== CMPBuild::SpecificItemReq
)
1161 ctrl
->setUseQuality(false);
1162 ctrl
->setUseQuantity(false);
1163 ctrl
->setGrayed(true);
1167 ctrl
->setUseQuality(true);
1168 ctrl
->setUseQuantity(true);
1169 ctrl
->setGrayed(false);
1176 // ***************************************************************************
1177 void CActionPhraseFaber::updateQuantityView(uint itemReqLine
)
1179 nlassert(itemReqLine
<MAX_ITEM_REQ_LINE
);
1181 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
1183 CCDBNodeLeaf
*node
= NLGUI::CDBManager::getInstance()->getDbProp(toString("%s:%d:SELECTED", MPQuantityDb
.c_str(), itemReqLine
), false);
1185 node
->setValue32(getTotalQuantitySetuped(itemReqLine
));
1186 node
= NLGUI::CDBManager::getInstance()->getDbProp(toString("%s:%d:REQUIRED", MPQuantityDb
.c_str(), itemReqLine
), false);
1188 node
->setValue32(_MPBuild
[itemReqLine
].QuantityReq
);
1192 // ***************************************************************************
1193 void CActionPhraseFaber::updateValidButton()
1195 // Check For All MPSlot: If All Ok, then can validate!
1196 bool canValid
= true;
1198 // can validate only if the Plan has been selected
1199 if(_ExecuteFromItemPlanBrick
)
1201 // Run all the current Build execution
1202 for(uint itemReqLine
=0;itemReqLine
<_MPBuildNumTotalItemReq
;itemReqLine
++)
1204 canValid
= canValid
&& getTotalQuantitySetuped(itemReqLine
)==_MPBuild
[itemReqLine
].QuantityReq
;
1210 // unfreeze if valid
1211 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
1212 CCtrlBaseButton
*validButton
= dynamic_cast<CCtrlBaseButton
*>(CWidgetManager::getInstance()->getElementFromId(FaberPhraseValidButton
));
1213 if(validButton
) validButton
->setFrozen(!canValid
);
1217 // ***************************************************************************
1218 void CActionPhraseFaber::deleteMpSlot(uint itemReqLine
, uint mpSlot
)
1220 nlassert(itemReqLine
<MAX_ITEM_REQ_LINE
);
1221 CMPBuild
&mpBuild
= _MPBuild
[itemReqLine
];
1222 nlassert(mpSlot
<mpBuild
.NumMpSlot
);
1223 uint invSlot
= mpBuild
.Id
[mpSlot
];
1224 nlassert(invSlot
<_InventoryMirror
.size());
1225 nlassert(_InventoryMirror
[invSlot
].Selected
& (1<<itemReqLine
));
1226 // NB: possible that mpBuild.QuantitySelected[mpSlot]==0 (call from removeMpSlotThatUseInvSlot())
1228 // restore quantity into inventory
1229 _InventoryMirror
[invSlot
].Quantity
+= mpBuild
.QuantitySelected
[mpSlot
];
1230 // no more selected for this itemReqLine, so can select it now
1231 _InventoryMirror
[invSlot
].Selected
&= ~(1<<itemReqLine
);
1233 // update the build by shifting in memory
1235 for(i
=mpSlot
;i
<mpBuild
.NumMpSlot
-1;i
++)
1237 mpBuild
.Id
[i
]= mpBuild
.Id
[i
+1];
1238 mpBuild
.QuantitySelected
[i
]= mpBuild
.QuantitySelected
[i
+1];
1240 mpBuild
.NumMpSlot
--;
1242 // update the execution view (just what needed)
1243 for(i
=mpSlot
;i
<mpBuild
.NumMpSlot
;i
++)
1245 CItem item
= _InventoryMirror
[mpBuild
.Id
[i
]];
1246 item
.Quantity
= mpBuild
.QuantitySelected
[i
];
1247 fillDBWithMP(toString("%s:%d:%d", MPFaberDB
.c_str(), itemReqLine
, i
), item
);
1250 // reset the empty slot!
1252 fillDBWithMP(toString("%s:%d:%d", MPFaberDB
.c_str(), itemReqLine
, mpBuild
.NumMpSlot
), item
);
1257 // ***************************************************************************
1258 // ***************************************************************************
1260 // ***************************************************************************
1261 // ***************************************************************************
1264 static CActionPhraseFaber
*ActionPhraseFaber
= NULL
;
1267 // ***************************************************************************
1268 // This expr is used only for define in phrase.xml.
1269 DECLARE_INTERFACE_CONSTANT(getPhraseMPSelectionMax
, MAX_MP_SELECTION_ENTRIES
)
1272 // ***************************************************************************
1273 class CHandlerPhraseFaberSelectMP
: public IActionHandler
1276 virtual void execute (CCtrlBase
*pCaller
, const string
&Params
)
1278 CDBCtrlSheet
*ctrl
= dynamic_cast<CDBCtrlSheet
*>(pCaller
);
1282 // get itemReqLine to Modify
1284 fromString(getParam(Params
, "item_req"), itemReqLine
);
1285 // get mpSlot edited
1286 uint mpSlot
= ctrl
->getIndexInDB();
1288 if (ActionPhraseFaber
== NULL
) ActionPhraseFaber
= new CActionPhraseFaber
;
1289 ActionPhraseFaber
->startMpSelection(itemReqLine
, mpSlot
);
1292 REGISTER_ACTION_HANDLER( CHandlerPhraseFaberSelectMP
, "phrase_faber_select_mp");
1295 // ***************************************************************************
1296 class CHandlerPhraseFaberValidateMP
: public IActionHandler
1299 virtual void execute (CCtrlBase
*pCaller
, const string
&/* Params */)
1301 CDBCtrlSheet
*ctrl
= dynamic_cast<CDBCtrlSheet
*>(pCaller
);
1304 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
1305 CWidgetManager::getInstance()->disableModalWindow();
1309 // get the selected MP.
1310 uint selectMP
= ctrl
->getIndexInDB();
1312 if (ActionPhraseFaber
== NULL
) ActionPhraseFaber
= new CActionPhraseFaber
;
1313 ActionPhraseFaber
->validateMpSelection(selectMP
);
1316 REGISTER_ACTION_HANDLER( CHandlerPhraseFaberValidateMP
, "phrase_faber_validate_mp");
1319 // ***************************************************************************
1320 class CHandlerPhraseFaberValidate
: public IActionHandler
1323 virtual void execute (CCtrlBase
* /* pCaller */, const string
&/* Params */)
1325 if (ActionPhraseFaber
== NULL
) ActionPhraseFaber
= new CActionPhraseFaber
;
1326 ActionPhraseFaber
->validateExecution();
1329 REGISTER_ACTION_HANDLER( CHandlerPhraseFaberValidate
, "phrase_faber_validate");
1332 // ***************************************************************************
1333 class CHandlerPhraseFaberValidateOnEnter
: public IActionHandler
1336 virtual void execute (CCtrlBase
* /* pCaller */, const string
&/* Params */)
1339 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
1340 CCtrlBaseButton
*button
= dynamic_cast<CCtrlBaseButton
*>(CWidgetManager::getInstance()->getElementFromId(FaberPhraseValidButton
));
1342 // Ok, button found. test if active.
1343 if( button
&& !button
->getFrozen() )
1345 // Act as if the player click on this button
1346 CAHManager::getInstance()->runActionHandler("phrase_faber_validate", button
);
1350 REGISTER_ACTION_HANDLER( CHandlerPhraseFaberValidateOnEnter
, "phrase_faber_validate_on_enter");
1353 // ***************************************************************************
1354 class CHandlerPhraseFaberSelectMpQuantity
: public IActionHandler
1357 virtual void execute (CCtrlBase
* /* pCaller */, const string
&/* Params */)
1359 if (ActionPhraseFaber
== NULL
) ActionPhraseFaber
= new CActionPhraseFaber
;
1360 ActionPhraseFaber
->validateMpSelectQuantity();
1363 REGISTER_ACTION_HANDLER( CHandlerPhraseFaberSelectMpQuantity
, "phrase_faber_select_mp_quantity");
1367 // ***************************************************************************
1368 void launchFaberCastWindow(sint32 memoryLine
, uint memoryIndex
, CSBrickSheet
*rootBrick
)
1370 if (ActionPhraseFaber
== NULL
) ActionPhraseFaber
= new CActionPhraseFaber
;
1371 ActionPhraseFaber
->launchFaberCastWindow(memoryLine
, memoryIndex
, rootBrick
);
1374 // ***************************************************************************
1375 void fillFaberPlanSelection(const std::string
&brickDB
, uint maxSelection
, TOOL_TYPE::TCraftingToolType toolType
)
1377 if (ActionPhraseFaber
== NULL
) ActionPhraseFaber
= new CActionPhraseFaber
;
1378 ActionPhraseFaber
->fillFaberPlanSelection(brickDB
, maxSelection
, toolType
);
1381 // ***************************************************************************
1382 void validateFaberPlanSelection(CSBrickSheet
*itemPlanBrick
)
1384 if (ActionPhraseFaber
== NULL
) ActionPhraseFaber
= new CActionPhraseFaber
;
1385 ActionPhraseFaber
->validateFaberPlanSelection(itemPlanBrick
);
1388 // ***************************************************************************
1389 void closeFaberCastWindow()
1391 if (ActionPhraseFaber
== NULL
) return;
1392 CGroupContainer
*window
= dynamic_cast<CGroupContainer
*>(CWidgetManager::getInstance()->getElementFromId(FaberPhraseWindow
));
1393 if(window
&& window
->getActive())
1394 window
->setActive(false);
1398 // ***************************************************************************
1399 class CHandlerPhraseFaberOnClose
: public IActionHandler
1402 virtual void execute (CCtrlBase
* /* pCaller */, const string
&/* Params */)
1404 if (ActionPhraseFaber
== NULL
) ActionPhraseFaber
= new CActionPhraseFaber
;
1405 ActionPhraseFaber
->onCloseFaberCastWindow();
1408 REGISTER_ACTION_HANDLER( CHandlerPhraseFaberOnClose
, "phrase_faber_on_close");
1411 // ***************************************************************************
1412 // ***************************************************************************
1413 // Management of Change in Inventory
1414 // ***************************************************************************
1415 // ***************************************************************************
1418 // ***************************************************************************
1419 void CActionPhraseFaber::removeMpSlotThatUseInvSlot(uint invSlot
, uint quantityToRemove
)
1421 if(quantityToRemove
==0)
1424 // remove from all mpSlots
1425 for(uint itemReqLine
=0;itemReqLine
<_MPBuildNumTotalItemReq
;itemReqLine
++)
1427 CMPBuild
&mpBuild
= _MPBuild
[itemReqLine
];
1428 for(uint mpSlot
=0;mpSlot
<mpBuild
.NumMpSlot
;)
1430 // if this mpSlot use the invSlot.
1431 if(mpBuild
.Id
[mpSlot
]==invSlot
)
1433 // then remove stack mp. If slot not enough
1434 uint removeSlotQuantity
;
1435 removeSlotQuantity
= min(quantityToRemove
, mpBuild
.QuantitySelected
[mpSlot
]);
1436 mpBuild
.QuantitySelected
[mpSlot
]-= removeSlotQuantity
;
1437 quantityToRemove
-= removeSlotQuantity
;
1439 // if slot completely removed, then remove it totaly
1440 if(mpBuild
.QuantitySelected
[mpSlot
]==0)
1442 // NB: nothing is restored to inventory since mpBuild.QuantitySelected[mpSlot] is reseted before
1443 deleteMpSlot(itemReqLine
, mpSlot
);
1447 // just change this DB view
1448 CItem item
= _InventoryMirror
[invSlot
];
1449 item
.Quantity
= mpBuild
.QuantitySelected
[mpSlot
];
1450 fillDBWithMP(toString("%s:%d:%d", MPFaberDB
.c_str(), itemReqLine
, mpSlot
), item
);
1456 // if ok, all req quantity removed, quit
1457 if(quantityToRemove
==0)
1467 // ***************************************************************************
1468 void CActionPhraseFaber::onInventoryChange()
1470 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
1473 bool displayChange
= false;
1475 // If the Faber Plan has not yet been selected, then must not check _InventoryMirror, since not initialized
1476 if(_ExecuteFromItemPlanBrick
==NULL
)
1481 uint indexInInv
= 0;
1482 for(i
=0;i
<_InventoryMirror
.size();i
++)
1484 CItemImage
*itemImage
= getInvMirrorItemImage(i
, invId
, indexInInv
);
1488 CSheetId sheetId
= CSheetId(itemImage
->getSheetID());
1489 CItemSheet
*mpSheet
= dynamic_cast<CItemSheet
*>(SheetMngr
.get(sheetId
));
1492 bool bLockedByOwner
= itemImage
->getLockedByOwner();
1494 // The item must be a mp, and the item must be available and unlocked
1495 if( isMpAvailable(mpSheet
, invId
, i
) && !bLockedByOwner
)
1497 newInvItem
.Sheet
= sheetId
;
1498 newInvItem
.Quality
= itemImage
->getQuality();
1499 newInvItem
.Quantity
= itemImage
->getQuantity();
1500 newInvItem
.UserColor
= itemImage
->getUserColor();
1501 newInvItem
.Weight
= itemImage
->getWeight();
1502 newInvItem
.OriginalQuantity
= newInvItem
.Quantity
;
1503 newInvItem
.LockedByOwner
= bLockedByOwner
;
1504 // remember these for sorting
1505 newInvItem
.MpFamily
= mpSheet
->Mp
.Family
;
1506 newInvItem
.Ecosystem
= mpSheet
->Mp
.Ecosystem
;
1507 newInvItem
.StatEnergy
= mpSheet
->Mp
.StatEnergy
;
1510 /* There is 5 cases:
1511 - no changes => no op.
1512 - new/unlocked Mp on a empty or non Mp slot. Easy, just add.
1513 - old Mp removed (not same sheetId/quality/userColor/locked)
1514 - old Mp with quantity changed to be greater
1515 - old Mp with quantity changed to be smaller
1518 CItem
&curInvItem
= _InventoryMirror
[i
];
1520 // Bkup Id in newInvItem (for ope= correctness)
1521 newInvItem
.InventoryId
= curInvItem
.InventoryId
;
1522 newInvItem
.IdInInventory
= curInvItem
.IdInInventory
;
1524 // If the item was not a mp
1525 if(_InventoryMirror
[i
].Sheet
==CSheetId::Unknown
)
1527 // if now it is, easy, just add if not locked
1528 if(newInvItem
.Sheet
!=CSheetId::Unknown
&& !newInvItem
.LockedByOwner
)
1529 curInvItem
= newInvItem
;
1531 // else must test change or remove
1535 sameMp
= curInvItem
.Sheet
== newInvItem
.Sheet
&&
1536 curInvItem
.Quality
== newInvItem
.Quality
&&
1537 curInvItem
.UserColor
== newInvItem
.UserColor
&&
1538 curInvItem
.LockedByOwner
== newInvItem
.LockedByOwner
;
1540 // if the Mp was deleted from this slot, delete it from all faber execution
1543 // remove all from current execution
1544 removeMpSlotThatUseInvSlot(i
, curInvItem
.OriginalQuantity
);
1546 // replace (with nothing or new different Mp)
1547 curInvItem
= newInvItem
;
1549 // mpSlot may have been deleted
1550 displayChange
= true;
1552 // test change of quantity
1555 // if the quantity is the same, no op!
1556 if(curInvItem
.OriginalQuantity
!=newInvItem
.OriginalQuantity
)
1558 // if the quantity is now greater, its easy
1559 if(newInvItem
.OriginalQuantity
> curInvItem
.OriginalQuantity
)
1561 // just add the difference to the original and current setuped quantity
1562 uint32 diff
= newInvItem
.OriginalQuantity
- curInvItem
.OriginalQuantity
;
1563 curInvItem
.OriginalQuantity
+= diff
;
1564 curInvItem
.Quantity
+= diff
;
1568 // complex, must remove the quantity that has changed
1569 uint32 diff
= curInvItem
.OriginalQuantity
- newInvItem
.OriginalQuantity
;
1570 // try first to remove it from remaining quantity
1571 if(curInvItem
.Quantity
>=(sint32
)diff
)
1573 // no change to current mpSlots!
1574 curInvItem
.Quantity
-= diff
;
1576 // must close the selection modal if opened
1577 displayChange
= true;
1579 // The remaining quantity is not enough, must also remove from mpSlot that use it!
1582 uint32 toRemoveFromSlot
= diff
- curInvItem
.Quantity
;
1583 curInvItem
.Quantity
= 0;
1584 // remove all needed to current mp slot.
1585 removeMpSlotThatUseInvSlot(i
, toRemoveFromSlot
);
1587 // mpSlot may have been deleted
1588 displayChange
= true;
1591 // bkup new original quantity
1592 curInvItem
.OriginalQuantity
= newInvItem
.OriginalQuantity
;
1600 // must update display?
1603 for(uint itemReqLine
= 0;itemReqLine
<_MPBuildNumTotalItemReq
;itemReqLine
++)
1605 updateEmptySlot(itemReqLine
);
1606 updateQuantityView(itemReqLine
);
1608 updateValidButton();
1610 // close selection modals if they are opened
1611 CInterfaceGroup
*quantityModal
= dynamic_cast<CInterfaceGroup
*>(CWidgetManager::getInstance()->getElementFromId(FaberPhraseMpQuantityModal
));
1612 if(quantityModal
&& CWidgetManager::getInstance()->getModalWindow()==quantityModal
)
1613 CWidgetManager::getInstance()->disableModalWindow();
1614 CInterfaceGroup
*listModal
= dynamic_cast<CInterfaceGroup
*>(CWidgetManager::getInstance()->getElementFromId(FaberPhraseMpListModal
));
1615 if(listModal
&& CWidgetManager::getInstance()->getModalWindow()==listModal
)
1616 CWidgetManager::getInstance()->disableModalWindow();
1618 // update item result
1623 // ***************************************************************************
1624 void CActionPhraseFaber::CDBInventoryObs::update(ICDBNode
* /* node */)
1626 if (ActionPhraseFaber
== NULL
) ActionPhraseFaber
= new CActionPhraseFaber
;
1627 ActionPhraseFaber
->onInventoryChange();
1630 // ***************************************************************************
1631 void CActionPhraseFaber::CDBAnimalObs::update(ICDBNode
* /* node */)
1633 if (ActionPhraseFaber
== NULL
) ActionPhraseFaber
= new CActionPhraseFaber
;
1634 ActionPhraseFaber
->onInventoryChange();
1639 // ***************************************************************************
1640 void CActionPhraseFaber::updateItemResult()
1642 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
1643 CSPhraseManager
*pPM
= CSPhraseManager::getInstance();
1644 CSBrickManager
*pBM
= CSBrickManager::getInstance();
1648 // level is the min level of MP
1649 sint32 minLevel
= INT_MAX
;
1650 // Stat is computed like server
1651 float statArray
[RM_FABER_STAT_TYPE::NumRMStatType
];
1652 float statCount
[RM_FABER_STAT_TYPE::NumRMStatType
];
1653 uint64 itemStatBF
= 0;
1654 for(i
=0;i
<RM_FABER_STAT_TYPE::NumRMStatType
;i
++)
1659 // Color stat (for armour)
1660 uint32 bestItemColor
[RM_COLOR::NumColors
];
1661 for(i
=0;i
<RM_COLOR::NumColors
;i
++)
1662 bestItemColor
[i
]= 0;
1663 // Stat energy is computed like server
1664 float statEnergy
= 0;
1667 // **** Parse all Bricks of the phrase executed, to get min level
1668 // take The brick with the lowest CR_RECOMMENDED
1669 uint phraseSlot
= pPM
->getMemorizedPhrase(_ExecuteFromMemoryLine
, _ExecuteFromMemoryIndex
);
1670 const CSPhraseCom
&phrase
= pPM
->getPhrase(phraseSlot
);
1671 uint32 recommendedPropId
= pBM
->getBrickPropId("cr_recommended");
1672 uint32 crHp
= pBM
->getBrickPropId("cr_hp");
1673 uint32 crSap
= pBM
->getBrickPropId("cr_sap");
1674 uint32 crSta
= pBM
->getBrickPropId("cr_sta");
1675 uint32 crFocus
= pBM
->getBrickPropId("cr_focus");
1679 sint32 focusBuff
= 0;
1680 for(i
=0;i
<phrase
.Bricks
.size();i
++)
1682 CSBrickSheet
*brick
= pBM
->getBrick(phrase
.Bricks
[i
]);
1685 for(uint j
=0;j
<brick
->Properties
.size();j
++)
1687 // if a CR_RECOMMENDED propId
1688 if(brick
->Properties
[j
].PropId
== recommendedPropId
)
1690 // minimze the level
1691 minLevel
= min(minLevel
, sint32(brick
->Properties
[j
].Value
));
1694 if (brick
->Properties
[j
].PropId
== crHp
)
1695 hpBuff
= sint32(brick
->Properties
[j
].Value
);
1696 if (brick
->Properties
[j
].PropId
== crSap
)
1697 sapBuff
= sint32(brick
->Properties
[j
].Value
);
1698 if (brick
->Properties
[j
].PropId
== crSta
)
1699 staBuff
= sint32(brick
->Properties
[j
].Value
);
1700 if (brick
->Properties
[j
].PropId
== crFocus
)
1701 focusBuff
= sint32(brick
->Properties
[j
].Value
);
1707 NLGUI::CDBManager
*cdb
= NLGUI::CDBManager::getInstance();
1708 NLMISC::CCDBNodeLeaf
*node
= cdb
->getDbProp(FaberPlanHpBuffDB
, false);
1709 if (node
) node
->setValue32(hpBuff
);
1710 node
= cdb
->getDbProp(FaberPlanSapBuffDB
, false);
1711 if (node
) node
->setValue32(sapBuff
);
1712 node
= cdb
->getDbProp(FaberPlanStaBuffDB
, false);
1713 if (node
) node
->setValue32(staBuff
);
1714 node
= cdb
->getDbProp(FaberPlanFocusBuffDB
, false);
1715 if (node
) node
->setValue32(focusBuff
);
1718 // **** Parse all MPs setuped, to compute level and stats
1719 uint totalItemPartMPReq
= 0;
1720 uint totalItemPartMPSetuped
= 0;
1721 for(i
=0;i
<_MPBuildNumTotalItemReq
;i
++)
1723 CMPBuild
&mpBuild
= _MPBuild
[i
];
1725 // --- ItemPart requirement?
1726 if(mpBuild
.RequirementType
==CMPBuild::ItemPartReq
)
1728 // For all slots setuped
1729 uint nSlot
= min((uint
)MAX_MP_SLOT
, mpBuild
.NumMpSlot
);
1730 for(uint j
=0;j
<nSlot
;j
++)
1732 // Try to get the MP in this slot
1733 CItemSheet
*mp
= dynamic_cast<CItemSheet
*>(SheetMngr
.get(_InventoryMirror
[mpBuild
.Id
[j
]].Sheet
));
1734 if(mp
&& mp
->canBuildItemPart(mpBuild
.FaberTypeRequired
))
1737 minLevel
= min(_InventoryMirror
[mpBuild
.Id
[j
]].Quality
, minLevel
);
1739 // Increment stat for each of this MP selected
1740 const CItemSheet::CMpItemPart
&mpIP
= mp
->getItemPart(mpBuild
.FaberTypeRequired
);
1742 // append to the stats
1743 uint numMps
= mpBuild
.QuantitySelected
[j
];
1744 for(uint k
=0;k
<RM_FABER_STAT_TYPE::NumRMStatType
;k
++)
1746 if(RM_FABER_STAT_TYPE::isStatRelevant(mpBuild
.FaberTypeRequired
, (RM_FABER_STAT_TYPE::TRMStatType
)k
))
1749 statArray
[k
]+= numMps
* (mpIP
.Stats
[k
]/100.f
);
1753 // Same for total energy
1754 statEnergy
+= numMps
* (mp
->Mp
.StatEnergy
/100.f
);
1756 // Increment color stat
1757 if(mp
->Mp
.MpColor
>=0 && mp
->Mp
.MpColor
<RM_COLOR::NumColors
)
1759 bestItemColor
[mp
->Mp
.MpColor
]+= numMps
;
1763 totalItemPartMPSetuped
+= numMps
;
1767 // get all stat for this item, and count MP req per stat
1768 for(uint k
=0;k
<RM_FABER_STAT_TYPE::NumRMStatType
;k
++)
1770 // if item part 'i' affect stat 'k'
1771 if(RM_FABER_STAT_TYPE::isStatRelevant(mpBuild
.FaberTypeRequired
, (RM_FABER_STAT_TYPE::TRMStatType
)k
))
1773 // StatPerItemPart ored in StatPerItem
1774 itemStatBF
|= uint64(1)<<k
;
1775 // Total Num MP per stat
1776 statCount
[k
]+= mpBuild
.QuantityReq
;
1781 totalItemPartMPReq
+= mpBuild
.QuantityReq
;
1784 // --- Specific Item requirement?
1785 else if(mpBuild
.RequirementType
==CMPBuild::SpecificItemReq
)
1787 // For all slots setuped
1788 uint nSlot
= min((uint
)MAX_MP_SLOT
, mpBuild
.NumMpSlot
);
1789 for(uint j
=0;j
<nSlot
;j
++)
1791 // Try to get the MP in this slot
1792 CItemSheet
*mp
= dynamic_cast<CItemSheet
*>(SheetMngr
.get(_InventoryMirror
[mpBuild
.Id
[j
]].Sheet
));
1793 if(mp
->Id
== mpBuild
.SpecificItemRequired
)
1796 minLevel
= min(_InventoryMirror
[mpBuild
.Id
[j
]].Quality
, minLevel
);
1798 // Formula 's Specific MPs don't impact on stats.
1805 for(i
=0;i
<RM_FABER_STAT_TYPE::NumRMStatType
;i
++)
1808 statArray
[i
]/= statCount
[i
];
1809 clamp(statArray
[i
], 0.f
, 1.f
);
1813 if(totalItemPartMPReq
)
1815 statEnergy
/= totalItemPartMPReq
;
1816 clamp(statEnergy
, 0.f
, 1.f
);
1819 // As in server, stretch the stats.
1820 // Add the special bonus ONLY when all MPs are setuped, for clearness
1821 RM_FABER_STAT_TYPE::stretchItemStats(statArray
, itemStatBF
, totalItemPartMPSetuped
>=totalItemPartMPReq
);
1825 if(minLevel
==INT_MAX
)
1827 CCDBNodeLeaf
*node
= NLGUI::CDBManager::getInstance()->getDbProp(ItemResultSheetLevel
, false);
1829 node
->setValue32(minLevel
);
1832 // **** change success rate too
1833 CViewText
*successView
= dynamic_cast<CViewText
*>(CWidgetManager::getInstance()->getElementFromId(FaberPhraseFpSuccessText
));
1836 string text
= CI18N::get("uiPhraseFaberSuccessRate");
1837 // Get the success rate of the related phrase
1838 uint phraseSlot
= pPM
->getMemorizedPhrase(_ExecuteFromMemoryLine
, _ExecuteFromMemoryIndex
);
1840 sint32 craftSuccessModifier
= 0;
1841 CCDBNodeLeaf
*nodeCSM
= NLGUI::CDBManager::getInstance()->getDbProp("SERVER:CHARACTER_INFO:SUCCESS_MODIFIER:CRAFT", false);
1844 craftSuccessModifier
= nodeCSM
->getValue32();
1846 // With the faber plan skill
1847 sint success
= pPM
->getCraftPhraseSuccessRate(pPM
->getPhrase(phraseSlot
), _ExecuteFromItemPlanBrick
->getSkill(), minLevel
, 0);
1848 sint bonus
= pPM
->getCraftPhraseSuccessRate(pPM
->getPhrase(phraseSlot
), _ExecuteFromItemPlanBrick
->getSkill(), minLevel
, (sint
) craftSuccessModifier
) - success
;
1852 successStr
= toString("@{FFFF}") + toString(success
);
1855 if( bonus
> 0 ) // bonus
1857 successStr
= "@{0F0F}" + toString(success
+ bonus
)
1859 + toString( success
)
1866 successStr
= "@{E42F}" + toString(success
+ bonus
)
1868 + toString( success
)
1870 + toString( abs(bonus
) )
1873 strFindReplace(text
, "%success", successStr
);
1874 successView
->setTextFormatTaged(text
);
1879 // Same than server code (NB: beige==1 per default)
1880 uint maxNumColor
= 0;
1881 uint dominanteColor
= 1;
1882 for(i
= 0; i
< RM_COLOR::NumColors
; ++i
)
1884 if( bestItemColor
[i
] > maxNumColor
)
1886 maxNumColor
= bestItemColor
[i
];
1890 node
= NLGUI::CDBManager::getInstance()->getDbProp(ItemResultSheetColor
, false);
1892 node
->setValue32(dominanteColor
);
1895 // **** Get Stat validity
1896 uint64 itemStatFinalUsageBF
= 0;
1897 // Some stat (magic protection and magic resist) are finaly used in the item only for the best ones
1898 itemStatFinalUsageBF
= RM_FABER_STAT_TYPE::getStatFinalValidity(statArray
, itemStatBF
);
1902 CInterfaceGroup
*groupMp
= dynamic_cast<CInterfaceGroup
*>(CWidgetManager::getInstance()->getElementFromId(FaberPhraseItemResultGroup
));
1905 // default: hide all
1906 for(i
=0;i
<RM_FABER_STAT_TYPE::NumRMStatType
;i
++)
1908 // get the stat group
1909 CInterfaceGroup
*groupStat
= dynamic_cast<CInterfaceGroup
*>(groupMp
->getElement(groupMp
->getId()+toString(":stat%d",i
) ));
1911 groupStat
->setActive(false);
1913 // enable only one that are relevant for this item
1915 for(i
=0;i
<RM_FABER_STAT_TYPE::NumRMStatType
;i
++)
1917 RM_FABER_STAT_TYPE::TRMStatType statType
= RM_FABER_STAT_TYPE::TRMStatType(i
);
1919 // if this stat is not relevant for the item, don't display it!
1920 if( (itemStatBF
&(uint64(1)<<i
)) == 0)
1923 // Is the stat finaly used? (magic protection for instance may not be)
1924 bool finalyUsed
= (itemStatFinalUsageBF
&(uint64(1)<<i
)) != 0;
1925 CRGBA usageColor
= finalyUsed
?(CRGBA::White
):CRGBA(128,128,128);
1927 // get the next stat group
1928 CInterfaceGroup
*groupStat
= dynamic_cast<CInterfaceGroup
*>(groupMp
->getElement(groupMp
->getId()+toString(":stat%d",groupIndex
) ));
1931 groupStat
->setActive(true);
1932 // fill text and bar according to stat
1933 CViewText
*statTitle
= dynamic_cast<CViewText
*>(groupStat
->getElement(groupStat
->getId()+":text" ));
1934 CDBViewBar
*statValueBar
= dynamic_cast<CDBViewBar
*>(groupStat
->getElement(groupStat
->getId()+":bar" ));
1935 CViewText
*statValueText
= dynamic_cast<CViewText
*>(groupStat
->getElement(groupStat
->getId()+":textstat" ));
1936 CCtrlBase
*statToolTip
= dynamic_cast<CCtrlBase
*>(groupStat
->getElement(groupStat
->getId()+":tt" ));
1937 uint sv
= uint(statArray
[i
]*100);
1940 statTitle
->setText(RM_FABER_STAT_TYPE::toLocalString(statType
));
1941 statTitle
->setColor(usageColor
);
1945 statValueBar
->setValue(sv
);
1946 statValueBar
->setColor(usageColor
);
1950 statValueText
->setText(toString(sv
)+"/100");
1951 statValueText
->setColor(usageColor
);
1957 // display something only for magic/protect stat
1958 if( RM_FABER_STAT_TYPE::isMagicResistStat(RM_FABER_STAT_TYPE::TRMStatType(i
)) ||
1959 RM_FABER_STAT_TYPE::isMagicProtectStat(RM_FABER_STAT_TYPE::TRMStatType(i
)) )
1960 statToolTip
->setDefaultContextHelp(CI18N::get("uiFaberStatActive"));
1962 statToolTip
->setDefaultContextHelp(std::string());
1965 statToolTip
->setDefaultContextHelp(CI18N::get("uiFaberStatGrayed"));
1974 // **** BestStat (for text over)
1975 node
= NLGUI::CDBManager::getInstance()->getDbProp(ItemResultSheetStatType
, false);
1978 float bestStatValue
=-1.0f
;
1979 RM_FABER_STAT_TYPE::TRMStatType bestStat
= RM_FABER_STAT_TYPE::NumRMStatType
;
1980 for( i
= 0; i
< RM_FABER_STAT_TYPE::NumRMStatType
; ++i
)
1982 // if this stat is not relevant for the item, don't use it!
1983 if( (itemStatBF
&(uint64(1)<<i
)) == 0)
1985 float value
= statArray
[i
];
1986 if( value
> bestStatValue
)
1988 bestStatValue
= value
;
1989 bestStat
= (RM_FABER_STAT_TYPE::TRMStatType
)i
;
1993 node
->setValue32(bestStat
);
1997 // **** ClassType (for text over)
1998 node
= NLGUI::CDBManager::getInstance()->getDbProp(ItemResultSheetClassType
, false);
2002 node
->setValue32(RM_CLASS_TYPE::getItemClass((uint32
)(100.0f
* statEnergy
)));
2007 /* Handle change of skill -> recompute success rate */
2008 void CActionPhraseFaber::CSkillObserver::onSkillChange()
2010 if (ActionPhraseFaber
== NULL
) ActionPhraseFaber
= new CActionPhraseFaber
;
2011 // Dont update if the plan has not yet been selected
2012 if(ActionPhraseFaber
->_ExecuteFromItemPlanBrick
==NULL
)
2014 ActionPhraseFaber
->updateItemResult();
2017 void CActionPhraseFaber::CDBModCraftObs::update(ICDBNode
* /* node */)
2019 if (ActionPhraseFaber
== NULL
|| ActionPhraseFaber
->_ExecuteFromItemPlanBrick
== NULL
)
2022 ActionPhraseFaber
->updateItemResult();