// 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_misc.h" #include "interface_manager.h" #include "ctrl_button.h" #include "group_container.h" #include "group_editbox.h" #include "people_interraction.h" #include "nel/misc/algo.h" #include "interface_expr.h" #include "interface_link.h" #include "../client_chat_manager.h" #include "../motion/user_controls.h" #include "../entity_cl.h" #include "../client_cfg.h" #include "../fog_map.h" #include "../sky_render.h" #include "../continent_manager.h" #include "../main_loop.h" #include "../misc.h" using namespace std; using namespace NLMISC; using namespace NL3D; //////////// // EXTERN // //////////// extern CClientChatManager ChatMngr; extern UScene *SceneRoot; extern UScene *SkyScene; extern UScene *Scene; extern CFogState MainFogState; extern CFogState RootFogState; extern CLightCycleManager LightCycleManager; extern UCamera MainCam; extern CContinentManager ContinentMngr; extern NLMISC::CLog g_log; //////////// // static // //////////// //static CCDBNodeLeaf *MenuColorWidgetValue = NULL; // db entry for the color menu widget (Red) static const string ScreenshotsDirectory("screenshots/"); // don't forget the final / void preRenderNewSky (); // *************************************************************************** class CAHCommand : public IActionHandler { public: virtual void execute (CCtrlBase * /* pCaller */, const string &Params) { ICommand::execute(Params, g_log); } }; REGISTER_ACTION_HANDLER (CAHCommand, "command"); // *************************************************************************** // *************************************************************************** // class CActionHandlerShowOne // *************************************************************************** // *************************************************************************** // *************************************************************************** REGISTER_ACTION_HANDLER (CActionHandlerShowOne, "show_one"); // *************************************************************************** void CActionHandlerShowOne::execute (CCtrlBase * /* pCaller */, const std::string ¶ms) { CInterfaceManager *mngr= CInterfaceManager::getInstance(); string wndListValue= getParam(params, "list"); string wndShow= getParam(params, "show"); // get the list vector wndList; splitString(wndListValue, ",", wndList); // hide all window from the list. for(uint i=0;igetElementFromId(wndList[i]); if(wnd) wnd->setActive(false); } // show the one needed CInterfaceElement *wnd= mngr->getElementFromId(wndShow); if(wnd) wnd->setActive(true); } // *************************************************************************** REGISTER_ACTION_HANDLER (CActionHandlerActive, "set_active"); // *************************************************************************** void CActionHandlerActive::execute (CCtrlBase * /* pCaller */, const std::string ¶ms) { std::string active = getParam(params, "active"); std::string target = getParam(params, "target"); CInterfaceExprValue activeValue; if (CInterfaceExpr::eval(active, activeValue, NULL)) { if (!activeValue.toBool()) { nlwarning(" The 'active' param must be convertible to a boolean"); return; } CInterfaceManager *mngr = CInterfaceManager::getInstance(); CInterfaceElement *wnd = mngr->getElementFromId(target); if(!wnd) { nlwarning(" Can't get window %s", target.c_str()); return; } wnd->setActive(activeValue.getBool()); } else { nlwarning(" can't parse the 'active' param"); return; } } // *************************************************************************** REGISTER_ACTION_HANDLER (CActionHandlerSetOpen, "set_open"); // *************************************************************************** void CActionHandlerSetOpen::execute (CCtrlBase * /* pCaller */, const std::string ¶ms) { std::string open = getParam(params, "open"); std::string target = getParam(params, "target"); CInterfaceExprValue activeValue; if (CInterfaceExpr::eval(open, activeValue, NULL)) { if (!activeValue.toBool()) { nlwarning(" The 'active' param must be co,vertible to a boolean"); return; } CInterfaceManager *mngr = CInterfaceManager::getInstance(); CGroupContainer *wnd = dynamic_cast(mngr->getElementFromId(target)); if(!wnd) { nlwarning(" Can't get window %s", target.c_str()); return; } wnd->setOpen(activeValue.getBool()); } else { nlwarning(" can't parse the 'active' param"); return; } } // *************************************************************************** // *************************************************************************** // CActionHandlerHideClose // *************************************************************************** // *************************************************************************** // *************************************************************************** REGISTER_ACTION_HANDLER (CActionHandlerHideClose, "hide_close"); // *************************************************************************** void CActionHandlerHideClose::execute (CCtrlBase * /* pCaller */, const std::string ¶ms) { CInterfaceManager *mngr= CInterfaceManager::getInstance(); string hideValue= getParam(params, "hide"); string closeValue= getParam(params, "close"); // get the list vector hideList; splitString(hideValue, ",", hideList); vector closeList; splitString(closeValue, ",", closeList); // hide all window from the hide list. uint i; for(i=0;igetElementFromId(hideList[i]); if(wnd) wnd->setActive(false); } // close all containers from the hide list. for(i=0;igetElementFromId(closeList[i]); CGroupContainer *pIC = dynamic_cast(wnd); if(pIC) pIC->close(); } } // *************************************************************************** // *************************************************************************** // Misc // *************************************************************************** // *************************************************************************** // *************************************************************************** REGISTER_ACTION_HANDLER (CActionHandlerEnterModal, "enter_modal"); REGISTER_ACTION_HANDLER (CActionHandlerPushModal, "push_modal"); REGISTER_ACTION_HANDLER (CActionHandlerLeaveModal, "leave_modal"); // *************************************************************************** void CActionHandlerEnterModal::execute(CCtrlBase *pCaller, const std::string ¶ms) { CInterfaceManager *pIM= CInterfaceManager::getInstance(); // get the group from param string groupName= getParam(params, "group"); CInterfaceGroup *group= dynamic_cast( pIM->getElementFromId(groupName) ); if(group) { UserControls.stopFreeLook(); // enable the modal pIM->enableModalWindow(pCaller, group); } else { nlwarning(" Couldn't find group %s", groupName.c_str()); } } // *************************************************************************** void CActionHandlerPushModal::execute(CCtrlBase *pCaller, const std::string ¶ms) { CInterfaceManager *mngr= CInterfaceManager::getInstance(); // get the group from param string groupName= getParam(params, "group"); CInterfaceGroup *group= dynamic_cast( mngr->getElementFromId(groupName) ); if(group) { // enable the modal mngr->pushModalWindow(pCaller, group); } else { nlwarning(" Couldn't find group %s", groupName.c_str()); } } // *************************************************************************** void CActionHandlerLeaveModal::execute(CCtrlBase * /* pCaller */, const std::string &/* params */) { CInterfaceManager *mngr= CInterfaceManager::getInstance(); // quit the modal mngr->popModalWindow(); } // *************************************************************************** // proc // *************************************************************************** class CActionHandlerProc : public IActionHandler { public: virtual void execute (CCtrlBase *pCaller, const std::string ¶ms) { CInterfaceManager *mngr= CInterfaceManager::getInstance(); // split the parameters vector paramList; splitString(params, "|", paramList); if(paramList.empty()) return; // execute the procedure mngr->runProcedure(paramList[0], pCaller, paramList); } }; REGISTER_ACTION_HANDLER (CActionHandlerProc, "proc"); /** Confirm that a group container can be deactivated */ class CActionHandlerConfirmCanDeactivate : public IActionHandler { public: virtual void execute (CCtrlBase * /* pCaller */, const std::string &/* params */) { CGroupContainer::validateCanDeactivate(true); } }; REGISTER_ACTION_HANDLER (CActionHandlerConfirmCanDeactivate, "confirm_can_deactivate"); /** Cancel a group container deactivation */ class CActionHandlerCancelCanDeactivate : public IActionHandler { public: virtual void execute (CCtrlBase * /* pCaller */, const std::string &/* params */) { CGroupContainer::validateCanDeactivate(false); } }; REGISTER_ACTION_HANDLER (CActionHandlerCancelCanDeactivate, "cancel_can_deactivate"); // *************************************************************************** // *************************************************************************** // EditBox // *************************************************************************** // *************************************************************************** // *************************************************************************** class CActionHandlerEditBoxNumber : public IActionHandler { public: virtual void execute (CCtrlBase *pCaller, const std::string ¶ms) { CGroupEditBox *pEditBox= dynamic_cast(pCaller); if(!pEditBox) return; // get the dblink dest string dblink= getParam(params, "value"); if(dblink.empty()) return; // get the value sint64 val= pEditBox->getInputStringAsInt64(); string valueStr; // see if a max value has been set valueStr = getParam(params, "max_value"); if (!valueStr.empty()) { CInterfaceExprValue maxValue; if (!CInterfaceExpr::eval(valueStr, maxValue) || !maxValue.toInteger()) { nlwarning(" Can't eval maxValue, or can't convert to integer : %s", valueStr.c_str()); return; } val = std::min(maxValue.getInteger(), val); } // see if a min value has been set valueStr = getParam(params, "min_value"); if (!valueStr.empty()) { CInterfaceExprValue minValue; if (!CInterfaceExpr::eval(valueStr, minValue) || !minValue.toInteger()) { nlwarning(" Can't eval minValue, or can't convert to integer : %s", valueStr.c_str()); return; } val = std::max(minValue.getInteger(), val); } // set in the database CInterfaceProperty prop; prop.link(dblink.c_str()); prop.setSInt64(val); string updateText = getParam(params, "update_text"); bool mustUpdate = updateText.empty() ? true : CInterfaceElement::convertBool(updateText.c_str()); if (mustUpdate) { // replace the editbox string pEditBox->setInputStringAsInt64(val); pEditBox->setSelectionAll(); } } }; REGISTER_ACTION_HANDLER (CActionHandlerEditBoxNumber, "editbox_number"); // *************************************************************************** // Dynamic creation of interface links // *************************************************************************** /** Add a link to an interface element */ class CActionHandlerAddLink : public IActionHandler { virtual void execute (CCtrlBase *pCaller, const std::string ¶ms) { std::string expr = getParam(params, "expr"); std::string targets = getParam(params, "target"); std::string id = getParam(params, "id"); std::string ah = getParam(params, "action"); std::string ahparam = getParam(params, "params"); std::string ahcond = getParam(params, "cond"); if (id.empty()) { nlwarning(" Must specify a link's id"); return; } CInterfaceGroup *parentGroup = dynamic_cast(pCaller); if (!parentGroup) { if (pCaller) parentGroup = pCaller->getParent(); } std::vector targetsVect; bool result = CInterfaceParser::splitLinkTargets(targets, parentGroup, targetsVect); if (!result) { nlwarning(" Couldn't parse all links"); } // add the link CInterfaceLink *il = new CInterfaceLink; il->init(targetsVect, expr, ah, ahparam, ahcond, parentGroup); CInterfaceManager *im = CInterfaceManager::getInstance(); im->addLink(il, id); il->update(); } }; REGISTER_ACTION_HANDLER (CActionHandlerAddLink, "add_link"); /** Remove a link from an interface element */ class CActionHandlerRemoveLink : public IActionHandler { virtual void execute (CCtrlBase * /* pCaller */, const std::string ¶ms) { std::string id = getParam(params, "id"); if (id.empty()) { nlwarning(" Must specify a link's id"); return; } CInterfaceManager *im = CInterfaceManager::getInstance(); im->removeLink(id); } }; REGISTER_ACTION_HANDLER (CActionHandlerRemoveLink, "remove_link"); // *************************************************************************** REGISTER_ACTION_HANDLER (CActionHandlerEvalExpr, "eval_expr"); // *************************************************************************** void CActionHandlerEvalExpr::execute(CCtrlBase * /* pCaller */, const std::string ¶ms) { std::string expr = getParam(params, "expr"); if (expr.empty()) { nlwarning(" 'expr' parameter not found or empty."); return; } CInterfaceExprValue dummyResult; // result not used if (!CInterfaceExpr::eval(expr, dummyResult)) { nlwarning(" Couldn't eval expression"); } return; } // *************************************************************************** CInterfaceGroup *createMenuColorWidget(const string &colDbEntry, const string &toolTipTextID, const string &ccdTitle) { CInterfaceManager *im = CInterfaceManager::getInstance(); pair params[3] = { make_pair(string("col_db_entry"), colDbEntry), make_pair(string("tooltip"), toolTipTextID), make_pair(string("ccd_title"), ccdTitle), }; return im->createGroupInstance("menu_color_widget", "", params, 3); } // *************************************************************************** struct CCameraBackup { CViewport Viewport; CFrustum Frustum; }; // ********************************************************* CCameraBackup setupCameraForScreenshot(UScene &scene, uint left, uint right, uint top, uint bottom, uint screenShotWidth, uint screenShotHeight) { CCameraBackup cb; cb.Frustum = scene.getCam().getFrustum(); cb.Viewport = scene.getViewport(); // Build a frustum CFrustum frustumPart; frustumPart.Left = cb.Frustum.Left+(cb.Frustum.Right-cb.Frustum.Left)*((float)left/(float)screenShotWidth); frustumPart.Right = cb.Frustum.Left+(cb.Frustum.Right-cb.Frustum.Left)*((float)right/(float)screenShotWidth); frustumPart.Top = cb.Frustum.Top+(cb.Frustum.Bottom-cb.Frustum.Top)*((float)top/(float)screenShotHeight); frustumPart.Bottom = cb.Frustum.Top+(cb.Frustum.Bottom-cb.Frustum.Top)*((float)bottom/(float)screenShotHeight); frustumPart.Near = cb.Frustum.Near; frustumPart.Far = cb.Frustum.Far; frustumPart.Perspective = cb.Frustum.Perspective; // Build a viewport CViewport viewport; viewport.init (0, 0, (float)(right-left)/Driver->getWindowWidth(), (float)(bottom-top)/Driver->getWindowHeight()); // Activate all this scene.getCam().setFrustum (frustumPart); scene.setViewport (viewport); return cb; } // ********************************************************* static void restoreCamera(UScene &scene, const CCameraBackup &backup) { scene.getCam().setFrustum (backup.Frustum); scene.setViewport(backup.Viewport); } // *************************************************************************** void renderSceneScreenShot (uint left, uint right, uint top, uint bottom, uint screenShotWidth, uint screenShotHeight) { CCameraBackup cbScene = setupCameraForScreenshot(*Scene, left, right, top, bottom, screenShotWidth, screenShotHeight); CCameraBackup cbCanopy = setupCameraForScreenshot(*SceneRoot, left, right, top, bottom, screenShotWidth, screenShotHeight); // sky setup are copied from main scene before rendering so no setup done here renderAll(ClientCfg.ScreenShotFullDetail); restoreCamera(*Scene, cbScene); restoreCamera(*SceneRoot, cbCanopy); } // *************************************************************************** void getBuffer (CBitmap &btm) { // if (ClientCfg.ScreenShotWidth && ClientCfg.ScreenShotHeight) { // Destination image CBitmap temp; btm.resize (ClientCfg.ScreenShotWidth, ClientCfg.ScreenShotHeight, CBitmap::RGBA); uint top; uint bottom = std::min (Driver->getWindowHeight (), ClientCfg.ScreenShotHeight); for (top=0; topgetWindowHeight ()) { uint left; uint right = std::min (Driver->getWindowWidth (), ClientCfg.ScreenShotWidth); for (left=0; leftgetWindowWidth ()) { Driver->clearBuffers (CRGBA::Black); renderSceneScreenShot (left, right, top, bottom, ClientCfg.ScreenShotWidth, ClientCfg.ScreenShotHeight); // Get the bitmap Driver->getBuffer (temp); Driver->swapBuffers (); btm.blit (temp, 0, Driver->getWindowHeight ()-(bottom-top), right-left, bottom-top, left, top); // Next right = std::min (right+Driver->getWindowWidth (), ClientCfg.ScreenShotWidth); } // Next bottom = std::min (bottom+Driver->getWindowHeight (), ClientCfg.ScreenShotHeight); } } else { Driver->getBuffer(btm); } } void displayScreenShotSavedInfo(const string &filename) { CInterfaceManager *pIM = CInterfaceManager::getInstance(); ucstring msg("'" + filename + "' " + CI18N::get("uiScreenshotSaved")); pIM->displaySystemInfo(msg); } void screenShotTGA() { CBitmap btm; getBuffer (btm); if(!ScreenshotsDirectory.empty() && !CFile::isExists(ScreenshotsDirectory)) CFile::createDirectory(ScreenshotsDirectory); string filename = CFile::findNewFile (ScreenshotsDirectory+"screenshot.tga"); COFile fs(filename); btm.writeTGA(fs, 24, false); nlinfo("Screenshot '%s' saved in tga format (%dx%d)", filename.c_str(), (int) ClientCfg.ScreenShotWidth, (int) ClientCfg.ScreenShotHeight); displayScreenShotSavedInfo(filename); }; void screenShotPNG() { CBitmap btm; getBuffer (btm); if(!ScreenshotsDirectory.empty() && !CFile::isExists(ScreenshotsDirectory)) CFile::createDirectory(ScreenshotsDirectory); string filename = CFile::findNewFile (ScreenshotsDirectory+"screenshot.png"); COFile fs(filename); if (!btm.writePNG(fs, 24)) { // PNG file has been incorrectly written (mainly because libpng1x.dll was not found) // so close and delete it fs.close(); CFile::deleteFile(filename); return; } nlinfo("Screenshot '%s' saved in png format (%dx%d)", filename.c_str(), (int) ClientCfg.ScreenShotWidth, (int) ClientCfg.ScreenShotHeight); displayScreenShotSavedInfo(filename); }; void screenShotJPG() { CBitmap btm; getBuffer (btm); if(!ScreenshotsDirectory.empty() && !CFile::isExists(ScreenshotsDirectory)) CFile::createDirectory(ScreenshotsDirectory); string filename = CFile::findNewFile (ScreenshotsDirectory+"screenshot.jpg"); COFile fs(filename); btm.writeJPG(fs); nlinfo("Screenshot '%s' saved in jpg format (%dx%d)", filename.c_str(), (int) ClientCfg.ScreenShotWidth, (int) ClientCfg.ScreenShotHeight); displayScreenShotSavedInfo(filename); }; // *************************************************************************** class CAHScreenShot : public IActionHandler { void execute(CCtrlBase * /* pCaller */, const std::string &/* params */) { // if custom screenshot size is asked, then do it right now if (ClientCfg.ScreenShotWidth && ClientCfg.ScreenShotHeight) { // Custom screen shot ? screenShotTGA(); } else { // post screenshot request ScreenshotRequest = ScreenshotRequestTGA; } } }; // *************************************************************************** REGISTER_ACTION_HANDLER (CAHScreenShot, "screen_shot"); // *************************************************************************** class CAHScreenShotJPG : public IActionHandler { void execute(CCtrlBase * /* pCaller */, const std::string &/* params */) { // if custom screenshot size is asked, then do it right now if (ClientCfg.ScreenShotWidth && ClientCfg.ScreenShotHeight) { screenShotJPG(); } else { // post screenshot request ScreenshotRequest = ScreenshotRequestJPG; } } }; // *************************************************************************** REGISTER_ACTION_HANDLER (CAHScreenShotJPG, "screen_shot_jpg"); // *************************************************************************** class CAHScreenShotPNG : public IActionHandler { void execute(CCtrlBase * /* pCaller */, const std::string &/* params */) { // if custom screenshot size is asked, then do it right now if (ClientCfg.ScreenShotWidth && ClientCfg.ScreenShotHeight) { screenShotPNG(); } else { // post screenshot request ScreenshotRequest = ScreenshotRequestPNG; } } }; // *************************************************************************** REGISTER_ACTION_HANDLER (CAHScreenShotPNG, "screen_shot_png"); // *************************************************************************** // Reply to the last people who talked in the chat -> this change the target of the main chat to the name of the last teller class CAHReplyTeller : public IActionHandler { void execute(CCtrlBase * /* pCaller */, const std::string &/* params */) { if (!PeopleInterraction.LastSenderName.empty()) { CChatWindow *w = PeopleInterraction.ChatGroup.Window; if (w) { w->setKeyboardFocus(); w->enableBlink(1); PeopleInterraction.ChatGroup.Filter.setTargetPlayer(CEntityCL::removeTitleAndShardFromName(PeopleInterraction.LastSenderName)); CGroupEditBox *eb = w->getEditBox(); if (eb != NULL) { eb->bypassNextKey(); } } } } }; REGISTER_ACTION_HANDLER (CAHReplyTeller, "reply_teller") // *************************************************************************** // Reply to the last people who talked in the chat only once (display '/tell name' in the last activated chat window) class CAHReplyTellerOnce : public IActionHandler { void execute(CCtrlBase * /* pCaller */, const std::string &/* params */) { // display a /tell command in the main chat if (!PeopleInterraction.LastSenderName.empty()) { CChatWindow *w = PeopleInterraction.ChatGroup.Window; if (w) { w->setKeyboardFocus(); w->enableBlink(1); w->setCommand(ucstring("tell ") + CEntityCL::removeTitleAndShardFromName(PeopleInterraction.LastSenderName) + ucstring(" "), false); CGroupEditBox *eb = w->getEditBox(); if (eb != NULL) { eb->bypassNextKey(); } } } } }; REGISTER_ACTION_HANDLER (CAHReplyTellerOnce, "reply_teller_once") // *************************************************************************** /** Cycle through the last people on which a 'tell' has been done. * Focus must be in a window with a target (main chat or user chat), otherwise the main chat is used */ class CAHCycleTell : public IActionHandler { void execute(CCtrlBase * /* pCaller */, const std::string &/* params */) { CInterfaceManager *im = CInterfaceManager::getInstance(); if (!im->isInGame()) return; const ucstring *lastTellPeople = ChatMngr.cycleLastTell(); if (!lastTellPeople) return; // just popup the main chat //CChatWindow *w = PeopleInterraction.MainChat.Window; CChatWindow *w = PeopleInterraction.ChatGroup.Window; if (w) { w->setKeyboardFocus(); w->enableBlink(1); //PeopleInterraction.MainChat.Filter.setTargetPlayer(*lastTellPeople); PeopleInterraction.ChatGroup.Filter.setTargetPlayer(*lastTellPeople); } } }; REGISTER_ACTION_HANDLER (CAHCycleTell, "cycle_tell") // temp for test : set last sender name NLMISC_COMMAND(slsn, "Temp : set the name of the last sender.", "") { if (args.size() != 1) return false; PeopleInterraction.LastSenderName = ucstring(args[0]); return true; } // *************************************************************************** bool CStringPostProcessRemoveName::cbIDStringReceived(ucstring &inOut) { // extract the replacement id std::string strNewTitle = CEntityCL::getTitleFromName(inOut); // retrieve the translated string if (!strNewTitle.empty()) inOut = STRING_MANAGER::CStringManagerClient::getTitleLocalizedName(strNewTitle,Woman); else inOut = ""; return true; } // *************************************************************************** bool CStringPostProcessRemoveTitle::cbIDStringReceived(ucstring &inOut) { inOut = CEntityCL::removeTitleAndShardFromName(inOut); return true; } // *************************************************************************** bool CStringPostProcessNPCRemoveTitle::cbIDStringReceived(ucstring &inOut) { ucstring sOut = CEntityCL::removeTitleAndShardFromName(inOut); if (sOut.empty()) { CStringPostProcessRemoveName SPPRM; SPPRM.cbIDStringReceived(inOut); } else { inOut = sOut; } return true; }