Fix css style order when using external css files
[ryzomcore.git] / ryzom / client / src / interface_v3 / dbgroup_build_phrase.cpp
blob43c03d5fc35df13c2ab6d8cf27925340fa9c39b0
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";
48 // ***************************************************************************
50 NLMISC_REGISTER_OBJECT(CViewBase, CDBGroupBuildPhrase, std::string, "build_phrase");
52 CDBGroupBuildPhrase::CDBGroupBuildPhrase(const TCtorParam &param)
53 :CInterfaceGroup(param)
55 _GroupValid= false;
56 _ValidateButton= NULL;
57 _NumMandatories= 0;
58 _NumOptionals= 0;
59 _NumCredits= 0;
61 _Setuped= false;
62 _TextureIdSlotDisabled= 0;
64 // Name of the magic sentence
65 _UserSentenceName= NULL;
66 _SpellView= NULL;
68 _NewSpellNumber= 0;
70 _TextPhraseDesc= NULL;
72 nlctassert(MaxRootBrickTypeFilter>0);
73 for(uint i=0;i<MaxRootBrickTypeFilter;i++)
75 _RootBrickTypeFilter[i]= BRICK_TYPE::UNKNOWN;
79 // ***************************************************************************
80 CDBGroupBuildPhrase::~CDBGroupBuildPhrase()
85 // ***************************************************************************
86 // ***************************************************************************
87 // Widget Setup
88 // ***************************************************************************
89 // ***************************************************************************
92 // ***************************************************************************
93 bool CDBGroupBuildPhrase::parse (xmlNodePtr cur, CInterfaceGroup *parentGroup)
95 if(!CInterfaceGroup::parse(cur, parentGroup))
96 return false;
98 CInterfaceManager *pIM= CInterfaceManager::getInstance();
100 // Init the disabled texture id
101 CViewRenderer &rVR = *CViewRenderer::getInstance();
102 _TextureIdSlotDisabled= rVR.getTextureIdFromName ("w_slot_brick_disabled.tga");
104 // Create now (before sons ctrl sheet parsing) the variables
105 uint i;
106 // Bricks and their Params
107 for(i=0;i<MaxBricks;i++)
109 NLGUI::CDBManager::getInstance()->getDbProp(BrickBuildDB + ":MAIN:" + toString(i)+":SHEET");
110 for(uint j=0;j<MaxParam;j++)
111 NLGUI::CDBManager::getInstance()->getDbProp(BrickBuildDB + ":PARAM:" + toString(i) + ":" + toString(j) + ":SHEET");
114 // spellView: to update the icon, use a special phrase manager entry
115 NLGUI::CDBManager::getInstance()->getDbProp(BrickBuildDB + ":EDITION_PHRASE:PHRASE")->setValue32(CSPhraseManager::EditionSlot);
117 return true;
120 // ***************************************************************************
121 void CDBGroupBuildPhrase::updateCoords ()
123 if(!_Setuped)
124 setupBuildSentence();
126 CInterfaceGroup::updateCoords();
129 // ***************************************************************************
130 void CDBGroupBuildPhrase::setupBuildSentence()
132 CInterfaceManager *pIM= CInterfaceManager::getInstance();
134 _Setuped= true;
136 // Get the widget controls
137 _ValidateButton= dynamic_cast<CCtrlBaseButton*>(CInterfaceGroup::getCtrl("ok_cancel:ok"));
138 if(_ValidateButton)
139 _ValidateButton->setFrozen(true);
141 _TextPhraseDesc= dynamic_cast<CViewText*>(CInterfaceGroup::getView("infos:phrase_desc"));
143 // retrieved brick view/ctrls
144 string idCtrl, idBack, idCost, idCredit, idInfo;
145 CDBCtrlSheet *ctrl;
146 CViewBitmap *back;
147 CViewText *cost;
148 CViewText *credit;
149 CViewText *info;
152 // **** get all bricks (including root)
153 sint index= 0;
154 for(;;)
156 // retrieve
157 idCtrl= string("bricks:main_brick")+toString(index);
158 idBack= string("bricks:main_back")+toString(index);
159 idCost= string("bricks:main_cost")+toString(index);
160 idCredit= string("bricks:main_credit")+toString(index);
161 idInfo= string("bricks:main_info")+toString(index);
162 ctrl= dynamic_cast<CDBCtrlSheet*>(CInterfaceGroup::getCtrl( idCtrl ));
163 back= dynamic_cast<CViewBitmap*>(CInterfaceGroup::getView( idBack ));
164 cost= dynamic_cast<CViewText*>(CInterfaceGroup::getView( idCost ));
165 credit= dynamic_cast<CViewText*>(CInterfaceGroup::getView( idCredit ));
166 info= dynamic_cast<CViewText*>(CInterfaceGroup::getView( idInfo ));
167 // A brick Slot is valid only if all Ctrl/View are ok, same for its param.
168 bool ok= true;
169 CWord newWord;
170 if(ctrl && back && cost && info)
172 newWord.Slot.Brick= ctrl;
173 newWord.Slot.Back= back;
174 newWord.CostView= cost;
175 newWord.CreditView= credit;
176 newWord.InfoView= info;
177 // Must have all params
178 for(uint i=0;i<MaxParam;i++)
180 idCtrl= string("bricks:param_brick") + toString(index) + "_" + toString(i);
181 idBack= string("bricks:param_back") + toString(index) + "_" + toString(i);
182 ctrl= dynamic_cast<CDBCtrlSheet*>(CInterfaceGroup::getCtrl( idCtrl ));
183 back= dynamic_cast<CViewBitmap*>(CInterfaceGroup::getView( idBack ));
184 if(ctrl && back)
186 newWord.ParamSlot[i].Brick= ctrl;
187 newWord.ParamSlot[i].Back= back;
189 else
191 // fails to find all params!
192 ok= false;
193 break;
197 else
198 ok= false;
199 // ok with this ctrl?
200 if(ok)
202 // unactive alls.
203 newWord.reset();
204 // append
205 _MainWords.push_back(newWord);
206 // next
207 index++;
209 else
211 // stop to search
212 break;
216 // If not at least find the root, error!
217 if(index==0)
219 nlwarning("ERROR: RootBrick not found!");
220 _GroupValid= false;
222 else
224 _GroupValid= true;
225 // Active at least the root brick.
226 _MainWords[0].setBrick(0);
229 // Setup special for Root
230 if(_GroupValid)
232 sint rootTextMaxw;
233 fromString(CWidgetManager::getInstance()->getParser()->getDefine("phrase_build_root_info_maxw"), rootTextMaxw);
234 _MainWords[0].InfoView->setLineMaxW(rootTextMaxw);
237 // Get the sentence texts
238 _UserSentenceName= dynamic_cast<CGroupEditBox*>(CInterfaceGroup::getGroup("eb_spell_name:eb"));
240 // Get the SpellView
241 _SpellView= dynamic_cast<CDBCtrlSheet*>(CInterfaceGroup::getCtrl( "spell_view" ));
245 // ***************************************************************************
246 void CDBGroupBuildPhrase::draw ()
248 CInterfaceGroup::draw();
252 // ***************************************************************************
253 const CSBrickSheet *CDBGroupBuildPhrase::getRootBrick()
255 if(!_GroupValid)
256 return NULL;
258 return _MainWords[0].Slot.Brick->asSBrickSheet();
262 // ***************************************************************************
263 // ***************************************************************************
264 // Setup operations
265 // ***************************************************************************
266 // ***************************************************************************
269 // ***************************************************************************
270 void CDBGroupBuildPhrase::clearBuildingPhrase()
272 if(!_GroupValid)
273 return;
275 // update display
276 _MainWords[0].reset();
277 _MainWords[0].setBrick(0);
278 updateDisplayFromRootBrick();
280 // Empty the name
281 if(_UserSentenceName)
283 _UserSentenceName->setInputString(std::string());
286 // update Display
287 updateAllDisplay();
291 // ***************************************************************************
292 void CDBGroupBuildPhrase::startComposition(const CSPhraseCom &phrase)
294 if(!_GroupValid)
295 return;
296 CSBrickManager *pBM= CSBrickManager::getInstance();
299 string name;
301 // if phrase empty (new phrase), invent a new name
302 if(phrase.empty())
304 // build a default name
305 name= CI18N::get("uimPhraseNew");
306 // Append a dummy number
307 _NewSpellNumber++;
308 name+= " " + toString(_NewSpellNumber);
310 else
312 // copy name
313 name= phrase.Name.toUtf8();
315 // get the root Brick. Must exist.
316 CSBrickSheet *rootBrick= pBM->getBrick(phrase.Bricks[0]);
317 if(rootBrick)
319 // Phrase to Ctrls: simulate clicks!
320 uint curBrickIndex= 1;
321 uint brickIndexForParam= 0;
322 uint curParam= 0;
323 uint numParam= 0;
325 // simulate a root selection
326 validateRoot(rootBrick);
327 // setup params of the root
328 numParam= (uint)rootBrick->ParameterFamilies.size();
329 brickIndexForParam= 0;
331 // For all brick not the root
332 for(uint i=1;i<phrase.Bricks.size();i++)
334 CSBrickSheet *brick= pBM->getBrick(phrase.Bricks[i]);
336 /* NB: the ORDER is important for grammar checkup
337 Must come first Root / Mandatory, then credit or optionals.
338 Each params must follow its related brick
339 Parameters May also have their own parameters
340 This is recursive, param sons may have params sons.
343 // a param of brick?
344 if(curParam<numParam)
346 validateParam(brickIndexForParam, curParam, brick);
347 curParam++;
348 // If this parameter has additonal parameter they follow
349 if( brick && !brick->ParameterFamilies.empty() )
350 numParam+= (uint)brick->ParameterFamilies.size();
352 // a mandatory/optional/credit?
353 else
355 // must be a mandatory?
356 if(curBrickIndex<1+_NumMandatories)
357 validateMain(curBrickIndex, brick);
358 // create a new optional/credit
359 else
360 validateNewOpCredit(brick);
362 // bkup index for param, and increment
363 brickIndexForParam= curBrickIndex;
364 curBrickIndex++;
365 // following bricks are its param!
366 curParam= 0;
367 numParam= 0;
368 if(brick)
369 numParam= (uint)brick->ParameterFamilies.size();
375 // set the editable name.
376 if(_UserSentenceName)
377 _UserSentenceName->setInputString(name);
381 // ***************************************************************************
382 // ***************************************************************************
383 // Start Selection of Bricks
384 // ***************************************************************************
385 // ***************************************************************************
388 // ***************************************************************************
389 void CDBGroupBuildPhrase::fillSelectionRoot()
391 // the root must be OK.
392 if(!_GroupValid) return;
393 CSBrickManager *pBM= CSBrickManager::getInstance();
395 // fillSelection with all root
396 std::vector<CSheetId> bricks;
397 bricks= pBM->getRootBricks();
398 // get only ones known
399 filterKnownBricks(bricks);
400 // get only ones that match The BrickType filter
401 filterRootBrickType(bricks);
402 // some additional root filter
403 filterRootPossibles(bricks);
404 // fill db
405 fillSelection(bricks);
407 // ***************************************************************************
408 void CDBGroupBuildPhrase::fillSelectionMain(uint index)
410 nlassert(index>0);
411 // the root must be OK.
412 if(!_GroupValid) return;
413 const CSBrickSheet *rootBrick= getRootBrick();
414 if(!rootBrick) return;
415 CSBrickManager *pBM= CSBrickManager::getInstance();
417 // error?
418 if(index>=_MainWords.size())
420 resetSelection();
421 return;
424 // get the current Brick.
425 std::vector<CSheetId> bricks;
426 const CSBrickSheet *brick= _MainWords[index].Slot.Brick->asSBrickSheet();
427 if(!brick)
429 // It is possible for Mandatory that this brick is still not validated
430 if(index<1+_NumMandatories)
432 // get the related family and bricks associated to it
433 bricks= pBM->getFamilyBricks(rootBrick->MandatoryFamilies[index-1]);
435 else
437 resetSelection();
438 return;
441 else
443 // fill selection with all bricks of the same family (whatever the main brick)
444 bricks= pBM->getFamilyBricks(brick->BrickFamily);
447 // get only ones known
448 filterKnownBricks(bricks);
450 // For mandatories, filter effects
451 CSPhraseCom currentPhrase;
452 buildCurrentPhrase(currentPhrase);
453 pBM->getSabrinaCom().filterMandatoryComposition(currentPhrase.Bricks, bricks);
455 // For Combat Optional, must filter by exclusion and combat exclusion
456 if(brick && brick->isCombat() && brick->isOptional() )
458 // Ensure not same bricks are setuped. Also don't insert me since I am already here...
459 filterBrickSetuped(bricks);
460 // Ensure only optional of compatible Skill are inserted. Don't test with me, since i may be removed!
461 filterSkillSetuped(bricks, true, false, index);
463 // for power optional, must filter by brick
464 else if(brick && brick->isSpecialPower() && (brick->isOptional()||brick->isMandatory()) )
466 // Ensure not same bricks are setuped. Also don't insert me since I am already here...
467 filterBrickSetuped(bricks);
470 // For optional or credit, filter by BrickExclusion.
471 if(index>=1/*+_NumMandatories*/)
472 filterBrickExclusion(bricks, index);
474 // For Optional/Credits, must append first the special "Remove Brick" choice
475 if(index>=1+_NumMandatories)
477 bricks.insert(bricks.begin(), pBM->getInterfaceRemoveBrick());
480 // fill db
481 fillSelection(bricks);
484 // ***************************************************************************
485 void CDBGroupBuildPhrase::fillSelectionParam(uint index, uint paramIndex)
487 // the root must be OK.
488 if(!_GroupValid) return;
489 const CSBrickSheet *rootBrick= getRootBrick();
490 if(!rootBrick) return;
491 CSBrickManager *pBM= CSBrickManager::getInstance();
493 // error?
494 if( index>=_MainWords.size() || paramIndex>=MaxParam)
496 resetSelection();
497 return;
500 // get the current Brick.
501 const CSBrickSheet *brick;
502 brick= _MainWords[index].ParamSlot[paramIndex].Brick->asSBrickSheet();
503 if(!brick)
505 resetSelection();
506 return;
508 // fill selection with all bricks of the same family (whatever the root)
509 std::vector<CSheetId> bricks;
510 bricks= pBM->getFamilyBricks(brick->BrickFamily);
511 // get only ones known
512 filterKnownBricks(bricks);
513 // fill db
514 fillSelection(bricks);
517 // ***************************************************************************
518 void CDBGroupBuildPhrase::fillSelectionNewOp()
520 // the root must be OK.
521 if(!_GroupValid) return;
522 const CSBrickSheet *rootBrick= getRootBrick();
523 if(!rootBrick) return;
525 // Build a brick array of possible new bricks.
526 std::vector<NLMISC::CSheetId> bricks;
527 fillNewOptionalBricks(bricks);
529 // fill db
530 fillSelection(bricks);
534 // ***************************************************************************
535 void CDBGroupBuildPhrase::fillSelectionNewCredit()
537 // the root must be OK.
538 if(!_GroupValid) return;
539 const CSBrickSheet *rootBrick= getRootBrick();
540 if(!rootBrick) return;
542 // Build a brick array of possible new bricks.
543 std::vector<NLMISC::CSheetId> bricks;
544 fillNewCreditBricks(bricks);
546 // fill db
547 fillSelection(bricks);
551 // ***************************************************************************
552 // ***************************************************************************
553 // Validate Selection of Bricks
554 // ***************************************************************************
555 // ***************************************************************************
558 // ***************************************************************************
559 void CDBGroupBuildPhrase::validateRoot(const CSBrickSheet *sheet)
561 // the root must be OK.
562 if(!_GroupValid) return;
564 // If same brick no op
565 if(getRootBrick() == sheet)
566 return;
568 // reset the whole sentence with default values
569 resetSentence(sheet->Id.asInt());
571 // update the display
572 updateAllDisplay();
576 // ***************************************************************************
577 void CDBGroupBuildPhrase::validateMain(uint index, const CSBrickSheet *sheet)
579 nlassert(index>0);
580 // the root must be OK.
581 if(!_GroupValid) return;
582 const CSBrickSheet *rootBrick= getRootBrick();
583 if(!rootBrick) return;
584 CSBrickManager *pBM= CSBrickManager::getInstance();
586 // If the brick chosen is actually the "Remove Brick", then call the correct method
587 if(sheet->Id == pBM->getInterfaceRemoveBrick())
589 deleteOpCredit(index);
590 return;
593 // set the brick!
594 if(sheet)
595 _MainWords[index].setBrick(sheet->Id.asInt());
597 // must update params if change!
598 updateParams(index);
600 // update the display
601 updateAllDisplay();
604 // ***************************************************************************
605 void CDBGroupBuildPhrase::validateParam(uint index, uint paramIndex, const CSBrickSheet *sheet)
607 // the root must be OK.
608 if(!_GroupValid) return;
609 const CSBrickSheet *rootBrick= getRootBrick();
610 if(!rootBrick) return;
611 if(paramIndex>=MaxParam) return;
613 // The setuped parameter may have also parameter sons
614 bool mustResetParamHrc= false;
615 vector<uint16> newParamSons;
616 if(sheet) newParamSons= sheet->ParameterFamilies;
617 mustResetParamHrc= newParamSons != _MainWords[index].ParamSlot[paramIndex].ViewParamFamilies;
619 // set the brick!
620 if(sheet)
622 _MainWords[index].setParamBrick(paramIndex, sheet->Id.asInt());
625 // update the param sons
626 if(mustResetParamHrc)
627 updateParamHrc(index);
629 // update the display
630 updateAllDisplay();
633 // ***************************************************************************
634 void CDBGroupBuildPhrase::validateNewOpCredit(const CSBrickSheet *sheet)
636 // the root must be OK.
637 if(!_GroupValid) return;
638 const CSBrickSheet *rootBrick= getRootBrick();
639 if(!rootBrick) return;
641 if(!sheet)
642 return;
644 // we should not have to do this test...
645 if(getNumMainBricks()>=_MainWords.size())
646 return;
648 // get the dest index.
649 uint index;
650 // credit brick?
651 if(sheet->isCredit())
652 index= 1+_NumMandatories+_NumOptionals+_NumCredits;
653 // else optional brick
654 else
655 index= 1+_NumMandatories+_NumOptionals;
657 // Shift Optional Row. Copy the Brick setup from index to index+1.
658 for(uint i= getNumMainBricks();i>index;i--)
660 _MainWords[i].copySetup(_MainWords[i-1]);
663 // set the brick!
664 _MainWords[index].setBrick(sheet->Id.asInt());
666 // Increment the number of options/credits setuped!
667 if(sheet->isCredit())
668 _NumCredits++;
669 else
670 _NumOptionals++;
672 // update the NewOp controler
673 updateNewButtons();
675 // must update params if change!
676 updateParams(index);
678 // update the display
679 updateAllDisplay();
682 // ***************************************************************************
683 void CDBGroupBuildPhrase::deleteOpCredit(uint index)
685 nlassert(index>0);
686 // the root must be OK.
687 if(!_GroupValid) return;
688 const CSBrickSheet *rootBrick= getRootBrick();
689 if(!rootBrick) return;
691 // check index
692 bool isCredit;
693 if(index>=1+_NumMandatories && index<1+_NumMandatories+_NumOptionals)
694 isCredit= false;
695 else if(index>=1+_NumMandatories+_NumOptionals && index<getNumMainBricks() )
696 isCredit= true;
697 else
698 return;
700 // Shift Optional Row. Copy the Brick setup from index+1 to index.
701 for(uint i= index+1;i<getNumMainBricks();i++)
703 _MainWords[i-1].copySetup(_MainWords[i]);
706 // reset the last row display
707 _MainWords[getNumMainBricks()-1].reset();
709 // an optional/credit is removed!
710 if(isCredit)
711 _NumCredits--;
712 else
713 _NumOptionals--;
715 // update the NewOp ctrl
716 updateNewButtons();
718 // update the display
719 updateAllDisplay();
723 // ***************************************************************************
724 // ***************************************************************************
725 // System
726 // ***************************************************************************
727 // ***************************************************************************
730 // ***************************************************************************
731 static uint getLowestBit(uint64 val)
733 uint ret= 0;
734 while(val)
736 if(val&1)
737 return ret;
738 ret++;
739 val>>=1;
741 return 0;
745 // ***************************************************************************
746 static void getDefaultSheetForFamily(uint familyId, sint32 &sheet, bool &valid)
748 CSBrickManager *pBM= CSBrickManager::getInstance();
750 uint64 knownBF= pBM->getKnownBrickBitField(familyId);
751 // Known?
752 if(knownBF)
754 // default: get the lowest sheet
755 sint posInFamily= getLowestBit(knownBF);
757 // get the sheet
758 sheet= pBM->getBrickSheet(familyId, posInFamily).asInt();
759 valid= true;
761 else
763 // setup the Sheet with the lowest brick
764 sheet= pBM->getBrickSheet(familyId, 0).asInt();
765 // invalidate the word
766 valid= false;
771 // ***************************************************************************
772 void CDBGroupBuildPhrase::updateParams(uint index)
774 // get the Word
775 CWord *word;
776 if(index<_MainWords.size())
777 word= &_MainWords[index];
778 else
779 return;
781 // Get the Brick setuped. may be NULL for unsetuped mandatories
782 const CSBrickSheet *brick= word->Slot.Brick->asSBrickSheet();
784 // retrieve brick paramFamilies
785 vector<uint16> paramFamilies;
786 if(brick)
787 paramFamilies= brick->ParameterFamilies;
789 // if param families of the new brick different from what setuped in view, reset all param hierachy
790 if(word->Slot.ViewParamFamilies != paramFamilies)
792 // must reset the view of parameters
793 word->resetParams();
795 // and compute all from setuped main brick
796 updateParamHrc(index);
801 // ***************************************************************************
802 /* used for updateParamHrc()
805 class CParamTreeNode
807 public:
808 const CSBrickSheet *Brick;
809 bool Valid;
810 std::vector<uint16> ViewParamFamilies;
811 CParamTreeNode *Parent;
812 std::vector<CParamTreeNode*> Sons;
814 public:
815 CParamTreeNode(CParamTreeNode *parent) : Brick(NULL), Valid(true), Parent(parent) {}
816 ~CParamTreeNode()
818 Parent= NULL;
819 Brick= NULL;
820 deleteSons();
823 // delete param sons
824 void deleteSons()
826 for(uint i=0;i<Sons.size();i++) delete Sons[i];
827 Sons.clear();
830 // rebuild default param sons (recurs) if BrickParamFamilies and ViewParamFamilies differ.
831 // return false if error
832 bool synchronizeParams(uint maxDepth)
834 if(maxDepth==0)
835 return false;
837 // get the brick Parameter Families.
838 vector<uint16> brickParamFamilies;
839 if(Brick)
840 brickParamFamilies= Brick->ParameterFamilies;
841 // compare with the current View one. if equals then OK! just recurs test sons
842 if(brickParamFamilies == ViewParamFamilies)
844 for(uint i=0;i<Sons.size();i++)
846 if(!Sons[i]->synchronizeParams(maxDepth-1))
847 return false;
849 return true;
851 // else must rebuild all this branch
852 else
854 return buildSonsFromBrick(maxDepth);
858 // build the son list from brick Setup, and recurs
859 // return false if error
860 bool buildSonsFromBrick(uint maxDepth)
862 if(maxDepth==0)
863 return false;
865 CSBrickManager *pBM= CSBrickManager::getInstance();
867 // first delete my sons, and any old view setup
868 deleteSons();
869 ViewParamFamilies.clear();
871 // then copy brick families to view families (=> view synchronized to brick)
872 if(Brick)
873 ViewParamFamilies= Brick->ParameterFamilies;
875 // Add a default Son for each family
876 uint i;
877 for(i=0;i<ViewParamFamilies.size();i++)
879 uint familyId= ViewParamFamilies[i];
880 sint32 sheet;
881 bool sonValid;
882 // bkup the valid state in this node
883 getDefaultSheetForFamily(familyId, sheet, sonValid);
885 // init son
886 CParamTreeNode *sonNode= new CParamTreeNode(this);
887 sonNode->Brick= pBM->getBrick(CSheetId(sheet));
888 sonNode->Valid= sonValid;
889 // add this son to its father
890 Sons.push_back(sonNode);
893 // recurs.
894 for(i=0;i<Sons.size();i++)
896 if(!Sons[i]->buildSonsFromBrick(maxDepth - 1))
897 return false;
900 return true;
903 // build the word raw param list from hierarchy
904 // return false if error
905 bool buildRawParamList(CDBGroupBuildPhrase::CWord &word, uint &rawParamIndex)
907 // If this is the root
908 if(!Parent)
910 // just copy the ViewParamFamilies
911 word.Slot.ViewParamFamilies= ViewParamFamilies;
913 // else, add this parameter to list
914 else
916 // Check possible Brick Data error
917 if(rawParamIndex >= CDBGroupBuildPhrase::MaxParam)
919 nlwarning("BRICK ERROR: Not enough param Space (%d) to add all son parameter", CDBGroupBuildPhrase::MaxParam);
920 return false;
923 // Setup this brick in the param list
924 CSheetId sheet;
925 if(Brick)
926 sheet= Brick->Id;
927 word.setParamBrick(rawParamIndex, sheet.asInt());
928 word.ParamSlot[rawParamIndex].Valid= Valid;
929 word.ParamSlot[rawParamIndex].Brick->setGrayed( !Valid );
931 // bkup its ViewParameters
932 word.ParamSlot[rawParamIndex].ViewParamFamilies= ViewParamFamilies;
934 // next param index
935 rawParamIndex++;
938 // for all sons, recurs
939 for(uint i=0;i<Sons.size();i++)
941 // recurs
942 if(!Sons[i]->buildRawParamList(word, rawParamIndex))
943 return false;
946 return true;
951 // ***************************************************************************
952 void CDBGroupBuildPhrase::updateParamHrc(uint index)
955 When we are here, we may have some Parameter Hierarchy inconsitency between the ViewParameterFamilies and
956 the Brick parameter Families.
957 we must fix them and rebuild all the raw param list
959 // get the Word
960 CWord *word;
961 if(index<_MainWords.size())
962 word= &_MainWords[index];
963 else
964 return;
966 // If a Param error has already been detected on this Slot, no-op
967 if(word->ParamError)
968 return;
971 // **** From the current View setup of 'word', build the Parameter Hierarchy (in simple tree form)
972 CParamTreeNode rootNode(NULL);
973 // NB: here rootNode represent the Main (ie mandatory, optional or credit) brick. Therefore, it is not a real parameter.
974 rootNode.Brick= word->Slot.Brick->asSBrickSheet();
975 rootNode.Valid= true;
976 rootNode.ViewParamFamilies= word->Slot.ViewParamFamilies;
977 uint rawParamIndex= 0;
978 CParamTreeNode *curNode= &rootNode;
979 while(curNode)
981 // if this node still need sons, then the next raw index param must be a son of curNode
982 if(curNode->Sons.size() < curNode->ViewParamFamilies.size())
984 nlassert(rawParamIndex < word->NumTotalParams);
985 // create a son node, and fill from rawList
986 CParamTreeNode *sonNode= new CParamTreeNode(curNode);
987 sonNode->Brick= word->ParamSlot[rawParamIndex].Brick->asSBrickSheet();
988 sonNode->Valid= word->ParamSlot[rawParamIndex].Valid;
989 sonNode->ViewParamFamilies= word->ParamSlot[rawParamIndex].ViewParamFamilies;
990 // append to the sons
991 curNode->Sons.push_back(sonNode);
992 // next in rawList
993 rawParamIndex++;
994 // recurs to son
995 curNode= sonNode;
997 // else the next must be a brother: return to parent
998 else
999 curNode= curNode->Parent;
1001 // we must have run all the raw list
1002 nlassert(rawParamIndex == word->NumTotalParams);
1003 nlassert(rootNode.Sons.size() == word->Slot.ViewParamFamilies.size());
1006 // **** Parse the Parameter tree, and invalidate each branch where View families and Brick families differs.
1007 // Avoid .sbrick data erros: allow only a max recurs level of 10
1008 if(!rootNode.synchronizeParams(10))
1010 // in this case, ABORT, but don't crash: setup 0 parameters...
1011 word->resetParams();
1012 word->ParamError= true;
1013 return;
1017 // **** rebuild completely the parameter list from the parameter tree.
1018 // clear first
1019 word->resetParams();
1020 // then rebuild
1021 rawParamIndex= 0;
1022 if(rootNode.buildRawParamList(*word, rawParamIndex))
1024 // then the new NumTotalParams is....
1025 word->NumTotalParams= rawParamIndex;
1027 // ERROR CASE
1028 else
1030 // in this case, ABORT, but don't crash: setup 0 parameters...
1031 word->resetParams();
1032 word->ParamError= true;
1033 return;
1039 // ***************************************************************************
1040 void CDBGroupBuildPhrase::updateAllDisplay(const CSPhraseCom &phrase)
1042 // NB: phrase MUST COME FROM buildCurrentPhrase() else doesn't work.
1044 CSBrickManager *pBM= CSBrickManager::getInstance();
1045 CInterfaceManager *pIM= CInterfaceManager::getInstance();
1046 CSPhraseManager *pPM= CSPhraseManager::getInstance();
1048 // **** update total cost
1049 // get the cost and credit
1050 uint32 totalCost, totalCredit;
1051 pBM->getSabrinaCom().getPhraseCost(phrase.Bricks, totalCost, totalCredit);
1053 // update database
1054 NLGUI::CDBManager::getInstance()->getDbProp("UI:PHRASE:BUILD:TOTAL_COST")->setValue32(totalCost);
1055 NLGUI::CDBManager::getInstance()->getDbProp("UI:PHRASE:BUILD:TOTAL_CREDIT")->setValue32(totalCredit);
1057 // **** Update the Cost of All Root/Mandat/ops/Credits.
1058 if(phrase.Bricks.size())
1060 // Parse the phrase, and setup the related Cost.
1061 uint curBrickIndex= 0;
1062 for(uint i=0;i<phrase.Bricks.size();)
1064 // Get the brick.
1065 CSBrickSheet *brick= pBM->getBrick(phrase.Bricks[i]);
1066 // if not found, skip it (eg important for mandatories not setuped)
1067 if(!brick)
1069 i++;
1071 else
1073 // get the cost for this brick and its params.
1074 sint32 cost;
1075 float relative_cost;
1076 cost= pBM->getSabrinaCom().getPhraseBrickAndParamCost(phrase.Bricks, i);
1077 relative_cost = pBM->getSabrinaCom().getPhraseBrickAndParamRelativeCost(phrase.Bricks, i);
1078 std::string costText;
1079 if( cost == 0 && relative_cost != 0.f )
1081 cost = (sint32)(relative_cost * 100.f);
1082 costText= toString("%+d", cost) + string("%");
1084 else
1085 costText= toString("%+d", cost);
1087 // set the MainWord cost
1088 if(cost>=0)
1090 _MainWords[curBrickIndex].CostView->setActive(true);
1091 _MainWords[curBrickIndex].CreditView->setActive(false);
1092 _MainWords[curBrickIndex].CostView->setText(costText);
1094 else
1096 _MainWords[curBrickIndex].CreditView->setActive(true);
1097 _MainWords[curBrickIndex].CostView->setActive(false);
1098 _MainWords[curBrickIndex].CreditView->setText(costText);
1101 // Next brick: skip me and my params
1102 i+= 1 + _MainWords[curBrickIndex].NumTotalParams;
1105 // next slot to setup. if all slots setuped, break.
1106 curBrickIndex++;
1107 if(curBrickIndex>=getNumMainBricks())
1108 break;
1112 // **** Additionaly Update the Info Text
1113 for(uint i=0;i<1+_NumMandatories;i++)
1115 CWord &word= _MainWords[i];
1116 // If the brick is setuped, hide the info text, else display
1117 if( word.Slot.Brick->asSBrickSheet() )
1118 word.InfoView->setActive(false);
1119 else
1121 word.InfoView->setActive(true);
1122 if(i==0)
1123 word.InfoView->setText( CI18N::get("uiTextHelpSelectRootBrick") );
1124 else
1125 // start effect index at 1 (human readable :) )
1126 word.InfoView->setText( CI18N::get("uiTextHelpSelectEffectBrick") + toString(i) );
1130 // **** Additionaly Update the New Buttons
1131 bool mandatOk= true;
1132 // If only one of root effect is not setuped...
1133 for(uint i=0;i<1+_NumMandatories;i++)
1135 CWord &word= _MainWords[i];
1136 if( !word.Slot.Brick->asSBrickSheet() )
1137 mandatOk= false;
1139 // set DB value accordeing to it.
1140 NLGUI::CDBManager::getInstance()->getDbProp("UI:PHRASE:BUILD:ROOT_EFFECT_VALID")->setValue32(mandatOk);
1142 // update valid button
1143 if(_ValidateButton)
1145 bool active= false;
1147 // valid only if all mandat active and cost ok
1148 active= totalCredit>=totalCost && mandatOk;
1150 // valid only if All bricks exist, and are known
1151 uint i;
1152 for(i=0;i<phrase.Bricks.size();i++)
1154 // Get the brick.
1155 CSBrickSheet *brick= pBM->getBrick(phrase.Bricks[i]);
1156 if(!brick || !pBM->isBrickKnown(brick->Id))
1158 active= false;
1159 break;
1163 // valid only if no parameter error has been encountered
1164 for(i=0;i<1+_NumMandatories+_NumOptionals+_NumCredits;i++)
1166 if(_MainWords[i].ParamError)
1168 active= false;
1169 break;
1173 // If OK, still do some check
1174 if(active)
1176 const CSBrickSheet *brick= getRootBrick();
1177 if(!brick)
1178 active= false;
1179 // check req size
1180 else if( brick->MandatoryFamilies.size()+1>_MainWords.size() )
1181 active= false;
1184 _ValidateButton->setFrozen(!active);
1188 // **** Additionaly Update the Combat Restrict options
1189 // Get the rootBrick
1190 const CSBrickSheet *rootBrick= getRootBrick();
1191 if(rootBrick && rootBrick->isCombat())
1193 // show the weapon restriction interface
1194 NLGUI::CDBManager::getInstance()->getDbProp("UI:PHRASE:BUILD:RESTRICT_COMBAT:ENABLED")->setValue32(1);
1196 // If not already done, retrieve the weapon skills, and fill the sbricks SHEET
1197 if(_WeaponSkills.empty())
1199 // get define, and verify data
1200 uint numWeaponSkill;
1201 fromString(CWidgetManager::getInstance()->getParser()->getDefine("phrase_max_restrict_combat"), numWeaponSkill);
1202 string strWeaponSkill= CWidgetManager::getInstance()->getParser()->getDefine("phrase_def_skill_restrict_combat");
1203 vector<string> weaponSkillList;
1204 splitString(strWeaponSkill, " ", weaponSkillList);
1205 nlassert(weaponSkillList.size()==numWeaponSkill);
1207 // NOTE TO CODER WHO CHANGE SKILLS::ESkill. If you change combat skills, ask yoyo for modification
1208 // or search "phrase_def_skill_restrict_combat" and "phrase_max_restrict_combat" in XML.
1209 nlctassert( SKILLS::SFM1SSM && SKILLS::SFM1SAM && SKILLS::SFM1BMM && SKILLS::SFM1BSM &&
1210 SKILLS::SFM1PSM && SKILLS::SFM2SSM && SKILLS::SFM2SAM && SKILLS::SFM2BMM &&
1211 SKILLS::SFM2PPM && SKILLS::SFMCADM && SKILLS::SFMCAHM && SKILLS::SFR1APM &&
1212 SKILLS::SFR2AAM && SKILLS::SFR2ALM && SKILLS::SFR2ARM);
1213 nlctassert(SKILLS::SH - SKILLS::SF == 47);
1215 // backup the skill array, and fill the associated brick in interface
1216 _WeaponSkills.resize(numWeaponSkill);
1217 for(uint i=0;i<numWeaponSkill;i++)
1219 _WeaponSkills[i]= SKILLS::toSkill(weaponSkillList[i]);
1221 // Get the associated brick
1222 uint32 viewBrickCombatSheetId= pBM->getVisualBrickForSkill(_WeaponSkills[i]).asInt();
1224 // And fill in DB
1225 NLGUI::CDBManager::getInstance()->getDbProp(toString("UI:PHRASE:BUILD:RESTRICT_COMBAT:%d:SHEET", i))->setValue32(viewBrickCombatSheetId);
1229 // For each weapon skill, test if match or not the current phrase
1230 for(uint i=0;i<_WeaponSkills.size();i++)
1232 bool ok= pPM->skillCompatibleWithCombatPhrase(_WeaponSkills[i], phrase.Bricks);
1233 NLGUI::CDBManager::getInstance()->getDbProp(toString("UI:PHRASE:BUILD:RESTRICT_COMBAT:%d:LOCKED", i))->setValue32(!ok);
1236 else
1238 // hide the weapon restriction interface
1239 NLGUI::CDBManager::getInstance()->getDbProp("UI:PHRASE:BUILD:RESTRICT_COMBAT:ENABLED")->setValue32(0);
1242 // **** Setup the phrase Desc
1243 if(_TextPhraseDesc)
1245 string text;
1246 pPM->buildPhraseDesc(text, phrase, 0, false, "composition");
1247 _TextPhraseDesc->setTextFormatTaged(text);
1251 // **** Since some bricks may have changed, update the spell view
1252 updateSpellView();
1257 // ***************************************************************************
1258 void CDBGroupBuildPhrase::updateAllDisplay()
1260 // build the current phrase
1261 CSPhraseCom newPhrase;
1262 buildCurrentPhrase(newPhrase);
1263 updateAllDisplay(newPhrase);
1267 // ***************************************************************************
1268 void CDBGroupBuildPhrase::resetSelection()
1270 CInterfaceManager *pIM= CInterfaceManager::getInstance();
1272 for(uint i=0;i<MaxSelection;i++)
1274 NLGUI::CDBManager::getInstance()->getDbProp(BrickSelectionDB+ ":" + toString(i) + ":SHEET")->setValue32(0);
1278 // ***************************************************************************
1279 void CDBGroupBuildPhrase::fillSelection(const std::vector<CSheetId> &bricks)
1281 CInterfaceManager *pIM= CInterfaceManager::getInstance();
1283 uint num= min((uint)MaxSelection, (uint)bricks.size());
1284 for(uint i=0;i<MaxSelection;i++)
1286 if(i<num)
1287 NLGUI::CDBManager::getInstance()->getDbProp(BrickSelectionDB+ ":" + toString(i) + ":SHEET")->setValue32(bricks[i].asInt());
1288 else
1289 NLGUI::CDBManager::getInstance()->getDbProp(BrickSelectionDB+ ":" + toString(i) + ":SHEET")->setValue32(0);
1293 // ***************************************************************************
1294 void CDBGroupBuildPhrase::filterKnownBricks(std::vector<CSheetId> &bricks)
1296 CSBrickManager *pBM= CSBrickManager::getInstance();
1298 pBM->filterKnownBricks(bricks);
1301 // ***************************************************************************
1302 void CDBGroupBuildPhrase::filterBrickExclusion(std::vector<CSheetId> &bricks, uint16 indexToSkip)
1304 CSBrickManager *pBM= CSBrickManager::getInstance();
1306 std::vector<CSheetId> res;
1307 res.reserve(bricks.size());
1309 static vector<string> forbidWords(30);
1311 // For All optionals/credits setuped, build the Exclude Set
1312 set<string> excludeSet;
1313 // test for all bricks
1314 for(uint j=1/*+_NumMandatories*/;j<1+_NumMandatories+_NumOptionals+_NumCredits;j++)
1316 // skip brick at index indexToSkip (if replacing a brick for example, don't consider it's forbiden flags)
1317 if (j == indexToSkip)
1318 continue;
1320 const CSBrickSheet *brick= _MainWords[j].Slot.Brick->asSBrickSheet();
1321 if(brick)
1323 // get all words.
1324 forbidWords.clear();
1325 splitString(brick->getForbiddenExclude(), ":", forbidWords);
1326 // for all words, insert in the set.
1327 for(uint j=0;j<forbidWords.size();j++)
1328 excludeSet.insert(forbidWords[j]);
1332 // keep only unfiltered ones
1333 for(uint i=0;i<bricks.size();i++)
1335 const CSBrickSheet *brick= pBM->getBrick(bricks[i]);
1336 if(brick)
1338 // For all define words, search if excluded from the current set of optional setup
1339 forbidWords.clear();
1340 splitString(brick->getForbiddenDef(), ":", forbidWords);
1341 bool ok= true;
1342 for(uint j=0;j<forbidWords.size();j++)
1344 if(excludeSet.find(forbidWords[j]) != excludeSet.end() )
1346 ok= false;
1347 break;
1351 // ok , add it
1352 if(ok)
1353 res.push_back(bricks[i]);
1357 // replace with filtered one
1358 bricks= res;
1362 // ***************************************************************************
1363 void CDBGroupBuildPhrase::filterFamilySetuped(std::vector<uint16> &families)
1365 std::vector<uint16> res;
1366 res.reserve(families.size());
1368 // keep only unsetuped ones
1369 for(uint i=0;i<families.size();i++)
1371 uint family= families[i];
1372 bool ok= true;
1374 // test for all opionals/Credits
1375 for(uint j=1+_NumMandatories;j<getNumMainBricks();j++)
1377 const CSBrickSheet *brick= _MainWords[j].Slot.Brick->asSBrickSheet();
1378 if(brick && brick->BrickFamily==(sint)family)
1380 ok= false;
1381 break;
1385 // insert only if not found
1386 if(ok)
1388 res.push_back(family);
1392 // replace with filtered one
1393 families= res;
1396 // ***************************************************************************
1397 void CDBGroupBuildPhrase::filterBrickSetuped(std::vector<NLMISC::CSheetId> &bricks)
1399 std::vector<CSheetId> res;
1400 res.reserve(bricks.size());
1402 // keep only unsetuped ones
1403 for(uint i=0;i<bricks.size();i++)
1405 CSheetId brick= bricks[i];
1406 bool ok= true;
1408 // test for all bricks
1409 for(uint j=1/*+_NumMandatories*/;j<getNumMainBricks();j++)
1411 if(brick == CSheetId(_MainWords[j].Slot.Brick->getSheetId()) )
1413 ok= false;
1414 break;
1418 // insert only if not found
1419 if(ok)
1421 res.push_back(brick);
1425 // replace with filtered one
1426 bricks= res;
1430 // ***************************************************************************
1431 void CDBGroupBuildPhrase::filterSkillSetuped(std::vector<NLMISC::CSheetId> &bricks, bool checkOptional, bool checkCredit, sint avoidCheckIndex)
1433 // check nothing => return.
1434 if(!checkOptional && !checkCredit)
1435 return;
1437 CSBrickManager *pBM= CSBrickManager::getInstance();
1440 // **** build the compatible skill formula for the bricks we want to check
1441 CReqSkillFormula testFormula;
1442 uint checkStart= checkOptional? 1+_NumMandatories : 1+_NumMandatories+_NumOptionals;
1443 uint checkEnd= checkCredit? 1+_NumMandatories+_NumOptionals : getNumMainBricks();
1445 // test for all optionals and/or Credits
1446 uint i;
1447 for(uint i= checkStart;i<checkEnd;i++)
1449 // For Replacement of brick, don't test with the brick replaced (suppose will be removed!)
1450 if(avoidCheckIndex==(sint)i)
1451 continue;
1453 const CSBrickSheet *brick= _MainWords[i].Slot.Brick->asSBrickSheet();
1454 // If bricks use a skill, and with the formula
1455 if(brick && brick->getSkill()!=SKILLS::unknown)
1457 CReqSkillFormula brickFormula;
1458 for(uint j=0;j<brick->UsedSkills.size();j++)
1460 brickFormula.orV(CSkillValue(brick->UsedSkills[j]));
1463 // and with the phraseFormula
1464 testFormula.andV(brickFormula);
1469 // **** check for each brick if compatible with this formula
1470 std::vector<CSheetId> res;
1471 res.reserve(bricks.size());
1473 // keep only unsetuped ones
1474 for(i=0;i<bricks.size();i++)
1476 const CSBrickSheet *brick= pBM->getBrick(bricks[i]);
1477 if(brick && brick->getSkill()!=SKILLS::unknown)
1479 // simulate a choose of this brick, ie AND its skill formula with the current phrase formula
1480 CReqSkillFormula brickFormula;
1481 for(uint j=0;j<brick->UsedSkills.size();j++)
1483 brickFormula.orV(CSkillValue(brick->UsedSkills[j]));
1486 CReqSkillFormula tempFormula= testFormula;
1487 tempFormula.andV(brickFormula);
1489 // Nb: the following test works if testFormula is empty(), because in this case
1490 // tempFormula.and(brickFormula)==brickFormula and hence is of form SFR | SFM | ....
1492 // if one of the ored skill has a size 1 (eg SFR&SFM fails), then it's ok!
1493 // else it's mean that there is no "skill on same branch solution".
1494 bool ok= false;
1495 std::list<CReqSkillFormula::CSkillValueAnd>::iterator it(tempFormula.OrSkills.begin()),
1496 end(tempFormula.OrSkills.end());
1497 for(;it!=end;it++)
1499 CReqSkillFormula::CSkillValueAnd skillAnd= *it;
1500 // ok, there is still one usable skill
1501 if(skillAnd.AndSkills.size()==1)
1503 ok= true;
1504 break;
1508 // insert only if ok
1509 if(ok)
1511 res.push_back(bricks[i]);
1516 // replace with filtered one
1517 bricks= res;
1522 // ***************************************************************************
1523 void CDBGroupBuildPhrase::filterRootBrickType(std::vector<NLMISC::CSheetId> &bricks)
1525 // no filter => ok.
1526 if(_RootBrickTypeFilter[0]==BRICK_TYPE::UNKNOWN)
1527 return;
1529 CSBrickManager *pBM= CSBrickManager::getInstance();
1530 std::vector<CSheetId> res;
1531 res.reserve(bricks.size());
1533 // keep only match ones
1534 for(uint i=0;i<bricks.size();i++)
1536 const CSBrickSheet *brick0= pBM->getBrick(bricks[i]);
1537 if(brick0)
1539 // insert if one filter match (OR)
1540 for(uint j=0;j<MaxRootBrickTypeFilter;j++)
1542 if( _RootBrickTypeFilter[j] != BRICK_TYPE::UNKNOWN &&
1543 _RootBrickTypeFilter[j] == BRICK_FAMILIES::brickType(brick0->BrickFamily) )
1545 res.push_back(bricks[i]);
1546 break;
1552 // replace with filtered one
1553 bricks= res;
1557 // ***************************************************************************
1558 void CDBGroupBuildPhrase::filterRootPossibles(std::vector<NLMISC::CSheetId> &bricks)
1560 CSBrickManager *pBM= CSBrickManager::getInstance();
1561 std::vector<CSheetId> res;
1562 res.reserve(bricks.size());
1564 // keep only match ones
1565 for(uint i=0;i<bricks.size();i++)
1567 const CSBrickSheet *brick0= pBM->getBrick(bricks[i]);
1568 if(brick0)
1570 // insert only if not a proc enchantment
1571 if(!brick0->isProcEnchantment())
1572 res.push_back(bricks[i]);
1576 // replace with filtered one
1577 bricks= res;
1581 // ***************************************************************************
1582 void CDBGroupBuildPhrase::CSlot::reset()
1584 // Must do the test for credits not setuped.
1585 if(Brick && Back)
1587 Brick->setActive(false);
1588 Brick->setSheetId(0);
1589 Back->setActive(false);
1592 // Sheet 0
1593 ViewParamFamilies.clear();
1596 // ***************************************************************************
1597 void CDBGroupBuildPhrase::CWord::resetParams()
1599 for(uint i=0;i<MaxParam;i++)
1600 ParamSlot[i].reset();
1601 // reset numParams to 0
1602 Slot.ViewParamFamilies.clear();
1603 NumTotalParams= 0;
1604 ParamError= false;
1607 // ***************************************************************************
1608 void CDBGroupBuildPhrase::CWord::reset()
1610 Slot.reset();
1611 // reset also all params
1612 resetParams();
1613 // Hide the Cost View
1614 CostView->setActive(false);
1615 CreditView->setActive(false);
1616 InfoView->setActive(false);
1619 // ***************************************************************************
1620 void CDBGroupBuildPhrase::CWord::setBrick(uint32 sheetId)
1622 Slot.Brick->setActive(true);
1623 Slot.Brick->setSheetId(sheetId);
1624 Slot.Back->setActive(true);
1627 // ***************************************************************************
1628 void CDBGroupBuildPhrase::CWord::setParamBrick(uint param, uint32 sheetId)
1630 if(param>=MaxParam)
1631 return;
1633 ParamSlot[param].Brick->setActive(true);
1634 ParamSlot[param].Brick->setSheetId(sheetId);
1635 ParamSlot[param].Back->setActive(true);
1638 // ***************************************************************************
1639 void CDBGroupBuildPhrase::CWord::copySetup(const CWord &w)
1641 // reset me first
1642 reset();
1644 // set the brick
1645 setBrick(w.Slot.Brick->getSheetId());
1646 Slot.Valid= w.Slot.Valid;
1647 Slot.ViewParamFamilies= w.Slot.ViewParamFamilies;
1649 // copy ParamBricks
1650 NumTotalParams= w.NumTotalParams;
1651 ParamError= w.ParamError;
1652 for(uint i=0;i<NumTotalParams;i++)
1654 setParamBrick(i, w.ParamSlot[i].Brick->getSheetId());
1655 ParamSlot[i].Valid= w.ParamSlot[i].Valid;
1656 ParamSlot[i].ViewParamFamilies= w.ParamSlot[i].ViewParamFamilies;
1659 // set the cost
1660 CostView->setText(w.CostView->getText());
1661 CostView->setActive(w.CostView->getActive());
1662 CreditView->setText(w.CreditView->getText());
1663 CreditView->setActive(w.CreditView->getActive());
1664 InfoView->setText(w.InfoView->getText());
1665 InfoView->setActive(w.InfoView->getActive());
1669 // ***************************************************************************
1670 void CDBGroupBuildPhrase::resetSentence(sint32 rootSheetId)
1672 if(!_GroupValid)
1673 return;
1675 uint i;
1677 // first update the root brick
1678 _MainWords[0].setBrick(rootSheetId);
1679 // then update display for others
1680 updateDisplayFromRootBrick();
1682 // get the root brick
1683 const CSBrickSheet *rootBrick= getRootBrick();
1684 if(!rootBrick)
1685 return;
1687 // *** Init Root
1688 // update parameters of the root
1689 updateParams(0);
1691 // *** Init Mandatories
1692 for(i=1;i<1+_NumMandatories;i++)
1694 // get the family Known BitField
1695 uint familyId= rootBrick->MandatoryFamilies[i-1];
1696 sint32 sheet;
1697 bool valid;
1698 getDefaultSheetForFamily(familyId, sheet, valid);
1700 // Setup the ctrl sheet of mandatory to 0 by default!
1701 _MainWords[i].setBrick(0);
1702 _MainWords[i].Slot.Valid= valid;
1704 // set the ctrl sheet display
1705 _MainWords[i].Slot.Brick->setGrayed( !valid );
1707 // update the parameters of this main brick
1708 updateParams(i);
1711 // *** Init Optional/Credits
1712 // ungray all optional slots.
1713 for(i=1+_NumMandatories;i<_MainWords.size();i++)
1715 _MainWords[i].Slot.Brick->setGrayed( false );
1718 // update the NewOp controler
1719 updateNewButtons();
1723 // ***************************************************************************
1724 void CDBGroupBuildPhrase::updateDisplayFromRootBrick()
1726 if(!_GroupValid)
1727 return;
1729 uint i;
1731 // get the root bricks
1732 const CSBrickSheet *brick= getRootBrick();
1734 // Reset the Root params only (don't reset the sheetId setuped!)
1735 _MainWords[0].resetParams();
1737 // Hide all other slots by default
1738 for(i=1;i<_MainWords.size();i++)
1740 _MainWords[i].reset();
1742 _NumMandatories= 0;
1743 _NumOptionals= 0;
1744 _NumCredits= 0;
1746 // if brick not found, or if not enough ctrl, hide all
1747 if(!brick || brick->MandatoryFamilies.size()+1>_MainWords.size() )
1749 // empty sheet
1750 _MainWords[0].Slot.Brick->setSheetId(0);
1752 // else ok, setup the composition
1753 else
1755 _NumMandatories= (uint32)brick->MandatoryFamilies.size();
1756 // Don't enable any optional/credit by default
1757 _NumCredits= 0;
1758 _NumOptionals= 0;
1761 // update the group and sons coords
1762 invalidateCoords();
1765 // ***************************************************************************
1766 void CDBGroupBuildPhrase::buildCurrentPhrase(CSPhraseCom &newPhrase)
1768 /* Word Order: Root/Mandatory/Optional/Credits (with all their params)
1771 // Reset.
1772 newPhrase.Name.clear();
1773 newPhrase.Bricks.clear();
1774 uint i;
1775 const CSBrickSheet *brick;
1777 // Add All bricks with their parameters
1778 for(i=0;i<getNumMainBricks();i++)
1780 CWord &word= _MainWords[i];
1781 brick= word.Slot.Brick->asSBrickSheet();
1782 newPhrase.Bricks.push_back(brick?brick->Id:CSheetId());
1783 // For all its params.
1784 for(uint j=0;j<word.NumTotalParams;j++)
1786 brick= word.ParamSlot[j].Brick->asSBrickSheet();
1787 newPhrase.Bricks.push_back(brick?brick->Id:CSheetId());
1791 // Set the Name
1792 if(_UserSentenceName)
1794 newPhrase.Name= ucstring::makeFromUtf8(_UserSentenceName->getInputString());
1799 // ***************************************************************************
1800 void CDBGroupBuildPhrase::updateNewButtons()
1802 // TODO_BRICK: have I to hide button and their text if not possible to add any op/credit?
1804 /*if(!_NewOpButton)
1805 return;
1807 uint newOpIndex= _NumMandatories+_NumOptionals;
1809 // if some place for a new optional, show and place the NewOpButton
1810 if(newOpIndex<_MandOpWords.size())
1812 // if comes from a delete, ensure the back+1 is hidden
1813 if(newOpIndex+1<_MandOpWords.size())
1815 _MandOpWords[newOpIndex+1].Slot.Back->setActive(false);
1818 // Show a new Optional possibilty ONLY if really possible!!
1819 std::vector<NLMISC::CSheetId> bricks;
1820 fillNewOptionalBricks(bricks);
1821 // if no choice possible
1822 if(bricks.empty())
1824 _NewOpButton->setActive(false);
1826 else
1828 // show the Back under the button
1829 _MandOpWords[newOpIndex].Slot.Back->setActive(true);
1830 // And move the button under it
1831 _NewOpButton->setParentPos(_MandOpWords[newOpIndex].Slot.Back);
1832 _NewOpButton->setActive(true);
1835 else
1837 _NewOpButton->setActive(false);
1840 // retrace all.
1841 invalidateCoords();*/
1844 // ***************************************************************************
1845 void CDBGroupBuildPhrase::updateSpellView()
1847 if(_SpellView)
1849 // Build the current phrase
1850 CSPhraseCom newPhrase;
1851 buildCurrentPhrase(newPhrase);
1853 // Set the edited version to the phrase Manager => auto updated in icon
1854 CSPhraseManager *pPM= CSPhraseManager::getInstance();
1856 // replace the content of the edited phrase.
1857 pPM->setPhrase(CSPhraseManager::EditionSlot, newPhrase);
1862 // ***************************************************************************
1863 void CDBGroupBuildPhrase::fillNewOptionalBricks(std::vector<NLMISC::CSheetId> &bricks)
1865 if(!_GroupValid) return;
1866 const CSBrickSheet *rootBrick= getRootBrick();
1867 if(!rootBrick) return;
1868 CSBrickManager *pBM= CSBrickManager::getInstance();
1870 // get all possible newFamilies
1871 vector<uint16> optionalFamilies;
1872 optionalFamilies= rootBrick->OptionalFamilies;
1873 // Filter ones that already exist in the composition
1874 // Don't filter Combat and Power optional families (Use Brick exclusion system instead)
1875 if( !rootBrick->isCombat() && !rootBrick->isSpecialPower())
1876 filterFamilySetuped(optionalFamilies);
1878 // Select all bricks for those families.
1879 for(uint i=0;i<optionalFamilies.size();i++)
1881 const vector<CSheetId> &famBricks= pBM->getFamilyBricks(optionalFamilies[i]);
1882 bricks.insert(bricks.end(), famBricks.begin(), famBricks.end());
1885 // get only ones known
1886 filterKnownBricks(bricks);
1888 // Combat special
1889 if( rootBrick->isCombat() )
1891 // Ensure not same bricks are setuped
1892 filterBrickSetuped(bricks);
1893 // Ensure only optional of compatible Skill are inserted
1894 filterSkillSetuped(bricks, true, false);
1896 else if ( rootBrick->isSpecialPower() )
1898 // Ensure not same bricks are setuped
1899 filterBrickSetuped(bricks);
1901 // filter by BrickExclusion
1902 filterBrickExclusion(bricks);
1905 // ***************************************************************************
1906 void CDBGroupBuildPhrase::fillNewCreditBricks(std::vector<NLMISC::CSheetId> &bricks)
1908 if(!_GroupValid) return;
1909 const CSBrickSheet *rootBrick= getRootBrick();
1910 if(!rootBrick) return;
1911 CSBrickManager *pBM= CSBrickManager::getInstance();
1913 // get all possible newFamilies
1914 vector<uint16> creditFamilies;
1915 creditFamilies= rootBrick->CreditFamilies;
1916 // Filter ones that already exist in the composition
1917 filterFamilySetuped(creditFamilies);
1919 // Select all bricks for those families.
1920 for(uint i=0;i<creditFamilies.size();i++)
1922 const vector<CSheetId> &famBricks= pBM->getFamilyBricks(creditFamilies[i]);
1923 bricks.insert(bricks.end(), famBricks.begin(), famBricks.end());
1926 // get only ones known
1927 filterKnownBricks(bricks);
1929 // filter by BrickExclusion
1930 filterBrickExclusion(bricks);
1934 // ***************************************************************************
1935 void CDBGroupBuildPhrase::setRootBrickTypeFilter(BRICK_TYPE::EBrickType rootBtFilter,
1936 BRICK_TYPE::EBrickType rootBtFilter2, BRICK_TYPE::EBrickType rootBtFilter3, BRICK_TYPE::EBrickType rootBtFilter4)
1938 nlctassert(MaxRootBrickTypeFilter==4);
1939 _RootBrickTypeFilter[0]= rootBtFilter;
1940 _RootBrickTypeFilter[1]= rootBtFilter2;
1941 _RootBrickTypeFilter[2]= rootBtFilter3;
1942 _RootBrickTypeFilter[3]= rootBtFilter4;