Advertisement
DrakensOT

spells.cpp

Apr 17th, 2023
102
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 34.41 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. Spell* Spells::getSpellByName(const std::string& name)
  200. {
  201. Spell* spell = getRuneSpellByName(name);
  202. if (!spell) {
  203. spell = getInstantSpellByName(name);
  204. }
  205. return spell;
  206. }
  207.  
  208. RuneSpell* Spells::getRuneSpell(uint32_t id)
  209. {
  210. auto it = runes.find(id);
  211. if (it == runes.end()) {
  212. for (auto& rune : runes) {
  213. if (rune.second.getId() == id) {
  214. return &rune.second;
  215. }
  216. }
  217. return nullptr;
  218. }
  219. return &it->second;
  220. }
  221.  
  222. RuneSpell* Spells::getRuneSpellByName(const std::string& name)
  223. {
  224. for (auto& it : runes) {
  225. if (strcasecmp(it.second.getName().c_str(), name.c_str()) == 0) {
  226. return &it.second;
  227. }
  228. }
  229. return nullptr;
  230. }
  231.  
  232. InstantSpell* Spells::getInstantSpell(const std::string& words)
  233. {
  234. InstantSpell* result = nullptr;
  235.  
  236. for (auto& it : instants) {
  237. const std::string& instantSpellWords = it.second.getWords();
  238. size_t spellLen = instantSpellWords.length();
  239. if (strncasecmp(instantSpellWords.c_str(), words.c_str(), spellLen) == 0) {
  240. if (!result || spellLen > result->getWords().length()) {
  241. result = &it.second;
  242. if (words.length() == spellLen) {
  243. break;
  244. }
  245. }
  246. }
  247. }
  248.  
  249. if (result) {
  250. const std::string& resultWords = result->getWords();
  251. if (words.length() > resultWords.length()) {
  252. if (!result->getHasParam()) {
  253. return nullptr;
  254. }
  255.  
  256. size_t spellLen = resultWords.length();
  257. size_t paramLen = words.length() - spellLen;
  258. if (paramLen < 2 || words[spellLen] != ' ') {
  259. return nullptr;
  260. }
  261. }
  262. return result;
  263. }
  264. return nullptr;
  265. }
  266.  
  267. InstantSpell* Spells::getInstantSpellByName(const std::string& name)
  268. {
  269. for (auto& it : instants) {
  270. if (strcasecmp(it.second.getName().c_str(), name.c_str()) == 0) {
  271. return &it.second;
  272. }
  273. }
  274. return nullptr;
  275. }
  276.  
  277. Position Spells::getCasterPosition(Creature* creature, Direction dir)
  278. {
  279. return getNextPosition(dir, creature->getPosition());
  280. }
  281.  
  282. CombatSpell::CombatSpell(Combat_ptr combat, bool needTarget, bool needDirection) :
  283. Event(&g_spells->getScriptInterface()),
  284. combat(combat),
  285. needDirection(needDirection),
  286. needTarget(needTarget)
  287. {}
  288.  
  289. bool CombatSpell::loadScriptCombat()
  290. {
  291. combat = g_luaEnvironment.getCombatObject(g_luaEnvironment.lastCombatId);
  292. return combat != nullptr;
  293. }
  294.  
  295. bool CombatSpell::castSpell(Creature* creature)
  296. {
  297. if (scripted) {
  298. LuaVariant var;
  299. var.type = VARIANT_POSITION;
  300.  
  301. if (needDirection) {
  302. var.pos = Spells::getCasterPosition(creature, creature->getDirection());
  303. } else {
  304. var.pos = creature->getPosition();
  305. }
  306.  
  307. return executeCastSpell(creature, var);
  308. }
  309.  
  310. Position pos;
  311. if (needDirection) {
  312. pos = Spells::getCasterPosition(creature, creature->getDirection());
  313. } else {
  314. pos = creature->getPosition();
  315. }
  316.  
  317. combat->doCombat(creature, pos);
  318. return true;
  319. }
  320.  
  321. bool CombatSpell::castSpell(Creature* creature, Creature* target)
  322. {
  323. if (scripted) {
  324. LuaVariant var;
  325.  
  326. if (combat->hasArea()) {
  327. var.type = VARIANT_POSITION;
  328.  
  329. if (needTarget) {
  330. var.pos = target->getPosition();
  331. } else if (needDirection) {
  332. var.pos = Spells::getCasterPosition(creature, creature->getDirection());
  333. } else {
  334. var.pos = creature->getPosition();
  335. }
  336. } else {
  337. var.type = VARIANT_NUMBER;
  338. var.number = target->getID();
  339. }
  340. return executeCastSpell(creature, var);
  341. }
  342.  
  343. if (combat->hasArea()) {
  344. if (needTarget) {
  345. combat->doCombat(creature, target->getPosition());
  346. } else {
  347. return castSpell(creature);
  348. }
  349. } else {
  350. combat->doCombat(creature, target);
  351. }
  352. return true;
  353. }
  354.  
  355. bool CombatSpell::executeCastSpell(Creature* creature, const LuaVariant& var)
  356. {
  357. //onCastSpell(creature, var)
  358. if (!scriptInterface->reserveScriptEnv()) {
  359. std::cout << "[Error - CombatSpell::executeCastSpell] Call stack overflow" << std::endl;
  360. return false;
  361. }
  362.  
  363. ScriptEnvironment* env = scriptInterface->getScriptEnv();
  364. env->setScriptId(scriptId, scriptInterface);
  365.  
  366. lua_State* L = scriptInterface->getLuaState();
  367.  
  368. scriptInterface->pushFunction(scriptId);
  369.  
  370. LuaScriptInterface::pushUserdata<Creature>(L, creature);
  371. LuaScriptInterface::setCreatureMetatable(L, -1, creature);
  372.  
  373. LuaScriptInterface::pushVariant(L, var);
  374.  
  375. return scriptInterface->callFunction(2);
  376. }
  377.  
  378. bool Spell::configureSpell(const pugi::xml_node& node)
  379. {
  380. pugi::xml_attribute nameAttribute = node.attribute("name");
  381. if (!nameAttribute) {
  382. std::cout << "[Error - Spell::configureSpell] Spell without name" << std::endl;
  383. return false;
  384. }
  385.  
  386. name = nameAttribute.as_string();
  387.  
  388. static const char* reservedList[] = {
  389. "melee",
  390. "physical",
  391. "poison",
  392. "fire",
  393. "energy",
  394. "drown",
  395. "lifedrain",
  396. "manadrain",
  397. "healing",
  398. "speed",
  399. "outfit",
  400. "invisible",
  401. "drunk",
  402. "firefield",
  403. "poisonfield",
  404. "energyfield",
  405. "firecondition",
  406. "poisoncondition",
  407. "energycondition",
  408. "drowncondition",
  409. "freezecondition",
  410. "cursecondition",
  411. "dazzlecondition"
  412. };
  413.  
  414. //static size_t size = sizeof(reservedList) / sizeof(const char*);
  415. //for (size_t i = 0; i < size; ++i) {
  416. for (const char* reserved : reservedList) {
  417. if (strcasecmp(reserved, name.c_str()) == 0) {
  418. std::cout << "[Error - Spell::configureSpell] Spell is using a reserved name: " << reserved << std::endl;
  419. return false;
  420. }
  421. }
  422.  
  423. pugi::xml_attribute attr;
  424. if ((attr = node.attribute("spellid"))) {
  425. spellId = pugi::cast<uint16_t>(attr.value());
  426. }
  427.  
  428. if ((attr = node.attribute("group"))) {
  429. std::string tmpStr = asLowerCaseString(attr.as_string());
  430. if (tmpStr == "none" || tmpStr == "0") {
  431. group = SPELLGROUP_NONE;
  432. } else if (tmpStr == "attack" || tmpStr == "1") {
  433. group = SPELLGROUP_ATTACK;
  434. } else if (tmpStr == "healing" || tmpStr == "2") {
  435. group = SPELLGROUP_HEALING;
  436. } else if (tmpStr == "support" || tmpStr == "3") {
  437. group = SPELLGROUP_SUPPORT;
  438. } else if (tmpStr == "special" || tmpStr == "4") {
  439. group = SPELLGROUP_SPECIAL;
  440. } else {
  441. std::cout << "[Warning - Spell::configureSpell] Unknown group: " << attr.as_string() << std::endl;
  442. }
  443. }
  444.  
  445. if ((attr = node.attribute("groupcooldown"))) {
  446. groupCooldown = pugi::cast<uint32_t>(attr.value());
  447. }
  448.  
  449. if ((attr = node.attribute("secondarygroup"))) {
  450. std::string tmpStr = asLowerCaseString(attr.as_string());
  451. if (tmpStr == "none" || tmpStr == "0") {
  452. secondaryGroup = SPELLGROUP_NONE;
  453. } else if (tmpStr == "attack" || tmpStr == "1") {
  454. secondaryGroup = SPELLGROUP_ATTACK;
  455. } else if (tmpStr == "healing" || tmpStr == "2") {
  456. secondaryGroup = SPELLGROUP_HEALING;
  457. } else if (tmpStr == "support" || tmpStr == "3") {
  458. secondaryGroup = SPELLGROUP_SUPPORT;
  459. } else if (tmpStr == "special" || tmpStr == "4") {
  460. secondaryGroup = SPELLGROUP_SPECIAL;
  461. } else {
  462. std::cout << "[Warning - Spell::configureSpell] Unknown secondarygroup: " << attr.as_string() << std::endl;
  463. }
  464. }
  465.  
  466. if ((attr = node.attribute("secondarygroupcooldown"))) {
  467. secondaryGroupCooldown = pugi::cast<uint32_t>(attr.value());
  468. }
  469.  
  470. if ((attr = node.attribute("level")) || (attr = node.attribute("lvl"))) {
  471. level = pugi::cast<uint32_t>(attr.value());
  472. }
  473.  
  474. if ((attr = node.attribute("magiclevel")) || (attr = node.attribute("maglv"))) {
  475. magLevel = pugi::cast<uint32_t>(attr.value());
  476. }
  477.  
  478. if ((attr = node.attribute("mana"))) {
  479. mana = pugi::cast<uint32_t>(attr.value());
  480. }
  481.  
  482. if ((attr = node.attribute("manapercent"))) {
  483. manaPercent = pugi::cast<uint32_t>(attr.value());
  484. }
  485.  
  486. if ((attr = node.attribute("soul"))) {
  487. soul = pugi::cast<uint32_t>(attr.value());
  488. }
  489.  
  490. if ((attr = node.attribute("range"))) {
  491. range = pugi::cast<int32_t>(attr.value());
  492. }
  493.  
  494. if ((attr = node.attribute("cooldown")) || (attr = node.attribute("exhaustion"))) {
  495. cooldown = pugi::cast<uint32_t>(attr.value());
  496. }
  497.  
  498. if ((attr = node.attribute("premium")) || (attr = node.attribute("prem"))) {
  499. premium = attr.as_bool();
  500. }
  501.  
  502. if ((attr = node.attribute("enabled"))) {
  503. enabled = attr.as_bool();
  504. }
  505.  
  506. if ((attr = node.attribute("needtarget"))) {
  507. needTarget = attr.as_bool();
  508. }
  509.  
  510. if ((attr = node.attribute("needweapon"))) {
  511. needWeapon = attr.as_bool();
  512. }
  513.  
  514. if ((attr = node.attribute("selftarget"))) {
  515. selfTarget = attr.as_bool();
  516. }
  517.  
  518. if ((attr = node.attribute("needlearn"))) {
  519. learnable = attr.as_bool();
  520. }
  521.  
  522. if ((attr = node.attribute("blocking"))) {
  523. blockingSolid = attr.as_bool();
  524. blockingCreature = blockingSolid;
  525. }
  526.  
  527. if ((attr = node.attribute("blocktype"))) {
  528. std::string tmpStrValue = asLowerCaseString(attr.as_string());
  529. if (tmpStrValue == "all") {
  530. blockingSolid = true;
  531. blockingCreature = true;
  532. } else if (tmpStrValue == "solid") {
  533. blockingSolid = true;
  534. } else if (tmpStrValue == "creature") {
  535. blockingCreature = true;
  536. } else {
  537. std::cout << "[Warning - Spell::configureSpell] Blocktype \"" << attr.as_string() << "\" does not exist." << std::endl;
  538. }
  539. }
  540.  
  541. if ((attr = node.attribute("pzlock"))) {
  542. pzLock = booleanString(attr.as_string());
  543. }
  544.  
  545. if ((attr = node.attribute("aggressive"))) {
  546. aggressive = booleanString(attr.as_string());
  547. }
  548.  
  549. if (group == SPELLGROUP_NONE) {
  550. group = (aggressive ? SPELLGROUP_ATTACK : SPELLGROUP_HEALING);
  551. }
  552.  
  553. for (auto vocationNode : node.children()) {
  554. if (!(attr = vocationNode.attribute("name"))) {
  555. continue;
  556. }
  557.  
  558. int32_t vocationId = g_vocations.getVocationId(attr.as_string());
  559. if (vocationId != -1) {
  560. attr = vocationNode.attribute("showInDescription");
  561. vocSpellMap[vocationId] = !attr || attr.as_bool();
  562. } else {
  563. std::cout << "[Warning - Spell::configureSpell] Wrong vocation name: " << attr.as_string() << std::endl;
  564. }
  565. }
  566. return true;
  567. }
  568.  
  569. bool Spell::playerSpellCheck(Player* player) const
  570. {
  571. if (player->hasFlag(PlayerFlag_CannotUseSpells)) {
  572. return false;
  573. }
  574.  
  575. if (player->hasFlag(PlayerFlag_IgnoreSpellCheck)) {
  576. return true;
  577. }
  578.  
  579. if (!enabled) {
  580. return false;
  581. }
  582.  
  583. /*if ((aggressive || pzLock) && (range < 1 || (range > 0 && !player->getAttackedCreature())) && player->getSkull() == SKULL_BLACK) {
  584. player->sendCancelMessage(RETURNVALUE_NOTPOSSIBLE);
  585. return false;
  586. }*/
  587.  
  588. if ((aggressive || pzLock) && player->hasCondition(CONDITION_PACIFIED)) {
  589. player->sendCancelMessage(RETURNVALUE_YOUAREEXHAUSTED);
  590. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  591. return false;
  592. }
  593.  
  594. if ((aggressive || pzLock) && !player->hasFlag(PlayerFlag_IgnoreProtectionZone) && player->getZone() == ZONE_PROTECTION) {
  595. player->sendCancelMessage(RETURNVALUE_ACTIONNOTPERMITTEDINPROTECTIONZONE);
  596. return false;
  597. }
  598.  
  599. if (player->hasCondition(CONDITION_SPELLGROUPCOOLDOWN, group) || player->hasCondition(CONDITION_SPELLCOOLDOWN, spellId) || (secondaryGroup != SPELLGROUP_NONE && player->hasCondition(CONDITION_SPELLGROUPCOOLDOWN, secondaryGroup))) {
  600. player->sendCancelMessage(RETURNVALUE_YOUAREEXHAUSTED);
  601.  
  602. if (isInstant()) {
  603. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  604. }
  605.  
  606. return false;
  607. }
  608.  
  609. if (player->getLevel() < level) {
  610. player->sendCancelMessage(RETURNVALUE_NOTENOUGHLEVEL);
  611. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  612. return false;
  613. }
  614.  
  615. if (player->getMagicLevel() < magLevel) {
  616. player->sendCancelMessage(RETURNVALUE_NOTENOUGHMAGICLEVEL);
  617. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  618. return false;
  619. }
  620.  
  621. if (player->getMana() < getManaCost(player) && !player->hasFlag(PlayerFlag_HasInfiniteMana)) {
  622. player->sendCancelMessage(RETURNVALUE_NOTENOUGHMANA);
  623. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  624. return false;
  625. }
  626.  
  627. if (player->getSoul() < soul && !player->hasFlag(PlayerFlag_HasInfiniteSoul)) {
  628. player->sendCancelMessage(RETURNVALUE_NOTENOUGHSOUL);
  629. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  630. return false;
  631. }
  632.  
  633. if (isInstant() && isLearnable()) {
  634. if (!player->hasLearnedInstantSpell(getName())) {
  635. player->sendCancelMessage(RETURNVALUE_YOUNEEDTOLEARNTHISSPELL);
  636. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  637. return false;
  638. }
  639. } else if (!vocSpellMap.empty() && vocSpellMap.find(player->getVocationId()) == vocSpellMap.end()) {
  640. player->sendCancelMessage(RETURNVALUE_YOURVOCATIONCANNOTUSETHISSPELL);
  641. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  642. return false;
  643. }
  644.  
  645. if (needWeapon) {
  646. switch (player->getWeaponType()) {
  647. case WEAPON_SWORD:
  648. case WEAPON_CLUB:
  649. case WEAPON_AXE:
  650. break;
  651.  
  652. default: {
  653. player->sendCancelMessage(RETURNVALUE_YOUNEEDAWEAPONTOUSETHISSPELL);
  654. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  655. return false;
  656. }
  657. }
  658. }
  659.  
  660. if (isPremium() && !player->isPremium()) {
  661. player->sendCancelMessage(RETURNVALUE_YOUNEEDPREMIUMACCOUNT);
  662. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  663. return false;
  664. }
  665.  
  666. return true;
  667. }
  668.  
  669. bool Spell::playerInstantSpellCheck(Player* player, const Position& toPos)
  670. {
  671. if (toPos.x == 0xFFFF) {
  672. return true;
  673. }
  674.  
  675. const Position& playerPos = player->getPosition();
  676. if (playerPos.z > toPos.z) {
  677. player->sendCancelMessage(RETURNVALUE_FIRSTGOUPSTAIRS);
  678. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  679. return false;
  680. } else if (playerPos.z < toPos.z) {
  681. player->sendCancelMessage(RETURNVALUE_FIRSTGODOWNSTAIRS);
  682. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  683. return false;
  684. }
  685.  
  686. Tile* tile = g_game.map.getTile(toPos);
  687. if (!tile) {
  688. tile = new StaticTile(toPos.x, toPos.y, toPos.z);
  689. g_game.map.setTile(toPos, tile);
  690. }
  691.  
  692. if (blockingCreature && tile->getBottomVisibleCreature(player) != nullptr) {
  693. player->sendCancelMessage(RETURNVALUE_NOTENOUGHROOM);
  694. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  695. return false;
  696. }
  697.  
  698. if (blockingSolid && tile->hasFlag(TILESTATE_BLOCKSOLID)) {
  699. player->sendCancelMessage(RETURNVALUE_NOTENOUGHROOM);
  700. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  701. return false;
  702. }
  703.  
  704. return true;
  705. }
  706.  
  707. bool Spell::playerRuneSpellCheck(Player* player, const Position& toPos)
  708. {
  709. if (!playerSpellCheck(player)) {
  710. return false;
  711. }
  712.  
  713. if (toPos.x == 0xFFFF) {
  714. return true;
  715. }
  716.  
  717. const Position& playerPos = player->getPosition();
  718. if (playerPos.z > toPos.z) {
  719. player->sendCancelMessage(RETURNVALUE_FIRSTGOUPSTAIRS);
  720. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  721. return false;
  722. } else if (playerPos.z < toPos.z) {
  723. player->sendCancelMessage(RETURNVALUE_FIRSTGODOWNSTAIRS);
  724. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  725. return false;
  726. }
  727.  
  728. Tile* tile = g_game.map.getTile(toPos);
  729. if (!tile) {
  730. player->sendCancelMessage(RETURNVALUE_NOTPOSSIBLE);
  731. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  732. return false;
  733. }
  734.  
  735. if (range != -1 && !g_game.canThrowObjectTo(playerPos, toPos, true, true, range, range)) {
  736. player->sendCancelMessage(RETURNVALUE_DESTINATIONOUTOFREACH);
  737. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  738. return false;
  739. }
  740.  
  741. ReturnValue ret = Combat::canDoCombat(player, tile, aggressive);
  742. if (ret != RETURNVALUE_NOERROR) {
  743. player->sendCancelMessage(ret);
  744. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  745. return false;
  746. }
  747.  
  748. const Creature* topVisibleCreature = tile->getBottomVisibleCreature(player);
  749. if (blockingCreature && topVisibleCreature) {
  750. player->sendCancelMessage(RETURNVALUE_NOTENOUGHROOM);
  751. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  752. return false;
  753. } else if (blockingSolid && tile->hasFlag(TILESTATE_BLOCKSOLID)) {
  754. player->sendCancelMessage(RETURNVALUE_NOTENOUGHROOM);
  755. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  756. return false;
  757. }
  758.  
  759. if (needTarget && !topVisibleCreature) {
  760. player->sendCancelMessage(RETURNVALUE_CANONLYUSETHISRUNEONCREATURES);
  761. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  762. return false;
  763. }
  764.  
  765. if (aggressive && needTarget && topVisibleCreature && player->hasSecureMode()) {
  766. const Player* targetPlayer = topVisibleCreature->getPlayer();
  767. if (targetPlayer && targetPlayer != player && player->getSkullClient(targetPlayer) == SKULL_NONE && !Combat::isInPvpZone(player, targetPlayer)) {
  768. player->sendCancelMessage(RETURNVALUE_TURNSECUREMODETOATTACKUNMARKEDPLAYERS);
  769. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  770. return false;
  771. }
  772. }
  773. return true;
  774. }
  775.  
  776. void Spell::postCastSpell(Player* player, bool finishedCast /*= true*/, bool payCost /*= true*/) const
  777. {
  778. if (finishedCast) {
  779. if (!player->hasFlag(PlayerFlag_HasNoExhaustion)) {
  780. if (cooldown > 0) {
  781. Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_SPELLCOOLDOWN, cooldown, 0, false, spellId);
  782. player->addCondition(condition);
  783. }
  784.  
  785. if (groupCooldown > 0) {
  786. Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_SPELLGROUPCOOLDOWN, groupCooldown, 0, false, group);
  787. player->addCondition(condition);
  788. }
  789.  
  790. if (secondaryGroupCooldown > 0) {
  791. Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_SPELLGROUPCOOLDOWN, secondaryGroupCooldown, 0, false, secondaryGroup);
  792. player->addCondition(condition);
  793. }
  794. }
  795.  
  796. if (aggressive) {
  797. player->addInFightTicks();
  798. }
  799. }
  800.  
  801. if (payCost) {
  802. Spell::postCastSpell(player, getManaCost(player), getSoulCost());
  803. }
  804. }
  805.  
  806. void Spell::postCastSpell(Player* player, uint32_t manaCost, uint32_t soulCost)
  807. {
  808. if (manaCost > 0) {
  809. player->addManaSpent(manaCost);
  810. player->changeMana(-static_cast<int32_t>(manaCost));
  811. }
  812.  
  813. if (!player->hasFlag(PlayerFlag_HasInfiniteSoul)) {
  814. if (soulCost > 0) {
  815. player->changeSoul(-static_cast<int32_t>(soulCost));
  816. }
  817. }
  818. }
  819.  
  820. uint32_t Spell::getManaCost(const Player* player) const
  821. {
  822. if (mana != 0) {
  823. return mana;
  824. }
  825.  
  826. if (manaPercent != 0) {
  827. uint32_t maxMana = player->getMaxMana();
  828. uint32_t manaCost = (maxMana * manaPercent) / 100;
  829. return manaCost;
  830. }
  831.  
  832. return 0;
  833. }
  834.  
  835. std::string InstantSpell::getScriptEventName() const
  836. {
  837. return "onCastSpell";
  838. }
  839.  
  840. bool InstantSpell::configureEvent(const pugi::xml_node& node)
  841. {
  842. if (!Spell::configureSpell(node)) {
  843. return false;
  844. }
  845.  
  846. if (!TalkAction::configureEvent(node)) {
  847. return false;
  848. }
  849.  
  850. spellType = SPELL_INSTANT;
  851.  
  852. pugi::xml_attribute attr;
  853. if ((attr = node.attribute("params"))) {
  854. hasParam = attr.as_bool();
  855. }
  856.  
  857. if ((attr = node.attribute("playernameparam"))) {
  858. hasPlayerNameParam = attr.as_bool();
  859. }
  860.  
  861. if ((attr = node.attribute("direction"))) {
  862. needDirection = attr.as_bool();
  863. } else if ((attr = node.attribute("casterTargetOrDirection"))) {
  864. casterTargetOrDirection = attr.as_bool();
  865. }
  866.  
  867. if ((attr = node.attribute("blockwalls"))) {
  868. checkLineOfSight = attr.as_bool();
  869. }
  870. return true;
  871. }
  872.  
  873. bool InstantSpell::playerCastInstant(Player* player, std::string& param)
  874. {
  875. if (!playerSpellCheck(player)) {
  876. return false;
  877. }
  878.  
  879. LuaVariant var;
  880.  
  881. if (selfTarget) {
  882. var.type = VARIANT_NUMBER;
  883. var.number = player->getID();
  884. } else if (needTarget || casterTargetOrDirection) {
  885. Creature* target = nullptr;
  886. bool useDirection = false;
  887.  
  888. if (hasParam) {
  889. Player* playerTarget = nullptr;
  890. ReturnValue ret = g_game.getPlayerByNameWildcard(param, playerTarget);
  891.  
  892. if (playerTarget && playerTarget->isAccessPlayer() && !player->isAccessPlayer()) {
  893. playerTarget = nullptr;
  894. }
  895.  
  896. target = playerTarget;
  897. if (!target || target->getHealth() <= 0) {
  898. if (!casterTargetOrDirection) {
  899. if (cooldown > 0) {
  900. Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_SPELLCOOLDOWN, cooldown, 0, false, spellId);
  901. player->addCondition(condition);
  902. }
  903.  
  904. if (groupCooldown > 0) {
  905. Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_SPELLGROUPCOOLDOWN, groupCooldown, 0, false, group);
  906. player->addCondition(condition);
  907. }
  908.  
  909. if (secondaryGroupCooldown > 0) {
  910. Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_SPELLGROUPCOOLDOWN, secondaryGroupCooldown, 0, false, secondaryGroup);
  911. player->addCondition(condition);
  912. }
  913.  
  914. player->sendCancelMessage(ret);
  915. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  916. return false;
  917. }
  918.  
  919. useDirection = true;
  920. }
  921.  
  922. if (playerTarget) {
  923. param = playerTarget->getName();
  924. }
  925. } else {
  926. target = player->getAttackedCreature();
  927. if (!target || target->getHealth() <= 0) {
  928. if (!casterTargetOrDirection) {
  929. player->sendCancelMessage(RETURNVALUE_YOUCANONLYUSEITONCREATURES);
  930. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  931. return false;
  932. }
  933.  
  934. useDirection = true;
  935. }
  936. }
  937.  
  938. if (!useDirection) {
  939. if (!canThrowSpell(player, target)) {
  940. player->sendCancelMessage(RETURNVALUE_CREATUREISNOTREACHABLE);
  941. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  942. return false;
  943. }
  944.  
  945. var.type = VARIANT_NUMBER;
  946. var.number = target->getID();
  947. } else {
  948. var.type = VARIANT_POSITION;
  949. var.pos = Spells::getCasterPosition(player, player->getDirection());
  950.  
  951. if (!playerInstantSpellCheck(player, var.pos)) {
  952. return false;
  953. }
  954. }
  955. } else if (hasParam) {
  956. var.type = VARIANT_STRING;
  957.  
  958. if (getHasPlayerNameParam()) {
  959. Player* playerTarget = nullptr;
  960. ReturnValue ret = g_game.getPlayerByNameWildcard(param, playerTarget);
  961.  
  962. if (ret != RETURNVALUE_NOERROR) {
  963. if (cooldown > 0) {
  964. Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_SPELLCOOLDOWN, cooldown, 0, false, spellId);
  965. player->addCondition(condition);
  966. }
  967.  
  968. if (groupCooldown > 0) {
  969. Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_SPELLGROUPCOOLDOWN, groupCooldown, 0, false, group);
  970. player->addCondition(condition);
  971. }
  972.  
  973. if (secondaryGroupCooldown > 0) {
  974. Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_SPELLGROUPCOOLDOWN, secondaryGroupCooldown, 0, false, secondaryGroup);
  975. player->addCondition(condition);
  976. }
  977.  
  978. player->sendCancelMessage(ret);
  979. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  980. return false;
  981. }
  982.  
  983. if (playerTarget && (!playerTarget->isAccessPlayer() || player->isAccessPlayer())) {
  984. param = playerTarget->getName();
  985. }
  986. }
  987.  
  988. var.text = param;
  989. } else {
  990. var.type = VARIANT_POSITION;
  991.  
  992. if (needDirection) {
  993. var.pos = Spells::getCasterPosition(player, player->getDirection());
  994. } else {
  995. var.pos = player->getPosition();
  996. }
  997.  
  998. if (!playerInstantSpellCheck(player, var.pos)) {
  999. return false;
  1000. }
  1001. }
  1002.  
  1003. bool result = internalCastSpell(player, var);
  1004. if (result) {
  1005. postCastSpell(player);
  1006. }
  1007.  
  1008. return result;
  1009. }
  1010.  
  1011. bool InstantSpell::canThrowSpell(const Creature* creature, const Creature* target) const
  1012. {
  1013. const Position& fromPos = creature->getPosition();
  1014. const Position& toPos = target->getPosition();
  1015. if (fromPos.z != toPos.z ||
  1016. (range == -1 && !g_game.canThrowObjectTo(fromPos, toPos, checkLineOfSight, true, Map::maxClientViewportX - 1, Map::maxClientViewportY - 1)) ||
  1017. (range != -1 && !g_game.canThrowObjectTo(fromPos, toPos, checkLineOfSight, true, range, range))) {
  1018. return false;
  1019. }
  1020. return true;
  1021. }
  1022.  
  1023. bool InstantSpell::castSpell(Creature* creature)
  1024. {
  1025. LuaVariant var;
  1026.  
  1027. if (casterTargetOrDirection) {
  1028. Creature* target = creature->getAttackedCreature();
  1029. if (target && target->getHealth() > 0) {
  1030. if (!canThrowSpell(creature, target)) {
  1031. return false;
  1032. }
  1033.  
  1034. var.type = VARIANT_NUMBER;
  1035. var.number = target->getID();
  1036. return internalCastSpell(creature, var);
  1037. }
  1038.  
  1039. return false;
  1040. } else if (needDirection) {
  1041. var.type = VARIANT_POSITION;
  1042. var.pos = Spells::getCasterPosition(creature, creature->getDirection());
  1043. } else {
  1044. var.type = VARIANT_POSITION;
  1045. var.pos = creature->getPosition();
  1046. }
  1047.  
  1048. return internalCastSpell(creature, var);
  1049. }
  1050.  
  1051. bool InstantSpell::castSpell(Creature* creature, Creature* target)
  1052. {
  1053. if (needTarget) {
  1054. LuaVariant var;
  1055. var.type = VARIANT_NUMBER;
  1056. var.number = target->getID();
  1057. return internalCastSpell(creature, var);
  1058. }
  1059. return castSpell(creature);
  1060. }
  1061.  
  1062. bool InstantSpell::internalCastSpell(Creature* creature, const LuaVariant& var)
  1063. {
  1064. return executeCastSpell(creature, var);
  1065. }
  1066.  
  1067. bool InstantSpell::executeCastSpell(Creature* creature, const LuaVariant& var)
  1068. {
  1069. //onCastSpell(creature, var)
  1070. if (!scriptInterface->reserveScriptEnv()) {
  1071. std::cout << "[Error - InstantSpell::executeCastSpell] Call stack overflow" << std::endl;
  1072. return false;
  1073. }
  1074.  
  1075. ScriptEnvironment* env = scriptInterface->getScriptEnv();
  1076. env->setScriptId(scriptId, scriptInterface);
  1077.  
  1078. lua_State* L = scriptInterface->getLuaState();
  1079.  
  1080. scriptInterface->pushFunction(scriptId);
  1081.  
  1082. LuaScriptInterface::pushUserdata<Creature>(L, creature);
  1083. LuaScriptInterface::setCreatureMetatable(L, -1, creature);
  1084.  
  1085. LuaScriptInterface::pushVariant(L, var);
  1086.  
  1087. return scriptInterface->callFunction(2);
  1088. }
  1089.  
  1090. bool InstantSpell::canCast(const Player* player) const
  1091. {
  1092. if (player->hasFlag(PlayerFlag_CannotUseSpells)) {
  1093. return false;
  1094. }
  1095.  
  1096. if (player->hasFlag(PlayerFlag_IgnoreSpellCheck)) {
  1097. return true;
  1098. }
  1099.  
  1100. if (isLearnable()) {
  1101. if (player->hasLearnedInstantSpell(getName())) {
  1102. return true;
  1103. }
  1104. } else {
  1105. if (vocSpellMap.empty() || vocSpellMap.find(player->getVocationId()) != vocSpellMap.end()) {
  1106. return true;
  1107. }
  1108. }
  1109.  
  1110. return false;
  1111. }
  1112.  
  1113. std::string RuneSpell::getScriptEventName() const
  1114. {
  1115. return "onCastSpell";
  1116. }
  1117.  
  1118. bool RuneSpell::configureEvent(const pugi::xml_node& node)
  1119. {
  1120. if (!Spell::configureSpell(node)) {
  1121. return false;
  1122. }
  1123.  
  1124. if (!Action::configureEvent(node)) {
  1125. return false;
  1126. }
  1127.  
  1128. spellType = SPELL_RUNE;
  1129.  
  1130. pugi::xml_attribute attr;
  1131. if (!(attr = node.attribute("id"))) {
  1132. std::cout << "[Error - RuneSpell::configureSpell] Rune spell without id." << std::endl;
  1133. return false;
  1134. }
  1135. runeId = pugi::cast<uint16_t>(attr.value());
  1136.  
  1137. if ((attr = node.attribute("charges"))) {
  1138. charges = pugi::cast<uint32_t>(attr.value());
  1139. } else {
  1140. charges = 0;
  1141. }
  1142.  
  1143. hasCharges = (charges > 0);
  1144. if (magLevel != 0 || level != 0) {
  1145. //Change information in the ItemType to get accurate description
  1146. ItemType& iType = Item::items.getItemType(runeId);
  1147. iType.runeMagLevel = magLevel;
  1148. iType.runeLevel = level;
  1149. iType.charges = charges;
  1150. }
  1151.  
  1152. return true;
  1153. }
  1154.  
  1155. ReturnValue RuneSpell::canExecuteAction(const Player* player, const Position& toPos)
  1156. {
  1157. if (player->hasFlag(PlayerFlag_CannotUseSpells)) {
  1158. return RETURNVALUE_CANNOTUSETHISOBJECT;
  1159. }
  1160.  
  1161. ReturnValue ret = Action::canExecuteAction(player, toPos);
  1162. if (ret != RETURNVALUE_NOERROR) {
  1163. return ret;
  1164. }
  1165.  
  1166. if (toPos.x == 0xFFFF) {
  1167. if (needTarget) {
  1168. return RETURNVALUE_CANONLYUSETHISRUNEONCREATURES;
  1169. } else if (!selfTarget) {
  1170. return RETURNVALUE_NOTENOUGHROOM;
  1171. }
  1172. }
  1173.  
  1174. return RETURNVALUE_NOERROR;
  1175. }
  1176.  
  1177. bool RuneSpell::executeUse(Player* player, Item* item, const Position&, Thing* target, const Position& toPosition, bool isHotkey)
  1178. {
  1179. if (!playerRuneSpellCheck(player, toPosition)) {
  1180. return false;
  1181. }
  1182.  
  1183. if (!scripted) {
  1184. return false;
  1185. }
  1186.  
  1187. LuaVariant var;
  1188.  
  1189. if (needTarget) {
  1190. var.type = VARIANT_NUMBER;
  1191.  
  1192. if (target == nullptr) {
  1193. Tile* toTile = g_game.map.getTile(toPosition);
  1194. if (toTile) {
  1195. const Creature* visibleCreature = toTile->getBottomVisibleCreature(player);
  1196. if (visibleCreature) {
  1197. var.number = visibleCreature->getID();
  1198. }
  1199. }
  1200. } else {
  1201. var.number = target->getCreature()->getID();
  1202. }
  1203. } else {
  1204. var.type = VARIANT_POSITION;
  1205. var.pos = toPosition;
  1206. }
  1207.  
  1208. if (!internalCastSpell(player, var, isHotkey)) {
  1209. return false;
  1210. }
  1211.  
  1212. postCastSpell(player);
  1213.  
  1214. target = g_game.getCreatureByID(var.number);
  1215. if (getPzLock() && target) {
  1216. player->onAttackedCreature(target->getCreature());
  1217. }
  1218.  
  1219. if (hasCharges && item && g_config.getBoolean(ConfigManager::REMOVE_RUNE_CHARGES)) {
  1220. int32_t newCount = std::max<int32_t>(0, item->getSubType() - 1);
  1221. g_game.transformItem(item, item->getID(), newCount);
  1222. }
  1223. return true;
  1224. }
  1225.  
  1226. bool RuneSpell::castSpell(Creature* creature)
  1227. {
  1228. LuaVariant var;
  1229. var.type = VARIANT_NUMBER;
  1230. var.number = creature->getID();
  1231. return internalCastSpell(creature, var, false);
  1232. }
  1233.  
  1234. bool RuneSpell::castSpell(Creature* creature, Creature* target)
  1235. {
  1236. LuaVariant var;
  1237. var.type = VARIANT_NUMBER;
  1238. var.number = target->getID();
  1239. return internalCastSpell(creature, var, false);
  1240. }
  1241.  
  1242. bool RuneSpell::internalCastSpell(Creature* creature, const LuaVariant& var, bool isHotkey)
  1243. {
  1244. bool result;
  1245. if (scripted) {
  1246. result = executeCastSpell(creature, var, isHotkey);
  1247. } else {
  1248. result = false;
  1249. }
  1250. return result;
  1251. }
  1252.  
  1253. bool RuneSpell::executeCastSpell(Creature* creature, const LuaVariant& var, bool isHotkey)
  1254. {
  1255. //onCastSpell(creature, var, isHotkey)
  1256. if (!scriptInterface->reserveScriptEnv()) {
  1257. std::cout << "[Error - RuneSpell::executeCastSpell] Call stack overflow" << std::endl;
  1258. return false;
  1259. }
  1260.  
  1261. ScriptEnvironment* env = scriptInterface->getScriptEnv();
  1262. env->setScriptId(scriptId, scriptInterface);
  1263.  
  1264. lua_State* L = scriptInterface->getLuaState();
  1265.  
  1266. scriptInterface->pushFunction(scriptId);
  1267.  
  1268. LuaScriptInterface::pushUserdata<Creature>(L, creature);
  1269. LuaScriptInterface::setCreatureMetatable(L, -1, creature);
  1270.  
  1271. LuaScriptInterface::pushVariant(L, var);
  1272.  
  1273. LuaScriptInterface::pushBoolean(L, isHotkey);
  1274.  
  1275. return scriptInterface->callFunction(3);
  1276. }
  1277.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement