Advertisement
Guest User

Untitled

a guest
Feb 8th, 2020
350
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 34.91 KB | None | 0 0
  1. /**
  2. * The Forgotten Server - a free and open-source MMORPG server emulator
  3. * Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License along
  16. * with this program; if not, write to the Free Software Foundation, Inc.,
  17. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  18. */
  19.  
  20. #include "otpch.h"
  21.  
  22. #include "combat.h"
  23. #include "configmanager.h"
  24. #include "game.h"
  25. #include "monster.h"
  26. #include "pugicast.h"
  27. #include "spells.h"
  28.  
  29. extern Game g_game;
  30. extern Spells* g_spells;
  31. extern Monsters g_monsters;
  32. extern Vocations g_vocations;
  33. extern ConfigManager g_config;
  34. extern LuaEnvironment g_luaEnvironment;
  35.  
  36. Spells::Spells()
  37. {
  38. scriptInterface.initState();
  39. }
  40.  
  41. Spells::~Spells()
  42. {
  43. clear(false);
  44. }
  45.  
  46. TalkActionResult_t Spells::playerSaySpell(Player* player, std::string& words)
  47. {
  48. std::string str_words = words;
  49.  
  50. //strip trailing spaces
  51. trimString(str_words);
  52.  
  53. InstantSpell* instantSpell = getInstantSpell(str_words);
  54. if (!instantSpell) {
  55. return TALKACTION_CONTINUE;
  56. }
  57.  
  58. std::string param;
  59.  
  60. if (instantSpell->getHasParam()) {
  61. size_t spellLen = instantSpell->getWords().length();
  62. size_t paramLen = str_words.length() - spellLen;
  63. std::string paramText = str_words.substr(spellLen, paramLen);
  64. if (!paramText.empty() && paramText.front() == ' ') {
  65. size_t loc1 = paramText.find('"', 1);
  66. if (loc1 != std::string::npos) {
  67. size_t loc2 = paramText.find('"', loc1 + 1);
  68. if (loc2 == std::string::npos) {
  69. loc2 = paramText.length();
  70. } else if (paramText.find_last_not_of(' ') != loc2) {
  71. return TALKACTION_CONTINUE;
  72. }
  73.  
  74. param = paramText.substr(loc1 + 1, loc2 - loc1 - 1);
  75. } else {
  76. trimString(paramText);
  77. loc1 = paramText.find(' ', 0);
  78. if (loc1 == std::string::npos) {
  79. param = paramText;
  80. } else {
  81. return TALKACTION_CONTINUE;
  82. }
  83. }
  84. }
  85. }
  86.  
  87. if (instantSpell->playerCastInstant(player, param)) {
  88. words = instantSpell->getWords();
  89.  
  90. if (instantSpell->getHasParam() && !param.empty()) {
  91. words += " \"" + param + "\"";
  92. }
  93.  
  94. return TALKACTION_BREAK;
  95. }
  96.  
  97. return TALKACTION_FAILED;
  98. }
  99.  
  100. void Spells::clearMaps(bool fromLua)
  101. {
  102. for (auto instant = instants.begin(); instant != instants.end(); ) {
  103. if (fromLua == instant->second.fromLua) {
  104. instant = instants.erase(instant);
  105. } else {
  106. ++instant;
  107. }
  108. }
  109.  
  110. for (auto rune = runes.begin(); rune != runes.end(); ) {
  111. if (fromLua == rune->second.fromLua) {
  112. rune = runes.erase(rune);
  113. } else {
  114. ++rune;
  115. }
  116. }
  117. }
  118.  
  119. void Spells::clear(bool fromLua)
  120. {
  121. clearMaps(fromLua);
  122.  
  123. reInitState(fromLua);
  124. }
  125.  
  126. LuaScriptInterface& Spells::getScriptInterface()
  127. {
  128. return scriptInterface;
  129. }
  130.  
  131. std::string Spells::getScriptBaseName() const
  132. {
  133. return "spells";
  134. }
  135.  
  136. Event_ptr Spells::getEvent(const std::string& nodeName)
  137. {
  138. if (strcasecmp(nodeName.c_str(), "rune") == 0) {
  139. return Event_ptr(new RuneSpell(&scriptInterface));
  140. } else if (strcasecmp(nodeName.c_str(), "instant") == 0) {
  141. return Event_ptr(new InstantSpell(&scriptInterface));
  142. }
  143. return nullptr;
  144. }
  145.  
  146. bool Spells::registerEvent(Event_ptr event, const pugi::xml_node&)
  147. {
  148. InstantSpell* instant = dynamic_cast<InstantSpell*>(event.get());
  149. if (instant) {
  150. auto result = instants.emplace(instant->getWords(), std::move(*instant));
  151. if (!result.second) {
  152. std::cout << "[Warning - Spells::registerEvent] Duplicate registered instant spell with words: " << instant->getWords() << std::endl;
  153. }
  154. return result.second;
  155. }
  156.  
  157. RuneSpell* rune = dynamic_cast<RuneSpell*>(event.get());
  158. if (rune) {
  159. auto result = runes.emplace(rune->getRuneItemId(), std::move(*rune));
  160. if (!result.second) {
  161. std::cout << "[Warning - Spells::registerEvent] Duplicate registered rune with id: " << rune->getRuneItemId() << std::endl;
  162. }
  163. return result.second;
  164. }
  165.  
  166. return false;
  167. }
  168.  
  169. bool Spells::registerInstantLuaEvent(InstantSpell* event)
  170. {
  171. InstantSpell_ptr instant { event };
  172. if (instant) {
  173. std::string words = instant->getWords();
  174. auto result = instants.emplace(instant->getWords(), std::move(*instant));
  175. if (!result.second) {
  176. std::cout << "[Warning - Spells::registerInstantLuaEvent] Duplicate registered instant spell with words: " << words << std::endl;
  177. }
  178. return result.second;
  179. }
  180.  
  181. return false;
  182. }
  183.  
  184. bool Spells::registerRuneLuaEvent(RuneSpell* event)
  185. {
  186. RuneSpell_ptr rune { event };
  187. if (rune) {
  188. uint16_t id = rune->getRuneItemId();
  189. auto result = runes.emplace(rune->getRuneItemId(), std::move(*rune));
  190. if (!result.second) {
  191. std::cout << "[Warning - Spells::registerRuneLuaEvent] Duplicate registered rune with id: " << id << std::endl;
  192. }
  193. return result.second;
  194. }
  195.  
  196. return false;
  197. }
  198.  
  199. std::list<uint16_t> Spells::getSpellsByVocation(uint16_t vocationId)
  200. {
  201. std::list<uint16_t> spellsList;
  202. for (const auto& it : instants) {
  203. VocSpellMap map = it.second.getVocMap();
  204. if (map.find(vocationId)->second) {
  205. spellsList.push_back(it.second.getId());
  206. }
  207. }
  208. return spellsList;
  209. }
  210.  
  211. Spell* Spells::getSpellByName(const std::string& name)
  212. {
  213. Spell* spell = getRuneSpellByName(name);
  214. if (!spell) {
  215. spell = getInstantSpellByName(name);
  216. }
  217. return spell;
  218. }
  219.  
  220. RuneSpell* Spells::getRuneSpell(uint32_t id)
  221. {
  222. auto it = runes.find(id);
  223. if (it == runes.end()) {
  224. for (auto& rune : runes) {
  225. if (rune.second.getId() == id) {
  226. return &rune.second;
  227. }
  228. }
  229. return nullptr;
  230. }
  231. return &it->second;
  232. }
  233.  
  234. RuneSpell* Spells::getRuneSpellByName(const std::string& name)
  235. {
  236. for (auto& it : runes) {
  237. if (strcasecmp(it.second.getName().c_str(), name.c_str()) == 0) {
  238. return &it.second;
  239. }
  240. }
  241. return nullptr;
  242. }
  243.  
  244. InstantSpell* Spells::getInstantSpell(const std::string& words)
  245. {
  246. InstantSpell* result = nullptr;
  247.  
  248. for (auto& it : instants) {
  249. const std::string& instantSpellWords = it.second.getWords();
  250. size_t spellLen = instantSpellWords.length();
  251. if (strncasecmp(instantSpellWords.c_str(), words.c_str(), spellLen) == 0) {
  252. if (!result || spellLen > result->getWords().length()) {
  253. result = &it.second;
  254. if (words.length() == spellLen) {
  255. break;
  256. }
  257. }
  258. }
  259. }
  260.  
  261. if (result) {
  262. const std::string& resultWords = result->getWords();
  263. if (words.length() > resultWords.length()) {
  264. if (!result->getHasParam()) {
  265. return nullptr;
  266. }
  267.  
  268. size_t spellLen = resultWords.length();
  269. size_t paramLen = words.length() - spellLen;
  270. if (paramLen < 2 || words[spellLen] != ' ') {
  271. return nullptr;
  272. }
  273. }
  274. return result;
  275. }
  276. return nullptr;
  277. }
  278.  
  279. InstantSpell* Spells::getInstantSpellById(uint32_t spellId)
  280. {
  281. for (auto& it : instants) {
  282. if (it.second.getId() == spellId) {
  283. return &it.second;
  284. }
  285. }
  286. return nullptr;
  287. }
  288.  
  289. InstantSpell* Spells::getInstantSpellByName(const std::string& name)
  290. {
  291. for (auto& it : instants) {
  292. if (strcasecmp(it.second.getName().c_str(), name.c_str()) == 0) {
  293. return &it.second;
  294. }
  295. }
  296. return nullptr;
  297. }
  298.  
  299. Position Spells::getCasterPosition(Creature* creature, Direction dir)
  300. {
  301. return getNextPosition(dir, creature->getPosition());
  302. }
  303.  
  304. CombatSpell::CombatSpell(Combat* combat, bool needTarget, bool needDirection) :
  305. Event(&g_spells->getScriptInterface()),
  306. combat(combat),
  307. needDirection(needDirection),
  308. needTarget(needTarget)
  309. {}
  310.  
  311. CombatSpell::~CombatSpell()
  312. {
  313. if (!scripted) {
  314. delete combat;
  315. }
  316. }
  317.  
  318. bool CombatSpell::loadScriptCombat()
  319. {
  320. combat = g_luaEnvironment.getCombatObject(g_luaEnvironment.lastCombatId);
  321. return combat != nullptr;
  322. }
  323.  
  324. bool CombatSpell::castSpell(Creature* creature)
  325. {
  326. if (scripted) {
  327. LuaVariant var;
  328. var.type = VARIANT_POSITION;
  329.  
  330. if (needDirection) {
  331. var.pos = Spells::getCasterPosition(creature, creature->getDirection());
  332. } else {
  333. var.pos = creature->getPosition();
  334. }
  335.  
  336. return executeCastSpell(creature, var);
  337. }
  338.  
  339. Position pos;
  340. if (needDirection) {
  341. pos = Spells::getCasterPosition(creature, creature->getDirection());
  342. } else {
  343. pos = creature->getPosition();
  344. }
  345.  
  346. combat->doCombat(creature, pos);
  347. return true;
  348. }
  349.  
  350. bool CombatSpell::castSpell(Creature* creature, Creature* target)
  351. {
  352. if (scripted) {
  353. LuaVariant var;
  354.  
  355. if (combat->hasArea()) {
  356. var.type = VARIANT_POSITION;
  357.  
  358. if (needTarget) {
  359. var.pos = target->getPosition();
  360. } else if (needDirection) {
  361. var.pos = Spells::getCasterPosition(creature, creature->getDirection());
  362. } else {
  363. var.pos = creature->getPosition();
  364. }
  365. } else {
  366. var.type = VARIANT_NUMBER;
  367. var.number = target->getID();
  368. }
  369. return executeCastSpell(creature, var);
  370. }
  371.  
  372. if (combat->hasArea()) {
  373. if (needTarget) {
  374. combat->doCombat(creature, target->getPosition());
  375. } else {
  376. return castSpell(creature);
  377. }
  378. } else {
  379. combat->doCombat(creature, target);
  380. }
  381. return true;
  382. }
  383.  
  384. bool CombatSpell::executeCastSpell(Creature* creature, const LuaVariant& var)
  385. {
  386. //onCastSpell(creature, var)
  387. if (!scriptInterface->reserveScriptEnv()) {
  388. std::cout << "[Error - CombatSpell::executeCastSpell] Call stack overflow" << std::endl;
  389. return false;
  390. }
  391.  
  392. ScriptEnvironment* env = scriptInterface->getScriptEnv();
  393. env->setScriptId(scriptId, scriptInterface);
  394.  
  395. lua_State* L = scriptInterface->getLuaState();
  396.  
  397. scriptInterface->pushFunction(scriptId);
  398.  
  399. LuaScriptInterface::pushUserdata<Creature>(L, creature);
  400. LuaScriptInterface::setCreatureMetatable(L, -1, creature);
  401.  
  402. LuaScriptInterface::pushVariant(L, var);
  403.  
  404. return scriptInterface->callFunction(2);
  405. }
  406.  
  407. bool Spell::configureSpell(const pugi::xml_node& node)
  408. {
  409. pugi::xml_attribute nameAttribute = node.attribute("name");
  410. if (!nameAttribute) {
  411. std::cout << "[Error - Spell::configureSpell] Spell without name" << std::endl;
  412. return false;
  413. }
  414.  
  415. name = nameAttribute.as_string();
  416.  
  417. static const char* reservedList[] = {
  418. "melee",
  419. "physical",
  420. "poison",
  421. "fire",
  422. "energy",
  423. "drown",
  424. "lifedrain",
  425. "manadrain",
  426. "healing",
  427. "speed",
  428. "outfit",
  429. "invisible",
  430. "drunk",
  431. "firefield",
  432. "poisonfield",
  433. "energyfield",
  434. "firecondition",
  435. "poisoncondition",
  436. "energycondition",
  437. "drowncondition",
  438. "freezecondition",
  439. "cursecondition",
  440. "dazzlecondition"
  441. };
  442.  
  443. //static size_t size = sizeof(reservedList) / sizeof(const char*);
  444. //for (size_t i = 0; i < size; ++i) {
  445. for (const char* reserved : reservedList) {
  446. if (strcasecmp(reserved, name.c_str()) == 0) {
  447. std::cout << "[Error - Spell::configureSpell] Spell is using a reserved name: " << reserved << std::endl;
  448. return false;
  449. }
  450. }
  451.  
  452. pugi::xml_attribute attr;
  453. if ((attr = node.attribute("spellid"))) {
  454. spellId = pugi::cast<uint16_t>(attr.value());
  455. }
  456.  
  457. if ((attr = node.attribute("group"))) {
  458. std::string tmpStr = asLowerCaseString(attr.as_string());
  459. if (tmpStr == "none" || tmpStr == "0") {
  460. group = SPELLGROUP_NONE;
  461. } else if (tmpStr == "attack" || tmpStr == "1") {
  462. group = SPELLGROUP_ATTACK;
  463. } else if (tmpStr == "healing" || tmpStr == "2") {
  464. group = SPELLGROUP_HEALING;
  465. } else if (tmpStr == "support" || tmpStr == "3") {
  466. group = SPELLGROUP_SUPPORT;
  467. } else if (tmpStr == "special" || tmpStr == "4") {
  468. group = SPELLGROUP_SPECIAL;
  469. } else {
  470. std::cout << "[Warning - Spell::configureSpell] Unknown group: " << attr.as_string() << std::endl;
  471. }
  472. }
  473.  
  474. if ((attr = node.attribute("groupcooldown"))) {
  475. groupCooldown = pugi::cast<uint32_t>(attr.value());
  476. }
  477.  
  478. if ((attr = node.attribute("secondarygroup"))) {
  479. std::string tmpStr = asLowerCaseString(attr.as_string());
  480. if (tmpStr == "none" || tmpStr == "0") {
  481. secondaryGroup = SPELLGROUP_NONE;
  482. } else if (tmpStr == "attack" || tmpStr == "1") {
  483. secondaryGroup = SPELLGROUP_ATTACK;
  484. } else if (tmpStr == "healing" || tmpStr == "2") {
  485. secondaryGroup = SPELLGROUP_HEALING;
  486. } else if (tmpStr == "support" || tmpStr == "3") {
  487. secondaryGroup = SPELLGROUP_SUPPORT;
  488. } else if (tmpStr == "special" || tmpStr == "4") {
  489. secondaryGroup = SPELLGROUP_SPECIAL;
  490. } else {
  491. std::cout << "[Warning - Spell::configureSpell] Unknown secondarygroup: " << attr.as_string() << std::endl;
  492. }
  493. }
  494.  
  495. if ((attr = node.attribute("secondarygroupcooldown"))) {
  496. secondaryGroupCooldown = pugi::cast<uint32_t>(attr.value());
  497. }
  498.  
  499. if ((attr = node.attribute("level")) || (attr = node.attribute("lvl"))) {
  500. level = pugi::cast<uint32_t>(attr.value());
  501. }
  502.  
  503. if ((attr = node.attribute("magiclevel")) || (attr = node.attribute("maglv"))) {
  504. magLevel = pugi::cast<uint32_t>(attr.value());
  505. }
  506.  
  507. if ((attr = node.attribute("mana"))) {
  508. mana = pugi::cast<uint32_t>(attr.value());
  509. }
  510.  
  511. if ((attr = node.attribute("manapercent"))) {
  512. manaPercent = pugi::cast<uint32_t>(attr.value());
  513. }
  514.  
  515. if ((attr = node.attribute("soul"))) {
  516. soul = pugi::cast<uint32_t>(attr.value());
  517. }
  518.  
  519. if ((attr = node.attribute("range"))) {
  520. range = pugi::cast<int32_t>(attr.value());
  521. }
  522.  
  523. if ((attr = node.attribute("cooldown")) || (attr = node.attribute("exhaustion"))) {
  524. cooldown = pugi::cast<uint32_t>(attr.value());
  525. }
  526.  
  527. if ((attr = node.attribute("premium")) || (attr = node.attribute("prem"))) {
  528. premium = attr.as_bool();
  529. }
  530.  
  531. if ((attr = node.attribute("enabled"))) {
  532. enabled = attr.as_bool();
  533. }
  534.  
  535. if ((attr = node.attribute("needtarget"))) {
  536. needTarget = attr.as_bool();
  537. }
  538.  
  539. if ((attr = node.attribute("needweapon"))) {
  540. needWeapon = attr.as_bool();
  541. }
  542.  
  543. if ((attr = node.attribute("selftarget"))) {
  544. selfTarget = attr.as_bool();
  545. }
  546.  
  547. if ((attr = node.attribute("needlearn"))) {
  548. learnable = attr.as_bool();
  549. }
  550.  
  551. if ((attr = node.attribute("blocking"))) {
  552. blockingSolid = attr.as_bool();
  553. blockingCreature = blockingSolid;
  554. }
  555.  
  556. if ((attr = node.attribute("blocktype"))) {
  557. std::string tmpStrValue = asLowerCaseString(attr.as_string());
  558. if (tmpStrValue == "all") {
  559. blockingSolid = true;
  560. blockingCreature = true;
  561. } else if (tmpStrValue == "solid") {
  562. blockingSolid = true;
  563. } else if (tmpStrValue == "creature") {
  564. blockingCreature = true;
  565. } else {
  566. std::cout << "[Warning - Spell::configureSpell] Blocktype \"" << attr.as_string() << "\" does not exist." << std::endl;
  567. }
  568. }
  569.  
  570. if ((attr = node.attribute("aggressive"))) {
  571. aggressive = booleanString(attr.as_string());
  572. }
  573.  
  574. if (group == SPELLGROUP_NONE) {
  575. group = (aggressive ? SPELLGROUP_ATTACK : SPELLGROUP_HEALING);
  576. }
  577.  
  578. for (auto vocationNode : node.children()) {
  579. if (!(attr = vocationNode.attribute("name"))) {
  580. continue;
  581. }
  582.  
  583. int32_t vocationId = g_vocations.getVocationId(attr.as_string());
  584. if (vocationId != -1) {
  585. attr = vocationNode.attribute("showInDescription");
  586. vocSpellMap[vocationId] = !attr || attr.as_bool();
  587. } else {
  588. std::cout << "[Warning - Spell::configureSpell] Wrong vocation name: " << attr.as_string() << std::endl;
  589. }
  590. }
  591. return true;
  592. }
  593.  
  594. bool Spell::playerSpellCheck(Player* player) const
  595. {
  596. if (player->hasFlag(PlayerFlag_CannotUseSpells)) {
  597. return false;
  598. }
  599.  
  600. if (player->hasFlag(PlayerFlag_IgnoreSpellCheck)) {
  601. return true;
  602. }
  603.  
  604. if (!enabled) {
  605. return false;
  606. }
  607.  
  608. if (aggressive && (range < 1 || (range > 0 && !player->getAttackedCreature())) && player->getSkull() == SKULL_BLACK) {
  609. player->sendCancelMessage(RETURNVALUE_NOTPOSSIBLE);
  610. return false;
  611. }
  612.  
  613. if (aggressive && player->hasCondition(CONDITION_PACIFIED)) {
  614. player->sendCancelMessage(RETURNVALUE_YOUAREEXHAUSTED);
  615. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  616. return false;
  617. }
  618.  
  619. if (aggressive && !player->hasFlag(PlayerFlag_IgnoreProtectionZone) && player->getZone() == ZONE_PROTECTION) {
  620. player->sendCancelMessage(RETURNVALUE_ACTIONNOTPERMITTEDINPROTECTIONZONE);
  621. return false;
  622. }
  623.  
  624. if (player->hasCondition(CONDITION_SPELLGROUPCOOLDOWN, group) || player->hasCondition(CONDITION_SPELLCOOLDOWN, spellId) || (secondaryGroup != SPELLGROUP_NONE && player->hasCondition(CONDITION_SPELLGROUPCOOLDOWN, secondaryGroup))) {
  625. player->sendCancelMessage(RETURNVALUE_YOUAREEXHAUSTED);
  626.  
  627. if (isInstant()) {
  628. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  629. }
  630.  
  631. return false;
  632. }
  633.  
  634. if (player->getLevel() < level) {
  635. player->sendCancelMessage(RETURNVALUE_NOTENOUGHLEVEL);
  636. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  637. return false;
  638. }
  639.  
  640. if (player->getMagicLevel() < magLevel) {
  641. player->sendCancelMessage(RETURNVALUE_NOTENOUGHMAGICLEVEL);
  642. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  643. return false;
  644. }
  645.  
  646. if (player->getMana() < getManaCost(player) && !player->hasFlag(PlayerFlag_HasInfiniteMana)) {
  647. player->sendCancelMessage(RETURNVALUE_NOTENOUGHMANA);
  648. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  649. return false;
  650. }
  651.  
  652. if (player->getSoul() < soul && !player->hasFlag(PlayerFlag_HasInfiniteSoul)) {
  653. player->sendCancelMessage(RETURNVALUE_NOTENOUGHSOUL);
  654. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  655. return false;
  656. }
  657.  
  658. if (isInstant() && isLearnable()) {
  659. if (!player->hasLearnedInstantSpell(getName())) {
  660. player->sendCancelMessage(RETURNVALUE_YOUNEEDTOLEARNTHISSPELL);
  661. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  662. return false;
  663. }
  664. } else if (!vocSpellMap.empty() && vocSpellMap.find(player->getVocationId()) == vocSpellMap.end()) {
  665. player->sendCancelMessage(RETURNVALUE_YOURVOCATIONCANNOTUSETHISSPELL);
  666. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  667. return false;
  668. }
  669.  
  670. if (needWeapon) {
  671. switch (player->getWeaponType()) {
  672. case WEAPON_SWORD:
  673. case WEAPON_CLUB:
  674. case WEAPON_AXE:
  675. break;
  676.  
  677. default: {
  678. player->sendCancelMessage(RETURNVALUE_YOUNEEDAWEAPONTOUSETHISSPELL);
  679. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  680. return false;
  681. }
  682. }
  683. }
  684.  
  685. if (isPremium() && !player->isPremium()) {
  686. player->sendCancelMessage(RETURNVALUE_YOUNEEDPREMIUMACCOUNT);
  687. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  688. return false;
  689. }
  690.  
  691. return true;
  692. }
  693.  
  694. bool Spell::playerInstantSpellCheck(Player* player, const Position& toPos)
  695. {
  696. if (toPos.x == 0xFFFF) {
  697. return true;
  698. }
  699.  
  700. const Position& playerPos = player->getPosition();
  701. if (playerPos.z > toPos.z) {
  702. player->sendCancelMessage(RETURNVALUE_FIRSTGOUPSTAIRS);
  703. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  704. return false;
  705. } else if (playerPos.z < toPos.z) {
  706. player->sendCancelMessage(RETURNVALUE_FIRSTGODOWNSTAIRS);
  707. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  708. return false;
  709. }
  710.  
  711. Tile* tile = g_game.map.getTile(toPos);
  712. if (!tile) {
  713. tile = new StaticTile(toPos.x, toPos.y, toPos.z);
  714. g_game.map.setTile(toPos, tile);
  715. }
  716.  
  717. ReturnValue ret = Combat::canDoCombat(player, tile, aggressive);
  718. if (ret != RETURNVALUE_NOERROR) {
  719. player->sendCancelMessage(ret);
  720. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  721. return false;
  722. }
  723.  
  724. if (blockingCreature && tile->getBottomVisibleCreature(player) != nullptr) {
  725. player->sendCancelMessage(RETURNVALUE_NOTENOUGHROOM);
  726. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  727. return false;
  728. }
  729.  
  730. if (blockingSolid && tile->hasFlag(TILESTATE_BLOCKSOLID)) {
  731. player->sendCancelMessage(RETURNVALUE_NOTENOUGHROOM);
  732. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  733. return false;
  734. }
  735.  
  736. return true;
  737. }
  738.  
  739. bool Spell::playerRuneSpellCheck(Player* player, const Position& toPos)
  740. {
  741. if (!playerSpellCheck(player)) {
  742. return false;
  743. }
  744.  
  745. if (toPos.x == 0xFFFF) {
  746. return true;
  747. }
  748.  
  749. const Position& playerPos = player->getPosition();
  750. if (playerPos.z > toPos.z) {
  751. player->sendCancelMessage(RETURNVALUE_FIRSTGOUPSTAIRS);
  752. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  753. return false;
  754. } else if (playerPos.z < toPos.z) {
  755. player->sendCancelMessage(RETURNVALUE_FIRSTGODOWNSTAIRS);
  756. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  757. return false;
  758. }
  759.  
  760. Tile* tile = g_game.map.getTile(toPos);
  761. if (!tile) {
  762. player->sendCancelMessage(RETURNVALUE_NOTPOSSIBLE);
  763. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  764. return false;
  765. }
  766.  
  767. if (range != -1 && !g_game.canThrowObjectTo(playerPos, toPos, true, range, range)) {
  768. player->sendCancelMessage(RETURNVALUE_DESTINATIONOUTOFREACH);
  769. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  770. return false;
  771. }
  772.  
  773. ReturnValue ret = Combat::canDoCombat(player, tile, aggressive);
  774. if (ret != RETURNVALUE_NOERROR) {
  775. player->sendCancelMessage(ret);
  776. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  777. return false;
  778. }
  779.  
  780. const Creature* topVisibleCreature = tile->getBottomVisibleCreature(player);
  781. if (blockingCreature && topVisibleCreature) {
  782. player->sendCancelMessage(RETURNVALUE_NOTENOUGHROOM);
  783. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  784. return false;
  785. } else if (blockingSolid && tile->hasFlag(TILESTATE_BLOCKSOLID)) {
  786. player->sendCancelMessage(RETURNVALUE_NOTENOUGHROOM);
  787. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  788. return false;
  789. }
  790.  
  791. if (needTarget && !topVisibleCreature) {
  792. player->sendCancelMessage(RETURNVALUE_CANONLYUSETHISRUNEONCREATURES);
  793. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  794. return false;
  795. }
  796.  
  797. if (aggressive && needTarget && topVisibleCreature && player->hasSecureMode()) {
  798. const Player* targetPlayer = topVisibleCreature->getPlayer();
  799. if (targetPlayer && targetPlayer != player && player->getSkullClient(targetPlayer) == SKULL_NONE && !Combat::isInPvpZone(player, targetPlayer)) {
  800. player->sendCancelMessage(RETURNVALUE_TURNSECUREMODETOATTACKUNMARKEDPLAYERS);
  801. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  802. return false;
  803. }
  804. }
  805. return true;
  806. }
  807.  
  808. void Spell::postCastSpell(Player* player, bool finishedCast /*= true*/, bool payCost /*= true*/) const
  809. {
  810. if (finishedCast) {
  811. if (!player->hasFlag(PlayerFlag_HasNoExhaustion)) {
  812. if (cooldown > 0) {
  813. Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_SPELLCOOLDOWN, cooldown, 0, false, spellId);
  814. player->addCondition(condition);
  815. }
  816.  
  817. if (groupCooldown > 0) {
  818. Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_SPELLGROUPCOOLDOWN, groupCooldown, 0, false, group);
  819. player->addCondition(condition);
  820. }
  821.  
  822. if (secondaryGroupCooldown > 0) {
  823. Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_SPELLGROUPCOOLDOWN, secondaryGroupCooldown, 0, false, secondaryGroup);
  824. player->addCondition(condition);
  825. }
  826. }
  827.  
  828. if (aggressive) {
  829. player->addInFightTicks();
  830. }
  831. }
  832.  
  833. if (payCost) {
  834. Spell::postCastSpell(player, getManaCost(player), getSoulCost());
  835. }
  836. }
  837.  
  838. void Spell::postCastSpell(Player* player, uint32_t manaCost, uint32_t soulCost)
  839. {
  840. if (manaCost > 0) {
  841. player->addManaSpent(manaCost);
  842. player->changeMana(-static_cast<int32_t>(manaCost));
  843. }
  844.  
  845. if (!player->hasFlag(PlayerFlag_HasInfiniteSoul)) {
  846. if (soulCost > 0) {
  847. player->changeSoul(-static_cast<int32_t>(soulCost));
  848. }
  849. }
  850. }
  851.  
  852. uint32_t Spell::getManaCost(const Player* player) const
  853. {
  854. if (mana != 0) {
  855. return mana;
  856. }
  857.  
  858. if (manaPercent != 0) {
  859. uint32_t maxMana = player->getMaxMana();
  860. uint32_t manaCost = (maxMana * manaPercent) / 100;
  861. return manaCost;
  862. }
  863.  
  864. return 0;
  865. }
  866.  
  867. std::string InstantSpell::getScriptEventName() const
  868. {
  869. return "onCastSpell";
  870. }
  871.  
  872. bool InstantSpell::configureEvent(const pugi::xml_node& node)
  873. {
  874. if (!Spell::configureSpell(node)) {
  875. return false;
  876. }
  877.  
  878. if (!TalkAction::configureEvent(node)) {
  879. return false;
  880. }
  881.  
  882. spellType = SPELL_INSTANT;
  883.  
  884. pugi::xml_attribute attr;
  885. if ((attr = node.attribute("params"))) {
  886. hasParam = attr.as_bool();
  887. }
  888.  
  889. if ((attr = node.attribute("playernameparam"))) {
  890. hasPlayerNameParam = attr.as_bool();
  891. }
  892.  
  893. if ((attr = node.attribute("direction"))) {
  894. needDirection = attr.as_bool();
  895. } else if ((attr = node.attribute("casterTargetOrDirection"))) {
  896. casterTargetOrDirection = attr.as_bool();
  897. }
  898.  
  899. if ((attr = node.attribute("blockwalls"))) {
  900. checkLineOfSight = attr.as_bool();
  901. }
  902. return true;
  903. }
  904.  
  905. bool InstantSpell::playerCastInstant(Player* player, std::string& param)
  906. {
  907. if (!playerSpellCheck(player)) {
  908. return false;
  909. }
  910.  
  911. LuaVariant var;
  912.  
  913. if (selfTarget) {
  914. var.type = VARIANT_NUMBER;
  915. var.number = player->getID();
  916. } else if (needTarget || casterTargetOrDirection) {
  917. Creature* target = nullptr;
  918. bool useDirection = false;
  919.  
  920. if (hasParam) {
  921. Player* playerTarget = nullptr;
  922. ReturnValue ret = g_game.getPlayerByNameWildcard(param, playerTarget);
  923.  
  924. if (playerTarget && playerTarget->isAccessPlayer() && !player->isAccessPlayer()) {
  925. playerTarget = nullptr;
  926. }
  927.  
  928. target = playerTarget;
  929. if (!target || target->getHealth() <= 0) {
  930. if (!casterTargetOrDirection) {
  931. if (cooldown > 0) {
  932. Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_SPELLCOOLDOWN, cooldown, 0, false, spellId);
  933. player->addCondition(condition);
  934. }
  935.  
  936. if (groupCooldown > 0) {
  937. Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_SPELLGROUPCOOLDOWN, groupCooldown, 0, false, group);
  938. player->addCondition(condition);
  939. }
  940.  
  941. if (secondaryGroupCooldown > 0) {
  942. Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_SPELLGROUPCOOLDOWN, secondaryGroupCooldown, 0, false, secondaryGroup);
  943. player->addCondition(condition);
  944. }
  945.  
  946. player->sendCancelMessage(ret);
  947. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  948. return false;
  949. }
  950.  
  951. useDirection = true;
  952. }
  953.  
  954. if (playerTarget) {
  955. param = playerTarget->getName();
  956. }
  957. } else {
  958. target = player->getAttackedCreature();
  959. if (!target || target->getHealth() <= 0) {
  960. if (!casterTargetOrDirection) {
  961. player->sendCancelMessage(RETURNVALUE_YOUCANONLYUSEITONCREATURES);
  962. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  963. return false;
  964. }
  965.  
  966. useDirection = true;
  967. }
  968. }
  969.  
  970. if (!useDirection) {
  971. if (!canThrowSpell(player, target)) {
  972. player->sendCancelMessage(RETURNVALUE_CREATUREISNOTREACHABLE);
  973. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  974. return false;
  975. }
  976.  
  977. var.type = VARIANT_NUMBER;
  978. var.number = target->getID();
  979. } else {
  980. var.type = VARIANT_POSITION;
  981. var.pos = Spells::getCasterPosition(player, player->getDirection());
  982.  
  983. if (!playerInstantSpellCheck(player, var.pos)) {
  984. return false;
  985. }
  986. }
  987. } else if (hasParam) {
  988. var.type = VARIANT_STRING;
  989.  
  990. if (getHasPlayerNameParam()) {
  991. Player* playerTarget = nullptr;
  992. ReturnValue ret = g_game.getPlayerByNameWildcard(param, playerTarget);
  993.  
  994. if (ret != RETURNVALUE_NOERROR) {
  995. if (cooldown > 0) {
  996. Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_SPELLCOOLDOWN, cooldown, 0, false, spellId);
  997. player->addCondition(condition);
  998. }
  999.  
  1000. if (groupCooldown > 0) {
  1001. Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_SPELLGROUPCOOLDOWN, groupCooldown, 0, false, group);
  1002. player->addCondition(condition);
  1003. }
  1004.  
  1005. if (secondaryGroupCooldown > 0) {
  1006. Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_SPELLGROUPCOOLDOWN, secondaryGroupCooldown, 0, false, secondaryGroup);
  1007. player->addCondition(condition);
  1008. }
  1009.  
  1010. player->sendCancelMessage(ret);
  1011. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  1012. return false;
  1013. }
  1014.  
  1015. if (playerTarget && (!playerTarget->isAccessPlayer() || player->isAccessPlayer())) {
  1016. param = playerTarget->getName();
  1017. }
  1018. }
  1019.  
  1020. var.text = param;
  1021. } else {
  1022. var.type = VARIANT_POSITION;
  1023.  
  1024. if (needDirection) {
  1025. var.pos = Spells::getCasterPosition(player, player->getDirection());
  1026. } else {
  1027. var.pos = player->getPosition();
  1028. }
  1029.  
  1030. if (!playerInstantSpellCheck(player, var.pos)) {
  1031. return false;
  1032. }
  1033. }
  1034.  
  1035. bool result = internalCastSpell(player, var);
  1036. if (result) {
  1037. postCastSpell(player);
  1038. }
  1039.  
  1040. return result;
  1041. }
  1042.  
  1043. bool InstantSpell::canThrowSpell(const Creature* creature, const Creature* target) const
  1044. {
  1045. const Position& fromPos = creature->getPosition();
  1046. const Position& toPos = target->getPosition();
  1047. if (fromPos.z != toPos.z ||
  1048. (range == -1 && !g_game.canThrowObjectTo(fromPos, toPos, checkLineOfSight)) ||
  1049. (range != -1 && !g_game.canThrowObjectTo(fromPos, toPos, checkLineOfSight, range, range))) {
  1050. return false;
  1051. }
  1052. return true;
  1053. }
  1054.  
  1055. bool InstantSpell::castSpell(Creature* creature)
  1056. {
  1057. LuaVariant var;
  1058.  
  1059. if (casterTargetOrDirection) {
  1060. Creature* target = creature->getAttackedCreature();
  1061. if (target && target->getHealth() > 0) {
  1062. if (!canThrowSpell(creature, target)) {
  1063. return false;
  1064. }
  1065.  
  1066. var.type = VARIANT_NUMBER;
  1067. var.number = target->getID();
  1068. return internalCastSpell(creature, var);
  1069. }
  1070.  
  1071. return false;
  1072. } else if (needDirection) {
  1073. var.type = VARIANT_POSITION;
  1074. var.pos = Spells::getCasterPosition(creature, creature->getDirection());
  1075. } else {
  1076. var.type = VARIANT_POSITION;
  1077. var.pos = creature->getPosition();
  1078. }
  1079.  
  1080. return internalCastSpell(creature, var);
  1081. }
  1082.  
  1083. bool InstantSpell::castSpell(Creature* creature, Creature* target)
  1084. {
  1085. if (needTarget) {
  1086. LuaVariant var;
  1087. var.type = VARIANT_NUMBER;
  1088. var.number = target->getID();
  1089. return internalCastSpell(creature, var);
  1090. } else {
  1091. return castSpell(creature);
  1092. }
  1093. }
  1094.  
  1095. bool InstantSpell::internalCastSpell(Creature* creature, const LuaVariant& var)
  1096. {
  1097. return executeCastSpell(creature, var);
  1098. }
  1099.  
  1100. bool InstantSpell::executeCastSpell(Creature* creature, const LuaVariant& var)
  1101. {
  1102. //onCastSpell(creature, var)
  1103. if (!scriptInterface->reserveScriptEnv()) {
  1104. std::cout << "[Error - InstantSpell::executeCastSpell] Call stack overflow" << std::endl;
  1105. return false;
  1106. }
  1107.  
  1108. ScriptEnvironment* env = scriptInterface->getScriptEnv();
  1109. env->setScriptId(scriptId, scriptInterface);
  1110.  
  1111. lua_State* L = scriptInterface->getLuaState();
  1112.  
  1113. scriptInterface->pushFunction(scriptId);
  1114.  
  1115. LuaScriptInterface::pushUserdata<Creature>(L, creature);
  1116. LuaScriptInterface::setCreatureMetatable(L, -1, creature);
  1117.  
  1118. LuaScriptInterface::pushVariant(L, var);
  1119.  
  1120. return scriptInterface->callFunction(2);
  1121. }
  1122.  
  1123. bool InstantSpell::canCast(const Player* player) const
  1124. {
  1125. if (player->hasFlag(PlayerFlag_CannotUseSpells)) {
  1126. return false;
  1127. }
  1128.  
  1129. if (player->hasFlag(PlayerFlag_IgnoreSpellCheck)) {
  1130. return true;
  1131. }
  1132.  
  1133. if (isLearnable()) {
  1134. if (player->hasLearnedInstantSpell(getName())) {
  1135. return true;
  1136. }
  1137. } else {
  1138. if (vocSpellMap.empty() || vocSpellMap.find(player->getVocationId()) != vocSpellMap.end()) {
  1139. return true;
  1140. }
  1141. }
  1142.  
  1143. return false;
  1144. }
  1145.  
  1146. std::string RuneSpell::getScriptEventName() const
  1147. {
  1148. return "onCastSpell";
  1149. }
  1150.  
  1151. bool RuneSpell::configureEvent(const pugi::xml_node& node)
  1152. {
  1153. if (!Spell::configureSpell(node)) {
  1154. return false;
  1155. }
  1156.  
  1157. if (!Action::configureEvent(node)) {
  1158. return false;
  1159. }
  1160.  
  1161. spellType = SPELL_RUNE;
  1162.  
  1163. pugi::xml_attribute attr;
  1164. if (!(attr = node.attribute("id"))) {
  1165. std::cout << "[Error - RuneSpell::configureSpell] Rune spell without id." << std::endl;
  1166. return false;
  1167. }
  1168. runeId = pugi::cast<uint16_t>(attr.value());
  1169.  
  1170. if ((attr = node.attribute("charges"))) {
  1171. charges = pugi::cast<uint32_t>(attr.value());
  1172. } else {
  1173. charges = 0;
  1174. }
  1175.  
  1176. hasCharges = (charges > 0);
  1177. if (magLevel != 0 || level != 0) {
  1178. //Change information in the ItemType to get accurate description
  1179. ItemType& iType = Item::items.getItemType(runeId);
  1180. iType.runeMagLevel = magLevel;
  1181. iType.runeLevel = level;
  1182. iType.charges = charges;
  1183. }
  1184.  
  1185. return true;
  1186. }
  1187.  
  1188. ReturnValue RuneSpell::canExecuteAction(const Player* player, const Position& toPos)
  1189. {
  1190. if (player->hasFlag(PlayerFlag_CannotUseSpells)) {
  1191. return RETURNVALUE_CANNOTUSETHISOBJECT;
  1192. }
  1193.  
  1194. ReturnValue ret = Action::canExecuteAction(player, toPos);
  1195. if (ret != RETURNVALUE_NOERROR) {
  1196. return ret;
  1197. }
  1198.  
  1199. if (toPos.x == 0xFFFF) {
  1200. if (needTarget) {
  1201. return RETURNVALUE_CANONLYUSETHISRUNEONCREATURES;
  1202. } else if (!selfTarget) {
  1203. return RETURNVALUE_NOTENOUGHROOM;
  1204. }
  1205. }
  1206.  
  1207. return RETURNVALUE_NOERROR;
  1208. }
  1209.  
  1210. bool RuneSpell::executeUse(Player* player, Item* item, const Position&, Thing* target, const Position& toPosition, bool isHotkey)
  1211. {
  1212. if (!playerRuneSpellCheck(player, toPosition)) {
  1213. return false;
  1214. }
  1215.  
  1216. if (!scripted) {
  1217. return false;
  1218. }
  1219.  
  1220. LuaVariant var;
  1221.  
  1222. if (needTarget) {
  1223. var.type = VARIANT_NUMBER;
  1224.  
  1225. if (target == nullptr) {
  1226. Tile* toTile = g_game.map.getTile(toPosition);
  1227. if (toTile) {
  1228. const Creature* visibleCreature = toTile->getBottomVisibleCreature(player);
  1229. if (visibleCreature) {
  1230. var.number = visibleCreature->getID();
  1231. }
  1232. }
  1233. } else {
  1234. var.number = target->getCreature()->getID();
  1235. }
  1236. } else {
  1237. var.type = VARIANT_POSITION;
  1238. var.pos = toPosition;
  1239. }
  1240.  
  1241. if (!internalCastSpell(player, var, isHotkey)) {
  1242. return false;
  1243. }
  1244.  
  1245. postCastSpell(player);
  1246. if (hasCharges && item && g_config.getBoolean(ConfigManager::REMOVE_RUNE_CHARGES)) {
  1247. int32_t newCount = std::max<int32_t>(0, item->getItemCount() - 1);
  1248. g_game.transformItem(item, item->getID(), newCount);
  1249. player->updateSupplyTracker(item);
  1250. }
  1251. return true;
  1252. }
  1253.  
  1254. bool RuneSpell::castSpell(Creature* creature)
  1255. {
  1256. LuaVariant var;
  1257. var.type = VARIANT_NUMBER;
  1258. var.number = creature->getID();
  1259. return internalCastSpell(creature, var, false);
  1260. }
  1261.  
  1262. bool RuneSpell::castSpell(Creature* creature, Creature* target)
  1263. {
  1264. LuaVariant var;
  1265. var.type = VARIANT_NUMBER;
  1266. var.number = target->getID();
  1267. return internalCastSpell(creature, var, false);
  1268. }
  1269.  
  1270. bool RuneSpell::internalCastSpell(Creature* creature, const LuaVariant& var, bool isHotkey)
  1271. {
  1272. bool result;
  1273. if (scripted) {
  1274. result = executeCastSpell(creature, var, isHotkey);
  1275. } else {
  1276. result = false;
  1277. }
  1278. return result;
  1279. }
  1280.  
  1281. bool RuneSpell::executeCastSpell(Creature* creature, const LuaVariant& var, bool isHotkey)
  1282. {
  1283. //onCastSpell(creature, var, isHotkey)
  1284. if (!scriptInterface->reserveScriptEnv()) {
  1285. std::cout << "[Error - RuneSpell::executeCastSpell] Call stack overflow" << std::endl;
  1286. return false;
  1287. }
  1288.  
  1289. ScriptEnvironment* env = scriptInterface->getScriptEnv();
  1290. env->setScriptId(scriptId, scriptInterface);
  1291.  
  1292. lua_State* L = scriptInterface->getLuaState();
  1293.  
  1294. scriptInterface->pushFunction(scriptId);
  1295.  
  1296. LuaScriptInterface::pushUserdata<Creature>(L, creature);
  1297. LuaScriptInterface::setCreatureMetatable(L, -1, creature);
  1298.  
  1299. LuaScriptInterface::pushVariant(L, var);
  1300.  
  1301. LuaScriptInterface::pushBoolean(L, isHotkey);
  1302.  
  1303. return scriptInterface->callFunction(3);
  1304. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement