/*
* The ManaPlus Client
* Copyright (C) 2012-2014 The ManaPlus Developers
*
* This file is part of The ManaPlus Client.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "actionmanager.h"
#include "actormanager.h"
#include "dropshortcut.h"
#include "emoteshortcut.h"
#include "game.h"
#include "itemshortcut.h"
#include "soundmanager.h"
#include "being/localplayer.h"
#include "being/playerinfo.h"
#include "being/playerrelations.h"
#include "input/inputmanager.h"
#include "gui/gui.h"
#include "gui/sdlinput.h"
#include "gui/viewport.h"
#include "gui/windows/skilldialog.h"
#include "gui/windows/socialwindow.h"
#include "gui/windows/statuswindow.h"
#include "gui/windows/tradewindow.h"
#include "gui/windows/questswindow.h"
#include "gui/windows/quitdialog.h"
#include "gui/windows/whoisonline.h"
#include "gui/windows/botcheckerwindow.h"
#include "gui/windows/buyselldialog.h"
#include "gui/windows/chatwindow.h"
#include "gui/windows/debugwindow.h"
#include "gui/windows/didyouknowwindow.h"
#include "gui/windows/equipmentwindow.h"
#include "gui/windows/helpwindow.h"
#include "gui/windows/inventorywindow.h"
#include "gui/windows/killstats.h"
#include "gui/windows/minimap.h"
#include "gui/windows/ministatuswindow.h"
#include "gui/windows/npcdialog.h"
#include "gui/windows/outfitwindow.h"
#include "gui/windows/setupwindow.h"
#include "gui/windows/shopwindow.h"
#include "gui/windows/shortcutwindow.h"
#include "gui/widgets/tabs/chattab.h"
#include "render/graphics.h"
#include "net/net.h"
#include "net/playerhandler.h"
#include "net/tradehandler.h"
#include "utils/gettext.h"
#ifdef ANDROID
#ifndef USE_SDL2
#include <SDL_screenkeyboard.h>
#endif
#endif
#include "debug.h"
#define impHandler(name) bool name(const InputEvent &event)
#define impHandler0(name) bool name(const InputEvent &event A_UNUSED)
extern ShortcutWindow *spellShortcutWindow;
extern std::string tradePartnerName;
extern QuitDialog *quitDialog;
namespace ActionManager
{
static bool closeMoveNpcDialog(bool focus)
{
NpcDialog *const dialog = NpcDialog::getActive();
if (dialog)
{
if (dialog->isCloseState())
{
dialog->closeDialog();
return true;
}
else if (focus)
{
dialog->refocus();
}
}
return false;
}
impHandler(moveUp)
{
if (inputManager.isActionActive(Input::KEY_EMOTE))
return directUp(event);
return closeMoveNpcDialog(false);
}
impHandler(moveDown)
{
if (inputManager.isActionActive(Input::KEY_EMOTE))
return directDown(event);
return closeMoveNpcDialog(false);
}
impHandler(moveLeft)
{
if (outfitWindow && inputManager.isActionActive(Input::KEY_WEAR_OUTFIT))
{
outfitWindow->wearPreviousOutfit();
if (Game::instance())
Game::instance()->setValidSpeed();
return true;
}
if (inputManager.isActionActive(Input::KEY_EMOTE))
return directLeft(event);
return closeMoveNpcDialog(false);
}
impHandler(moveRight)
{
if (outfitWindow && inputManager.isActionActive(Input::KEY_WEAR_OUTFIT))
{
outfitWindow->wearNextOutfit();
if (Game::instance())
Game::instance()->setValidSpeed();
return true;
}
if (inputManager.isActionActive(Input::KEY_EMOTE))
return directRight(event);
return closeMoveNpcDialog(false);
}
impHandler(moveForward)
{
if (inputManager.isActionActive(Input::KEY_EMOTE))
return directRight(event);
return closeMoveNpcDialog(false);
}
impHandler(emote)
{
const int emotion = 1 + event.action - Input::KEY_EMOTE_1;
if (emotion > 0)
{
if (emoteShortcut)
emoteShortcut->useEmote(emotion);
if (Game::instance())
Game::instance()->setValidSpeed();
return true;
}
return false;
}
impHandler(moveToPoint)
{
const int num = event.action - Input::KEY_MOVE_TO_POINT_1;
if (socialWindow && num >= 0)
{
socialWindow->selectPortal(num);
return true;
}
return false;
}
impHandler(outfit)
{
if (inputManager.isActionActive(Input::KEY_WEAR_OUTFIT))
{
const int num = event.action - Input::KEY_OUTFIT_1;
if (outfitWindow && num >= 0)
{
outfitWindow->wearOutfit(num);
if (Game::instance())
Game::instance()->setValidSpeed();
return true;
}
}
else if (inputManager.isActionActive(Input::KEY_COPY_OUTFIT))
{
const int num = event.action - Input::KEY_OUTFIT_1;
if (outfitWindow && num >= 0)
{
outfitWindow->copyOutfit(num);
if (Game::instance())
Game::instance()->setValidSpeed();
return true;
}
}
return false;
}
impHandler0(mouseClick)
{
if (!guiInput || !gui)
return false;
int mouseX, mouseY;
Gui::getMouseState(&mouseX, &mouseY);
guiInput->simulateMouseClick(mouseX, mouseY, MouseEvent::RIGHT);
return true;
}
impHandler0(ok)
{
// Close the Browser if opened
if (helpWindow && helpWindow->isWindowVisible())
{
helpWindow->setVisible(false);
return true;
}
// Close the config window, cancelling changes if opened
else if (setupWindow && setupWindow->isWindowVisible())
{
setupWindow->action(ActionEvent(nullptr, "cancel"));
return true;
}
else if (NpcDialog *const dialog = NpcDialog::getActive())
{
dialog->action(ActionEvent(nullptr, "ok"));
return true;
}
return false;
}
impHandler(shortcut)
{
if (itemShortcutWindow)
{
const int num = itemShortcutWindow->getTabIndex();
if (num >= 0 && num < static_cast<int>(SHORTCUT_TABS))
{
if (itemShortcut[num])
{
itemShortcut[num]->useItem(event.action
- Input::KEY_SHORTCUT_1);
}
}
return true;
}
return false;
}
impHandler0(toggleChat)
{
return chatWindow ? chatWindow->requestChatFocus() : false;
}
impHandler0(prevChatTab)
{
if (chatWindow)
{
chatWindow->prevTab();
return true;
}
return false;
}
impHandler0(nextChatTab)
{
if (chatWindow)
{
chatWindow->nextTab();
return true;
}
return false;
}
impHandler0(closeChatTab)
{
if (chatWindow)
{
chatWindow->closeTab();
return true;
}
return false;
}
impHandler0(prevSocialTab)
{
if (socialWindow)
{
socialWindow->prevTab();
return true;
}
return false;
}
impHandler0(nextSocialTab)
{
if (socialWindow)
{
socialWindow->nextTab();
return true;
}
return false;
}
impHandler0(scrollChatUp)
{
if (chatWindow && chatWindow->isWindowVisible())
{
chatWindow->scroll(-DEFAULT_CHAT_WINDOW_SCROLL);
return true;
}
return false;
}
impHandler0(scrollChatDown)
{
if (chatWindow && chatWindow->isWindowVisible())
{
chatWindow->scroll(DEFAULT_CHAT_WINDOW_SCROLL);
return true;
}
return false;
}
impHandler0(quit)
{
if (!Game::instance())
return false;
if (viewport && viewport->isPopupMenuVisible())
{
viewport->closePopupMenu();
return true;
}
else if (!quitDialog)
{
quitDialog = new QuitDialog(&quitDialog);
quitDialog->postInit();
quitDialog->requestMoveToTop();
return true;
}
return false;
}
impHandler0(dropItem0)
{
if (dropShortcut)
{
dropShortcut->dropFirst();
return true;
}
return false;
}
impHandler0(dropItem)
{
if (dropShortcut)
{
dropShortcut->dropItems();
return true;
}
return false;
}
impHandler0(switchQuickDrop)
{
if (player_node && !player_node->getDisableGameModifiers())
{
player_node->changeQuickDropCounter();
return true;
}
return false;
}
impHandler0(heal)
{
if (actorManager)
{
if (inputManager.isActionActive(Input::KEY_STOP_ATTACK))
{
Being *target = player_node->getTarget();
if (!target || target->getType() != ActorSprite::PLAYER)
{
target = actorManager->findNearestLivingBeing(
player_node, 10, ActorSprite::PLAYER);
if (target)
player_node->setTarget(target);
}
}
actorManager->healTarget();
if (Game::instance())
Game::instance()->setValidSpeed();
return true;
}
return false;
}
impHandler0(crazyMoves)
{
if (player_node)
{
player_node->crazyMove();
return true;
}
return false;
}
impHandler0(itenplz)
{
if (actorManager)
{
if (Net::getPlayerHandler() && Net::getPlayerHandler()->canUseMagic()
&& PlayerInfo::getAttribute(PlayerInfo::MP) >= 3)
{
actorManager->itenplz();
}
return true;
}
return false;
}
impHandler0(changeCrazyMove)
{
if (player_node)
{
player_node->changeCrazyMoveType();
return true;
}
return false;
}
impHandler0(changePickupType)
{
if (player_node)
{
player_node->changePickUpType();
return true;
}
return false;
}
impHandler0(moveToTarget)
{
if (player_node && !inputManager.isActionActive(Input::KEY_TARGET_ATTACK)
&& !inputManager.isActionActive(Input::KEY_ATTACK))
{
player_node->moveToTarget();
return true;
}
return false;
}
impHandler0(moveToHome)
{
if (player_node && !inputManager.isActionActive(Input::KEY_TARGET_ATTACK)
&& !inputManager.isActionActive(Input::KEY_ATTACK))
{
player_node->moveToHome();
if (Game::instance())
Game::instance()->setValidSpeed();
return true;
}
return false;
}
impHandler0(setHome)
{
if (player_node)
{
player_node->setHome();
return true;
}
return false;
}
impHandler0(changeMoveType)
{
if (player_node)
{
player_node->invertDirection();
return true;
}
return false;
}
impHandler0(changeAttackWeaponType)
{
if (player_node)
{
player_node->changeAttackWeaponType();
return true;
}
return false;
}
impHandler0(changeAttackType)
{
if (player_node)
{
player_node->changeAttackType();
return true;
}
return false;
}
impHandler0(changeFollowMode)
{
if (player_node)
{
player_node->changeFollowMode();
return true;
}
return false;
}
impHandler0(changeImitationMode)
{
if (player_node)
{
player_node->changeImitationMode();
return true;
}
return false;
}
impHandler0(magicAttack)
{
if (player_node)
{
player_node->magicAttack();
return true;
}
return false;
}
impHandler0(changeMagicAttack)
{
if (player_node)
{
player_node->switchMagicAttack();
return true;
}
return false;
}
impHandler0(changePvpMode)
{
if (player_node)
{
player_node->switchPvpAttack();
return true;
}
return false;
}
impHandler0(changeMoveToTarget)
{
if (player_node)
{
player_node->changeMoveToTargetType();
return true;
}
return false;
}
impHandler0(copyEquippedToOutfit)
{
if (outfitWindow)
{
outfitWindow->copyFromEquiped();
return true;
}
return false;
}
impHandler0(changeGameModifier)
{
if (player_node)
{
player_node->switchGameModifiers();
return true;
}
return false;
}
impHandler0(changeAudio)
{
soundManager.changeAudio();
return true;
}
impHandler0(away)
{
if (player_node)
{
player_node->changeAwayMode();
player_node->updateStatus();
if (Game::instance())
Game::instance()->setValidSpeed();
return true;
}
return false;
}
impHandler0(camera)
{
if (viewport)
{
viewport->toggleCameraMode();
if (Game::instance())
Game::instance()->setValidSpeed();
return true;
}
return false;
}
impHandler0(setupWindowShow)
{
if (setupWindow)
{
if (setupWindow->isWindowVisible())
{
setupWindow->doCancel();
}
else
{
setupWindow->setVisible(true);
setupWindow->requestMoveToTop();
}
return true;
}
return false;
}
impHandler0(pickup)
{
if (player_node)
{
player_node->pickUpItems();
return true;
}
return false;
}
impHandler0(sit)
{
if (player_node)
{
if (inputManager.isActionActive(Input::KEY_EMOTE))
player_node->updateSit();
else
player_node->toggleSit();
return true;
}
return false;
}
impHandler0(hideWindows)
{
if (statusWindow)
statusWindow->setVisible(false);
if (inventoryWindow)
inventoryWindow->setVisible(false);
if (shopWindow)
shopWindow->setVisible(false);
if (skillDialog)
skillDialog->setVisible(false);
if (setupWindow)
setupWindow->setVisible(false);
if (equipmentWindow)
equipmentWindow->setVisible(false);
if (helpWindow)
helpWindow->setVisible(false);
if (debugWindow)
debugWindow->setVisible(false);
if (outfitWindow)
outfitWindow->setVisible(false);
if (dropShortcutWindow)
dropShortcutWindow->setVisible(false);
if (spellShortcutWindow)
spellShortcutWindow->setVisible(false);
if (botCheckerWindow)
botCheckerWindow->setVisible(false);
if (socialWindow)
socialWindow->setVisible(false);
if (questsWindow)
questsWindow->setVisible(false);
return true;
}
static bool showHelpPage(const std::string &page)
{
if (helpWindow)
{
if (helpWindow->isWindowVisible())
{
helpWindow->setVisible(false);
}
else
{
helpWindow->loadHelp(page);
helpWindow->requestMoveToTop();
}
return true;
}
return false;
}
impHandler0(helpWindowShow)
{
showHelpPage("index");
}
impHandler0(aboutWindowShow)
{
showHelpPage("about");
}
static void showHideWindow(Window *const window)
{
if (window)
{
window->setVisible(!window->isWindowVisible());
if (window->isWindowVisible())
window->requestMoveToTop();
}
}
impHandler0(statusWindowShow)
{
showHideWindow(statusWindow);
return true;
}
impHandler0(inventoryWindowShow)
{
showHideWindow(inventoryWindow);
return true;
}
impHandler0(equipmentWindowShow)
{
showHideWindow(equipmentWindow);
return true;
}
impHandler0(skillDialogShow)
{
showHideWindow(skillDialog);
return true;
}
impHandler0(minimapWindowShow)
{
if (minimap)
{
minimap->toggle();
return true;
}
return false;
}
impHandler0(chatWindowShow)
{
showHideWindow(chatWindow);
return true;
}
impHandler0(shortcutWindowShow)
{
showHideWindow(itemShortcutWindow);
return true;
}
impHandler0(debugWindowShow)
{
showHideWindow(debugWindow);
return true;
}
impHandler0(socialWindowShow)
{
showHideWindow(socialWindow);
return true;
}
impHandler0(emoteShortcutWindowShow)
{
showHideWindow(emoteShortcutWindow);
return true;
}
impHandler0(outfitWindowShow)
{
showHideWindow(outfitWindow);
return true;
}
impHandler0(shopWindowShow)
{
showHideWindow(shopWindow);
return true;
}
impHandler0(dropShortcutWindowShow)
{
showHideWindow(dropShortcutWindow);
return true;
}
impHandler0(killStatsWindowShow)
{
showHideWindow(killStats);
return true;
}
impHandler0(spellShortcutWindowShow)
{
showHideWindow(spellShortcutWindow);
return true;
}
impHandler0(botcheckerWindowShow)
{
showHideWindow(botCheckerWindow);
return true;
}
impHandler0(whoIsOnlineWindowShow)
{
showHideWindow(whoIsOnline);
return true;
}
impHandler0(didYouKnowWindowShow)
{
showHideWindow(didYouKnowWindow);
return true;
}
impHandler0(questsWindowShow)
{
showHideWindow(questsWindow);
return true;
}
impHandler0(changeMapMode)
{
if (viewport)
viewport->toggleDebugPath();
if (miniStatusWindow)
miniStatusWindow->updateStatus();
if (Game::instance())
{
if (Map *const map = Game::instance()->getCurrentMap())
map->redrawMap();
}
return true;
}
impHandler0(changeTrade)
{
unsigned int deflt = player_relations.getDefault();
if (deflt & PlayerRelation::TRADE)
{
if (localChatTab)
{
// TRANSLATORS: disable trades message
localChatTab->chatLog(_("Ignoring incoming trade requests"),
BY_SERVER);
}
deflt &= ~PlayerRelation::TRADE;
}
else
{
if (localChatTab)
{
// TRANSLATORS: enable trades message
localChatTab->chatLog(_("Accepting incoming trade requests"),
BY_SERVER);
}
deflt |= PlayerRelation::TRADE;
}
player_relations.setDefault(deflt);
return true;
}
impHandler0(screenshot)
{
Game::createScreenshot();
return true;
}
impHandler0(ignoreInput)
{
return true;
}
impHandler0(directUp)
{
if (player_node)
{
if (player_node->getDirection() != Being::UP)
{
// if (client->limitPackets(PACKET_DIRECTION))
{
player_node->setDirection(Being::UP);
if (Net::getPlayerHandler())
Net::getPlayerHandler()->setDirection(Being::UP);
}
}
return true;
}
return false;
}
impHandler0(directDown)
{
if (player_node)
{
if (player_node->getDirection() != Being::DOWN)
{
// if (client->limitPackets(PACKET_DIRECTION))
{
player_node->setDirection(Being::DOWN);
if (Net::getPlayerHandler())
Net::getPlayerHandler()->setDirection(Being::DOWN);
}
}
return true;
}
return false;
}
impHandler0(directLeft)
{
if (player_node)
{
if (player_node->getDirection() != Being::LEFT)
{
// if (client->limitPackets(PACKET_DIRECTION))
{
player_node->setDirection(Being::LEFT);
if (Net::getPlayerHandler())
Net::getPlayerHandler()->setDirection(Being::LEFT);
}
}
return true;
}
return false;
}
impHandler0(directRight)
{
if (player_node)
{
if (player_node->getDirection() != Being::RIGHT)
{
// if (client->limitPackets(PACKET_DIRECTION))
{
player_node->setDirection(Being::RIGHT);
if (Net::getPlayerHandler())
Net::getPlayerHandler()->setDirection(Being::RIGHT);
}
}
return true;
}
return false;
}
impHandler0(talk)
{
if (player_node)
{
Being *target = player_node->getTarget();
if (!target && actorManager)
{
target = actorManager->findNearestLivingBeing(
player_node, 1, ActorSprite::NPC);
// ignore closest target if distance in each direction more than 1
if (target)
{
if (abs(target->getTileX() - player_node->getTileX()) > 1
|| abs(target->getTileY() - player_node->getTileY()) > 1)
{
return true;
}
}
}
if (target)
{
if (target->canTalk())
target->talkTo();
else if (target->getType() == Being::PLAYER)
new BuySellDialog(target->getName());
}
return true;
}
return false;
}
impHandler0(stopAttack)
{
if (player_node)
{
player_node->stopAttack();
// not consume if target attack key pressed
if (inputManager.isActionActive(Input::KEY_TARGET_ATTACK))
return false;
return true;
}
return false;
}
impHandler0(untarget)
{
if (player_node)
{
player_node->untarget();
return true;
}
return false;
}
impHandler0(attack)
{
if (player_node)
{
Being *const target = player_node->getTarget();
if (target)
player_node->attack(target, true);
return true;
}
return false;
}
impHandler0(targetAttack)
{
if (player_node && actorManager)
{
Being *target = nullptr;
const bool newTarget = !inputManager.isActionActive(
Input::KEY_STOP_ATTACK);
// A set target has highest priority
if (!player_node->getTarget())
{
// Only auto target Monsters
target = actorManager->findNearestLivingBeing(
player_node, 90, ActorSprite::MONSTER);
}
else
{
target = player_node->getTarget();
}
player_node->attack2(target, newTarget);
return true;
}
return false;
}
static bool setTarget(const ActorSprite::Type type)
{
if (actorManager && player_node)
{
Being *const target = actorManager->findNearestLivingBeing(
player_node, 20, type);
if (target && target != player_node->getTarget())
player_node->setTarget(target);
return true;
}
return false;
}
impHandler0(targetPlayer)
{
return setTarget(ActorSprite::PLAYER);
}
impHandler0(targetMonster)
{
return setTarget(ActorSprite::MONSTER);
}
impHandler0(targetNPC)
{
return setTarget(ActorSprite::NPC);
}
impHandler0(safeVideoMode)
{
if (mainGraphics)
mainGraphics->setFullscreen(false);
return true;
}
impHandler0(stopSit)
{
if (player_node)
{
player_node->stopAttack();
// not consume if target attack key pressed
if (inputManager.isActionActive(Input::KEY_TARGET_ATTACK))
return false;
if (!player_node->getTarget())
{
if (inputManager.isActionActive(Input::KEY_EMOTE))
player_node->updateSit();
else
player_node->toggleSit();
}
return true;
}
return false;
}
impHandler0(showKeyboard)
{
#ifdef ANDROID
#ifdef USE_SDL2
if (SDL_IsTextInputActive())
SDL_StopTextInput();
else
SDL_StartTextInput();
#else
SDL_ANDROID_ToggleScreenKeyboardTextInput(nullptr);
#endif
return true;
#else
return false;
#endif
}
impHandler0(showWindows)
{
if (viewport)
{
viewport->showWindowsPopup();
return true;
}
return false;
}
impHandler0(nextShortcutsTab)
{
if (itemShortcutWindow)
{
itemShortcutWindow->nextTab();
return true;
}
return false;
}
impHandler0(prevShortcutsTab)
{
if (itemShortcutWindow)
{
itemShortcutWindow->prevTab();
return true;
}
return false;
}
impHandler0(nextCommandsTab)
{
if (spellShortcutWindow)
{
spellShortcutWindow->nextTab();
return true;
}
return false;
}
impHandler0(prevCommandsTab)
{
if (spellShortcutWindow)
{
spellShortcutWindow->prevTab();
return true;
}
return false;
}
impHandler0(openTrade)
{
const Being *const being = player_node->getTarget();
if (being && being->getType() == ActorSprite::PLAYER)
{
Net::getTradeHandler()->request(being);
tradePartnerName = being->getName();
if (tradeWindow)
tradeWindow->clear();
return true;
}
return false;
}
} // namespace ActionManager