/* * The ManaPlus Client * Copyright (C) 2009 The Mana World Development Team * Copyright (C) 2009-2010 Andrei Karas * Copyright (C) 2011-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 "spellmanager.h" #include "configuration.h" #include "being/attributes.h" #include "being/localplayer.h" #include "being/playerinfo.h" #include "gui/windows/chatwindow.h" #include "net/net.h" #include "net/playerhandler.h" #include "utils/dtor.h" #include "debug.h" SpellManager *spellManager = nullptr; SpellManager::SpellManager() : mSpells(), mSpellsVector() { load(); } SpellManager::~SpellManager() { delete_all(mSpells); mSpells.clear(); mSpellsVector.clear(); } TextCommand* SpellManager::getSpell(const int spellId) const { if (spellId < 0 || static_cast<size_t>(spellId) >= mSpells.size()) return nullptr; const std::map<unsigned int, TextCommand*>::const_iterator it = mSpells.find(spellId); return it != mSpells.end() ? (*it).second : nullptr; } const TextCommand* SpellManager::getSpellByItem(const int itemId) const { return getSpell(itemId - SPELL_MIN_ID); } void SpellManager::fillSpells() { // id, std::string name, std::string symbol, ST type, int basicLvl, // MagicSchool school, int schoolLvl, int mana) addSpell(new TextCommand(0, "lum", "#lum", "heal with lifestones", ALLOWTARGET, "", 1, SKILL_MAGIC_LIFE, 0, 6)); addSpell(new TextCommand(1, "inm", "#inma", "heal", NEEDTARGET, "", 2, SKILL_MAGIC_LIFE, 2, 10)); addSpell(new TextCommand(2, "fla", "#flar", "", NOTARGET, "", 1, SKILL_MAGIC_WAR, 0, 10)); addSpell(new TextCommand(3, "chi", "#chiza", "", NOTARGET, "", 1, SKILL_MAGIC_WAR, 0, 9)); addSpell(new TextCommand(4, "ing", "#ingrav", "", NOTARGET, "", 2, SKILL_MAGIC_WAR, 2, 20)); addSpell(new TextCommand(5, "fri", "#frillyar", "", NOTARGET, "", 2, SKILL_MAGIC_WAR, 2, 25)); addSpell(new TextCommand(6, "upm", "#upmarmu", "", NOTARGET, "", 2, SKILL_MAGIC_WAR, 2, 20)); addSpell(new TextCommand(7, "ite", "#itenplz", "", NOTARGET, "", 1, SKILL_MAGIC_NATURE, 0, 3)); addSpell(new TextCommand(8, "bet", "#betsanc", "", ALLOWTARGET, "", 2, SKILL_MAGIC_NATURE, 2, 14)); addSpell(new TextCommand(9, "abi", "#abizit", "", NOTARGET, "", 1, SKILL_MAGIC, 0, 1)); addSpell(new TextCommand(10, "inw", "#inwilt", "", NOTARGET, "", 2, SKILL_MAGIC, 2, 7)); addSpell(new TextCommand(11, "hi", "hi", "", NOTARGET, "")); addSpell(new TextCommand(12, "hea", "heal", "", NOTARGET, "")); addSpell(new TextCommand(13, "@sp", "@spawn maggot 10", "", NOTARGET, "")); for (unsigned f = 12; f < SPELL_SHORTCUT_ITEMS * SPELL_SHORTCUT_TABS; f++) addSpell(new TextCommand(f)); } bool SpellManager::addSpell(TextCommand *const spell) { if (!spell) return false; const std::map<unsigned int, TextCommand*>::const_iterator i = mSpells.find(spell->getId()); if (i == mSpells.end()) { mSpells[spell->getId()] = spell; mSpellsVector.push_back(spell); return true; } return false; } const std::vector<TextCommand*> &SpellManager::getAll() const { return mSpellsVector; } void SpellManager::useItem(const int itemId) const { invoke(itemId - SPELL_MIN_ID); } void SpellManager::invoke(const int spellId) const { if (!player_node) return; const TextCommand *const spell = getSpell(spellId); if (!spell) return; if (spell->getCommand() == "") return; if (spell->getCommandType() == TEXT_COMMAND_TEXT || (Net::getPlayerHandler()->canUseMagic() && PlayerInfo::getSkillLevel(SKILL_MAGIC) >= static_cast<signed>(spell->getBaseLvl()) && PlayerInfo::getSkillLevel(static_cast<int>( spell->getSchool())) >= static_cast<signed>(spell->getSchoolLvl()) && PlayerInfo::getAttribute(Attributes::MP) >= spell->getMana())) { const Being *const target = player_node->getTarget(); if (spell->getTargetType() == NOTARGET) { invokeSpell(spell); } if ((target && (target->getType() != ActorType::MONSTER || spell->getCommandType() == TEXT_COMMAND_TEXT)) && (spell->getTargetType() == ALLOWTARGET || spell->getTargetType() == NEEDTARGET)) { invokeSpell(spell, target); } else if (spell->getTargetType() == ALLOWTARGET) { invokeSpell(spell); } } } void SpellManager::invokeSpell(const TextCommand *const spell) { if (!chatWindow || !spell) return; chatWindow->localChatInput(parseCommand(spell->getCommand(), nullptr)); } void SpellManager::invokeSpell(const TextCommand *const spell, const Being *const target) { if (!chatWindow || !spell || !target) return; chatWindow->localChatInput(parseCommand(spell->getCommand(), target)); } std::string SpellManager::parseCommand(std::string command, const Being *const target) { if (!player_node) return command; std::string name; std::string id; std::string name2; if (target) { name = target->getName(); name2 = name; id = toString(target->getId()); } else { name2 = player_node->getName(); } bool found = false; size_t idx = command.find("<TARGET>"); if (idx != std::string::npos) { found = true; command = replaceAll(command, "<TARGET>", name); } idx = command.find("<TARGETID>"); if (idx != std::string::npos) { found = true; command = replaceAll(command, "<TARGETID>", id); } idx = command.find("<TARGETORSELF>"); if (idx != std::string::npos) { found = true; command = replaceAll(command, "<TARGETORSELF>", name2); } if (!found && !name.empty()) command.append(" ").append(name); return command; } TextCommand *SpellManager::createNewSpell() const { return new TextCommand(static_cast<unsigned>(mSpellsVector.size())); } void SpellManager::load(const bool oldConfig) { const Configuration *cfg; if (oldConfig) cfg = &config; else cfg = &serverConfig; delete_all(mSpells); mSpells.clear(); mSpellsVector.clear(); if (cfg->getValue("commandShortcutFlags0", "") == "") { fillSpells(); save(); return; } unsigned int targetType; unsigned int basicLvl; unsigned int school; unsigned int schoolLvl; unsigned int mana; unsigned int commandType; for (unsigned i = 0; i < SPELL_SHORTCUT_ITEMS * SPELL_SHORTCUT_TABS; i++) { std::string flags = cfg->getValue("commandShortcutFlags" + toString(i), ""); std::stringstream ss(flags); ss >> commandType; ss >> targetType; ss >> basicLvl; ss >> school; ss >> schoolLvl; ss >> mana; std::string cmd = cfg->getValue("commandShortcutCmd" + toString(i), ""); std::string comment = cfg->getValue("commandShortcutComment" + toString(i), ""); std::string symbol = cfg->getValue("commandShortcutSymbol" + toString(i), ""); std::string icon = cfg->getValue("commandShortcutIcon" + toString(i), ""); if (static_cast<TextCommandType>(commandType) == TEXT_COMMAND_MAGIC) { addSpell(new TextCommand(i, symbol, cmd, comment, static_cast<SpellTarget>(targetType), icon, basicLvl, static_cast<MagicSchool>(school), schoolLvl, mana)); } else { addSpell(new TextCommand(i, symbol, cmd, comment, static_cast<SpellTarget>(targetType), icon)); } } } void SpellManager::save() const { for (unsigned i = 0; i < SPELL_SHORTCUT_ITEMS * SPELL_SHORTCUT_TABS; i++) { const TextCommand *const spell = mSpellsVector[i]; if (spell) { if (spell->getCommand() != "") { serverConfig.setValue("commandShortcutCmd" + toString(i), spell->getCommand()); } else { serverConfig.deleteKey("commandShortcutCmd" + toString(i)); } if (spell->getComment() != "") { serverConfig.setValue("commandShortcutComment" + toString(i), spell->getComment()); } else { serverConfig.deleteKey("commandShortcutComment" + toString(i)); } if (spell->getSymbol() != "") { serverConfig.setValue("commandShortcutSymbol" + toString(i), spell->getSymbol()); } else { serverConfig.deleteKey("commandShortcutSymbol" + toString(i)); } if (spell->getIcon() != "") { serverConfig.setValue("commandShortcutIcon" + toString(i), spell->getIcon()); } else { serverConfig.deleteKey("commandShortcutIcon" + toString(i)); } if (spell->getCommand() != "" && spell->getSymbol() != "") { serverConfig.setValue("commandShortcutFlags" + toString(i), strprintf("%u %u %u %u %u %u", static_cast<unsigned>( spell->getCommandType()), static_cast<unsigned>( spell->getTargetType()), spell->getBaseLvl(), static_cast<unsigned>(spell->getSchool()), spell->getSchoolLvl(), static_cast<unsigned>( spell->getMana()))); } else { serverConfig.deleteKey("commandShortcutFlags" + toString(i)); } } } } std::string SpellManager::autoComplete(const std::string &partName) const { std::vector<TextCommand*>::const_iterator i = mSpellsVector.begin(); const std::vector<TextCommand*>::const_iterator i_end = mSpellsVector.end(); std::string newName; const TextCommand *newCommand = nullptr; while (i != i_end) { const TextCommand *const cmd = *i; const std::string line = cmd->getCommand(); if (!line.empty()) { const size_t pos = line.find(partName, 0); if (pos == 0) { if (!newName.empty()) { newName = findSameSubstring(line, newName); newCommand = nullptr; } else { newName = line; newCommand = cmd; } } } ++i; } if (!newName.empty() && newCommand && newCommand->getTargetType() == NEEDTARGET) { return newName.append(" "); } return newName; } void SpellManager::swap(const int id1, const int id2) { TextCommand *const spell1 = mSpells[id1]; TextCommand *const spell2 = mSpells[id2]; if (!spell1 || !spell2) return; // swap in map mSpells[id1] = spell2; mSpells[id2] = spell1; // swap id const int tmp = spell1->getId(); spell1->setId(spell2->getId()); spell2->setId(tmp); // swap in vector const size_t sz = SPELL_SHORTCUT_ITEMS * SPELL_SHORTCUT_TABS; for (size_t f = 0; f < sz; f++) { const TextCommand *const spellA = mSpellsVector[f]; if (spellA == spell1) { for (size_t d = 0; d < sz; d++) { const TextCommand *const spellB = mSpellsVector[d]; if (spellB == spell2) { mSpellsVector[f] = spell2; mSpellsVector[d] = spell1; return; } } } } }