// Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include "stdpch.h" #include "action_handler.h" #include "../motion/user_controls.h" #include "../view.h" #include "../misc.h" #include "../input.h" #include "../client_cfg.h" #include "../actions_client.h" #include "../sheet_manager.h" #include "interface_manager.h" #include "dbctrl_sheet.h" #include "dbgroup_build_phrase.h" #include "group_container.h" #include "sphrase_manager.h" #include "sbrick_manager.h" #include "ctrl_button.h" #include "../user_entity.h" #include "skill_manager.h" #include "inventory_manager.h" #include "game_share/memorization_set_types.h" #include "action_handler_help.h" #include "bot_chat_page_all.h" #include "bot_chat_page_trade.h" #include "../net_manager.h" #include "../entities.h" #include "macrocmd_manager.h" #include "group_menu.h" #include "nel/misc/algo.h" #include "group_tree.h" extern CSheetManager SheetMngr; using namespace std; using namespace NLMISC; // *************************************************************************** void launchPhraseComposition(bool creation); const std::string PhraseComposition="ui:interface:phrase_composition"; const std::string PhraseCompositionGroup="ui:interface:phrase_composition:header_opened"; const std::string PhraseMemoryCtrlBase= "ui:interface:gestionsets:shortcuts:s"; // ********************************************************************************************************** // debug update the action bar void debugUpdateActionBar() { CInterfaceManager *pIM= CInterfaceManager::getInstance(); pIM->getDbProp("SERVER:USER:ACT_TSTART")->setValue64(NetMngr.getCurrentServerTick()); pIM->getDbProp("SERVER:USER:ACT_TEND")->setValue64(NetMngr.getCurrentServerTick()+30); } // *************************************************************************** // *************************************************************************** // *************************************************************************** // PHRASE BOOK EDITION // *************************************************************************** // *************************************************************************** // *************************************************************************** // *************************************************************************** class CHandlerPhraseEdit : public IActionHandler { public: virtual void execute(CCtrlBase *pCaller, const string &/* Params */) { CDBCtrlSheet *pCSDst = dynamic_cast(pCaller); if (pCSDst == NULL || !pCSDst->isSPhraseId()) return; // get the phrase id. sint32 id= pCSDst->getSPhraseId(); // Nb: Yoyo: this slot can come from eiter the Action Book, or the Memorized sentence // set the phrase to edit CSPhraseManager *pPM= CSPhraseManager::getInstance(); pPM->CompositionPhraseId= id; pPM->CompositionPhraseMemoryLineDest= -1; pPM->CompositionPhraseMemorySlotDest= -1; // Launch the composition window launchPhraseComposition(false); } }; REGISTER_ACTION_HANDLER( CHandlerPhraseEdit, "phrase_edit" ); // *************************************************************************** class CHandlerPhraseNew : public IActionHandler { public: virtual void execute(CCtrlBase *pCaller, const string &/* Params */) { // Get A free slot to edit (not allocated). CSPhraseManager *pPM= CSPhraseManager::getInstance(); // if possible if(pPM->hasFreeSlot()) { // Set the phrase to edit to 0, to indicate a new phrase. CANNOT "ALLOCATE" THE ID NOW, else may // crash if buy a botchatphrase, while editing a new phrase!!!! pPM->CompositionPhraseId= 0; // If the caller is ctrl sheet (may be a standard button else), and if comes from memory CDBCtrlSheet *pCSDst= dynamic_cast(pCaller); if(pCSDst && pCSDst->isSPhraseId() && pCSDst->isSPhraseIdMemory()) { // then will auto-memorize it in this slot pPM->CompositionPhraseMemoryLineDest= pPM->getSelectedMemoryLineDB(); pPM->CompositionPhraseMemorySlotDest= pCSDst->getIndexInDB(); } // else no auto memorize else { pPM->CompositionPhraseMemoryLineDest= -1; pPM->CompositionPhraseMemorySlotDest= -1; } // Launch the composition window launchPhraseComposition(true); } } }; REGISTER_ACTION_HANDLER( CHandlerPhraseNew, "phrase_new" ); // *************************************************************************** class CHandlerPhraseValidate : public IActionHandler { public: virtual void execute(CCtrlBase *pCaller, const string &/* Params */) { // NB: The user can validate only if the server was OK. // get our father build sentence CInterfaceGroup *parent = pCaller->getParent(); if (parent) { CSPhraseManager *pPM= CSPhraseManager::getInstance(); CDBGroupBuildPhrase *buildGroup= dynamic_cast(parent->getParent()); if(!buildGroup) return; // is this an action creation or action edition? bool actionCreation= pPM->CompositionPhraseId==0; // For a new created phrase, the CompositionPhraseId is 0, allocate it now if(!pPM->CompositionPhraseId) { pPM->CompositionPhraseId= pPM->allocatePhraseSlot(); // fail? if(!pPM->CompositionPhraseId) return; } // build the edited phrase CSPhraseCom newPhrase; buildGroup->buildCurrentPhrase(newPhrase); // the new slot of the phrase uint32 slotId= pPM->CompositionPhraseId; // Action Creation case. if(actionCreation) { // Append in the Phrase Manager. pPM->setPhrase(slotId, newPhrase); // inform the server of our book change, with the edited name pPM->sendLearnToServer(slotId); // if this action creation requires an auto "memorize in slot" sint32 memoryLine= pPM->CompositionPhraseMemoryLineDest; sint32 memorySlot= pPM->CompositionPhraseMemorySlotDest; if( memoryLine>=0 && memorySlot>=0 && memorySlotmemorizePhrase(memoryLine, memorySlot, slotId); pPM->sendMemorizeToServer(memoryLine, memorySlot, slotId); } } // Action edition case else { // Replace in the Phrase Manager. pPM->setPhrase(slotId, newPhrase); // inform the server of our book change, with the edited name pPM->sendLearnToServer(slotId); // Then, auto-re_memorize all after, changing Ctrl Gray States if needed, and sending msg to server pPM->rememorizeAllThatUsePhrase(slotId); } // Close the Composition Window pCaller->getRootWindow()->setActive(false); } } }; REGISTER_ACTION_HANDLER( CHandlerPhraseValidate, "phrase_validate" ); // *************************************************************************** class CHandlerPhraseValidateOnEnter : public IActionHandler { public: virtual void execute(CCtrlBase *pCaller, const string &/* Params */) { // Test if the OK control is valid. CGroupContainer *pGC= dynamic_cast(pCaller); if(!pGC) return; if(!pGC->getHeaderOpened()) return; CDBGroupBuildPhrase *buildPhrase= dynamic_cast(pGC->getHeaderOpened()); if(!buildPhrase) return; CCtrlBaseButton *button= buildPhrase->getValidateButton(); // Ok, button found. test if active and not frozen. if( button && button->getActive() && !button->getFrozen() ) { // Act as if the player click on this button CInterfaceManager *pIM = CInterfaceManager::getInstance(); pIM->runActionHandler(button->getActionOnLeftClick(), button, button->getParamsOnLeftClick() ); } } }; REGISTER_ACTION_HANDLER( CHandlerPhraseValidateOnEnter, "phrase_validate_on_enter"); // *************************************************************************** void launchPhraseComposition(bool creation) { CInterfaceManager *pIM= CInterfaceManager::getInstance(); // Launch the composition window CGroupContainer *window= dynamic_cast( pIM->getElementFromId(PhraseComposition) ); if(window) { CDBGroupBuildPhrase *buildSentenceTarget= dynamic_cast( pIM->getElementFromId(PhraseCompositionGroup) ); // if found if(buildSentenceTarget) { // enable the window window->setActive(true); // Set the Text of the Window if(creation) window->setUCTitle(CI18N::get("uiPhraseCreate")); else window->setUCTitle(CI18N::get("uiPhraseEdit")); // clear the sentence for a New Phrase creation. buildSentenceTarget->clearBuildingPhrase(); // copy phrase to edit CSPhraseManager *pPM= CSPhraseManager::getInstance(); // get the edited (or empty if new) phrase. const CSPhraseCom &phrase= pPM->getPhrase(pPM->CompositionPhraseId); // Start the composition buildSentenceTarget->startComposition(phrase); /** if edition, avoid changing the root type, it behaves better */ // Default, no filter (important for creation) if(creation) { // all root are possible => no filter buildSentenceTarget->setRootBrickTypeFilter(BRICK_TYPE::UNKNOWN); } // if edition else { if(phrase.empty()) { buildSentenceTarget->setRootBrickTypeFilter(BRICK_TYPE::UNKNOWN); } else { CSBrickManager *pBM= CSBrickManager::getInstance(); const CSBrickSheet *rootBrick= pBM->getBrick(phrase.Bricks[0]); // can select only bricks of the same type if(rootBrick) buildSentenceTarget->setRootBrickTypeFilter(BRICK_FAMILIES::brickType(rootBrick->BrickFamily)); // maybe data error: filter nothing else buildSentenceTarget->setRootBrickTypeFilter(BRICK_TYPE::UNKNOWN); } } } } } // *************************************************************************** // *************************************************************************** // *************************************************************************** // PHRASE COMPOSITION // *************************************************************************** // *************************************************************************** // *************************************************************************** // ********************************************************************************************************** /** Called when the user select a brick from the list of possible bricks */ class CHandlerPhraseValidateBrick : public IActionHandler { public: virtual void execute(CCtrlBase *pCaller, const string &/* Params */) { CInterfaceManager *pIM = CInterfaceManager::getInstance(); CDBCtrlSheet *pCSSrc = dynamic_cast(pCaller); if(!pCSSrc || !pCSSrc->isSBrick()) return; // get the selected brick const CSBrickSheet *brick= pCSSrc->asSBrickSheet(); if(brick==NULL) return; // and validate the composition // Standard Case: selection for action composition if(BrickType != FaberPlan) { nlassert(BuildPhraseGroup); switch(BrickType) { case Root: BuildPhraseGroup->validateRoot(brick); break; case OtherMain: BuildPhraseGroup->validateMain(Index, brick); break; case Param: BuildPhraseGroup->validateParam(Index, ParamIndex, brick); break; case NewOpCredit: BuildPhraseGroup->validateNewOpCredit(brick); break; default: break; } } // Special Case: selection for faber plan else { extern void validateFaberPlanSelection(CSBrickSheet *itemPlanBrick); validateFaberPlanSelection(const_cast(brick)); } // And hide the modal pIM->disableModalWindow(); } public: enum TType {Root, OtherMain, Param, NewOpCredit, FaberPlan}; static TType BrickType; static uint Index; static uint ParamIndex; static CDBGroupBuildPhrase *BuildPhraseGroup; }; REGISTER_ACTION_HANDLER( CHandlerPhraseValidateBrick, "phrase_validate_brick" ); CHandlerPhraseValidateBrick::TType CHandlerPhraseValidateBrick::BrickType; uint CHandlerPhraseValidateBrick::Index; uint CHandlerPhraseValidateBrick::ParamIndex; CDBGroupBuildPhrase *CHandlerPhraseValidateBrick::BuildPhraseGroup= NULL; // *************************************************************************** class CHandlerPhraseSelectMainBrick : public IActionHandler { public: virtual void execute(CCtrlBase *pCaller, const string &Params) { CInterfaceManager *pIM= CInterfaceManager::getInstance(); // get the type and index in the current build sentence uint index; fromString(getParam(Params, "index"), index); CHandlerPhraseValidateBrick::Index= index; if(index==0) CHandlerPhraseValidateBrick::BrickType= CHandlerPhraseValidateBrick::Root; else CHandlerPhraseValidateBrick::BrickType= CHandlerPhraseValidateBrick::OtherMain; // get our father build sentence CDBGroupBuildPhrase *buildGroup= dynamic_cast(pCaller->getParent()->getParent()); if(!buildGroup) return; // setup the validation CHandlerPhraseValidateBrick::BuildPhraseGroup= buildGroup; // build the list of possible bricks if(index==0) buildGroup->fillSelectionRoot(); else buildGroup->fillSelectionMain(index); // launch the modal CInterfaceGroup *group= dynamic_cast( pIM->getElementFromId( CDBGroupBuildPhrase::BrickSelectionModal ) ); if(group) { // enable the modal pIM->enableModalWindow(pCaller, group); } } }; REGISTER_ACTION_HANDLER( CHandlerPhraseSelectMainBrick, "phrase_select_main_brick" ); // *************************************************************************** class CHandlerPhraseSelectParamBrick : public IActionHandler { public: virtual void execute(CCtrlBase *pCaller, const string &Params) { CInterfaceManager *pIM= CInterfaceManager::getInstance(); // get the type and index in the current build sentence CHandlerPhraseValidateBrick::BrickType= CHandlerPhraseValidateBrick::Param; uint index, paramIndex; fromString(getParam(Params, "index"), index); CHandlerPhraseValidateBrick::Index= index; fromString(getParam(Params, "param_index"), paramIndex); CHandlerPhraseValidateBrick::ParamIndex= paramIndex; // get our father build sentence CDBGroupBuildPhrase *buildGroup= dynamic_cast(pCaller->getParent()->getParent()); if(!buildGroup) return; // setup the validation CHandlerPhraseValidateBrick::BuildPhraseGroup= buildGroup; // build the list of possible bricks buildGroup->fillSelectionParam(index, paramIndex); // launch the modal CInterfaceGroup *group= dynamic_cast( pIM->getElementFromId( CDBGroupBuildPhrase::BrickSelectionModal ) ); if(group) { // enable the modal pIM->enableModalWindow(pCaller, group); } } }; REGISTER_ACTION_HANDLER( CHandlerPhraseSelectParamBrick, "phrase_select_param_brick" ); // *************************************************************************** class CHandlerPhraseSelectNewBrick : public IActionHandler { public: virtual void execute(CCtrlBase *pCaller, const string &Params) { CInterfaceManager *pIM= CInterfaceManager::getInstance(); // get the type and index in the current build sentence CHandlerPhraseValidateBrick::BrickType= CHandlerPhraseValidateBrick::NewOpCredit; string typeStr= getParam(Params, "type"); // get our father build sentence CDBGroupBuildPhrase *buildGroup= dynamic_cast(pCaller->getParent()->getParent()); if(!buildGroup) return; // setup the validation CHandlerPhraseValidateBrick::BuildPhraseGroup= buildGroup; // build the list of possible bricks if(typeStr=="optional") buildGroup->fillSelectionNewOp(); else if(typeStr=="credit") buildGroup->fillSelectionNewCredit(); // launch the modal CInterfaceGroup *group= dynamic_cast( pIM->getElementFromId( CDBGroupBuildPhrase::BrickSelectionModal ) ); if(group) { // enable the modal pIM->enableModalWindow(pCaller, group); } } }; REGISTER_ACTION_HANDLER( CHandlerPhraseSelectNewBrick, "phrase_select_new_brick" ); // *************************************************************************** class CHandlerPhraseChangeName : public IActionHandler { public: virtual void execute(CCtrlBase *pCaller, const string &/* Params */) { // The BuildPhrase should be the grandParent CDBGroupBuildPhrase *buildPhrase= dynamic_cast(pCaller->getParent()->getParent()); if(!buildPhrase) return; // update the edited icon buildPhrase->updateSpellView(); } }; REGISTER_ACTION_HANDLER( CHandlerPhraseChangeName, "phrase_change_name"); // *************************************************************************** /* * Special For Faber Plan selection */ class CHandlerPhraseFaberSelectPlan : public IActionHandler { public: virtual void execute(CCtrlBase *pCaller, const string &/* Params */) { CInterfaceManager *pIM= CInterfaceManager::getInstance(); // Launch the modal to select the faber plan extern void fillFaberPlanSelection(const std::string &brickDB, uint maxSelection); fillFaberPlanSelection(CDBGroupBuildPhrase::BrickSelectionDB, CDBGroupBuildPhrase::MaxSelection); // setup the validation CHandlerPhraseValidateBrick::BuildPhraseGroup= NULL; CHandlerPhraseValidateBrick::BrickType= CHandlerPhraseValidateBrick::FaberPlan; // launch the modal CInterfaceGroup *group= dynamic_cast( pIM->getElementFromId( CDBGroupBuildPhrase::BrickSelectionModal ) ); if(group) { // enable the modal pIM->enableModalWindow(pCaller, group); } } }; REGISTER_ACTION_HANDLER( CHandlerPhraseFaberSelectPlan, "phrase_faber_select_plan" ); // *************************************************************************** // *************************************************************************** // *************************************************************************** // PHRASE MEMORISATION / EXECUTION / MISC // *************************************************************************** // *************************************************************************** // *************************************************************************** // *************************************************************************** static void updateAllSPhraseInfo() { CInterfaceManager *pIM= CInterfaceManager::getInstance(); // update all info windows CInterfaceHelp::updateWindowSPhraseTexts(); // If the composition is opened, refresh CInterfaceGroup *pIG= dynamic_cast(pIM->getElementFromId("ui:interface:phrase_composition")); if(pIG && pIG->getActive()) { CDBGroupBuildPhrase *buildPhrase= dynamic_cast(pIG->getGroup("header_opened")); if(buildPhrase) buildPhrase->updateAllDisplay(); } // update bot chat if(BotChatPageAll && BotChatPageAll->Trade) BotChatPageAll->Trade->updateSPhraseBuyDialog(); } // ********************************************************************************************************** /** Called when the Item in Right Hand change */ class CHandlerPhraseUpdateFromHand : public IActionHandler { public: virtual void execute (CCtrlBase * /* pCaller */, const string &/* Params */) { CSPhraseManager *pPM = CSPhraseManager::getInstance(); // **** Update the grayed state of all memory ctrls pPM->updateAllMemoryCtrlState(); // **** Update misc Action Infos related to items weared updateAllSPhraseInfo(); } }; REGISTER_ACTION_HANDLER (CHandlerPhraseUpdateFromHand, "phrase_update_from_hand"); // ********************************************************************************************************** /** Called when the Item in equip change (Action Malus due to armor) */ class CHandlerPhraseUpdateFromActionMalus : public IActionHandler { public: virtual void execute (CCtrlBase * /* pCaller */, const string &/* Params */) { // **** Update misc Action Infos related to items weared updateAllSPhraseInfo(); } }; REGISTER_ACTION_HANDLER(CHandlerPhraseUpdateFromActionMalus, "phrase_update_from_action_malus"); // ********************************************************************************************************** /** drag'n'drop: cannot drag PhraseSheet that are not castable */ class CHandlerCanDragPhrase : public IActionHandler { public: virtual void execute (CCtrlBase *pCaller, const string &/* Params */) { CSPhraseManager *pPM= CSPhraseManager::getInstance(); CDBCtrlSheet *pCSSrc = dynamic_cast(pCaller); if(!pCSSrc || !pCSSrc->isSPhrase()) return; // can drag only if memorizable pCSSrc->setTempCanDrag(pPM->isPhraseCastable(pCSSrc->getSheetId())); } }; REGISTER_ACTION_HANDLER (CHandlerCanDragPhrase, "phrase_can_drag_castable"); // ********************************************************************************************************** /** drag'n'drop: true if the src ctrlSheet is a Phrase and the dest is in memory. Or if both are in memory */ class CHandlerCanMemorizePhraseOrMacro : public IActionHandler { public: virtual void execute (CCtrlBase *pCaller, const string &Params) { CInterfaceManager *pIM = CInterfaceManager::getInstance(); CSPhraseManager *pPM = CSPhraseManager::getInstance(); CSBrickManager *pBM = CSBrickManager::getInstance(); CMacroCmdManager *pMM = CMacroCmdManager::getInstance(); string src = getParam(Params, "src"); CInterfaceElement *pElt = pIM->getElementFromId(src); CDBCtrlSheet *pCSSrc = dynamic_cast(pElt); CDBCtrlSheet *pCSDst = dynamic_cast(pCaller); // can be a phrase id (comes from memory), a phraseSheet (comes from progression), or a macro, if (pCSSrc->isSPhraseId() || pCSSrc->isMacro() || pCSSrc->isSPhrase()) if (pCSDst->isSPhraseId() || pCSDst->isMacro()) { // check if incoming phrase ok if(pCSSrc->isSPhraseId()) { // get the src phrase. const CSPhraseCom &phrase= pPM->getPhrase(pCSSrc->getSPhraseId()); if(!phrase.empty()) { // Get the RootBrick of the Phrase CSBrickSheet *brick= pBM->getBrick(phrase.Bricks[0]); if(brick) pCSDst->setCanDrop (true); } } // can be a phrase sheet else if(pCSSrc->isSPhrase()) { CSPhraseSheet *phrase= dynamic_cast(SheetMngr.get(NLMISC::CSheetId(pCSSrc->getSheetId()))); if(phrase && !phrase->Bricks.empty()) { // Get the RootBrick of the Phrase CSBrickSheet *brick= pBM->getBrick(phrase->Bricks[0]); if(brick) pCSDst->setCanDrop (true); } } // check if incoming macro ok else { // get the macro const CMacroCmd *macroCmd= pMM->getMacroFromMacroID(pCSSrc->getMacroId()); if(macroCmd) pCSDst->setCanDrop(true); } } } }; REGISTER_ACTION_HANDLER (CHandlerCanMemorizePhraseOrMacro, "can_memorize_phrase_or_macro"); class CHandlerPhraseMemoryCopy : public IActionHandler { public: static bool haveLastPhraseElement; static bool isMacro; static sint32 sPhraseId; static sint32 macroId; virtual void execute(CCtrlBase *pCaller, const string &Params) { CDBCtrlSheet *ctrl= dynamic_cast(pCaller); if(ctrl && ctrl->isSPhraseIdMemory()) { haveLastPhraseElement = true; isMacro = ctrl->isMacro(); sPhraseId = ctrl->getSPhraseId(); macroId = ctrl->getMacroId(); string mode = getParam(Params, "mode"); //default mode is copy if (mode == "cut") //need delete src { CInterfaceManager::getInstance()->runActionHandler("forget_phrase_or_macro", ctrl); } } } }; REGISTER_ACTION_HANDLER( CHandlerPhraseMemoryCopy, "phrase_memory_copy"); bool CHandlerPhraseMemoryCopy::haveLastPhraseElement = false; bool CHandlerPhraseMemoryCopy::isMacro = false; sint32 CHandlerPhraseMemoryCopy::sPhraseId = 0; sint32 CHandlerPhraseMemoryCopy::macroId = 0; // ********************************************************************************************************** // debug update the action bar extern void debugUpdateActionBar(); // ********************************************************************************************************** /** Memorize a combat Brick into a Memory slot. * Called when the user drop a combat brick on a spell slot. */ class CHandlerMemorizePhraseOrMacro : public IActionHandler { public: virtual void execute (CCtrlBase *pCaller, const string &Params); void memorizePhraseOrMacro(uint dstMemoryIndex, bool isMacro, sint32 phraseId, sint32 macroId); void memorizePhraseSheet(uint dstMemoryIndex, uint32 sheetId); }; REGISTER_ACTION_HANDLER( CHandlerMemorizePhraseOrMacro, "memorize_phrase_or_macro"); void CHandlerMemorizePhraseOrMacro::execute (CCtrlBase *pCaller, const string &Params) { CInterfaceManager *pIM = CInterfaceManager::getInstance(); CSPhraseManager *pPM = CSPhraseManager::getInstance(); string src = getParam(Params, "src"); CDBCtrlSheet *pCSSrc; CDBCtrlSheet *pCSDst = dynamic_cast(pCaller); // NB: THIS IS UGLY BUT WORKS BECAUSE Memory ctrls are first initialized as SPhrase (branchname init) // type check if (pCSDst == NULL) return; // The dest must be a memory or a macro memory if (!pCSDst->isSPhraseIdMemory() && !pCSDst->isMacroMemory()) return; // get the memory line and memory index sint32 dstMemoryLine= pPM->getSelectedMemoryLineDB(); uint dstMemoryIndex= pCSDst->getIndexInDB(); bool srcIsMacro; sint32 srcPhraseId; sint32 srcMacroId; bool dstIsMacro= pCSDst->isMacro(); sint32 dstPhraseId= pCSDst->getSPhraseId(); sint32 dstMacroId= pCSDst->getMacroId(); if ((src == "") && (CHandlerPhraseMemoryCopy::haveLastPhraseElement)) { // get the slot ids from save srcIsMacro= CHandlerPhraseMemoryCopy::isMacro; srcPhraseId= CHandlerPhraseMemoryCopy::sPhraseId; srcMacroId= CHandlerPhraseMemoryCopy::macroId; // if a phrase if(!srcIsMacro) { // \toto yoyo: There is a Network BUG which prevents us from simply doing {Forget(),Delete()} Old phrase, // then {Learn(),Memorize()} new one (Messages are shuffled). // Instead, replace the old phrase if needed uint16 newPhraseId= (uint16)pPM->getMemorizedPhraseIfLastOrNewSlot(dstMemoryLine, dstMemoryIndex); if(!newPhraseId) return; // set it, copy from srcPhraseId pPM->setPhrase(newPhraseId, pPM->getPhrase(srcPhraseId)); // send learn to server pPM->sendLearnToServer(newPhraseId); // memorize the new phrase memorizePhraseOrMacro(dstMemoryIndex, srcIsMacro, newPhraseId, srcMacroId); } } else { CInterfaceElement *pElt = pIM->getElementFromId(src); pCSSrc = dynamic_cast(pElt); // type check if (pCSSrc == NULL) return; // The src must be a phraseid, a phrasesheet, or a macro droped if (!pCSSrc->isSPhraseId() && !pCSSrc->isSPhrase() && !pCSSrc->isMacro()) return; // get the slot ids. srcIsMacro= pCSSrc->isMacro(); srcPhraseId= pCSSrc->getSPhraseId(); srcMacroId= pCSSrc->getMacroId(); // If the src comes not from a memory if(!pCSSrc->isSPhraseIdMemory() && !pCSSrc->isMacroMemory()) { // if the src is a phrase sheet if(pCSSrc->isSPhrase()) { // learn and memorize this phrase memorizePhraseSheet(dstMemoryIndex, pCSSrc->getSheetId()); } else { // We may replace a phrase with a macro => must delete the phrase under us if(srcIsMacro) pPM->fullDeletePhraseIfLast(dstMemoryLine, dstMemoryIndex); // memorize the phrase or macro memorizePhraseOrMacro(dstMemoryIndex, srcIsMacro, srcPhraseId, srcMacroId); } } // Else the src is a memory too else { // if Drag copy => this is a copy! if(pCSSrc->canDragCopy() && pIM->testDragCopyKey()) { // if a phrase if(!srcIsMacro) { // \toto yoyo: There is a Network BUG which prevents us from simply doing {Forget(),Delete()} Old phrase, // then {Learn(),Memorize()} new one (Messages are shuffled). // Instead, replace the old phrase if needed uint16 newPhraseId= (uint16)pPM->getMemorizedPhraseIfLastOrNewSlot(dstMemoryLine, dstMemoryIndex); if(!newPhraseId) return; // set it, copy from srcPhraseId pPM->setPhrase(newPhraseId, pPM->getPhrase(srcPhraseId)); // send learn to server pPM->sendLearnToServer(newPhraseId); // memorize the new phrase memorizePhraseOrMacro(dstMemoryIndex, srcIsMacro, newPhraseId, srcMacroId); } else { // We may replace a phrase with a macro => must delete the phrase under us pPM->fullDeletePhraseIfLast(dstMemoryLine, dstMemoryIndex); // memorize the macro (still a reference) memorizePhraseOrMacro(dstMemoryIndex, srcIsMacro, srcPhraseId, srcMacroId); } } // else this is a swap! else { // if the dest exist, swap if(dstPhraseId || dstIsMacro) { // get the memory index for src uint srcMemoryIndex= pCSSrc->getIndexInDB(); // memorize dst into src memorizePhraseOrMacro(srcMemoryIndex, dstIsMacro, dstPhraseId, dstMacroId); // memorize src into dst memorizePhraseOrMacro(dstMemoryIndex, srcIsMacro, srcPhraseId, srcMacroId); } // else, it's a move else { // copy memorizePhraseOrMacro(dstMemoryIndex, srcIsMacro, srcPhraseId, srcMacroId); // forget src (after shorctut change!) pIM->runActionHandler("forget_phrase_or_macro", pCSSrc); } } } } } // memorize a spell void CHandlerMemorizePhraseOrMacro::memorizePhraseOrMacro(uint memoryIndex, bool isMacro, sint32 phraseId, sint32 macroId) { CSPhraseManager *pPM= CSPhraseManager::getInstance(); sint32 memoryLine= pPM->getSelectedMemoryLineDB(); if(memoryLine<0) return; if(isMacro) { pPM->memorizeMacro(memoryLine, memoryIndex, macroId); } else { // memorize in local pPM->memorizePhrase(memoryLine, memoryIndex, phraseId); // Send the Server msg pPM->sendMemorizeToServer(memoryLine, memoryIndex, phraseId); } } // memorize a default spell void CHandlerMemorizePhraseOrMacro::memorizePhraseSheet(uint memoryIndex, uint32 sheetId) { CSPhraseManager *pPM= CSPhraseManager::getInstance(); sint32 memoryLine= pPM->getSelectedMemoryLineDB(); if(memoryLine<0) return; // this should have been checked in CanDrag if(!pPM->isPhraseCastable(sheetId)) return; // build the com phrase CSPhraseCom phraseCom; pPM->buildPhraseFromSheet(phraseCom, sheetId); if(phraseCom.empty()) return; // **** first learn this phrase // \toto yoyo: There is a Network BUG which prevents us from simply doing {Forget(),Delete()} Old phrase, // then {Learn(),Memorize()} new one (Messages are shuffled). // Instead, replace the old phrase if needed uint16 newPhraseId= (uint16)pPM->getMemorizedPhraseIfLastOrNewSlot(memoryLine, memoryIndex); if(!newPhraseId) return; // set it pPM->setPhrase(newPhraseId, phraseCom); // send learn to server pPM->sendLearnToServer(newPhraseId); // **** memorize // memorize in local pPM->memorizePhrase(memoryLine, memoryIndex, newPhraseId); // Send the Server msg pPM->sendMemorizeToServer(memoryLine, memoryIndex, newPhraseId); } // ********************************************************************************************************** /** Forget a Phrase from a Memory slot * Called when the user choose to free a spell memory slot */ class CHandlerForgetPhraseOrMacro : public IActionHandler { public: virtual void execute (CCtrlBase *pCaller, const string &/* Params */) { CSPhraseManager *pPM = CSPhraseManager::getInstance(); CDBCtrlSheet *pCSDst = dynamic_cast(pCaller); if (pCSDst == NULL) return; if (!pCSDst->isSPhraseIdMemory() && !pCSDst->isMacroMemory()) return; // Ok, the user try to forget a phrase slot. sint32 memoryLine= pPM->getSelectedMemoryLineDB(); if(memoryLine<0) return; // get the memory index uint memoryIndex= pCSDst->getIndexInDB(); if(pCSDst->isMacro()) { pPM->forgetMacro(memoryLine, memoryIndex); } else { // forget in local. pPM->forgetPhrase(memoryLine, memoryIndex); // Server com. pPM->sendForgetToServer(memoryLine, memoryIndex); } } }; REGISTER_ACTION_HANDLER( CHandlerForgetPhraseOrMacro, "forget_phrase_or_macro"); // ********************************************************************************************************** /** Forget a Phrase from a Memory slot * Called when the user choose to free a spell memory slot */ class CHandlerDeletePhraseOrForgetMacro : public IActionHandler { public: virtual void execute (CCtrlBase *pCaller, const string & Params) { CDBCtrlSheet *pCSDst = dynamic_cast(pCaller); if (pCSDst == NULL) return; if (!pCSDst->isSPhraseIdMemory() && !pCSDst->isMacroMemory()) return; // get the memory index uint memoryIndex = pCSDst->getIndexInDB(); bool isMacro = pCSDst->isMacro(); sint32 phraseId = pCSDst->getSPhraseId(); // build params string string sParams; sParams.append("memoryIndex="); sParams.append(toString(memoryIndex)); sParams.append("|isMacro="); sParams.append(toString(isMacro)); sParams.append("|phraseId="); sParams.append(toString(phraseId)); if (!Params.empty()) { sParams.append("|"); sParams.append(Params); } // Ask if ok before CInterfaceManager *pIM = CInterfaceManager::getInstance(); pIM->validMessageBox(CInterfaceManager::QuestionIconMsg, CI18N::get("uiQDeleteAction"), "do_delete_phrase_or_forget_macro", sParams); } }; REGISTER_ACTION_HANDLER( CHandlerDeletePhraseOrForgetMacro, "delete_phrase_or_forget_macro"); // ********************************************************************************************************** /** Forget a Phrase from a Memory slot * Called when the user confirmed that he want to free a spell memory slot */ class CHandlerDoDeletePhraseOrForgetMacro : public IActionHandler { public: virtual void execute (CCtrlBase *pCaller, const string &Params) { // Ok, the user try to forget a phrase slot CSPhraseManager *pPM = CSPhraseManager::getInstance(); sint32 memoryLine = pPM->getSelectedMemoryLineDB(); if (memoryLine<0) return; // get params uint memoryIndex; fromString(getParam(Params, "memoryIndex"), memoryIndex); bool isMacro; fromString(getParam(Params, "isMacro"),isMacro); sint32 phraseId; fromString(getParam(Params, "phraseId"),phraseId); if (isMacro) { pPM->forgetMacro(memoryLine, memoryIndex); } else { // do all the thing to delete properly this phrase pPM->fullDelete(phraseId); } } }; REGISTER_ACTION_HANDLER( CHandlerDoDeletePhraseOrForgetMacro, "do_delete_phrase_or_forget_macro"); // ********************************************************************************************************** /** Cast a spell from a memory slot (combat or magic) * Called when the user click on a memory slot. Can be called also from CAHRunShortcut, or from * MoveToAction system (in CSPhraseManager) */ class CHandlerCastPhrase : public IActionHandler { public: static sint64 LastHitTime; static sint LastIndex; public: virtual void execute (CCtrlBase *pCaller, const string &/* Params */) { CInterfaceManager *pIM = CInterfaceManager::getInstance(); CSPhraseManager *pPM = CSPhraseManager::getInstance(); CSBrickManager *pBM= CSBrickManager::getInstance(); CDBCtrlSheet *pCSDst = dynamic_cast(pCaller); if (pCSDst == NULL) return; if (!pCSDst->isSPhraseIdMemory()) return; // Can cast only if not Latent (ie grayed) !! if (pCSDst->getGrayed()) return; // Ok, the user try to cast a phrase slot. sint32 memoryLine= pPM->getSelectedMemoryLineDB(); if(memoryLine<0) return; // get the memory index uint memoryIndex= pCSDst->getIndexInDB(); // Check If the phrase exist sint phraseId= pCSDst->getSPhraseId(); if(!phraseId) return; const CSPhraseCom &phraseCom= pPM->getPhrase(phraseId); if(phraseCom.empty()) return; CSBrickSheet *rootBrick= pBM->getBrick(phraseCom.Bricks[0]); if(!rootBrick) return; // **** Check If the phrase is a Craft Phrase. if( rootBrick->isFaber() ) { extern void launchFaberCastWindow(sint32 , uint , CSBrickSheet *); launchFaberCastWindow(memoryLine, memoryIndex, rootBrick); // Cancel any moveTo, because don't want to continue reaching the prec entity UserEntity->resetAnyMoveTo(); } // **** Else standart cast else { // **** Cyclic Cast? (dblclick) bool cyclic; // Manage "DblHit" uint dbclickDelay = pIM->getUserDblClickDelay(); // if success to "dblclick" if(LastIndex==(sint)memoryIndex && T1<=LastHitTime+dbclickDelay ) cyclic= true; else cyclic= false; // for next hit LastHitTime= T1; LastIndex= memoryIndex; // can't cast magic phrase while moving if( rootBrick->isMagic() ) { if( UserControls.isMoving() || (UserEntity && UserEntity->follow() && UserEntity->speed()!=0.0) ) { // display "you can't cast while moving" CInterfaceManager *pIM= CInterfaceManager::getInstance(); ucstring msg = CI18N::get("msgNoCastWhileMoving"); string cat = getStringCategory(msg, msg); pIM->displaySystemInfo(msg, cat); return; } } // Can't cyclic cast Magic, SpecialPower or Harvest phrases (forage_extraction are auto) if( rootBrick->isMagic() || rootBrick->isHarvest() || rootBrick->isSpecialPower() ) cyclic= false; // auto cyclic for forage extraction if( rootBrick->isForageExtraction() ) cyclic= true; // even for extraction, if AvoidCyclic in any bricks, no cyclic! if( pPM->avoidCyclicForPhrase(phraseCom) ) cyclic= false; // **** Launch the cast // Cast only if their is a target, or if it is not a combat action CEntityCL *target = EntitiesMngr.entity(UserEntity->targetSlot()); if(target || !rootBrick->isCombat()) { // combat (may moveTo before) ? if(rootBrick->isCombat()) { if( !UserEntity->canEngageCombat() ) return; UserEntity->executeCombatWithPhrase(target, memoryLine, memoryIndex, cyclic); } // else can cast soon! else if ( rootBrick->isForageExtraction() && (! UserEntity->isRiding()) ) // if mounted, send directly to server (without moving) to receive the error message { // Yoyo: TEMP if a target selected, must be a forage source if(!target || target->isForageSource()) { // Cancel any follow UserEntity->disableFollow(); // reset any moveTo also (if target==NULL, moveToExtractionPhrase() and therefore resetAnyMoveTo() not called) // VERY important if previous MoveTo was a SPhrase MoveTo (because cancelClientExecute() must be called) UserEntity->resetAnyMoveTo(); // Move to targetted source if ( target ) UserEntity->moveToExtractionPhrase( target->slot(), MaxExtractionDistance, memoryLine, memoryIndex, cyclic ); // start client execution pPM->clientExecute(memoryLine, memoryIndex, cyclic); if ( ! target ) { // inform Server of phrase cast pPM->sendExecuteToServer(memoryLine, memoryIndex, cyclic); } } } else { // Cancel any moveTo(), because don't want to continue reaching the prec entity // VERY important if previous MoveTo was a SPhrase MoveTo (because cancelClientExecute() must be called) UserEntity->resetAnyMoveTo(); // start client execution: NB: start client execution even if it pPM->clientExecute(memoryLine, memoryIndex, cyclic); // inform Server of phrase cast pPM->sendExecuteToServer(memoryLine, memoryIndex, cyclic); } } } } }; REGISTER_ACTION_HANDLER( CHandlerCastPhrase, "cast_phrase"); sint64 CHandlerCastPhrase::LastHitTime= 0; sint CHandlerCastPhrase::LastIndex= -1; // *************************************************************************** /** Called when user hit the 1.2.3.4.5..... key */ class CAHRunShortcut : public IActionHandler { public: virtual void execute (CCtrlBase * /* pCaller */, const string &Params) { sint shortcut; fromString(Params, shortcut); if (shortcut>=0 && shortcut <= RYZOM_MAX_SHORTCUT) { CInterfaceManager *pIM= CInterfaceManager::getInstance(); // get the control CInterfaceElement *elm= pIM->getElementFromId(PhraseMemoryCtrlBase + toString(shortcut) ); CDBCtrlSheet *ctrl= dynamic_cast(elm); if(ctrl) { // run the standard cast case. if(ctrl->isMacro()) pIM->runActionHandler("cast_macro", ctrl); else pIM->runActionHandler("cast_phrase", ctrl); } } } }; REGISTER_ACTION_HANDLER (CAHRunShortcut, "run_shortcut"); // *************************************************************************** /** Called when the user click on a memory slot. Different AH called if the slot is empty or full */ class CHandlerCastPhraseOrCreateNew : public IActionHandler { public: virtual void execute (CCtrlBase *pCaller, const string &Params) { CInterfaceManager *pIM = CInterfaceManager::getInstance(); CDBCtrlSheet *pCSDst = dynamic_cast(pCaller); if (pCSDst == NULL) return; if (!pCSDst->isSPhraseIdMemory()) return; // get the phrase id under it sint phraseId= pCSDst->getSPhraseId(); // if a phrase is on this slot, just cast the phrase if(phraseId) { pIM->runActionHandler("cast_phrase", pCaller, Params); } // else open the RightMenuEmpty, to have "NewAction" else { string menu= pCSDst->getListMenuRightEmptySlot(); // opens only if no dragged sheet if( !menu.empty() && CDBCtrlSheet::getDraggedSheet()==NULL ) { // opens the menu CDBCtrlSheet::setCurrSelSheet(pCSDst); pIM->enableModalWindow (pCSDst, menu); } } } }; REGISTER_ACTION_HANDLER (CHandlerCastPhraseOrCreateNew, "cast_phrase_or_create_new"); // *************************************************************************** /** Called to get info on Phrase Link */ class CHandlerPhraseLinkCtrlRClick : public IActionHandler { public: virtual void execute (CCtrlBase *pCaller, const string &/* Params */) { CInterfaceManager *pIM= CInterfaceManager::getInstance(); CInterfaceGroup *parent= pCaller->getParent(); if(parent) { // Get the Brother CtrlSheet CDBCtrlSheet *ctrl= dynamic_cast(parent->getCtrl("ctrl_phrase")); if(ctrl) { pIM->runActionHandler(ctrl->getActionOnRightClick(), ctrl, ctrl->getParamsOnRightClick()); } } } }; REGISTER_ACTION_HANDLER (CHandlerPhraseLinkCtrlRClick, "phrase_link_ctrl_rclick"); // *************************************************************************** /** Called to cancel a Phrase link */ class CHandlerPhraseLinkStop : public IActionHandler { public: virtual void execute(CCtrlBase * /* pCaller */, const string &Params) { CInterfaceManager *pIM= CInterfaceManager::getInstance(); // get the link index uint8 index; fromString(Params, index); // Get the link counter. Used to verify that the client cancel the correct link according to server uint8 counter= 0; CCDBNodeLeaf *node= pIM->getDbProp(toString("SERVER:EXECUTE_PHRASE:LINK:%d:COUNTER", index), false); if(node) counter= node->getValue8(); // Send msg to server if (!ClientCfg.Local) { NLMISC::CBitMemStream out; if(GenericMsgHeaderMngr.pushNameToStream("PHRASE:CANCEL_LINK", out)) { out.serial(index); out.serial(counter); NetMngr.push(out); } else { nlwarning(" unknown message name '%s'", "PHRASE:CANCEL_LINK"); } } else { // debug: pIM->displaySystemInfo( toString("PHRASE:CANCEL_LINK %d, %d", index, counter) ); } } }; REGISTER_ACTION_HANDLER(CHandlerPhraseLinkStop, "phrase_link_stop"); // *************************************************************************** /** Called to cancel a Phrase link */ class CHandlerPhraseCancelCast: public IActionHandler { public: virtual void execute(CCtrlBase * /* pCaller */, const string &/* Params */) { CInterfaceManager *pIM= CInterfaceManager::getInstance(); // Send msg to server if (!ClientCfg.Local) { UserEntity->cancelAllPhrases(); } else { // debug: pIM->displaySystemInfo( ucstring("PHRASE:CANCEL_ALL") ); } } }; REGISTER_ACTION_HANDLER(CHandlerPhraseCancelCast, "phrase_cancel_cast"); // *************************************************************************** /// Called when one of the BRICK_TICK_RANGE has changed class CHandlerPhraseUpdateAllMemoryRegenTickRange : public IActionHandler { public: virtual void execute(CCtrlBase *, const string &) { CSPhraseManager *pPM= CSPhraseManager::getInstance(); pPM->updateAllMemoryCtrlState(); pPM->touchRegenTickRangeFlag(); } }; REGISTER_ACTION_HANDLER(CHandlerPhraseUpdateAllMemoryRegenTickRange, "phrase_update_all_memory_ctrl_regen_tick_range"); // *************************************************************************** /// Called when we right click on a brick in the memories class CHandlerPhraseCheckCanCristalize: public IActionHandler { public: virtual void execute(CCtrlBase *pCaller, const string &/* Params */) { const string sCristalizePath = "ui:interface:cm_memory_phrase:cri"; CInterfaceManager *pIM = CInterfaceManager::getInstance(); CSPhraseManager *pPM = CSPhraseManager::getInstance(); CSBrickManager *pBM = CSBrickManager::getInstance(); CInterfaceElement *pCristalizeMenuOption = pIM->getElementFromId(sCristalizePath); if (pCristalizeMenuOption == NULL) return; // The default is to not display the cristalize menu option pCristalizeMenuOption->setActive(false); if (pCaller == NULL) return; // Get the interface control sheet CDBCtrlSheet *pCS = dynamic_cast(pIM->getCtrlLaunchingModal()); if (pCS == NULL) return; if (!pCS->isSPhraseIdMemory()) return; // If its a phrase id in memory then get the phrase const CSPhraseCom &phrase = pPM->getPhrase(pCS->getSheetId()); if (phrase.empty()) return; // If the phrase is not empty get the root to known if its a magic phrase or not // And if its a magic phrase display the cristalize menu option CSBrickSheet *pBrick = pBM->getBrick(phrase.Bricks[0]); if (pBrick != NULL) { if (pBrick->isMagic()) { pCristalizeMenuOption->setActive(true); // Disable the cristalize item if the player has a forage in progress CViewTextMenu* vtm = dynamic_cast(pCristalizeMenuOption); if ( vtm ) { CTempInvManager *tim = CTempInvManager::getInstance(); bool isForageInProgress = tim && tim->isOpened() && (tim->getMode() == TEMP_INV_MODE::Forage); vtm->setGrayed( isForageInProgress ); } } } } }; REGISTER_ACTION_HANDLER(CHandlerPhraseCheckCanCristalize, "phrase_check_can_cristalize"); // *************************************************************************** /// Called after the cm_memory_phrase menu has been opened on a magic phrase class CHandlerPhraseCristalize: public IActionHandler { public: virtual void execute(CCtrlBase *pCaller, const string &/* Params */) { CSPhraseManager *pPM = CSPhraseManager::getInstance(); CDBCtrlSheet *pCSDst = dynamic_cast(pCaller); if (pCSDst == NULL) return; if (!pCSDst->isSPhraseIdMemory()) return; // Can cast only if not Latent (ie grayed) !! if (pCSDst->getGrayed()) return; // Ok, the user try to cast a phrase slot. sint32 memoryLine= pPM->getSelectedMemoryLineDB(); if(memoryLine<0) return; // get the memory index uint memoryIndex= pCSDst->getIndexInDB(); // execute both client and server pPM->executeCristalize(memoryLine, memoryIndex); } }; REGISTER_ACTION_HANDLER(CHandlerPhraseCristalize, "phrase_cristalize"); // *************************************************************************** class CHandlerPhraseBookSkillFilter : public IActionHandler { public: virtual void execute(CCtrlBase * /* pCaller */, const string &Params) { CSPhraseManager *pPM= CSPhraseManager::getInstance(); // If the param is a BrickType Filter... string btFilter= getParam(Params, "bt"); if(!btFilter.empty()) { BRICK_TYPE::EBrickType bt= BRICK_TYPE::toBrickType(btFilter); if(bt!=BRICK_TYPE::UNKNOWN) pPM->setBookFilter(bt, SKILLS::unknown); } // else it is a skill filter else { sint index; fromString(Params, index); if(index>=0 && indexsetBookFilter(BRICK_TYPE::UNKNOWN, (SKILLS::ESkills)index); else pPM->setBookFilter(BRICK_TYPE::UNKNOWN, SKILLS::unknown); } } }; REGISTER_ACTION_HANDLER(CHandlerPhraseBookSkillFilter, "phrase_book_skill_filter"); // *************************************************************************** class CHandlerPhraseSelectMemory : public IActionHandler { public: virtual void execute(CCtrlBase * /* pCaller */, const string &Params) { string expr = getParam (Params, "value"); CInterfaceExprValue value; if (CInterfaceExpr::eval(expr, value, NULL)) { if (!value.toInteger()) { nlwarning(" expression doesn't evaluate to a numerical value"); } else { CSPhraseManager *pPM= CSPhraseManager::getInstance(); sint val= (sint32)value.getInteger(); clamp(val, 0, MEM_SET_TYPES::NumMemories-1); pPM->selectMemoryLineDB(val); } } } }; REGISTER_ACTION_HANDLER(CHandlerPhraseSelectMemory, "phrase_select_memory"); // *************************************************************************** class CHandlerPhraseSelectShortcutBar : public IActionHandler { public: virtual void execute(CCtrlBase * /* pCaller */, const string &Params) { CInterfaceManager *pIM= CInterfaceManager::getInstance(); CCDBNodeLeaf *node= pIM->getDbProp("UI:PHRASE:SELECT_MEMORY", false); if(node) { sint32 val; fromString(Params, val); node->setValue32(val); } } }; REGISTER_ACTION_HANDLER(CHandlerPhraseSelectShortcutBar, "select_shortcut_bar"); // *************************************************************************** // *************************************************************************** // *************************************************************************** // HELP / LINKS // *************************************************************************** // *************************************************************************** // *************************************************************************** // *************************************************************************** // This expr is used only for define in phrase.xml. DECLARE_INTERFACE_CONSTANT(getPhraseBrickSelectionMax, CDBGroupBuildPhrase::MaxSelection) // *************************************************************************** // Get the UC name of a phraseId static DECLARE_INTERFACE_USER_FCT(getSPhraseName) { if (args.size() > 0) { if(!args[0].toInteger()) return false; sint sphraseId= (sint)args[0].getInteger(); CSPhraseManager *pPM= CSPhraseManager::getInstance(); result.setUCString(pPM->getPhrase(sphraseId).Name); return true; } else { return false; } } REGISTER_INTERFACE_USER_FCT("getSPhraseName", getSPhraseName) // *************************************************************************** // Get the tooltip of a Combat Weapon restriction brick class CHandlerCombatRestrictTooltip : public IActionHandler { public: virtual void execute (CCtrlBase *pCaller, const string &/* Params */) { CInterfaceManager *pIM= CInterfaceManager::getInstance(); CDBCtrlSheet *ctrlSheet= dynamic_cast(pCaller); if(!ctrlSheet) return; ucstring str(STRING_MANAGER::CStringManagerClient::getSBrickLocalizedName(CSheetId(ctrlSheet->getSheetId()))); // According to locked state if(ctrlSheet->getGrayed()) strFindReplace(str, "%comp", CI18N::get("uittPhraseCombatRestrictKO")); else strFindReplace(str, "%comp", CI18N::get("uittPhraseCombatRestrictOK")); pIM->setContextHelpText(str); } }; REGISTER_ACTION_HANDLER( CHandlerCombatRestrictTooltip, "phrase_combat_restrict_tooltip"); // *************************************************************************** // *************************************************************************** // *************************************************************************** // BOT CHAT // *************************************************************************** // *************************************************************************** // *************************************************************************** // *************************************************************************** void phraseBotChatBuyBySheet(NLMISC::CSheetId sheetId, uint16 phraseId) { uint32 sheetNum= sheetId.asInt(); if (!ClientCfg.Local) { NLMISC::CBitMemStream out; if(GenericMsgHeaderMngr.pushNameToStream("PHRASE:BUY_SHEET", out)) { out.serial(sheetNum); out.serial(phraseId); NetMngr.push(out); } else { nlwarning(" unknown message name '%s'", "PHRASE:BUY_SHEET"); } } else { // debug: CInterfaceManager *pIM= CInterfaceManager::getInstance(); pIM->displaySystemInfo( toString("PHRASE:BUY_SHEET => ") + toString(phraseId) ); // **** Server emulation // learn all bricks of this phrase CSPhraseSheet *phrase= dynamic_cast(SheetMngr.get(sheetId)); if(phrase) { CSBrickManager *pBM= CSBrickManager::getInstance(); // For all bricks of this phrase for(uint i=0;iBricks.size();i++) { CSBrickSheet *brick= pBM->getBrick(phrase->Bricks[i]); if(brick) { // force learn it. CCDBNodeLeaf * node= pBM->getKnownBrickBitFieldDB(brick->BrickFamily); if(node) { uint64 flags= node->getValue64(); flags|= uint64(1)<<(brick->IndexInFamily-1); node->setValue64(flags); } } } } // ack phrase learn CSPhraseManager *pPM= CSPhraseManager::getInstance(); if(phraseId) pPM->receiveBotChatConfirmBuy(phraseId, true); // synchronize uint counter= pIM->getLocalSyncActionCounter(); pIM->getDbProp("SERVER:INVENTORY:COUNTER")->setValue32(counter); pIM->getDbProp("SERVER:EXCHANGE:COUNTER")->setValue32(counter); pIM->getDbProp("SERVER:TARGET:CONTEXT_MENU:COUNTER")->setValue32(counter); pIM->getDbProp("SERVER:USER:COUNTER")->setValue32(counter); } } // *************************************************************************** void phraseBotChatBuyActionByIndex(uint8 index, uint16 phraseId) { if (!ClientCfg.Local) { // send the selection to the server NLMISC::CBitMemStream out; if(GenericMsgHeaderMngr.pushNameToStream("PHRASE:BUY", out)) { out.serial(index); out.serial(phraseId); NetMngr.push(out); } else nlwarning(" unknown message name 'PHRASE:BUY"); } else { // debug: CInterfaceManager *pIM= CInterfaceManager::getInstance(); pIM->displaySystemInfo("PHRASE:BUY => " + toString(phraseId) ); } } // *************************************************************************** /* Called from CConfirmBuyItem action handler */ void phraseBuyBotChat(CDBCtrlSheet *ctrl, uint8 index, bool useBuySheetMsg) { CSBrickManager *pBM= CSBrickManager::getInstance(); CSPhraseManager *pSM= CSPhraseManager::getInstance(); if(!ctrl->isSPhrase()) return; // Get the SPhrase const CSPhraseSheet *sp= ctrl->asSPhraseSheet(); if(!sp || sp->Bricks.empty()) return; // Verify that the phrase is not a special "CHARACTERISTIC BUYING" phrase bool isCharacBuying= false; CSBrickSheet *brickSheet= pBM->getBrick(CSheetId(sp->Bricks[0])); if(brickSheet && BRICK_FAMILIES::isCharacBuyFamily(brickSheet->BrickFamily) ) isCharacBuying= true; // confirm the buy { // default: not append to the manager uint16 phraseId= 0; // Append the phrase to the manager. ONLY if this phrase is castable if(sp->Castable && !isCharacBuying) { CSPhraseCom phraseCom; pSM->buildPhraseFromSheet(phraseCom, ctrl->getSheetId()); if(phraseCom.empty()) return; // get the new phraseId phraseId= (uint16)pSM->allocatePhraseSlot(); // Since we are not sure this slot work, lock it! pSM->setPhrase(phraseId, phraseCom, true); } // Special for LOCAL:USER:SKILL_POINTS_ update CInterfaceManager *pIM= CInterfaceManager::getInstance(); pIM->incLocalSyncActionCounter(); // Send msg to server if(useBuySheetMsg) phraseBotChatBuyBySheet(sp->Id, phraseId); else phraseBotChatBuyActionByIndex(index, phraseId); } } // *************************************************************************** // Command for Debug BotChat ACK. NLMISC_COMMAND(phraseComfirmBuy, "Debug: confirm a phrase BotChat buy", "") { if(args.size() != 2) return false; uint phraseId; fromString(args[0], phraseId); bool confirm; fromString(args[1], confirm); CSPhraseManager *pSM= CSPhraseManager::getInstance(); pSM->receiveBotChatConfirmBuy(phraseId, confirm); return true; } // *************************************************************************** // *************************************************************************** // *************************************************************************** // MACRO // *************************************************************************** // *************************************************************************** // *************************************************************************** // *************************************************************************** class CHandlerCastMacro : public IActionHandler { public: virtual void execute (CCtrlBase *pCaller, const string &/* Params */) { CMacroCmdManager *pMM = CMacroCmdManager::getInstance(); CDBCtrlSheet *pCSDst = dynamic_cast(pCaller); if (pCSDst == NULL) return; if (!pCSDst->isMacroMemory()) return; // Can cast only if not grayed if (pCSDst->getGrayed()) return; // execute the macro id pMM->executeID(pCSDst->getMacroId()); } }; REGISTER_ACTION_HANDLER( CHandlerCastMacro, "cast_macro"); // *************************************************************************** // *************************************************************************** // *************************************************************************** // MISC // *************************************************************************** // *************************************************************************** // *************************************************************************** // *************************************************************************** class CHandlerPhraseMemoryBeforeMenu : public IActionHandler { public: static uint32 LastPhraseIdMenu; virtual void execute(CCtrlBase *pCaller, const string &/* Params */) { CDBCtrlSheet *ctrl= dynamic_cast(pCaller); if(ctrl && ctrl->isSPhraseIdMemory()) { LastPhraseIdMenu= ctrl->getSPhraseId(); } } }; REGISTER_ACTION_HANDLER( CHandlerPhraseMemoryBeforeMenu, "phrase_memory_before_menu"); uint32 CHandlerPhraseMemoryBeforeMenu::LastPhraseIdMenu= 0; // *************************************************************************** static DECLARE_INTERFACE_USER_FCT(isPhraseMenuNotExecuting) { bool ok= true; // if the PhraseId for this menu is equal to either cyclic action, or next action, fails CSPhraseManager *pPM= CSPhraseManager::getInstance(); if(CHandlerPhraseMemoryBeforeMenu::LastPhraseIdMenu!=0) { if(pPM->getCycleExecutePhraseId()==CHandlerPhraseMemoryBeforeMenu::LastPhraseIdMenu) ok= false; if(pPM->getNextExecutePhraseId()==CHandlerPhraseMemoryBeforeMenu::LastPhraseIdMenu) ok= false; } result.setBool(ok); return true; } REGISTER_INTERFACE_USER_FCT("isPhraseMenuNotExecuting", isPhraseMenuNotExecuting)