Merge branch '138-toggle-free-look-with-hotkey' into main/gingo-test
[ryzomcore.git] / ryzom / client / src / interface_v3 / dbgroup_build_phrase.cpp
blob61edbc6a6553b46858acb0bc326b9ce9f02e2e24
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
6 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 //
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as
10 // published by the Free Software Foundation, either version 3 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "stdpch.h"
24 #include "dbgroup_build_phrase.h"
25 #include "sbrick_manager.h"
26 #include "sphrase_manager.h"
27 #include "interface_manager.h"
28 #include "dbctrl_sheet.h"
29 #include "nel/gui/view_bitmap.h"
30 #include "nel/gui/ctrl_button.h"
31 #include "nel/gui/group_editbox.h"
32 #include "../client_cfg.h"
33 #include "nel/gui/view_text.h"
34 #include "skill_manager.h"
35 #include "../string_manager_client.h"
38 using namespace std;
39 using namespace NLMISC;
42 // ***************************************************************************
43 const std::string CDBGroupBuildPhrase::BrickSelectionModal= "ui:interface:build_phrase_select_brick";
44 const std::string CDBGroupBuildPhrase::BrickSelectionDB= "UI:PHRASE:SELECT";
45 const std::string CDBGroupBuildPhrase::BrickBuildDB= "UI:PHRASE:BUILD";
46 const std::string CDBGroupBuildPhrase::BrickIconSelectionModal= "ui:interface:build_phrase_select_icon";
49 // ***************************************************************************
51 NLMISC_REGISTER_OBJECT(CViewBase, CDBGroupBuildPhrase, std::string, "build_phrase");
53 CDBGroupBuildPhrase::CDBGroupBuildPhrase(const TCtorParam &param)
54 :CInterfaceGroup(param)
56 _GroupValid= false;
57 _ValidateButton= NULL;
58 _NumMandatories= 0;
59 _NumOptionals= 0;
60 _NumCredits= 0;
62 _Setuped= false;
63 _TextureIdSlotDisabled= 0;
65 // Name of the magic sentence
66 _UserSentenceName= NULL;
67 _SpellView= NULL;
69 _NewSpellNumber= 0;
71 _TextPhraseDesc= NULL;
73 nlctassert(MaxRootBrickTypeFilter>0);
74 for(uint i=0;i<MaxRootBrickTypeFilter;i++)
76 _RootBrickTypeFilter[i]= BRICK_TYPE::UNKNOWN;
79 m_IconIndex = std::numeric_limits<uint8>::max();
82 // ***************************************************************************
83 CDBGroupBuildPhrase::~CDBGroupBuildPhrase()
88 // ***************************************************************************
89 // ***************************************************************************
90 // Widget Setup
91 // ***************************************************************************
92 // ***************************************************************************
95 // ***************************************************************************
96 bool CDBGroupBuildPhrase::parse (xmlNodePtr cur, CInterfaceGroup *parentGroup)
98 if(!CInterfaceGroup::parse(cur, parentGroup))
99 return false;
101 CInterfaceManager *pIM= CInterfaceManager::getInstance();
103 // Init the disabled texture id
104 CViewRenderer &rVR = *CViewRenderer::getInstance();
105 _TextureIdSlotDisabled= rVR.getTextureIdFromName ("w_slot_brick_disabled.tga");
107 // Create now (before sons ctrl sheet parsing) the variables
108 uint i;
109 // Bricks and their Params
110 for(i=0;i<MaxBricks;i++)
112 NLGUI::CDBManager::getInstance()->getDbProp(BrickBuildDB + ":MAIN:" + toString(i)+":SHEET");
113 for(uint j=0;j<MaxParam;j++)
114 NLGUI::CDBManager::getInstance()->getDbProp(BrickBuildDB + ":PARAM:" + toString(i) + ":" + toString(j) + ":SHEET");
117 // spellView: to update the icon, use a special phrase manager entry
118 NLGUI::CDBManager::getInstance()->getDbProp(BrickBuildDB + ":EDITION_PHRASE:PHRASE")->setValue32(CSPhraseManager::EditionSlot);
120 return true;
123 // ***************************************************************************
124 void CDBGroupBuildPhrase::updateCoords ()
126 if(!_Setuped)
127 setupBuildSentence();
129 CInterfaceGroup::updateCoords();
132 // ***************************************************************************
133 void CDBGroupBuildPhrase::setupBuildSentence()
135 CInterfaceManager *pIM= CInterfaceManager::getInstance();
137 _Setuped= true;
139 // Get the widget controls
140 _ValidateButton= dynamic_cast<CCtrlBaseButton*>(CInterfaceGroup::getCtrl("ok_cancel:ok"));
141 if(_ValidateButton)
142 _ValidateButton->setFrozen(true);
144 _TextPhraseDesc= dynamic_cast<CViewText*>(CInterfaceGroup::getView("infos:phrase_desc"));
146 // retrieved brick view/ctrls
147 string idCtrl, idBack, idCost, idCredit, idInfo;
148 CDBCtrlSheet *ctrl;
149 CViewBitmap *back;
150 CViewText *cost;
151 CViewText *credit;
152 CViewText *info;
155 // **** get all bricks (including root)
156 sint index= 0;
157 for(;;)
159 // retrieve
160 idCtrl= string("bricks:main_brick")+toString(index);
161 idBack= string("bricks:main_back")+toString(index);
162 idCost= string("bricks:main_cost")+toString(index);
163 idCredit= string("bricks:main_credit")+toString(index);
164 idInfo= string("bricks:main_info")+toString(index);
165 ctrl= dynamic_cast<CDBCtrlSheet*>(CInterfaceGroup::getCtrl( idCtrl ));
166 back= dynamic_cast<CViewBitmap*>(CInterfaceGroup::getView( idBack ));
167 cost= dynamic_cast<CViewText*>(CInterfaceGroup::getView( idCost ));
168 credit= dynamic_cast<CViewText*>(CInterfaceGroup::getView( idCredit ));
169 info= dynamic_cast<CViewText*>(CInterfaceGroup::getView( idInfo ));
170 // A brick Slot is valid only if all Ctrl/View are ok, same for its param.
171 bool ok= true;
172 CWord newWord;
173 if(ctrl && back && cost && info)
175 newWord.Slot.Brick= ctrl;
176 newWord.Slot.Back= back;
177 newWord.CostView= cost;
178 newWord.CreditView= credit;
179 newWord.InfoView= info;
180 // Must have all params
181 for(uint i=0;i<MaxParam;i++)
183 idCtrl= string("bricks:param_brick") + toString(index) + "_" + toString(i);
184 idBack= string("bricks:param_back") + toString(index) + "_" + toString(i);
185 ctrl= dynamic_cast<CDBCtrlSheet*>(CInterfaceGroup::getCtrl( idCtrl ));
186 back= dynamic_cast<CViewBitmap*>(CInterfaceGroup::getView( idBack ));
187 if(ctrl && back)
189 newWord.ParamSlot[i].Brick= ctrl;
190 newWord.ParamSlot[i].Back= back;
192 else
194 // fails to find all params!
195 ok= false;
196 break;
200 else
201 ok= false;
202 // ok with this ctrl?
203 if(ok)
205 // unactive alls.
206 newWord.reset();
207 // append
208 _MainWords.push_back(newWord);
209 // next
210 index++;
212 else
214 // stop to search
215 break;
219 // If not at least find the root, error!
220 if(index==0)
222 nlwarning("ERROR: RootBrick not found!");
223 _GroupValid= false;
225 else
227 _GroupValid= true;
228 // Active at least the root brick.
229 _MainWords[0].setBrick(0);
232 // Setup special for Root
233 if(_GroupValid)
235 sint rootTextMaxw;
236 fromString(CWidgetManager::getInstance()->getParser()->getDefine("phrase_build_root_info_maxw"), rootTextMaxw);
237 _MainWords[0].InfoView->setLineMaxW(rootTextMaxw);
240 // Get the sentence texts
241 _UserSentenceName= dynamic_cast<CGroupEditBox*>(CInterfaceGroup::getGroup("eb_spell_name:eb"));
243 // Get the SpellView
244 _SpellView= dynamic_cast<CDBCtrlSheet*>(CInterfaceGroup::getCtrl( "spell_view" ));
248 // ***************************************************************************
249 void CDBGroupBuildPhrase::draw ()
251 CInterfaceGroup::draw();
255 // ***************************************************************************
256 const CSBrickSheet *CDBGroupBuildPhrase::getRootBrick()
258 if(!_GroupValid)
259 return NULL;
261 return _MainWords[0].Slot.Brick->asSBrickSheet();
265 // ***************************************************************************
266 // ***************************************************************************
267 // Setup operations
268 // ***************************************************************************
269 // ***************************************************************************
272 // ***************************************************************************
273 void CDBGroupBuildPhrase::clearBuildingPhrase()
275 if(!_GroupValid)
276 return;
278 // update display
279 _MainWords[0].reset();
280 _MainWords[0].setBrick(0);
281 updateDisplayFromRootBrick();
283 // Empty the name
284 if(_UserSentenceName)
286 _UserSentenceName->setInputString(std::string());
289 // update Display
290 updateAllDisplay();
294 // ***************************************************************************
295 void CDBGroupBuildPhrase::startComposition(const CSPhraseCom &phrase)
297 if(!_GroupValid)
298 return;
299 CSBrickManager *pBM= CSBrickManager::getInstance();
302 string name;
304 // if phrase empty (new phrase), invent a new name
305 if(phrase.empty())
307 // build a default name
308 name= CI18N::get("uimPhraseNew");
309 // Append a dummy number
310 _NewSpellNumber++;
311 name+= " " + toString(_NewSpellNumber);
313 m_IconIndex = std::numeric_limits<uint8>::max();
315 else
317 // copy name
318 name= phrase.Name.toUtf8();
319 m_IconIndex = phrase.IconIndex;
321 // get the root Brick. Must exist.
322 CSBrickSheet *rootBrick= pBM->getBrick(phrase.Bricks[0]);
323 if(rootBrick)
325 // Phrase to Ctrls: simulate clicks!
326 uint curBrickIndex= 1;
327 uint brickIndexForParam= 0;
328 uint curParam= 0;
329 uint numParam= 0;
331 // simulate a root selection
332 validateRoot(rootBrick);
333 // setup params of the root
334 numParam= (uint)rootBrick->ParameterFamilies.size();
335 brickIndexForParam= 0;
337 // For all brick not the root
338 for(uint i=1;i<phrase.Bricks.size();i++)
340 CSBrickSheet *brick= pBM->getBrick(phrase.Bricks[i]);
342 /* NB: the ORDER is important for grammar checkup
343 Must come first Root / Mandatory, then credit or optionals.
344 Each params must follow its related brick
345 Parameters May also have their own parameters
346 This is recursive, param sons may have params sons.
349 // a param of brick?
350 if(curParam<numParam)
352 validateParam(brickIndexForParam, curParam, brick);
353 curParam++;
354 // If this parameter has additonal parameter they follow
355 if( brick && !brick->ParameterFamilies.empty() )
356 numParam+= (uint)brick->ParameterFamilies.size();
358 // a mandatory/optional/credit?
359 else
361 // must be a mandatory?
362 if(curBrickIndex<1+_NumMandatories)
363 validateMain(curBrickIndex, brick);
364 // create a new optional/credit
365 else
366 validateNewOpCredit(brick);
368 // bkup index for param, and increment
369 brickIndexForParam= curBrickIndex;
370 curBrickIndex++;
371 // following bricks are its param!
372 curParam= 0;
373 numParam= 0;
374 if(brick)
375 numParam= (uint)brick->ParameterFamilies.size();
381 // set the editable name.
382 if(_UserSentenceName)
383 _UserSentenceName->setInputString(name);
387 // ***************************************************************************
388 // ***************************************************************************
389 // Start Selection of Bricks
390 // ***************************************************************************
391 // ***************************************************************************
394 // ***************************************************************************
395 void CDBGroupBuildPhrase::fillSelectionRoot()
397 // the root must be OK.
398 if(!_GroupValid) return;
399 CSBrickManager *pBM= CSBrickManager::getInstance();
401 // fillSelection with all root
402 std::vector<CSheetId> bricks;
403 bricks= pBM->getRootBricks();
404 // get only ones known
405 filterKnownBricks(bricks);
406 // get only ones that match The BrickType filter
407 filterRootBrickType(bricks);
408 // some additional root filter
409 filterRootPossibles(bricks);
410 // fill db
411 fillSelection(bricks);
413 // ***************************************************************************
414 void CDBGroupBuildPhrase::fillSelectionMain(uint index)
416 nlassert(index>0);
417 // the root must be OK.
418 if(!_GroupValid) return;
419 const CSBrickSheet *rootBrick= getRootBrick();
420 if(!rootBrick) return;
421 CSBrickManager *pBM= CSBrickManager::getInstance();
423 // error?
424 if(index>=_MainWords.size())
426 resetSelection();
427 return;
430 // get the current Brick.
431 std::vector<CSheetId> bricks;
432 const CSBrickSheet *brick= _MainWords[index].Slot.Brick->asSBrickSheet();
433 if(!brick)
435 // It is possible for Mandatory that this brick is still not validated
436 if(index<1+_NumMandatories)
438 // get the related family and bricks associated to it
439 bricks= pBM->getFamilyBricks(rootBrick->MandatoryFamilies[index-1]);
441 else
443 resetSelection();
444 return;
447 else
449 // fill selection with all bricks of the same family (whatever the main brick)
450 bricks= pBM->getFamilyBricks(brick->BrickFamily);
453 // get only ones known
454 filterKnownBricks(bricks);
456 // For mandatories, filter effects
457 CSPhraseCom currentPhrase;
458 buildCurrentPhrase(currentPhrase);
459 pBM->getSabrinaCom().filterMandatoryComposition(currentPhrase.Bricks, bricks);
461 // For Combat Optional, must filter by exclusion and combat exclusion
462 if(brick && brick->isCombat() && brick->isOptional() )
464 // Ensure not same bricks are setuped. Also don't insert me since I am already here...
465 filterBrickSetuped(bricks);
466 // Ensure only optional of compatible Skill are inserted. Don't test with me, since i may be removed!
467 filterSkillSetuped(bricks, true, false, index);
469 // for power optional, must filter by brick
470 else if(brick && brick->isSpecialPower() && (brick->isOptional()||brick->isMandatory()) )
472 // Ensure not same bricks are setuped. Also don't insert me since I am already here...
473 filterBrickSetuped(bricks);
476 // For optional or credit, filter by BrickExclusion.
477 if(index>=1/*+_NumMandatories*/)
478 filterBrickExclusion(bricks, index);
480 // For Optional/Credits, must append first the special "Remove Brick" choice
481 if(index>=1+_NumMandatories)
483 bricks.insert(bricks.begin(), pBM->getInterfaceRemoveBrick());
486 // fill db
487 fillSelection(bricks);
490 // ***************************************************************************
491 void CDBGroupBuildPhrase::fillSelectionParam(uint index, uint paramIndex)
493 // the root must be OK.
494 if(!_GroupValid) return;
495 const CSBrickSheet *rootBrick= getRootBrick();
496 if(!rootBrick) return;
497 CSBrickManager *pBM= CSBrickManager::getInstance();
499 // error?
500 if( index>=_MainWords.size() || paramIndex>=MaxParam)
502 resetSelection();
503 return;
506 // get the current Brick.
507 const CSBrickSheet *brick;
508 brick= _MainWords[index].ParamSlot[paramIndex].Brick->asSBrickSheet();
509 if(!brick)
511 resetSelection();
512 return;
514 // fill selection with all bricks of the same family (whatever the root)
515 std::vector<CSheetId> bricks;
516 bricks= pBM->getFamilyBricks(brick->BrickFamily);
517 // get only ones known
518 filterKnownBricks(bricks);
519 // fill db
520 fillSelection(bricks);
523 // ***************************************************************************
524 void CDBGroupBuildPhrase::fillSelectionNewOp()
526 // the root must be OK.
527 if(!_GroupValid) return;
528 const CSBrickSheet *rootBrick= getRootBrick();
529 if(!rootBrick) return;
531 // Build a brick array of possible new bricks.
532 std::vector<NLMISC::CSheetId> bricks;
533 fillNewOptionalBricks(bricks);
535 // fill db
536 fillSelection(bricks);
540 // ***************************************************************************
541 void CDBGroupBuildPhrase::fillSelectionNewCredit()
543 // the root must be OK.
544 if(!_GroupValid) return;
545 const CSBrickSheet *rootBrick= getRootBrick();
546 if(!rootBrick) return;
548 // Build a brick array of possible new bricks.
549 std::vector<NLMISC::CSheetId> bricks;
550 fillNewCreditBricks(bricks);
552 // fill db
553 fillSelection(bricks);
557 // ***************************************************************************
558 // ***************************************************************************
559 // Validate Selection of Bricks
560 // ***************************************************************************
561 // ***************************************************************************
564 // ***************************************************************************
565 void CDBGroupBuildPhrase::validateRoot(const CSBrickSheet *sheet)
567 // the root must be OK.
568 if(!_GroupValid) return;
570 // If same brick no op
571 if(getRootBrick() == sheet)
572 return;
574 // reset the whole sentence with default values
575 resetSentence(sheet->Id.asInt());
577 // update the display
578 updateAllDisplay();
582 // ***************************************************************************
583 void CDBGroupBuildPhrase::validateMain(uint index, const CSBrickSheet *sheet)
585 nlassert(index>0);
586 // the root must be OK.
587 if(!_GroupValid) return;
588 const CSBrickSheet *rootBrick= getRootBrick();
589 if(!rootBrick) return;
590 CSBrickManager *pBM= CSBrickManager::getInstance();
592 // If the brick chosen is actually the "Remove Brick", then call the correct method
593 if(sheet->Id == pBM->getInterfaceRemoveBrick())
595 deleteOpCredit(index);
596 return;
599 // set the brick!
600 if(sheet)
601 _MainWords[index].setBrick(sheet->Id.asInt());
603 // must update params if change!
604 updateParams(index);
606 // update the display
607 updateAllDisplay();
610 // ***************************************************************************
611 void CDBGroupBuildPhrase::validateParam(uint index, uint paramIndex, const CSBrickSheet *sheet)
613 // the root must be OK.
614 if(!_GroupValid) return;
615 const CSBrickSheet *rootBrick= getRootBrick();
616 if(!rootBrick) return;
617 if(paramIndex>=MaxParam) return;
619 // The setuped parameter may have also parameter sons
620 bool mustResetParamHrc= false;
621 vector<uint16> newParamSons;
622 if(sheet) newParamSons= sheet->ParameterFamilies;
623 mustResetParamHrc= newParamSons != _MainWords[index].ParamSlot[paramIndex].ViewParamFamilies;
625 // set the brick!
626 if(sheet)
628 _MainWords[index].setParamBrick(paramIndex, sheet->Id.asInt());
631 // update the param sons
632 if(mustResetParamHrc)
633 updateParamHrc(index);
635 // update the display
636 updateAllDisplay();
639 // ***************************************************************************
640 void CDBGroupBuildPhrase::validateNewOpCredit(const CSBrickSheet *sheet)
642 // the root must be OK.
643 if(!_GroupValid) return;
644 const CSBrickSheet *rootBrick= getRootBrick();
645 if(!rootBrick) return;
647 if(!sheet)
648 return;
650 // we should not have to do this test...
651 if(getNumMainBricks()>=_MainWords.size())
652 return;
654 // get the dest index.
655 uint index;
656 // credit brick?
657 if(sheet->isCredit())
658 index= 1+_NumMandatories+_NumOptionals+_NumCredits;
659 // else optional brick
660 else
661 index= 1+_NumMandatories+_NumOptionals;
663 // Shift Optional Row. Copy the Brick setup from index to index+1.
664 for(uint i= getNumMainBricks();i>index;i--)
666 _MainWords[i].copySetup(_MainWords[i-1]);
669 // set the brick!
670 _MainWords[index].setBrick(sheet->Id.asInt());
672 // Increment the number of options/credits setuped!
673 if(sheet->isCredit())
674 _NumCredits++;
675 else
676 _NumOptionals++;
678 // update the NewOp controler
679 updateNewButtons();
681 // must update params if change!
682 updateParams(index);
684 // update the display
685 updateAllDisplay();
688 // ***************************************************************************
689 void CDBGroupBuildPhrase::deleteOpCredit(uint index)
691 nlassert(index>0);
692 // the root must be OK.
693 if(!_GroupValid) return;
694 const CSBrickSheet *rootBrick= getRootBrick();
695 if(!rootBrick) return;
697 // check index
698 bool isCredit;
699 if(index>=1+_NumMandatories && index<1+_NumMandatories+_NumOptionals)
700 isCredit= false;
701 else if(index>=1+_NumMandatories+_NumOptionals && index<getNumMainBricks() )
702 isCredit= true;
703 else
704 return;
706 // Shift Optional Row. Copy the Brick setup from index+1 to index.
707 for(uint i= index+1;i<getNumMainBricks();i++)
709 _MainWords[i-1].copySetup(_MainWords[i]);
712 // reset the last row display
713 _MainWords[getNumMainBricks()-1].reset();
715 // an optional/credit is removed!
716 if(isCredit)
717 _NumCredits--;
718 else
719 _NumOptionals--;
721 // update the NewOp ctrl
722 updateNewButtons();
724 // update the display
725 updateAllDisplay();
728 // ***************************************************************************
729 void CDBGroupBuildPhrase::setPhraseIcon(uint8 index)
731 CSPhraseCom phrase;
732 buildCurrentPhrase(phrase);
734 if (index < phrase.Bricks.size())
735 m_IconIndex = index;
736 else
737 m_IconIndex = std::numeric_limits<uint8>::max();
739 updateSpellView();
743 // ***************************************************************************
744 // ***************************************************************************
745 // System
746 // ***************************************************************************
747 // ***************************************************************************
750 // ***************************************************************************
751 static uint getLowestBit(uint64 val)
753 uint ret= 0;
754 while(val)
756 if(val&1)
757 return ret;
758 ret++;
759 val>>=1;
761 return 0;
765 // ***************************************************************************
766 static void getDefaultSheetForFamily(uint familyId, sint32 &sheet, bool &valid)
768 CSBrickManager *pBM= CSBrickManager::getInstance();
770 uint64 knownBF= pBM->getKnownBrickBitField(familyId);
771 // Known?
772 if(knownBF)
774 // default: get the lowest sheet
775 sint posInFamily= getLowestBit(knownBF);
777 // get the sheet
778 sheet= pBM->getBrickSheet(familyId, posInFamily).asInt();
779 valid= true;
781 else
783 // setup the Sheet with the lowest brick
784 sheet= pBM->getBrickSheet(familyId, 0).asInt();
785 // invalidate the word
786 valid= false;
791 // ***************************************************************************
792 void CDBGroupBuildPhrase::updateParams(uint index)
794 // get the Word
795 CWord *word;
796 if(index<_MainWords.size())
797 word= &_MainWords[index];
798 else
799 return;
801 // Get the Brick setuped. may be NULL for unsetuped mandatories
802 const CSBrickSheet *brick= word->Slot.Brick->asSBrickSheet();
804 // retrieve brick paramFamilies
805 vector<uint16> paramFamilies;
806 if(brick)
807 paramFamilies= brick->ParameterFamilies;
809 // if param families of the new brick different from what setuped in view, reset all param hierachy
810 if(word->Slot.ViewParamFamilies != paramFamilies)
812 // must reset the view of parameters
813 word->resetParams();
815 // and compute all from setuped main brick
816 updateParamHrc(index);
821 // ***************************************************************************
822 /* used for updateParamHrc()
825 class CParamTreeNode
827 public:
828 const CSBrickSheet *Brick;
829 bool Valid;
830 std::vector<uint16> ViewParamFamilies;
831 CParamTreeNode *Parent;
832 std::vector<CParamTreeNode*> Sons;
834 public:
835 CParamTreeNode(CParamTreeNode *parent) : Brick(NULL), Valid(true), Parent(parent) {}
836 ~CParamTreeNode()
838 Parent= NULL;
839 Brick= NULL;
840 deleteSons();
843 // delete param sons
844 void deleteSons()
846 for(uint i=0;i<Sons.size();i++) delete Sons[i];
847 Sons.clear();
850 // rebuild default param sons (recurs) if BrickParamFamilies and ViewParamFamilies differ.
851 // return false if error
852 bool synchronizeParams(uint maxDepth)
854 if(maxDepth==0)
855 return false;
857 // get the brick Parameter Families.
858 vector<uint16> brickParamFamilies;
859 if(Brick)
860 brickParamFamilies= Brick->ParameterFamilies;
861 // compare with the current View one. if equals then OK! just recurs test sons
862 if(brickParamFamilies == ViewParamFamilies)
864 for(uint i=0;i<Sons.size();i++)
866 if(!Sons[i]->synchronizeParams(maxDepth-1))
867 return false;
869 return true;
871 // else must rebuild all this branch
872 else
874 return buildSonsFromBrick(maxDepth);
878 // build the son list from brick Setup, and recurs
879 // return false if error
880 bool buildSonsFromBrick(uint maxDepth)
882 if(maxDepth==0)
883 return false;
885 CSBrickManager *pBM= CSBrickManager::getInstance();
887 // first delete my sons, and any old view setup
888 deleteSons();
889 ViewParamFamilies.clear();
891 // then copy brick families to view families (=> view synchronized to brick)
892 if(Brick)
893 ViewParamFamilies= Brick->ParameterFamilies;
895 // Add a default Son for each family
896 uint i;
897 for(i=0;i<ViewParamFamilies.size();i++)
899 uint familyId= ViewParamFamilies[i];
900 sint32 sheet;
901 bool sonValid;
902 // bkup the valid state in this node
903 getDefaultSheetForFamily(familyId, sheet, sonValid);
905 // init son
906 CParamTreeNode *sonNode= new CParamTreeNode(this);
907 sonNode->Brick= pBM->getBrick(CSheetId(sheet));
908 sonNode->Valid= sonValid;
909 // add this son to its father
910 Sons.push_back(sonNode);
913 // recurs.
914 for(i=0;i<Sons.size();i++)
916 if(!Sons[i]->buildSonsFromBrick(maxDepth - 1))
917 return false;
920 return true;
923 // build the word raw param list from hierarchy
924 // return false if error
925 bool buildRawParamList(CDBGroupBuildPhrase::CWord &word, uint &rawParamIndex)
927 // If this is the root
928 if(!Parent)
930 // just copy the ViewParamFamilies
931 word.Slot.ViewParamFamilies= ViewParamFamilies;
933 // else, add this parameter to list
934 else
936 // Check possible Brick Data error
937 if(rawParamIndex >= CDBGroupBuildPhrase::MaxParam)
939 nlwarning("BRICK ERROR: Not enough param Space (%d) to add all son parameter", CDBGroupBuildPhrase::MaxParam);
940 return false;
943 // Setup this brick in the param list
944 CSheetId sheet;
945 if(Brick)
946 sheet= Brick->Id;
947 word.setParamBrick(rawParamIndex, sheet.asInt());
948 word.ParamSlot[rawParamIndex].Valid= Valid;
949 word.ParamSlot[rawParamIndex].Brick->setGrayed( !Valid );
951 // bkup its ViewParameters
952 word.ParamSlot[rawParamIndex].ViewParamFamilies= ViewParamFamilies;
954 // next param index
955 rawParamIndex++;
958 // for all sons, recurs
959 for(uint i=0;i<Sons.size();i++)
961 // recurs
962 if(!Sons[i]->buildRawParamList(word, rawParamIndex))
963 return false;
966 return true;
971 // ***************************************************************************
972 void CDBGroupBuildPhrase::updateParamHrc(uint index)
975 When we are here, we may have some Parameter Hierarchy inconsitency between the ViewParameterFamilies and
976 the Brick parameter Families.
977 we must fix them and rebuild all the raw param list
979 // get the Word
980 CWord *word;
981 if(index<_MainWords.size())
982 word= &_MainWords[index];
983 else
984 return;
986 // If a Param error has already been detected on this Slot, no-op
987 if(word->ParamError)
988 return;
991 // **** From the current View setup of 'word', build the Parameter Hierarchy (in simple tree form)
992 CParamTreeNode rootNode(NULL);
993 // NB: here rootNode represent the Main (ie mandatory, optional or credit) brick. Therefore, it is not a real parameter.
994 rootNode.Brick= word->Slot.Brick->asSBrickSheet();
995 rootNode.Valid= true;
996 rootNode.ViewParamFamilies= word->Slot.ViewParamFamilies;
997 uint rawParamIndex= 0;
998 CParamTreeNode *curNode= &rootNode;
999 while(curNode)
1001 // if this node still need sons, then the next raw index param must be a son of curNode
1002 if(curNode->Sons.size() < curNode->ViewParamFamilies.size())
1004 nlassert(rawParamIndex < word->NumTotalParams);
1005 // create a son node, and fill from rawList
1006 CParamTreeNode *sonNode= new CParamTreeNode(curNode);
1007 sonNode->Brick= word->ParamSlot[rawParamIndex].Brick->asSBrickSheet();
1008 sonNode->Valid= word->ParamSlot[rawParamIndex].Valid;
1009 sonNode->ViewParamFamilies= word->ParamSlot[rawParamIndex].ViewParamFamilies;
1010 // append to the sons
1011 curNode->Sons.push_back(sonNode);
1012 // next in rawList
1013 rawParamIndex++;
1014 // recurs to son
1015 curNode= sonNode;
1017 // else the next must be a brother: return to parent
1018 else
1019 curNode= curNode->Parent;
1021 // we must have run all the raw list
1022 nlassert(rawParamIndex == word->NumTotalParams);
1023 nlassert(rootNode.Sons.size() == word->Slot.ViewParamFamilies.size());
1026 // **** Parse the Parameter tree, and invalidate each branch where View families and Brick families differs.
1027 // Avoid .sbrick data erros: allow only a max recurs level of 10
1028 if(!rootNode.synchronizeParams(10))
1030 // in this case, ABORT, but don't crash: setup 0 parameters...
1031 word->resetParams();
1032 word->ParamError= true;
1033 return;
1037 // **** rebuild completely the parameter list from the parameter tree.
1038 // clear first
1039 word->resetParams();
1040 // then rebuild
1041 rawParamIndex= 0;
1042 if(rootNode.buildRawParamList(*word, rawParamIndex))
1044 // then the new NumTotalParams is....
1045 word->NumTotalParams= rawParamIndex;
1047 // ERROR CASE
1048 else
1050 // in this case, ABORT, but don't crash: setup 0 parameters...
1051 word->resetParams();
1052 word->ParamError= true;
1053 return;
1059 // ***************************************************************************
1060 void CDBGroupBuildPhrase::updateAllDisplay(const CSPhraseCom &phrase)
1062 // NB: phrase MUST COME FROM buildCurrentPhrase() else doesn't work.
1064 CSBrickManager *pBM= CSBrickManager::getInstance();
1065 CInterfaceManager *pIM= CInterfaceManager::getInstance();
1066 CSPhraseManager *pPM= CSPhraseManager::getInstance();
1068 // **** update total cost
1069 // get the cost and credit
1070 uint32 totalCost, totalCredit;
1071 pBM->getSabrinaCom().getPhraseCost(phrase.Bricks, totalCost, totalCredit);
1073 // update database
1074 NLGUI::CDBManager::getInstance()->getDbProp("UI:PHRASE:BUILD:TOTAL_COST")->setValue32(totalCost);
1075 NLGUI::CDBManager::getInstance()->getDbProp("UI:PHRASE:BUILD:TOTAL_CREDIT")->setValue32(totalCredit);
1077 // **** Update the Cost of All Root/Mandat/ops/Credits.
1078 if(phrase.Bricks.size())
1080 // Parse the phrase, and setup the related Cost.
1081 uint curBrickIndex= 0;
1082 for(uint i=0;i<phrase.Bricks.size();)
1084 // Get the brick.
1085 CSBrickSheet *brick= pBM->getBrick(phrase.Bricks[i]);
1086 // if not found, skip it (eg important for mandatories not setuped)
1087 if(!brick)
1089 i++;
1091 else
1093 // get the cost for this brick and its params.
1094 sint32 cost;
1095 float relative_cost;
1096 cost= pBM->getSabrinaCom().getPhraseBrickAndParamCost(phrase.Bricks, i);
1097 relative_cost = pBM->getSabrinaCom().getPhraseBrickAndParamRelativeCost(phrase.Bricks, i);
1098 std::string costText;
1099 if( cost == 0 && relative_cost != 0.f )
1101 cost = (sint32)(relative_cost * 100.f);
1102 costText= toString("%+d", cost) + string("%");
1104 else
1105 costText= toString("%+d", cost);
1107 // set the MainWord cost
1108 if(cost>=0)
1110 _MainWords[curBrickIndex].CostView->setActive(true);
1111 _MainWords[curBrickIndex].CreditView->setActive(false);
1112 _MainWords[curBrickIndex].CostView->setText(costText);
1114 else
1116 _MainWords[curBrickIndex].CreditView->setActive(true);
1117 _MainWords[curBrickIndex].CostView->setActive(false);
1118 _MainWords[curBrickIndex].CreditView->setText(costText);
1121 // Next brick: skip me and my params
1122 i+= 1 + _MainWords[curBrickIndex].NumTotalParams;
1125 // next slot to setup. if all slots setuped, break.
1126 curBrickIndex++;
1127 if(curBrickIndex>=getNumMainBricks())
1128 break;
1132 // **** Additionaly Update the Info Text
1133 for(uint i=0;i<1+_NumMandatories;i++)
1135 CWord &word= _MainWords[i];
1136 // If the brick is setuped, hide the info text, else display
1137 if( word.Slot.Brick->asSBrickSheet() )
1138 word.InfoView->setActive(false);
1139 else
1141 word.InfoView->setActive(true);
1142 if(i==0)
1143 word.InfoView->setText( CI18N::get("uiTextHelpSelectRootBrick") );
1144 else
1145 // start effect index at 1 (human readable :) )
1146 word.InfoView->setText( CI18N::get("uiTextHelpSelectEffectBrick") + toString(i) );
1150 // **** Additionaly Update the New Buttons
1151 bool mandatOk= true;
1152 // If only one of root effect is not setuped...
1153 for(uint i=0;i<1+_NumMandatories;i++)
1155 CWord &word= _MainWords[i];
1156 if( !word.Slot.Brick->asSBrickSheet() )
1157 mandatOk= false;
1159 // set DB value accordeing to it.
1160 NLGUI::CDBManager::getInstance()->getDbProp("UI:PHRASE:BUILD:ROOT_EFFECT_VALID")->setValue32(mandatOk);
1162 // update valid button
1163 if(_ValidateButton)
1165 bool active= false;
1167 // valid only if all mandat active and cost ok
1168 active= totalCredit>=totalCost && mandatOk;
1170 // valid only if All bricks exist, and are known
1171 uint i;
1172 for(i=0;i<phrase.Bricks.size();i++)
1174 // Get the brick.
1175 CSBrickSheet *brick= pBM->getBrick(phrase.Bricks[i]);
1176 if(!brick || !pBM->isBrickKnown(brick->Id))
1178 active= false;
1179 break;
1183 // valid only if no parameter error has been encountered
1184 for(i=0;i<1+_NumMandatories+_NumOptionals+_NumCredits;i++)
1186 if(_MainWords[i].ParamError)
1188 active= false;
1189 break;
1193 // If OK, still do some check
1194 if(active)
1196 const CSBrickSheet *brick= getRootBrick();
1197 if(!brick)
1198 active= false;
1199 // check req size
1200 else if( brick->MandatoryFamilies.size()+1>_MainWords.size() )
1201 active= false;
1204 _ValidateButton->setFrozen(!active);
1208 // **** Additionaly Update the Combat Restrict options
1209 // Get the rootBrick
1210 const CSBrickSheet *rootBrick= getRootBrick();
1211 if(rootBrick && rootBrick->isCombat())
1213 // show the weapon restriction interface
1214 NLGUI::CDBManager::getInstance()->getDbProp("UI:PHRASE:BUILD:RESTRICT_COMBAT:ENABLED")->setValue32(1);
1216 // If not already done, retrieve the weapon skills, and fill the sbricks SHEET
1217 if(_WeaponSkills.empty())
1219 // get define, and verify data
1220 uint numWeaponSkill;
1221 fromString(CWidgetManager::getInstance()->getParser()->getDefine("phrase_max_restrict_combat"), numWeaponSkill);
1222 string strWeaponSkill= CWidgetManager::getInstance()->getParser()->getDefine("phrase_def_skill_restrict_combat");
1223 vector<string> weaponSkillList;
1224 splitString(strWeaponSkill, " ", weaponSkillList);
1225 nlassert(weaponSkillList.size()==numWeaponSkill);
1227 // NOTE TO CODER WHO CHANGE SKILLS::ESkill. If you change combat skills, ask yoyo for modification
1228 // or search "phrase_def_skill_restrict_combat" and "phrase_max_restrict_combat" in XML.
1229 nlctassert( SKILLS::SFM1SSM && SKILLS::SFM1SAM && SKILLS::SFM1BMM && SKILLS::SFM1BSM &&
1230 SKILLS::SFM1PSM && SKILLS::SFM2SSM && SKILLS::SFM2SAM && SKILLS::SFM2BMM &&
1231 SKILLS::SFM2PPM && SKILLS::SFMCADM && SKILLS::SFMCAHM && SKILLS::SFR1APM &&
1232 SKILLS::SFR2AAM && SKILLS::SFR2ALM && SKILLS::SFR2ARM);
1233 nlctassert(SKILLS::SH - SKILLS::SF == 47);
1235 // backup the skill array, and fill the associated brick in interface
1236 _WeaponSkills.resize(numWeaponSkill);
1237 for(uint i=0;i<numWeaponSkill;i++)
1239 _WeaponSkills[i]= SKILLS::toSkill(weaponSkillList[i]);
1241 // Get the associated brick
1242 uint32 viewBrickCombatSheetId= pBM->getVisualBrickForSkill(_WeaponSkills[i]).asInt();
1244 // And fill in DB
1245 NLGUI::CDBManager::getInstance()->getDbProp(toString("UI:PHRASE:BUILD:RESTRICT_COMBAT:%d:SHEET", i))->setValue32(viewBrickCombatSheetId);
1249 // For each weapon skill, test if match or not the current phrase
1250 for(uint i=0;i<_WeaponSkills.size();i++)
1252 bool ok= pPM->skillCompatibleWithCombatPhrase(_WeaponSkills[i], phrase.Bricks);
1253 NLGUI::CDBManager::getInstance()->getDbProp(toString("UI:PHRASE:BUILD:RESTRICT_COMBAT:%d:LOCKED", i))->setValue32(!ok);
1256 else
1258 // hide the weapon restriction interface
1259 NLGUI::CDBManager::getInstance()->getDbProp("UI:PHRASE:BUILD:RESTRICT_COMBAT:ENABLED")->setValue32(0);
1262 // **** Setup the phrase Desc
1263 if(_TextPhraseDesc)
1265 string text;
1266 pPM->buildPhraseDesc(text, phrase, 0, false, "composition");
1267 _TextPhraseDesc->setTextFormatTaged(text);
1270 // **** icons
1271 uint nbBricks = phrase.Bricks.size();
1272 uint maxBricks = 0;
1273 fromString(CWidgetManager::getInstance()->getParser()->getDefine("phrase_max_brick"), maxBricks);
1275 NLGUI::CDBManager::getInstance()->getDbProp("UI:PHRASE:BUILD:ICON:0:SHEET")->setValue32(pBM->getInterfaceRemoveBrick().asInt());
1276 NLGUI::CDBManager::getInstance()->getDbProp("UI:PHRASE:BUILD:ICON:0:INDEX")->setValue32(maxBricks);
1278 std::set< std::pair<uint64, uint64> > dupcheck;
1279 for(uint i = 0, j = 1; i < maxBricks; i++)
1281 if (i < nbBricks)
1283 CSBrickSheet *pBR = pBM->getBrick(phrase.Bricks[i]);
1284 if (pBR)
1286 // ignore back icon, as its replaced anyway
1287 uint64 key1 = ((uint64)pBR->IdIcon << 32) | pBR->IconColor.getPacked();
1288 uint64 key2 = ((uint64)pBR->IdIconOver << 32) | pBR->IdIconOver2;
1290 if (dupcheck.insert(make_pair(key1, key2)).second)
1292 NLGUI::CDBManager::getInstance()->getDbProp(toString("UI:PHRASE:BUILD:ICON:%d:SHEET", j))->setValue32(phrase.Bricks[i].asInt());
1293 NLGUI::CDBManager::getInstance()->getDbProp(toString("UI:PHRASE:BUILD:ICON:%d:INDEX", j))->setValue32(i);
1294 j++;
1297 else
1299 nlwarning("Invalid CSBrickSheet (%d:%s)", phrase.Bricks[i].asInt(), phrase.Bricks[i].toString().c_str());
1302 else
1304 NLGUI::CDBManager::getInstance()->getDbProp(toString("UI:PHRASE:BUILD:ICON:%d:SHEET", j))->setValue32(0);
1305 j++;
1310 // **** Since some bricks may have changed, update the spell view
1311 updateSpellView();
1316 // ***************************************************************************
1317 void CDBGroupBuildPhrase::updateAllDisplay()
1319 // build the current phrase
1320 CSPhraseCom newPhrase;
1321 buildCurrentPhrase(newPhrase);
1322 updateAllDisplay(newPhrase);
1326 // ***************************************************************************
1327 void CDBGroupBuildPhrase::resetSelection()
1329 CInterfaceManager *pIM= CInterfaceManager::getInstance();
1331 for(uint i=0;i<MaxSelection;i++)
1333 NLGUI::CDBManager::getInstance()->getDbProp(BrickSelectionDB+ ":" + toString(i) + ":SHEET")->setValue32(0);
1337 // ***************************************************************************
1338 void CDBGroupBuildPhrase::fillSelection(const std::vector<CSheetId> &bricks)
1340 CInterfaceManager *pIM= CInterfaceManager::getInstance();
1342 uint num= min((uint)MaxSelection, (uint)bricks.size());
1343 for(uint i=0;i<MaxSelection;i++)
1345 if(i<num)
1346 NLGUI::CDBManager::getInstance()->getDbProp(BrickSelectionDB+ ":" + toString(i) + ":SHEET")->setValue32(bricks[i].asInt());
1347 else
1348 NLGUI::CDBManager::getInstance()->getDbProp(BrickSelectionDB+ ":" + toString(i) + ":SHEET")->setValue32(0);
1352 // ***************************************************************************
1353 void CDBGroupBuildPhrase::filterKnownBricks(std::vector<CSheetId> &bricks)
1355 CSBrickManager *pBM= CSBrickManager::getInstance();
1357 pBM->filterKnownBricks(bricks);
1360 // ***************************************************************************
1361 void CDBGroupBuildPhrase::filterBrickExclusion(std::vector<CSheetId> &bricks, uint16 indexToSkip)
1363 CSBrickManager *pBM= CSBrickManager::getInstance();
1365 std::vector<CSheetId> res;
1366 res.reserve(bricks.size());
1368 static vector<string> forbidWords(30);
1370 // For All optionals/credits setuped, build the Exclude Set
1371 set<string> excludeSet;
1372 // test for all bricks
1373 for(uint j=1/*+_NumMandatories*/;j<1+_NumMandatories+_NumOptionals+_NumCredits;j++)
1375 // skip brick at index indexToSkip (if replacing a brick for example, don't consider it's forbiden flags)
1376 if (j == indexToSkip)
1377 continue;
1379 const CSBrickSheet *brick= _MainWords[j].Slot.Brick->asSBrickSheet();
1380 if(brick)
1382 // get all words.
1383 forbidWords.clear();
1384 splitString(brick->getForbiddenExclude(), ":", forbidWords);
1385 // for all words, insert in the set.
1386 for(uint j=0;j<forbidWords.size();j++)
1387 excludeSet.insert(forbidWords[j]);
1391 // keep only unfiltered ones
1392 for(uint i=0;i<bricks.size();i++)
1394 const CSBrickSheet *brick= pBM->getBrick(bricks[i]);
1395 if(brick)
1397 // For all define words, search if excluded from the current set of optional setup
1398 forbidWords.clear();
1399 splitString(brick->getForbiddenDef(), ":", forbidWords);
1400 bool ok= true;
1401 for(uint j=0;j<forbidWords.size();j++)
1403 if(excludeSet.find(forbidWords[j]) != excludeSet.end() )
1405 ok= false;
1406 break;
1410 // ok , add it
1411 if(ok)
1412 res.push_back(bricks[i]);
1416 // replace with filtered one
1417 bricks= res;
1421 // ***************************************************************************
1422 void CDBGroupBuildPhrase::filterFamilySetuped(std::vector<uint16> &families)
1424 std::vector<uint16> res;
1425 res.reserve(families.size());
1427 // keep only unsetuped ones
1428 for(uint i=0;i<families.size();i++)
1430 uint family= families[i];
1431 bool ok= true;
1433 // test for all opionals/Credits
1434 for(uint j=1+_NumMandatories;j<getNumMainBricks();j++)
1436 const CSBrickSheet *brick= _MainWords[j].Slot.Brick->asSBrickSheet();
1437 if(brick && brick->BrickFamily==(sint)family)
1439 ok= false;
1440 break;
1444 // insert only if not found
1445 if(ok)
1447 res.push_back(family);
1451 // replace with filtered one
1452 families= res;
1455 // ***************************************************************************
1456 void CDBGroupBuildPhrase::filterBrickSetuped(std::vector<NLMISC::CSheetId> &bricks)
1458 std::vector<CSheetId> res;
1459 res.reserve(bricks.size());
1461 // keep only unsetuped ones
1462 for(uint i=0;i<bricks.size();i++)
1464 CSheetId brick= bricks[i];
1465 bool ok= true;
1467 // test for all bricks
1468 for(uint j=1/*+_NumMandatories*/;j<getNumMainBricks();j++)
1470 if(brick == CSheetId(_MainWords[j].Slot.Brick->getSheetId()) )
1472 ok= false;
1473 break;
1477 // insert only if not found
1478 if(ok)
1480 res.push_back(brick);
1484 // replace with filtered one
1485 bricks= res;
1489 // ***************************************************************************
1490 void CDBGroupBuildPhrase::filterSkillSetuped(std::vector<NLMISC::CSheetId> &bricks, bool checkOptional, bool checkCredit, sint avoidCheckIndex)
1492 // check nothing => return.
1493 if(!checkOptional && !checkCredit)
1494 return;
1496 CSBrickManager *pBM= CSBrickManager::getInstance();
1499 // **** build the compatible skill formula for the bricks we want to check
1500 CReqSkillFormula testFormula;
1501 uint checkStart= checkOptional? 1+_NumMandatories : 1+_NumMandatories+_NumOptionals;
1502 uint checkEnd= checkCredit? 1+_NumMandatories+_NumOptionals : getNumMainBricks();
1504 // test for all optionals and/or Credits
1505 uint i;
1506 for(uint i= checkStart;i<checkEnd;i++)
1508 // For Replacement of brick, don't test with the brick replaced (suppose will be removed!)
1509 if(avoidCheckIndex==(sint)i)
1510 continue;
1512 const CSBrickSheet *brick= _MainWords[i].Slot.Brick->asSBrickSheet();
1513 // If bricks use a skill, and with the formula
1514 if(brick && brick->getSkill()!=SKILLS::unknown)
1516 CReqSkillFormula brickFormula;
1517 for(uint j=0;j<brick->UsedSkills.size();j++)
1519 brickFormula.orV(CSkillValue(brick->UsedSkills[j]));
1522 // and with the phraseFormula
1523 testFormula.andV(brickFormula);
1528 // **** check for each brick if compatible with this formula
1529 std::vector<CSheetId> res;
1530 res.reserve(bricks.size());
1532 // keep only unsetuped ones
1533 for(i=0;i<bricks.size();i++)
1535 const CSBrickSheet *brick= pBM->getBrick(bricks[i]);
1536 if(brick && brick->getSkill()!=SKILLS::unknown)
1538 // simulate a choose of this brick, ie AND its skill formula with the current phrase formula
1539 CReqSkillFormula brickFormula;
1540 for(uint j=0;j<brick->UsedSkills.size();j++)
1542 brickFormula.orV(CSkillValue(brick->UsedSkills[j]));
1545 CReqSkillFormula tempFormula= testFormula;
1546 tempFormula.andV(brickFormula);
1548 // Nb: the following test works if testFormula is empty(), because in this case
1549 // tempFormula.and(brickFormula)==brickFormula and hence is of form SFR | SFM | ....
1551 // if one of the ored skill has a size 1 (eg SFR&SFM fails), then it's ok!
1552 // else it's mean that there is no "skill on same branch solution".
1553 bool ok= false;
1554 std::list<CReqSkillFormula::CSkillValueAnd>::iterator it(tempFormula.OrSkills.begin()),
1555 end(tempFormula.OrSkills.end());
1556 for(;it!=end;it++)
1558 CReqSkillFormula::CSkillValueAnd skillAnd= *it;
1559 // ok, there is still one usable skill
1560 if(skillAnd.AndSkills.size()==1)
1562 ok= true;
1563 break;
1567 // insert only if ok
1568 if(ok)
1570 res.push_back(bricks[i]);
1575 // replace with filtered one
1576 bricks= res;
1581 // ***************************************************************************
1582 void CDBGroupBuildPhrase::filterRootBrickType(std::vector<NLMISC::CSheetId> &bricks)
1584 // no filter => ok.
1585 if(_RootBrickTypeFilter[0]==BRICK_TYPE::UNKNOWN)
1586 return;
1588 CSBrickManager *pBM= CSBrickManager::getInstance();
1589 std::vector<CSheetId> res;
1590 res.reserve(bricks.size());
1592 // keep only match ones
1593 for(uint i=0;i<bricks.size();i++)
1595 const CSBrickSheet *brick0= pBM->getBrick(bricks[i]);
1596 if(brick0)
1598 // insert if one filter match (OR)
1599 for(uint j=0;j<MaxRootBrickTypeFilter;j++)
1601 if( _RootBrickTypeFilter[j] != BRICK_TYPE::UNKNOWN &&
1602 _RootBrickTypeFilter[j] == BRICK_FAMILIES::brickType(brick0->BrickFamily) )
1604 res.push_back(bricks[i]);
1605 break;
1611 // replace with filtered one
1612 bricks= res;
1616 // ***************************************************************************
1617 void CDBGroupBuildPhrase::filterRootPossibles(std::vector<NLMISC::CSheetId> &bricks)
1619 CSBrickManager *pBM= CSBrickManager::getInstance();
1620 std::vector<CSheetId> res;
1621 res.reserve(bricks.size());
1623 // keep only match ones
1624 for(uint i=0;i<bricks.size();i++)
1626 const CSBrickSheet *brick0= pBM->getBrick(bricks[i]);
1627 if(brick0)
1629 // insert only if not a proc enchantment
1630 if(!brick0->isProcEnchantment())
1631 res.push_back(bricks[i]);
1635 // replace with filtered one
1636 bricks= res;
1640 // ***************************************************************************
1641 void CDBGroupBuildPhrase::CSlot::reset()
1643 // Must do the test for credits not setuped.
1644 if(Brick && Back)
1646 Brick->setActive(false);
1647 Brick->setSheetId(0);
1648 Back->setActive(false);
1651 // Sheet 0
1652 ViewParamFamilies.clear();
1655 // ***************************************************************************
1656 void CDBGroupBuildPhrase::CWord::resetParams()
1658 for(uint i=0;i<MaxParam;i++)
1659 ParamSlot[i].reset();
1660 // reset numParams to 0
1661 Slot.ViewParamFamilies.clear();
1662 NumTotalParams= 0;
1663 ParamError= false;
1666 // ***************************************************************************
1667 void CDBGroupBuildPhrase::CWord::reset()
1669 Slot.reset();
1670 // reset also all params
1671 resetParams();
1672 // Hide the Cost View
1673 CostView->setActive(false);
1674 CreditView->setActive(false);
1675 InfoView->setActive(false);
1678 // ***************************************************************************
1679 void CDBGroupBuildPhrase::CWord::setBrick(uint32 sheetId)
1681 Slot.Brick->setActive(true);
1682 Slot.Brick->setSheetId(sheetId);
1683 Slot.Back->setActive(true);
1686 // ***************************************************************************
1687 void CDBGroupBuildPhrase::CWord::setParamBrick(uint param, uint32 sheetId)
1689 if(param>=MaxParam)
1690 return;
1692 ParamSlot[param].Brick->setActive(true);
1693 ParamSlot[param].Brick->setSheetId(sheetId);
1694 ParamSlot[param].Back->setActive(true);
1697 // ***************************************************************************
1698 void CDBGroupBuildPhrase::CWord::copySetup(const CWord &w)
1700 // reset me first
1701 reset();
1703 // set the brick
1704 setBrick(w.Slot.Brick->getSheetId());
1705 Slot.Valid= w.Slot.Valid;
1706 Slot.ViewParamFamilies= w.Slot.ViewParamFamilies;
1708 // copy ParamBricks
1709 NumTotalParams= w.NumTotalParams;
1710 ParamError= w.ParamError;
1711 for(uint i=0;i<NumTotalParams;i++)
1713 setParamBrick(i, w.ParamSlot[i].Brick->getSheetId());
1714 ParamSlot[i].Valid= w.ParamSlot[i].Valid;
1715 ParamSlot[i].ViewParamFamilies= w.ParamSlot[i].ViewParamFamilies;
1718 // set the cost
1719 CostView->setText(w.CostView->getText());
1720 CostView->setActive(w.CostView->getActive());
1721 CreditView->setText(w.CreditView->getText());
1722 CreditView->setActive(w.CreditView->getActive());
1723 InfoView->setText(w.InfoView->getText());
1724 InfoView->setActive(w.InfoView->getActive());
1728 // ***************************************************************************
1729 void CDBGroupBuildPhrase::resetSentence(sint32 rootSheetId)
1731 if(!_GroupValid)
1732 return;
1734 uint i;
1736 // first update the root brick
1737 _MainWords[0].setBrick(rootSheetId);
1738 // then update display for others
1739 updateDisplayFromRootBrick();
1741 // get the root brick
1742 const CSBrickSheet *rootBrick= getRootBrick();
1743 if(!rootBrick)
1744 return;
1746 // *** Init Root
1747 // update parameters of the root
1748 updateParams(0);
1750 // *** Init Mandatories
1751 for(i=1;i<1+_NumMandatories;i++)
1753 // get the family Known BitField
1754 uint familyId= rootBrick->MandatoryFamilies[i-1];
1755 sint32 sheet;
1756 bool valid;
1757 getDefaultSheetForFamily(familyId, sheet, valid);
1759 // Setup the ctrl sheet of mandatory to 0 by default!
1760 _MainWords[i].setBrick(0);
1761 _MainWords[i].Slot.Valid= valid;
1763 // set the ctrl sheet display
1764 _MainWords[i].Slot.Brick->setGrayed( !valid );
1766 // update the parameters of this main brick
1767 updateParams(i);
1770 // *** Init Optional/Credits
1771 // ungray all optional slots.
1772 for(i=1+_NumMandatories;i<_MainWords.size();i++)
1774 _MainWords[i].Slot.Brick->setGrayed( false );
1777 // update the NewOp controler
1778 updateNewButtons();
1782 // ***************************************************************************
1783 void CDBGroupBuildPhrase::updateDisplayFromRootBrick()
1785 if(!_GroupValid)
1786 return;
1788 uint i;
1790 // get the root bricks
1791 const CSBrickSheet *brick= getRootBrick();
1793 // Reset the Root params only (don't reset the sheetId setuped!)
1794 _MainWords[0].resetParams();
1796 // Hide all other slots by default
1797 for(i=1;i<_MainWords.size();i++)
1799 _MainWords[i].reset();
1801 _NumMandatories= 0;
1802 _NumOptionals= 0;
1803 _NumCredits= 0;
1805 // if brick not found, or if not enough ctrl, hide all
1806 if(!brick || brick->MandatoryFamilies.size()+1>_MainWords.size() )
1808 // empty sheet
1809 _MainWords[0].Slot.Brick->setSheetId(0);
1811 // else ok, setup the composition
1812 else
1814 _NumMandatories= (uint32)brick->MandatoryFamilies.size();
1815 // Don't enable any optional/credit by default
1816 _NumCredits= 0;
1817 _NumOptionals= 0;
1820 // update the group and sons coords
1821 invalidateCoords();
1824 // ***************************************************************************
1825 void CDBGroupBuildPhrase::buildCurrentPhrase(CSPhraseCom &newPhrase)
1827 /* Word Order: Root/Mandatory/Optional/Credits (with all their params)
1830 // Reset.
1831 newPhrase.Name.clear();
1832 newPhrase.Bricks.clear();
1833 uint i;
1834 const CSBrickSheet *brick;
1836 // Add All bricks with their parameters
1837 for(i=0;i<getNumMainBricks();i++)
1839 CWord &word= _MainWords[i];
1840 brick= word.Slot.Brick->asSBrickSheet();
1841 newPhrase.Bricks.push_back(brick?brick->Id:CSheetId());
1842 // For all its params.
1843 for(uint j=0;j<word.NumTotalParams;j++)
1845 brick= word.ParamSlot[j].Brick->asSBrickSheet();
1846 newPhrase.Bricks.push_back(brick?brick->Id:CSheetId());
1850 // Set the Name
1851 if(_UserSentenceName)
1853 newPhrase.Name= ucstring::makeFromUtf8(_UserSentenceName->getInputString());
1856 newPhrase.IconIndex = m_IconIndex;
1860 // ***************************************************************************
1861 void CDBGroupBuildPhrase::updateNewButtons()
1863 // TODO_BRICK: have I to hide button and their text if not possible to add any op/credit?
1865 /*if(!_NewOpButton)
1866 return;
1868 uint newOpIndex= _NumMandatories+_NumOptionals;
1870 // if some place for a new optional, show and place the NewOpButton
1871 if(newOpIndex<_MandOpWords.size())
1873 // if comes from a delete, ensure the back+1 is hidden
1874 if(newOpIndex+1<_MandOpWords.size())
1876 _MandOpWords[newOpIndex+1].Slot.Back->setActive(false);
1879 // Show a new Optional possibilty ONLY if really possible!!
1880 std::vector<NLMISC::CSheetId> bricks;
1881 fillNewOptionalBricks(bricks);
1882 // if no choice possible
1883 if(bricks.empty())
1885 _NewOpButton->setActive(false);
1887 else
1889 // show the Back under the button
1890 _MandOpWords[newOpIndex].Slot.Back->setActive(true);
1891 // And move the button under it
1892 _NewOpButton->setParentPos(_MandOpWords[newOpIndex].Slot.Back);
1893 _NewOpButton->setActive(true);
1896 else
1898 _NewOpButton->setActive(false);
1901 // retrace all.
1902 invalidateCoords();*/
1905 // ***************************************************************************
1906 void CDBGroupBuildPhrase::updateSpellView()
1908 if(_SpellView)
1910 // Build the current phrase
1911 CSPhraseCom newPhrase;
1912 buildCurrentPhrase(newPhrase);
1914 // Set the edited version to the phrase Manager => auto updated in icon
1915 CSPhraseManager *pPM= CSPhraseManager::getInstance();
1917 // replace the content of the edited phrase.
1918 pPM->setPhrase(CSPhraseManager::EditionSlot, newPhrase);
1923 // ***************************************************************************
1924 void CDBGroupBuildPhrase::fillNewOptionalBricks(std::vector<NLMISC::CSheetId> &bricks)
1926 if(!_GroupValid) return;
1927 const CSBrickSheet *rootBrick= getRootBrick();
1928 if(!rootBrick) return;
1929 CSBrickManager *pBM= CSBrickManager::getInstance();
1931 // get all possible newFamilies
1932 vector<uint16> optionalFamilies;
1933 optionalFamilies= rootBrick->OptionalFamilies;
1934 // Filter ones that already exist in the composition
1935 // Don't filter Combat and Power optional families (Use Brick exclusion system instead)
1936 if( !rootBrick->isCombat() && !rootBrick->isSpecialPower())
1937 filterFamilySetuped(optionalFamilies);
1939 // Select all bricks for those families.
1940 for(uint i=0;i<optionalFamilies.size();i++)
1942 const vector<CSheetId> &famBricks= pBM->getFamilyBricks(optionalFamilies[i]);
1943 bricks.insert(bricks.end(), famBricks.begin(), famBricks.end());
1946 // get only ones known
1947 filterKnownBricks(bricks);
1949 // Combat special
1950 if( rootBrick->isCombat() )
1952 // Ensure not same bricks are setuped
1953 filterBrickSetuped(bricks);
1954 // Ensure only optional of compatible Skill are inserted
1955 filterSkillSetuped(bricks, true, false);
1957 else if ( rootBrick->isSpecialPower() )
1959 // Ensure not same bricks are setuped
1960 filterBrickSetuped(bricks);
1962 // filter by BrickExclusion
1963 filterBrickExclusion(bricks);
1966 // ***************************************************************************
1967 void CDBGroupBuildPhrase::fillNewCreditBricks(std::vector<NLMISC::CSheetId> &bricks)
1969 if(!_GroupValid) return;
1970 const CSBrickSheet *rootBrick= getRootBrick();
1971 if(!rootBrick) return;
1972 CSBrickManager *pBM= CSBrickManager::getInstance();
1974 // get all possible newFamilies
1975 vector<uint16> creditFamilies;
1976 creditFamilies= rootBrick->CreditFamilies;
1977 // Filter ones that already exist in the composition
1978 filterFamilySetuped(creditFamilies);
1980 // Select all bricks for those families.
1981 for(uint i=0;i<creditFamilies.size();i++)
1983 const vector<CSheetId> &famBricks= pBM->getFamilyBricks(creditFamilies[i]);
1984 bricks.insert(bricks.end(), famBricks.begin(), famBricks.end());
1987 // get only ones known
1988 filterKnownBricks(bricks);
1990 // filter by BrickExclusion
1991 filterBrickExclusion(bricks);
1995 // ***************************************************************************
1996 void CDBGroupBuildPhrase::setRootBrickTypeFilter(BRICK_TYPE::EBrickType rootBtFilter,
1997 BRICK_TYPE::EBrickType rootBtFilter2, BRICK_TYPE::EBrickType rootBtFilter3, BRICK_TYPE::EBrickType rootBtFilter4)
1999 nlctassert(MaxRootBrickTypeFilter==4);
2000 _RootBrickTypeFilter[0]= rootBtFilter;
2001 _RootBrickTypeFilter[1]= rootBtFilter2;
2002 _RootBrickTypeFilter[2]= rootBtFilter3;
2003 _RootBrickTypeFilter[3]= rootBtFilter4;