Advertisement
Guest User

Untitled

a guest
Jan 24th, 2017
105
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 50.34 KB | None | 0 0
  1. /**
  2. * The Forgotten Server - a free and open-source MMORPG server emulator
  3. * Copyright (C) 2015 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 "const.h"
  25. #include "game.h"
  26. #include "house.h"
  27. #include "housetile.h"
  28. #include "monster.h"
  29. #include "monsters.h"
  30. #include "pugicast.h"
  31. #include "spells.h"
  32. #include "tools.h"
  33.  
  34. extern Game g_game;
  35. extern Spells* g_spells;
  36. extern Monsters g_monsters;
  37. extern Vocations g_vocations;
  38. extern ConfigManager g_config;
  39. extern LuaEnvironment g_luaEnvironment;
  40.  
  41. Spells::Spells():
  42. m_scriptInterface("Spell Interface")
  43. {
  44. m_scriptInterface.initState();
  45. }
  46.  
  47. Spells::~Spells()
  48. {
  49. clear();
  50. }
  51.  
  52. TalkActionResult_t Spells::playerSaySpell(Player* player, std::string& words)
  53. {
  54. std::string str_words = words;
  55.  
  56. //strip trailing spaces
  57. trimString(str_words);
  58.  
  59. InstantSpell* instantSpell = getInstantSpell(str_words);
  60. if (!instantSpell) {
  61. return TALKACTION_CONTINUE;
  62. }
  63.  
  64. std::string param;
  65.  
  66. if (instantSpell->getHasParam()) {
  67. size_t spellLen = instantSpell->getWords().length();
  68. size_t paramLen = str_words.length() - spellLen;
  69. std::string paramText = str_words.substr(spellLen, paramLen);
  70. if (!paramText.empty() && paramText.front() == ' ') {
  71. size_t loc1 = paramText.find('"', 1);
  72. if (loc1 != std::string::npos) {
  73. size_t loc2 = paramText.find('"', loc1 + 1);
  74. if (loc2 == std::string::npos) {
  75. loc2 = paramText.length();
  76. } else if (paramText.find_last_not_of(' ') != loc2) {
  77. return TALKACTION_CONTINUE;
  78. }
  79.  
  80. param = paramText.substr(loc1 + 1, loc2 - loc1 - 1);
  81. } else {
  82. trimString(paramText);
  83. loc1 = paramText.find(' ', 0);
  84. if (loc1 == std::string::npos) {
  85. param = paramText;
  86. } else {
  87. return TALKACTION_CONTINUE;
  88. }
  89. }
  90. }
  91. }
  92.  
  93. if (instantSpell->playerCastInstant(player, param)) {
  94. words = instantSpell->getWords();
  95.  
  96. if (instantSpell->getHasParam() && !param.empty()) {
  97. words += " \"" + param + "\"";
  98. }
  99.  
  100. return TALKACTION_BREAK;
  101. }
  102.  
  103. return TALKACTION_FAILED;
  104. }
  105.  
  106. void Spells::clear()
  107. {
  108. for (const auto& it : runes) {
  109. delete it.second;
  110. }
  111. runes.clear();
  112.  
  113. for (const auto& it : instants) {
  114. delete it.second;
  115. }
  116. instants.clear();
  117.  
  118. m_scriptInterface.reInitState();
  119. }
  120.  
  121. LuaScriptInterface& Spells::getScriptInterface()
  122. {
  123. return m_scriptInterface;
  124. }
  125.  
  126. std::string Spells::getScriptBaseName() const
  127. {
  128. return "spells";
  129. }
  130.  
  131. Event* Spells::getEvent(const std::string& nodeName)
  132. {
  133. if (strcasecmp(nodeName.c_str(), "rune") == 0) {
  134. return new RuneSpell(&m_scriptInterface);
  135. } else if (strcasecmp(nodeName.c_str(), "instant") == 0) {
  136. return new InstantSpell(&m_scriptInterface);
  137. } else if (strcasecmp(nodeName.c_str(), "conjure") == 0) {
  138. return new ConjureSpell(&m_scriptInterface);
  139. }
  140. return nullptr;
  141. }
  142.  
  143. bool Spells::registerEvent(Event* event, const pugi::xml_node&)
  144. {
  145. InstantSpell* instant = dynamic_cast<InstantSpell*>(event);
  146. if (instant) {
  147. auto result = instants.emplace(instant->getWords(), instant);
  148. if (!result.second) {
  149. std::cout << "[Warning - Spells::registerEvent] Duplicate registered instant spell with words: " << instant->getWords() << std::endl;
  150. }
  151. return result.second;
  152. }
  153.  
  154. RuneSpell* rune = dynamic_cast<RuneSpell*>(event);
  155. if (rune) {
  156. auto result = runes.emplace(rune->getRuneItemId(), rune);
  157. if (!result.second) {
  158. std::cout << "[Warning - Spells::registerEvent] Duplicate registered rune with id: " << rune->getRuneItemId() << std::endl;
  159. }
  160. return result.second;
  161. }
  162.  
  163. return false;
  164. }
  165.  
  166. Spell* Spells::getSpellByName(const std::string& name)
  167. {
  168. Spell* spell = getRuneSpellByName(name);
  169. if (!spell) {
  170. spell = getInstantSpellByName(name);
  171. }
  172. return spell;
  173. }
  174.  
  175. RuneSpell* Spells::getRuneSpell(uint32_t id)
  176. {
  177. auto it = runes.find(id);
  178. if (it == runes.end()) {
  179. return nullptr;
  180. }
  181. return it->second;
  182. }
  183.  
  184. RuneSpell* Spells::getRuneSpellByName(const std::string& name)
  185. {
  186. for (const auto& it : runes) {
  187. if (strcasecmp(it.second->getName().c_str(), name.c_str()) == 0) {
  188. return it.second;
  189. }
  190. }
  191. return nullptr;
  192. }
  193.  
  194. InstantSpell* Spells::getInstantSpell(const std::string& words)
  195. {
  196. InstantSpell* result = nullptr;
  197.  
  198. for (const auto& it : instants) {
  199. InstantSpell* instantSpell = it.second;
  200.  
  201. const std::string& instantSpellWords = instantSpell->getWords();
  202. size_t spellLen = instantSpellWords.length();
  203. if (strncasecmp(instantSpellWords.c_str(), words.c_str(), spellLen) == 0) {
  204. if (!result || spellLen > result->getWords().length()) {
  205. result = instantSpell;
  206. }
  207. }
  208. }
  209.  
  210. if (result) {
  211. const std::string& resultWords = result->getWords();
  212. if (words.length() > resultWords.length()) {
  213. if (!result->getHasParam()) {
  214. return nullptr;
  215. }
  216.  
  217. size_t spellLen = resultWords.length();
  218. size_t paramLen = words.length() - spellLen;
  219. if (paramLen < 2 || words[spellLen] != ' ') {
  220. return nullptr;
  221. }
  222. }
  223. return result;
  224. }
  225. return nullptr;
  226. }
  227.  
  228. uint32_t Spells::getInstantSpellCount(const Player* player) const
  229. {
  230. uint32_t count = 0;
  231. for (const auto& it : instants) {
  232. InstantSpell* instantSpell = it.second;
  233. if (instantSpell->canCast(player)) {
  234. ++count;
  235. }
  236. }
  237. return count;
  238. }
  239.  
  240. InstantSpell* Spells::getInstantSpellByIndex(const Player* player, uint32_t index)
  241. {
  242. uint32_t count = 0;
  243. for (const auto& it : instants) {
  244. InstantSpell* instantSpell = it.second;
  245. if (instantSpell->canCast(player)) {
  246. if (count == index) {
  247. return instantSpell;
  248. }
  249. ++count;
  250. }
  251. }
  252. return nullptr;
  253. }
  254.  
  255. InstantSpell* Spells::getInstantSpellByName(const std::string& name)
  256. {
  257. for (const auto& it : instants) {
  258. if (strcasecmp(it.second->getName().c_str(), name.c_str()) == 0) {
  259. return it.second;
  260. }
  261. }
  262. return nullptr;
  263. }
  264.  
  265. Position Spells::getCasterPosition(Creature* creature, Direction dir)
  266. {
  267. return getNextPosition(dir, creature->getPosition());
  268. }
  269.  
  270. CombatSpell::CombatSpell(Combat* _combat, bool _needTarget, bool _needDirection) :
  271. Event(&g_spells->getScriptInterface())
  272. {
  273. combat = _combat;
  274. needTarget = _needTarget;
  275. needDirection = _needDirection;
  276. }
  277.  
  278. CombatSpell::~CombatSpell()
  279. {
  280. if (!m_scripted) {
  281. delete combat;
  282. }
  283. }
  284.  
  285. bool CombatSpell::loadScriptCombat()
  286. {
  287. combat = g_luaEnvironment.getCombatObject(g_luaEnvironment.m_lastCombatId);
  288. return combat != nullptr;
  289. }
  290.  
  291. bool CombatSpell::castSpell(Creature* creature)
  292. {
  293. if (m_scripted) {
  294. LuaVariant var;
  295. var.type = VARIANT_POSITION;
  296.  
  297. if (needDirection) {
  298. var.pos = Spells::getCasterPosition(creature, creature->getDirection());
  299. } else {
  300. var.pos = creature->getPosition();
  301. }
  302.  
  303. return executeCastSpell(creature, var);
  304. }
  305.  
  306. Position pos;
  307. if (needDirection) {
  308. pos = Spells::getCasterPosition(creature, creature->getDirection());
  309. } else {
  310. pos = creature->getPosition();
  311. }
  312.  
  313. combat->doCombat(creature, pos);
  314. return true;
  315. }
  316.  
  317. bool CombatSpell::castSpell(Creature* creature, Creature* target)
  318. {
  319. if (m_scripted) {
  320. LuaVariant var;
  321.  
  322. if (combat->hasArea()) {
  323. var.type = VARIANT_POSITION;
  324.  
  325. if (needTarget) {
  326. var.pos = target->getPosition();
  327. } else if (needDirection) {
  328. var.pos = Spells::getCasterPosition(creature, creature->getDirection());
  329. } else {
  330. var.pos = creature->getPosition();
  331. }
  332. } else {
  333. var.type = VARIANT_NUMBER;
  334. var.number = target->getID();
  335. }
  336. return executeCastSpell(creature, var);
  337. }
  338.  
  339. if (combat->hasArea()) {
  340. if (needTarget) {
  341. combat->doCombat(creature, target->getPosition());
  342. } else {
  343. return castSpell(creature);
  344. }
  345. } else {
  346. combat->doCombat(creature, target);
  347. }
  348. return true;
  349. }
  350.  
  351. bool CombatSpell::executeCastSpell(Creature* creature, const LuaVariant& var)
  352. {
  353. //onCastSpell(creature, var)
  354. if (!m_scriptInterface->reserveScriptEnv()) {
  355. std::cout << "[Error - CombatSpell::executeCastSpell] Call stack overflow" << std::endl;
  356. return false;
  357. }
  358.  
  359. ScriptEnvironment* env = m_scriptInterface->getScriptEnv();
  360. env->setScriptId(m_scriptId, m_scriptInterface);
  361.  
  362. lua_State* L = m_scriptInterface->getLuaState();
  363.  
  364. m_scriptInterface->pushFunction(m_scriptId);
  365.  
  366. LuaScriptInterface::pushUserdata<Creature>(L, creature);
  367. LuaScriptInterface::setCreatureMetatable(L, -1, creature);
  368.  
  369. LuaScriptInterface::pushVariant(L, var);
  370.  
  371. return m_scriptInterface->callFunction(2);
  372. }
  373.  
  374. Spell::Spell()
  375. {
  376. spellId = 0;
  377. level = 0;
  378. magLevel = 0;
  379. mana = 0;
  380. manaPercent = 0;
  381. soul = 0;
  382. range = -1;
  383. cooldown = 0;
  384. needTarget = false;
  385. needWeapon = false;
  386. selfTarget = false;
  387. blockingSolid = false;
  388. blockingCreature = false;
  389. premium = false;
  390. enabled = true;
  391. aggressive = true;
  392. learnable = false;
  393. }
  394.  
  395. bool Spell::configureSpell(const pugi::xml_node& node)
  396. {
  397. pugi::xml_attribute nameAttribute = node.attribute("name");
  398. if (!nameAttribute) {
  399. std::cout << "[Error - Spell::configureSpell] Spell without name" << std::endl;
  400. return false;
  401. }
  402.  
  403. name = nameAttribute.as_string();
  404.  
  405. static const char* reservedList[] = {
  406. "melee",
  407. "physical",
  408. "poison",
  409. "fire",
  410. "energy",
  411. "drown",
  412. "lifedrain",
  413. "manadrain",
  414. "healing",
  415. "speed",
  416. "outfit",
  417. "invisible",
  418. "drunk",
  419. "firefield",
  420. "poisonfield",
  421. "energyfield",
  422. "firecondition",
  423. "poisoncondition",
  424. "energycondition",
  425. "drowncondition",
  426. "freezecondition",
  427. "cursecondition",
  428. "dazzlecondition"
  429. };
  430.  
  431. //static size_t size = sizeof(reservedList) / sizeof(const char*);
  432. //for (size_t i = 0; i < size; ++i) {
  433. for (const char* reserved : reservedList) {
  434. if (strcasecmp(reserved, name.c_str()) == 0) {
  435. std::cout << "[Error - Spell::configureSpell] Spell is using a reserved name: " << reserved << std::endl;
  436. return false;
  437. }
  438. }
  439.  
  440. pugi::xml_attribute attr;
  441. if ((attr = node.attribute("spellid"))) {
  442. spellId = pugi::cast<uint16_t>(attr.value());
  443. }
  444.  
  445. if ((attr = node.attribute("lvl"))) {
  446. level = pugi::cast<uint32_t>(attr.value());
  447. }
  448.  
  449. if ((attr = node.attribute("maglv"))) {
  450. magLevel = pugi::cast<uint32_t>(attr.value());
  451. }
  452.  
  453. if ((attr = node.attribute("mana"))) {
  454. mana = pugi::cast<uint32_t>(attr.value());
  455. }
  456.  
  457. if ((attr = node.attribute("manapercent"))) {
  458. manaPercent = pugi::cast<uint32_t>(attr.value());
  459. }
  460.  
  461. if ((attr = node.attribute("soul"))) {
  462. soul = pugi::cast<uint32_t>(attr.value());
  463. }
  464.  
  465. if ((attr = node.attribute("range"))) {
  466. range = pugi::cast<int32_t>(attr.value());
  467. }
  468.  
  469. if ((attr = node.attribute("exhaustion")) || (attr = node.attribute("cooldown"))) {
  470. cooldown = pugi::cast<uint32_t>(attr.value());
  471. }
  472.  
  473. if ((attr = node.attribute("prem"))) {
  474. premium = attr.as_bool();
  475. }
  476.  
  477. if ((attr = node.attribute("enabled"))) {
  478. enabled = attr.as_bool();
  479. }
  480.  
  481. if ((attr = node.attribute("needtarget"))) {
  482. needTarget = attr.as_bool();
  483. }
  484.  
  485. if ((attr = node.attribute("needweapon"))) {
  486. needWeapon = attr.as_bool();
  487. }
  488.  
  489. if ((attr = node.attribute("selftarget"))) {
  490. selfTarget = attr.as_bool();
  491. }
  492.  
  493. if ((attr = node.attribute("needlearn"))) {
  494. learnable = attr.as_bool();
  495. }
  496.  
  497. if ((attr = node.attribute("blocking"))) {
  498. blockingSolid = attr.as_bool();
  499. blockingCreature = blockingSolid;
  500. }
  501.  
  502. if ((attr = node.attribute("blocktype"))) {
  503. std::string tmpStrValue = asLowerCaseString(attr.as_string());
  504. if (tmpStrValue == "all") {
  505. blockingSolid = true;
  506. blockingCreature = true;
  507. } else if (tmpStrValue == "solid") {
  508. blockingSolid = true;
  509. } else if (tmpStrValue == "creature") {
  510. blockingCreature = true;
  511. } else {
  512. std::cout << "[Warning - Spell::configureSpell] Blocktype \"" << attr.as_string() << "\" does not exist." << std::endl;
  513. }
  514. }
  515.  
  516. if ((attr = node.attribute("aggressive"))) {
  517. aggressive = booleanString(attr.as_string());
  518. }
  519.  
  520. for (pugi::xml_node vocationNode = node.first_child(); vocationNode; vocationNode = vocationNode.next_sibling()) {
  521. if (!(attr = vocationNode.attribute("name"))) {
  522. continue;
  523. }
  524.  
  525. int32_t vocationId = g_vocations.getVocationId(attr.as_string());
  526. if (vocationId != -1) {
  527. vocSpellMap[vocationId] = true;
  528. int32_t promotedVocation = g_vocations.getPromotedVocation(vocationId);
  529. if (promotedVocation != VOCATION_NONE) {
  530. vocSpellMap[promotedVocation] = true;
  531. }
  532. } else {
  533. std::cout << "[Warning - Spell::configureSpell] Wrong vocation name: " << attr.as_string() << std::endl;
  534. }
  535. }
  536. return true;
  537. }
  538.  
  539. bool Spell::playerSpellCheck(Player* player) const
  540. {
  541. if (player->hasFlag(PlayerFlag_CannotUseSpells)) {
  542. return false;
  543. }
  544.  
  545. if (player->hasFlag(PlayerFlag_IgnoreSpellCheck)) {
  546. return true;
  547. }
  548.  
  549. if (!enabled) {
  550. return false;
  551. }
  552.  
  553. if (aggressive && !player->hasFlag(PlayerFlag_IgnoreProtectionZone) && player->getZone() == ZONE_PROTECTION) {
  554. player->sendCancelMessage(RETURNVALUE_ACTIONNOTPERMITTEDINPROTECTIONZONE);
  555. return false;
  556. }
  557.  
  558. if (player->hasCondition(CONDITION_EXHAUST_COMBAT) || player->hasCondition(CONDITION_EXHAUST_HEAL)) {
  559. player->sendCancelMessage(RETURNVALUE_YOUAREEXHAUSTED);
  560.  
  561. if (isInstant()) {
  562. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  563. }
  564.  
  565. return false;
  566. }
  567.  
  568. if (player->getLevel() < level) {
  569. player->sendCancelMessage(RETURNVALUE_NOTENOUGHLEVEL);
  570. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  571. return false;
  572. }
  573.  
  574. if (player->getMagicLevel() < magLevel) {
  575. player->sendCancelMessage(RETURNVALUE_NOTENOUGHMAGICLEVEL);
  576. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  577. return false;
  578. }
  579.  
  580. if (player->getMana() < getManaCost(player) && !player->hasFlag(PlayerFlag_HasInfiniteMana)) {
  581. player->sendCancelMessage(RETURNVALUE_NOTENOUGHMANA);
  582. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  583. return false;
  584. }
  585.  
  586. if (player->getSoul() < soul && !player->hasFlag(PlayerFlag_HasInfiniteSoul)) {
  587. player->sendCancelMessage(RETURNVALUE_NOTENOUGHSOUL);
  588. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  589. return false;
  590. }
  591.  
  592. if (isInstant() && isLearnable()) {
  593. if (!player->hasLearnedInstantSpell(getName())) {
  594. player->sendCancelMessage(RETURNVALUE_YOUNEEDTOLEARNTHISSPELL);
  595. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  596. return false;
  597. }
  598. } else if (!vocSpellMap.empty() && vocSpellMap.find(player->getVocationId()) == vocSpellMap.end()) {
  599. player->sendCancelMessage(RETURNVALUE_YOURVOCATIONCANNOTUSETHISSPELL);
  600. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  601. return false;
  602. }
  603.  
  604. if (needWeapon) {
  605. switch (player->getWeaponType()) {
  606. case WEAPON_SWORD:
  607. case WEAPON_CLUB:
  608. case WEAPON_AXE:
  609. break;
  610.  
  611. default: {
  612. player->sendCancelMessage(RETURNVALUE_YOUNEEDAWEAPONTOUSETHISSPELL);
  613. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  614. return false;
  615. }
  616. }
  617. }
  618.  
  619. if (isPremium() && !player->isPremium()) {
  620. player->sendCancelMessage(RETURNVALUE_YOUNEEDPREMIUMACCOUNT);
  621. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  622. return false;
  623. }
  624.  
  625. return true;
  626. }
  627.  
  628. bool Spell::playerInstantSpellCheck(Player* player, const Position& toPos)
  629. {
  630. if (toPos.x == 0xFFFF) {
  631. return true;
  632. }
  633.  
  634. const Position& playerPos = player->getPosition();
  635. if (playerPos.z > toPos.z) {
  636. player->sendCancelMessage(RETURNVALUE_FIRSTGOUPSTAIRS);
  637. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  638. return false;
  639. } else if (playerPos.z < toPos.z) {
  640. player->sendCancelMessage(RETURNVALUE_FIRSTGODOWNSTAIRS);
  641. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  642. return false;
  643. }
  644.  
  645. Tile* tile = g_game.map.getTile(toPos);
  646. if (!tile) {
  647. tile = new StaticTile(toPos.x, toPos.y, toPos.z);
  648. g_game.map.setTile(toPos, tile);
  649. }
  650.  
  651. ReturnValue ret = Combat::canDoCombat(player, tile, aggressive);
  652. if (ret != RETURNVALUE_NOERROR) {
  653. player->sendCancelMessage(ret);
  654. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  655. return false;
  656. }
  657.  
  658. if (blockingCreature && tile->getBottomVisibleCreature(player) != nullptr) {
  659. player->sendCancelMessage(RETURNVALUE_NOTENOUGHROOM);
  660. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  661. return false;
  662. }
  663.  
  664. if (blockingSolid && tile->hasProperty(CONST_PROP_BLOCKSOLID)) {
  665. player->sendCancelMessage(RETURNVALUE_NOTENOUGHROOM);
  666. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  667. return false;
  668. }
  669.  
  670. return true;
  671. }
  672.  
  673. bool Spell::playerRuneSpellCheck(Player* player, const Position& toPos)
  674. {
  675. if (!playerSpellCheck(player)) {
  676. return false;
  677. }
  678.  
  679. if (toPos.x == 0xFFFF) {
  680. return true;
  681. }
  682.  
  683. const Position& playerPos = player->getPosition();
  684. if (playerPos.z > toPos.z) {
  685. player->sendCancelMessage(RETURNVALUE_FIRSTGOUPSTAIRS);
  686. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  687. return false;
  688. } else if (playerPos.z < toPos.z) {
  689. player->sendCancelMessage(RETURNVALUE_FIRSTGODOWNSTAIRS);
  690. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  691. return false;
  692. }
  693.  
  694. Tile* tile = g_game.map.getTile(toPos);
  695. if (!tile) {
  696. player->sendCancelMessage(RETURNVALUE_NOTPOSSIBLE);
  697. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  698. return false;
  699. }
  700.  
  701. if (range != -1 && !g_game.canThrowObjectTo(playerPos, toPos, true, range, range)) {
  702. player->sendCancelMessage(RETURNVALUE_DESTINATIONOUTOFREACH);
  703. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  704. return false;
  705. }
  706.  
  707. ReturnValue ret = Combat::canDoCombat(player, tile, aggressive);
  708. if (ret != RETURNVALUE_NOERROR) {
  709. player->sendCancelMessage(ret);
  710. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  711. return false;
  712. }
  713.  
  714. const Creature* topVisibleCreature = tile->getBottomCreature();
  715. if (blockingCreature && topVisibleCreature) {
  716. player->sendCancelMessage(RETURNVALUE_NOTENOUGHROOM);
  717. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  718. return false;
  719. } else if (blockingSolid && tile->hasProperty(CONST_PROP_BLOCKSOLID)) {
  720. player->sendCancelMessage(RETURNVALUE_NOTENOUGHROOM);
  721. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  722. return false;
  723. }
  724.  
  725. if (needTarget && !topVisibleCreature) {
  726. player->sendCancelMessage(RETURNVALUE_CANONLYUSETHISRUNEONCREATURES);
  727. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  728. return false;
  729. }
  730.  
  731. if (aggressive && needTarget && topVisibleCreature && player->hasSecureMode()) {
  732. const Player* targetPlayer = topVisibleCreature->getPlayer();
  733. if (targetPlayer && targetPlayer != player && player->getSkullClient(targetPlayer) == SKULL_NONE && !Combat::isInPvpZone(player, targetPlayer)) {
  734. player->sendCancelMessage(RETURNVALUE_TURNSECUREMODETOATTACKUNMARKEDPLAYERS);
  735. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  736. return false;
  737. }
  738. }
  739. return true;
  740. }
  741.  
  742. void Spell::postCastSpell(Player* player, bool finishedCast /*= true*/, bool payCost /*= true*/) const
  743. {
  744. if (finishedCast) {
  745. if (!player->hasFlag(PlayerFlag_HasNoExhaustion)) {
  746. if (aggressive) {
  747. if (cooldown > 0) {
  748. Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_EXHAUST_COMBAT, cooldown);
  749. player->addCondition(condition);
  750. } else {
  751. Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_EXHAUST_COMBAT, 2000);
  752. player->addCondition(condition);
  753. }
  754. } else {
  755. if (cooldown > 0) {
  756. Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_EXHAUST_COMBAT, cooldown);
  757. player->addCondition(condition);
  758. } else {
  759. Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_EXHAUST_COMBAT, 1000);
  760. player->addCondition(condition);
  761. }
  762. }
  763. }
  764.  
  765. if (aggressive) {
  766. player->addInFightTicks();
  767. }
  768. }
  769.  
  770. if (payCost) {
  771. Spell::postCastSpell(player, getManaCost(player), getSoulCost());
  772. }
  773. }
  774.  
  775. void Spell::postCastSpell(Player* player, uint32_t manaCost, uint32_t soulCost)
  776. {
  777. if (manaCost > 0) {
  778. player->addManaSpent(manaCost);
  779. player->changeMana(-static_cast<int32_t>(manaCost));
  780. }
  781.  
  782. if (!player->hasFlag(PlayerFlag_HasInfiniteSoul)) {
  783. if (soulCost > 0) {
  784. player->changeSoul(-static_cast<int32_t>(soulCost));
  785. }
  786. }
  787. }
  788.  
  789. uint32_t Spell::getManaCost(const Player* player) const
  790. {
  791. if (mana != 0) {
  792. return mana;
  793. }
  794.  
  795. if (manaPercent != 0) {
  796. uint32_t maxMana = player->getMaxMana();
  797. uint32_t manaCost = (maxMana * manaPercent) / 100;
  798. return manaCost;
  799. }
  800.  
  801. return 0;
  802. }
  803.  
  804. ReturnValue Spell::CreateIllusion(Creature* creature, const Outfit_t& outfit, int32_t time)
  805. {
  806. ConditionOutfit* outfitCondition = new ConditionOutfit(CONDITIONID_COMBAT, CONDITION_OUTFIT, time);
  807. outfitCondition->setOutfit(outfit);
  808. creature->addCondition(outfitCondition);
  809. return RETURNVALUE_NOERROR;
  810. }
  811.  
  812. ReturnValue Spell::CreateIllusion(Creature* creature, const std::string& name, int32_t time)
  813. {
  814. uint32_t mId = g_monsters.getIdByName(name);
  815. if (mId == 0) {
  816. return RETURNVALUE_CREATUREDOESNOTEXIST;
  817. }
  818.  
  819. const MonsterType* mType = g_monsters.getMonsterType(mId);
  820. if (mType == nullptr) {
  821. return RETURNVALUE_CREATUREDOESNOTEXIST;
  822. }
  823.  
  824. Player* player = creature->getPlayer();
  825. if (player && !player->hasFlag(PlayerFlag_CanIllusionAll)) {
  826. if (!mType->isIllusionable) {
  827. return RETURNVALUE_NOTPOSSIBLE;
  828. }
  829. }
  830.  
  831. return CreateIllusion(creature, mType->outfit, time);
  832. }
  833.  
  834. ReturnValue Spell::CreateIllusion(Creature* creature, uint32_t itemId, int32_t time)
  835. {
  836. const ItemType& it = Item::items[itemId];
  837. if (it.id == 0) {
  838. return RETURNVALUE_NOTPOSSIBLE;
  839. }
  840.  
  841. Outfit_t outfit;
  842. outfit.lookTypeEx = itemId;
  843.  
  844. return CreateIllusion(creature, outfit, time);
  845. }
  846.  
  847. InstantSpell::InstantSpell(LuaScriptInterface* _interface) :
  848. TalkAction(_interface)
  849. {
  850. needDirection = false;
  851. hasParam = false;
  852. hasPlayerNameParam = false;
  853. checkLineOfSight = true;
  854. casterTargetOrDirection = false;
  855. function = nullptr;
  856. }
  857.  
  858. std::string InstantSpell::getScriptEventName() const
  859. {
  860. return "onCastSpell";
  861. }
  862.  
  863. bool InstantSpell::configureEvent(const pugi::xml_node& node)
  864. {
  865. if (!Spell::configureSpell(node)) {
  866. return false;
  867. }
  868.  
  869. if (!TalkAction::configureEvent(node)) {
  870. return false;
  871. }
  872.  
  873. pugi::xml_attribute attr;
  874. if ((attr = node.attribute("params"))) {
  875. hasParam = attr.as_bool();
  876. }
  877.  
  878. if ((attr = node.attribute("playernameparam"))) {
  879. hasPlayerNameParam = attr.as_bool();
  880. }
  881.  
  882. if ((attr = node.attribute("direction"))) {
  883. needDirection = attr.as_bool();
  884. } else if ((attr = node.attribute("casterTargetOrDirection"))) {
  885. casterTargetOrDirection = attr.as_bool();
  886. }
  887.  
  888. if ((attr = node.attribute("blockwalls"))) {
  889. checkLineOfSight = attr.as_bool();
  890. }
  891. return true;
  892. }
  893.  
  894. bool InstantSpell::loadFunction(const pugi::xml_attribute& attr)
  895. {
  896. const char* functionName = attr.as_string();
  897. if (strcasecmp(functionName, "edithouseguest") == 0) {
  898. function = HouseGuestList;
  899. } else if (strcasecmp(functionName, "edithousesubowner") == 0) {
  900. function = HouseSubOwnerList;
  901. } else if (strcasecmp(functionName, "edithousedoor") == 0) {
  902. function = HouseDoorList;
  903. } else if (strcasecmp(functionName, "housekick") == 0) {
  904. function = HouseKick;
  905. } else if (strcasecmp(functionName, "searchplayer") == 0) {
  906. function = SearchPlayer;
  907. } else if (strcasecmp(functionName, "levitate") == 0) {
  908. function = Levitate;
  909. } else if (strcasecmp(functionName, "illusion") == 0) {
  910. function = Illusion;
  911. } else if (strcasecmp(functionName, "summonmonster") == 0) {
  912. function = SummonMonster;
  913. } else {
  914. std::cout << "[Warning - InstantSpell::loadFunction] Function \"" << functionName << "\" does not exist." << std::endl;
  915. return false;
  916. }
  917.  
  918. m_scripted = false;
  919. return true;
  920. }
  921.  
  922. bool InstantSpell::playerCastInstant(Player* player, std::string& param)
  923. {
  924. if (!playerSpellCheck(player)) {
  925. return false;
  926. }
  927.  
  928. LuaVariant var;
  929.  
  930. if (selfTarget) {
  931. var.type = VARIANT_NUMBER;
  932. var.number = player->getID();
  933. } else if (needTarget || casterTargetOrDirection) {
  934. Creature* target = nullptr;
  935. bool useDirection = false;
  936.  
  937. if (hasParam) {
  938. Player* playerTarget = nullptr;
  939. ReturnValue ret = g_game.getPlayerByNameWildcard(param, playerTarget);
  940.  
  941. if (playerTarget && playerTarget->isAccessPlayer() && !player->isAccessPlayer()) {
  942. playerTarget = nullptr;
  943. }
  944.  
  945. target = playerTarget;
  946. if (!target || target->getHealth() <= 0) {
  947. if (!casterTargetOrDirection) {
  948. player->sendCancelMessage(ret);
  949. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  950. return false;
  951. }
  952.  
  953. useDirection = true;
  954. }
  955.  
  956. if (playerTarget) {
  957. param = playerTarget->getName();
  958. }
  959. } else {
  960. target = player->getAttackedCreature();
  961. if (!target || target->getHealth() <= 0) {
  962. if (!casterTargetOrDirection) {
  963. player->sendCancelMessage(RETURNVALUE_YOUCANONLYUSEITONCREATURES);
  964. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  965. return false;
  966. }
  967.  
  968. useDirection = true;
  969. }
  970. }
  971.  
  972. if (!useDirection) {
  973. if (!canThrowSpell(player, target)) {
  974. player->sendCancelMessage(RETURNVALUE_CREATUREISNOTREACHABLE);
  975. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  976. return false;
  977. }
  978.  
  979. var.type = VARIANT_NUMBER;
  980. var.number = target->getID();
  981. } else {
  982. var.type = VARIANT_POSITION;
  983. var.pos = Spells::getCasterPosition(player, player->getDirection());
  984.  
  985. if (!playerInstantSpellCheck(player, var.pos)) {
  986. return false;
  987. }
  988. }
  989. } else if (hasParam) {
  990. var.type = VARIANT_STRING;
  991.  
  992. if (getHasPlayerNameParam()) {
  993. Player* playerTarget = nullptr;
  994. ReturnValue ret = g_game.getPlayerByNameWildcard(param, playerTarget);
  995.  
  996. if (ret != RETURNVALUE_NOERROR) {
  997. player->sendCancelMessage(ret);
  998. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  999. return false;
  1000. }
  1001.  
  1002. if (playerTarget && (!playerTarget->isAccessPlayer() || player->isAccessPlayer())) {
  1003. param = playerTarget->getName();
  1004. }
  1005. }
  1006.  
  1007. var.text = param;
  1008. } else {
  1009. var.type = VARIANT_POSITION;
  1010.  
  1011. if (needDirection) {
  1012. var.pos = Spells::getCasterPosition(player, player->getDirection());
  1013. } else {
  1014. var.pos = player->getPosition();
  1015. }
  1016.  
  1017. if (!playerInstantSpellCheck(player, var.pos)) {
  1018. return false;
  1019. }
  1020. }
  1021.  
  1022. bool result = internalCastSpell(player, var);
  1023. if (result) {
  1024. postCastSpell(player);
  1025. }
  1026.  
  1027. return result;
  1028. }
  1029.  
  1030. bool InstantSpell::canThrowSpell(const Creature* creature, const Creature* target) const
  1031. {
  1032. const Position& fromPos = creature->getPosition();
  1033. const Position& toPos = target->getPosition();
  1034. if (fromPos.z != toPos.z ||
  1035. (range == -1 && !g_game.canThrowObjectTo(fromPos, toPos, checkLineOfSight)) ||
  1036. (range != -1 && !g_game.canThrowObjectTo(fromPos, toPos, checkLineOfSight, range, range))) {
  1037. return false;
  1038. }
  1039. return true;
  1040. }
  1041.  
  1042. bool InstantSpell::castSpell(Creature* creature)
  1043. {
  1044. LuaVariant var;
  1045.  
  1046. if (casterTargetOrDirection) {
  1047. Creature* target = creature->getAttackedCreature();
  1048. if (target && target->getHealth() > 0) {
  1049. if (!canThrowSpell(creature, target)) {
  1050. return false;
  1051. }
  1052.  
  1053. var.type = VARIANT_NUMBER;
  1054. var.number = target->getID();
  1055. return internalCastSpell(creature, var);
  1056. }
  1057.  
  1058. return false;
  1059. } else if (needDirection) {
  1060. var.type = VARIANT_POSITION;
  1061. var.pos = Spells::getCasterPosition(creature, creature->getDirection());
  1062. } else {
  1063. var.type = VARIANT_POSITION;
  1064. var.pos = creature->getPosition();
  1065. }
  1066.  
  1067. return internalCastSpell(creature, var);
  1068. }
  1069.  
  1070. bool InstantSpell::castSpell(Creature* creature, Creature* target)
  1071. {
  1072. if (needTarget) {
  1073. LuaVariant var;
  1074. var.type = VARIANT_NUMBER;
  1075. var.number = target->getID();
  1076. return internalCastSpell(creature, var);
  1077. } else {
  1078. return castSpell(creature);
  1079. }
  1080. }
  1081.  
  1082. bool InstantSpell::internalCastSpell(Creature* creature, const LuaVariant& var)
  1083. {
  1084. if (m_scripted) {
  1085. return executeCastSpell(creature, var);
  1086. } else if (function) {
  1087. return function(this, creature, var.text);
  1088. }
  1089.  
  1090. return false;
  1091. }
  1092.  
  1093. bool InstantSpell::executeCastSpell(Creature* creature, const LuaVariant& var)
  1094. {
  1095. //onCastSpell(creature, var)
  1096. if (!m_scriptInterface->reserveScriptEnv()) {
  1097. std::cout << "[Error - InstantSpell::executeCastSpell] Call stack overflow" << std::endl;
  1098. return false;
  1099. }
  1100.  
  1101. ScriptEnvironment* env = m_scriptInterface->getScriptEnv();
  1102. env->setScriptId(m_scriptId, m_scriptInterface);
  1103.  
  1104. lua_State* L = m_scriptInterface->getLuaState();
  1105.  
  1106. m_scriptInterface->pushFunction(m_scriptId);
  1107.  
  1108. LuaScriptInterface::pushUserdata<Creature>(L, creature);
  1109. LuaScriptInterface::setCreatureMetatable(L, -1, creature);
  1110.  
  1111. LuaScriptInterface::pushVariant(L, var);
  1112.  
  1113. return m_scriptInterface->callFunction(2);
  1114. }
  1115.  
  1116. House* InstantSpell::getHouseFromPos(Creature* creature)
  1117. {
  1118. if (!creature) {
  1119. return nullptr;
  1120. }
  1121.  
  1122. Player* player = creature->getPlayer();
  1123. if (!player) {
  1124. return nullptr;
  1125. }
  1126.  
  1127. HouseTile* houseTile = dynamic_cast<HouseTile*>(player->getTile());
  1128. if (!houseTile) {
  1129. return nullptr;
  1130. }
  1131.  
  1132. House* house = houseTile->getHouse();
  1133. if (!house) {
  1134. return nullptr;
  1135. }
  1136.  
  1137. return house;
  1138. }
  1139.  
  1140. bool InstantSpell::HouseGuestList(const InstantSpell*, Creature* creature, const std::string&)
  1141. {
  1142. House* house = getHouseFromPos(creature);
  1143. if (!house) {
  1144. return false;
  1145. }
  1146.  
  1147. Player* player = creature->getPlayer();
  1148. if (house->canEditAccessList(GUEST_LIST, player)) {
  1149. player->setEditHouse(house, GUEST_LIST);
  1150. player->sendHouseWindow(house, GUEST_LIST);
  1151. } else {
  1152. player->sendCancelMessage(RETURNVALUE_NOTPOSSIBLE);
  1153. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  1154. }
  1155. return true;
  1156. }
  1157.  
  1158. bool InstantSpell::HouseSubOwnerList(const InstantSpell*, Creature* creature, const std::string&)
  1159. {
  1160. House* house = getHouseFromPos(creature);
  1161. if (!house) {
  1162. return false;
  1163. }
  1164.  
  1165. Player* player = creature->getPlayer();
  1166. if (house->canEditAccessList(SUBOWNER_LIST, player)) {
  1167. player->setEditHouse(house, SUBOWNER_LIST);
  1168. player->sendHouseWindow(house, SUBOWNER_LIST);
  1169. } else {
  1170. player->sendCancelMessage(RETURNVALUE_NOTPOSSIBLE);
  1171. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  1172. }
  1173. return true;
  1174. }
  1175.  
  1176. bool InstantSpell::HouseDoorList(const InstantSpell*, Creature* creature, const std::string&)
  1177. {
  1178. House* house = getHouseFromPos(creature);
  1179. if (!house) {
  1180. return false;
  1181. }
  1182.  
  1183. Player* player = creature->getPlayer();
  1184. Position pos = Spells::getCasterPosition(player, player->getDirection());
  1185. Door* door = house->getDoorByPosition(pos);
  1186. if (door && house->canEditAccessList(door->getDoorId(), player)) {
  1187. player->setEditHouse(house, door->getDoorId());
  1188. player->sendHouseWindow(house, door->getDoorId());
  1189. } else {
  1190. player->sendCancelMessage(RETURNVALUE_NOTPOSSIBLE);
  1191. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  1192. }
  1193. return true;
  1194. }
  1195.  
  1196. bool InstantSpell::HouseKick(const InstantSpell*, Creature* creature, const std::string& param)
  1197. {
  1198. Player* player = creature->getPlayer();
  1199.  
  1200. Player* targetPlayer = g_game.getPlayerByName(param);
  1201. if (!targetPlayer) {
  1202. targetPlayer = player;
  1203. }
  1204.  
  1205. House* house = getHouseFromPos(targetPlayer);
  1206. if (!house) {
  1207. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  1208. player->sendCancelMessage(RETURNVALUE_NOTPOSSIBLE);
  1209. return false;
  1210. }
  1211.  
  1212. if (!house->kickPlayer(player, targetPlayer)) {
  1213. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  1214. player->sendCancelMessage(RETURNVALUE_NOTPOSSIBLE);
  1215. return false;
  1216. }
  1217. return true;
  1218. }
  1219.  
  1220. bool InstantSpell::SearchPlayer(const InstantSpell*, Creature* creature, const std::string& param)
  1221. {
  1222. //a. From 1 to 4 sq's [Person] is standing next to you.
  1223. //b. From 5 to 100 sq's [Person] is to the south, north, east, west.
  1224. //c. From 101 to 274 sq's [Person] is far to the south, north, east, west.
  1225. //d. From 275 to infinite sq's [Person] is very far to the south, north, east, west.
  1226. //e. South-west, s-e, n-w, n-e (corner coordinates): this phrase appears if the player you're looking for has moved five squares in any direction from the south, north, east or west.
  1227. //f. Lower level to the (direction): this phrase applies if the person you're looking for is from 1-25 squares up/down the actual floor you're in.
  1228. //g. Higher level to the (direction): this phrase applies if the person you're looking for is from 1-25 squares up/down the actual floor you're in.
  1229.  
  1230. Player* player = creature->getPlayer();
  1231. if (!player) {
  1232. return false;
  1233. }
  1234.  
  1235. enum distance_t {
  1236. DISTANCE_BESIDE,
  1237. DISTANCE_CLOSE,
  1238. DISTANCE_FAR,
  1239. DISTANCE_VERYFAR,
  1240. };
  1241.  
  1242. enum direction_t {
  1243. DIR_N, DIR_S, DIR_E, DIR_W,
  1244. DIR_NE, DIR_NW, DIR_SE, DIR_SW,
  1245. };
  1246.  
  1247. enum level_t {
  1248. LEVEL_HIGHER,
  1249. LEVEL_LOWER,
  1250. LEVEL_SAME,
  1251. };
  1252.  
  1253. Player* playerExiva = g_game.getPlayerByName(param);
  1254. if (!playerExiva) {
  1255. return false;
  1256. }
  1257.  
  1258. if (playerExiva->isAccessPlayer() && !player->isAccessPlayer()) {
  1259. player->sendCancelMessage(RETURNVALUE_PLAYERWITHTHISNAMEISNOTONLINE);
  1260. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  1261. return false;
  1262. }
  1263.  
  1264. const Position& lookPos = player->getPosition();
  1265. const Position& searchPos = playerExiva->getPosition();
  1266.  
  1267. int32_t dx = Position::getOffsetX(lookPos, searchPos);
  1268. int32_t dy = Position::getOffsetY(lookPos, searchPos);
  1269. int32_t dz = Position::getOffsetZ(lookPos, searchPos);
  1270.  
  1271. distance_t distance;
  1272.  
  1273. direction_t direction;
  1274.  
  1275. level_t level;
  1276.  
  1277. //getting floor
  1278. if (dz > 0) {
  1279. level = LEVEL_HIGHER;
  1280. } else if (dz < 0) {
  1281. level = LEVEL_LOWER;
  1282. } else {
  1283. level = LEVEL_SAME;
  1284. }
  1285.  
  1286. //getting distance
  1287. if (std::abs(dx) < 4 && std::abs(dy) < 4) {
  1288. distance = DISTANCE_BESIDE;
  1289. } else {
  1290. int32_t distance2 = dx * dx + dy * dy;
  1291. if (distance2 < 10000) {
  1292. distance = DISTANCE_CLOSE;
  1293. } else if (distance2 < 75076) {
  1294. distance = DISTANCE_FAR;
  1295. } else {
  1296. distance = DISTANCE_VERYFAR;
  1297. }
  1298. }
  1299.  
  1300. //getting direction
  1301. float tan;
  1302. if (dx != 0) {
  1303. tan = static_cast<float>(dy) / dx;
  1304. } else {
  1305. tan = 10.;
  1306. }
  1307.  
  1308. if (std::abs(tan) < 0.4142) {
  1309. if (dx > 0) {
  1310. direction = DIR_W;
  1311. } else {
  1312. direction = DIR_E;
  1313. }
  1314. } else if (std::abs(tan) < 2.4142) {
  1315. if (tan > 0) {
  1316. if (dy > 0) {
  1317. direction = DIR_NW;
  1318. } else {
  1319. direction = DIR_SE;
  1320. }
  1321. } else {
  1322. if (dx > 0) {
  1323. direction = DIR_SW;
  1324. } else {
  1325. direction = DIR_NE;
  1326. }
  1327. }
  1328. } else {
  1329. if (dy > 0) {
  1330. direction = DIR_N;
  1331. } else {
  1332. direction = DIR_S;
  1333. }
  1334. }
  1335.  
  1336. std::ostringstream ss;
  1337. ss << playerExiva->getName();
  1338.  
  1339. if (distance == DISTANCE_BESIDE) {
  1340. if (level == LEVEL_SAME) {
  1341. ss << " is standing next to you.";
  1342. } else if (level == LEVEL_HIGHER) {
  1343. ss << " is above you.";
  1344. } else if (level == LEVEL_LOWER) {
  1345. ss << " is below you.";
  1346. }
  1347. } else {
  1348. switch (distance) {
  1349. case DISTANCE_CLOSE:
  1350. if (level == LEVEL_SAME) {
  1351. ss << " is to the ";
  1352. } else if (level == LEVEL_HIGHER) {
  1353. ss << " is on a higher level to the ";
  1354. } else if (level == LEVEL_LOWER) {
  1355. ss << " is on a lower level to the ";
  1356. }
  1357. break;
  1358. case DISTANCE_FAR:
  1359. ss << " is far to the ";
  1360. break;
  1361. case DISTANCE_VERYFAR:
  1362. ss << " is very far to the ";
  1363. break;
  1364. default:
  1365. break;
  1366. }
  1367.  
  1368. switch (direction) {
  1369. case DIR_N:
  1370. ss << "north.";
  1371. break;
  1372. case DIR_S:
  1373. ss << "south.";
  1374. break;
  1375. case DIR_E:
  1376. ss << "east.";
  1377. break;
  1378. case DIR_W:
  1379. ss << "west.";
  1380. break;
  1381. case DIR_NE:
  1382. ss << "north-east.";
  1383. break;
  1384. case DIR_NW:
  1385. ss << "north-west.";
  1386. break;
  1387. case DIR_SE:
  1388. ss << "south-east.";
  1389. break;
  1390. case DIR_SW:
  1391. ss << "south-west.";
  1392. break;
  1393. }
  1394. }
  1395. player->sendTextMessage(MESSAGE_INFO_DESCR, ss.str());
  1396. g_game.addMagicEffect(player->getPosition(), CONST_ME_MAGIC_BLUE);
  1397. return true;
  1398. }
  1399.  
  1400. bool InstantSpell::SummonMonster(const InstantSpell* spell, Creature* creature, const std::string& param)
  1401. {
  1402. Player* player = creature->getPlayer();
  1403. if (!player) {
  1404. return false;
  1405. }
  1406.  
  1407. MonsterType* mType = g_monsters.getMonsterType(param);
  1408. if (!mType) {
  1409. player->sendCancelMessage(RETURNVALUE_NOTPOSSIBLE);
  1410. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  1411. return false;
  1412. }
  1413.  
  1414. if (!player->hasFlag(PlayerFlag_CanSummonAll)) {
  1415. if (!mType->isSummonable) {
  1416. player->sendCancelMessage(RETURNVALUE_NOTPOSSIBLE);
  1417. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  1418. return false;
  1419. }
  1420.  
  1421. if (player->getMana() < mType->manaCost) {
  1422. player->sendCancelMessage(RETURNVALUE_NOTENOUGHMANA);
  1423. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  1424. return false;
  1425. }
  1426.  
  1427. if (player->getSummonCount() >= 2) {
  1428. player->sendCancelMessage("You cannot summon more creatures.");
  1429. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  1430. return false;
  1431. }
  1432. }
  1433.  
  1434. Monster* monster = Monster::createMonster(param);
  1435. if (!monster) {
  1436. player->sendCancelMessage(RETURNVALUE_NOTPOSSIBLE);
  1437. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  1438. return false;
  1439. }
  1440.  
  1441. // Place the monster
  1442. creature->addSummon(monster);
  1443.  
  1444. if (!g_game.placeCreature(monster, creature->getPosition(), true)) {
  1445. creature->removeSummon(monster);
  1446. player->sendCancelMessage(RETURNVALUE_NOTENOUGHROOM);
  1447. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  1448. return false;
  1449. }
  1450.  
  1451. Spell::postCastSpell(player, mType->manaCost, spell->getSoulCost());
  1452. g_game.addMagicEffect(player->getPosition(), CONST_ME_MAGIC_BLUE);
  1453. g_game.addMagicEffect(monster->getPosition(), CONST_ME_TELEPORT);
  1454. return true;
  1455. }
  1456.  
  1457. bool InstantSpell::Levitate(const InstantSpell*, Creature* creature, const std::string& param)
  1458. {
  1459. Player* player = creature->getPlayer();
  1460. if (!player) {
  1461. return false;
  1462. }
  1463.  
  1464. const Position& currentPos = creature->getPosition();
  1465. const Position& destPos = Spells::getCasterPosition(creature, creature->getDirection());
  1466.  
  1467. ReturnValue ret = RETURNVALUE_NOTPOSSIBLE;
  1468.  
  1469. if (strcasecmp(param.c_str(), "up") == 0) {
  1470. if (currentPos.z != 8) {
  1471. Tile* tmpTile = g_game.map.getTile(currentPos.x, currentPos.y, currentPos.getZ() - 1);
  1472. if (tmpTile == nullptr || (tmpTile->getGround() == nullptr && !tmpTile->hasProperty(CONST_PROP_IMMOVABLEBLOCKSOLID))) {
  1473. tmpTile = g_game.map.getTile(destPos.x, destPos.y, destPos.getZ() - 1);
  1474. if (tmpTile && tmpTile->getGround() && !tmpTile->hasProperty(CONST_PROP_IMMOVABLEBLOCKSOLID)) {
  1475. ret = g_game.internalMoveCreature(*player, *tmpTile, FLAG_IGNOREBLOCKITEM | FLAG_IGNOREBLOCKCREATURE);
  1476. }
  1477. }
  1478. }
  1479. } else if (strcasecmp(param.c_str(), "down") == 0) {
  1480. if (currentPos.z != 7) {
  1481. Tile* tmpTile = g_game.map.getTile(destPos);
  1482. if (tmpTile == nullptr || (tmpTile->getGround() == nullptr && !tmpTile->hasProperty(CONST_PROP_BLOCKSOLID))) {
  1483. tmpTile = g_game.map.getTile(destPos.x, destPos.y, destPos.z + 1);
  1484. if (tmpTile && tmpTile->getGround() && !tmpTile->hasProperty(CONST_PROP_IMMOVABLEBLOCKSOLID)) {
  1485. ret = g_game.internalMoveCreature(*player, *tmpTile, FLAG_IGNOREBLOCKITEM | FLAG_IGNOREBLOCKCREATURE);
  1486. }
  1487. }
  1488. }
  1489. }
  1490.  
  1491. if (ret != RETURNVALUE_NOERROR) {
  1492. player->sendCancelMessage(ret);
  1493. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  1494. return false;
  1495. }
  1496.  
  1497. g_game.addMagicEffect(player->getPosition(), CONST_ME_TELEPORT);
  1498. return true;
  1499. }
  1500.  
  1501. bool InstantSpell::Illusion(const InstantSpell*, Creature* creature, const std::string& param)
  1502. {
  1503. Player* player = creature->getPlayer();
  1504. if (!player) {
  1505. return false;
  1506. }
  1507.  
  1508. ReturnValue ret = CreateIllusion(creature, param, 180000);
  1509. if (ret != RETURNVALUE_NOERROR) {
  1510. player->sendCancelMessage(ret);
  1511. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  1512. return false;
  1513. }
  1514.  
  1515. g_game.addMagicEffect(player->getPosition(), CONST_ME_MAGIC_RED);
  1516. return true;
  1517. }
  1518.  
  1519. bool InstantSpell::canCast(const Player* player) const
  1520. {
  1521. if (player->hasFlag(PlayerFlag_CannotUseSpells)) {
  1522. return false;
  1523. }
  1524.  
  1525. if (player->hasFlag(PlayerFlag_IgnoreSpellCheck)) {
  1526. return true;
  1527. }
  1528.  
  1529. if (isLearnable()) {
  1530. if (player->hasLearnedInstantSpell(getName())) {
  1531. return true;
  1532. }
  1533. } else {
  1534. if (vocSpellMap.empty() || vocSpellMap.find(player->getVocationId()) != vocSpellMap.end()) {
  1535. return true;
  1536. }
  1537. }
  1538.  
  1539. return false;
  1540. }
  1541.  
  1542.  
  1543. ConjureSpell::ConjureSpell(LuaScriptInterface* _interface) :
  1544. InstantSpell(_interface)
  1545. {
  1546. aggressive = false;
  1547. conjureId = 0;
  1548. conjureCount = 1;
  1549. conjureReagentId = 0;
  1550. }
  1551.  
  1552. std::string ConjureSpell::getScriptEventName() const
  1553. {
  1554. return "onCastSpell";
  1555. }
  1556.  
  1557. bool ConjureSpell::configureEvent(const pugi::xml_node& node)
  1558. {
  1559. if (!InstantSpell::configureEvent(node)) {
  1560. return false;
  1561. }
  1562.  
  1563. pugi::xml_attribute attr;
  1564. if ((attr = node.attribute("conjureId"))) {
  1565. conjureId = pugi::cast<uint32_t>(attr.value());
  1566. }
  1567.  
  1568. if ((attr = node.attribute("conjureCount"))) {
  1569. conjureCount = pugi::cast<uint32_t>(attr.value());
  1570. } else if (conjureId != 0) {
  1571. // load default charges from items.xml
  1572. const ItemType& it = Item::items[conjureId];
  1573. if (it.charges != 0) {
  1574. conjureCount = it.charges;
  1575. }
  1576. }
  1577.  
  1578. if ((attr = node.attribute("reagentId"))) {
  1579. conjureReagentId = pugi::cast<uint32_t>(attr.value());
  1580. }
  1581.  
  1582. ItemType& iType = Item::items.getItemType(conjureId);
  1583. if (iType.isRune()) {
  1584. iType.runeSpellName = words;
  1585. }
  1586. return true;
  1587. }
  1588.  
  1589. bool ConjureSpell::loadFunction(const pugi::xml_attribute&)
  1590. {
  1591. m_scripted = false;
  1592. return true;
  1593. }
  1594.  
  1595. ReturnValue ConjureSpell::internalConjureItem(Player* player, uint32_t conjureId, uint32_t conjureCount)
  1596. {
  1597. Item* newItem = Item::CreateItem(conjureId, conjureCount);
  1598. if (!newItem) {
  1599. return RETURNVALUE_NOTPOSSIBLE;
  1600. }
  1601.  
  1602. ReturnValue result = g_game.internalPlayerAddItem(player, newItem);
  1603. if (result != RETURNVALUE_NOERROR) {
  1604. delete newItem;
  1605. }
  1606.  
  1607. return result;
  1608. }
  1609.  
  1610. bool ConjureSpell::conjureItem(Creature* creature) const
  1611. {
  1612. Player* player = creature->getPlayer();
  1613. if (!player) {
  1614. return false;
  1615. }
  1616.  
  1617. if (getReagentId() != 0) {
  1618. Item* item = player->getInventoryItem(CONST_SLOT_LEFT);
  1619. if (item && item->getID() == getReagentId()) {
  1620. g_game.internalRemoveItem(item);
  1621. } else {
  1622. item = player->getInventoryItem(CONST_SLOT_RIGHT);
  1623. if (item && item->getID() == getReagentId()) {
  1624. g_game.internalRemoveItem(item);
  1625. } else {
  1626. player->sendCancelMessage(RETURNVALUE_YOUNEEDAMAGICITEMTOCASTSPELL);
  1627. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  1628. return false;
  1629. }
  1630. }
  1631.  
  1632. Item* newItem = Item::CreateItem(getConjureId(), getConjureCount());
  1633. if (!newItem) {
  1634. return false;
  1635. }
  1636.  
  1637. ReturnValue ret = g_game.internalPlayerAddItem(player, newItem);
  1638. if (ret != RETURNVALUE_NOERROR) {
  1639. delete newItem;
  1640. return false;
  1641. }
  1642.  
  1643. g_game.startDecay(newItem);
  1644.  
  1645. } else if (internalConjureItem(player, getConjureId(), getConjureCount()) != RETURNVALUE_NOERROR) {
  1646. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  1647. return false;
  1648. }
  1649.  
  1650. postCastSpell(player);
  1651. g_game.addMagicEffect(player->getPosition(), CONST_ME_MAGIC_RED);
  1652. return true;
  1653. }
  1654.  
  1655. bool ConjureSpell::playerCastInstant(Player* player, std::string& param)
  1656. {
  1657. if (!playerSpellCheck(player)) {
  1658. return false;
  1659. }
  1660.  
  1661. if (m_scripted) {
  1662. LuaVariant var;
  1663. var.type = VARIANT_STRING;
  1664. var.text = param;
  1665. return executeCastSpell(player, var);
  1666. }
  1667. return conjureItem(player);
  1668. }
  1669.  
  1670. RuneSpell::RuneSpell(LuaScriptInterface* _interface) :
  1671. Action(_interface)
  1672. {
  1673. hasCharges = true;
  1674. runeId = 0;
  1675. runeFunction = nullptr;
  1676.  
  1677. allowFarUse = true;
  1678. }
  1679.  
  1680. std::string RuneSpell::getScriptEventName() const
  1681. {
  1682. return "onCastSpell";
  1683. }
  1684.  
  1685. bool RuneSpell::configureEvent(const pugi::xml_node& node)
  1686. {
  1687. if (!Spell::configureSpell(node)) {
  1688. return false;
  1689. }
  1690.  
  1691. if (!Action::configureEvent(node)) {
  1692. return false;
  1693. }
  1694.  
  1695. pugi::xml_attribute attr;
  1696. if (!(attr = node.attribute("id"))) {
  1697. std::cout << "[Error - RuneSpell::configureSpell] Rune spell without id." << std::endl;
  1698. return false;
  1699. }
  1700. runeId = pugi::cast<uint16_t>(attr.value());
  1701.  
  1702. uint32_t charges;
  1703. if ((attr = node.attribute("charges"))) {
  1704. charges = pugi::cast<uint32_t>(attr.value());
  1705. } else {
  1706. charges = 0;
  1707. }
  1708.  
  1709. hasCharges = (charges > 0);
  1710.  
  1711. //Change information in the ItemType to get accurate description
  1712. ItemType& iType = Item::items.getItemType(runeId);
  1713. iType.runeMagLevel = magLevel;
  1714. iType.runeLevel = level;
  1715. iType.charges = charges;
  1716. return true;
  1717. }
  1718.  
  1719. bool RuneSpell::loadFunction(const pugi::xml_attribute& attr)
  1720. {
  1721. const char* functionName = attr.as_string();
  1722. if (strcasecmp(functionName, "chameleon") == 0) {
  1723. runeFunction = Illusion;
  1724. } else if (strcasecmp(functionName, "convince") == 0) {
  1725. runeFunction = Convince;
  1726. } else {
  1727. std::cout << "[Warning - RuneSpell::loadFunction] Function \"" << functionName << "\" does not exist." << std::endl;
  1728. return false;
  1729. }
  1730.  
  1731. m_scripted = false;
  1732. return true;
  1733. }
  1734.  
  1735. bool RuneSpell::Illusion(const RuneSpell*, Player* player, const Position& posTo)
  1736. {
  1737. Thing* thing = g_game.internalGetThing(player, posTo, 0, 0, STACKPOS_MOVE);
  1738. if (!thing) {
  1739. player->sendCancelMessage(RETURNVALUE_NOTPOSSIBLE);
  1740. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  1741. return false;
  1742. }
  1743.  
  1744. Item* illusionItem = thing->getItem();
  1745. if (!illusionItem || !illusionItem->isMoveable()) {
  1746. player->sendCancelMessage(RETURNVALUE_NOTPOSSIBLE);
  1747. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  1748. return false;
  1749. }
  1750.  
  1751. ReturnValue ret = CreateIllusion(player, illusionItem->getID(), 200000);
  1752. if (ret != RETURNVALUE_NOERROR) {
  1753. player->sendCancelMessage(ret);
  1754. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  1755. return false;
  1756. }
  1757.  
  1758. g_game.addMagicEffect(player->getPosition(), CONST_ME_MAGIC_RED);
  1759. return true;
  1760. }
  1761.  
  1762. bool RuneSpell::Convince(const RuneSpell* spell, Player* player, const Position& posTo)
  1763. {
  1764. if (!player->hasFlag(PlayerFlag_CanConvinceAll)) {
  1765. if (player->getSummonCount() >= 2) {
  1766. player->sendCancelMessage(RETURNVALUE_NOTPOSSIBLE);
  1767. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  1768. return false;
  1769. }
  1770. }
  1771.  
  1772. Thing* thing = g_game.internalGetThing(player, posTo, 0, 0, STACKPOS_LOOK);
  1773. if (!thing) {
  1774. player->sendCancelMessage(RETURNVALUE_NOTPOSSIBLE);
  1775. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  1776. return false;
  1777. }
  1778.  
  1779. Creature* convinceCreature = thing->getCreature();
  1780. if (!convinceCreature) {
  1781. player->sendCancelMessage(RETURNVALUE_NOTPOSSIBLE);
  1782. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  1783. return false;
  1784. }
  1785.  
  1786. uint32_t manaCost = 0;
  1787. if (convinceCreature->getMonster()) {
  1788. manaCost = convinceCreature->getMonster()->getManaCost();
  1789. }
  1790.  
  1791. if (!player->hasFlag(PlayerFlag_HasInfiniteMana) && player->getMana() < manaCost) {
  1792. player->sendCancelMessage(RETURNVALUE_NOTENOUGHMANA);
  1793. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  1794. return false;
  1795. }
  1796.  
  1797. if (!convinceCreature->convinceCreature(player)) {
  1798. player->sendCancelMessage(RETURNVALUE_NOTPOSSIBLE);
  1799. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  1800. return false;
  1801. }
  1802.  
  1803. Spell::postCastSpell(player, manaCost, spell->getSoulCost());
  1804. g_game.addMagicEffect(player->getPosition(), CONST_ME_MAGIC_RED);
  1805. return true;
  1806. }
  1807.  
  1808. ReturnValue RuneSpell::canExecuteAction(const Player* player, const Position& toPos)
  1809. {
  1810. if (player->hasFlag(PlayerFlag_CannotUseSpells)) {
  1811. return RETURNVALUE_CANNOTUSETHISOBJECT;
  1812. }
  1813.  
  1814. ReturnValue ret = Action::canExecuteAction(player, toPos);
  1815. if (ret != RETURNVALUE_NOERROR) {
  1816. return ret;
  1817. }
  1818.  
  1819. if (toPos.x == 0xFFFF) {
  1820. if (needTarget) {
  1821. return RETURNVALUE_CANONLYUSETHISRUNEONCREATURES;
  1822. } else if (!selfTarget) {
  1823. return RETURNVALUE_NOTENOUGHROOM;
  1824. }
  1825. }
  1826.  
  1827. return RETURNVALUE_NOERROR;
  1828. }
  1829.  
  1830. bool RuneSpell::executeUse(Player* player, Item* item, const Position&, Thing* target, const Position& toPosition)
  1831. {
  1832. if (!playerRuneSpellCheck(player, toPosition)) {
  1833. return false;
  1834. }
  1835.  
  1836. bool result = false;
  1837. if (m_scripted) {
  1838. LuaVariant var;
  1839.  
  1840. if (needTarget) {
  1841. var.type = VARIANT_NUMBER;
  1842.  
  1843. if (target == nullptr) {
  1844. Tile* toTile = g_game.map.getTile(toPosition);
  1845. if (toTile) {
  1846. const Creature* visibleCreature = toTile->getBottomCreature();
  1847. if (visibleCreature) {
  1848. var.number = visibleCreature->getID();
  1849. }
  1850. }
  1851. } else {
  1852. var.number = target->getCreature()->getID();
  1853. }
  1854. } else {
  1855. var.type = VARIANT_POSITION;
  1856. var.pos = toPosition;
  1857. }
  1858.  
  1859. result = internalCastSpell(player, var);
  1860. } else if (runeFunction) {
  1861. result = runeFunction(this, player, toPosition);
  1862. }
  1863.  
  1864. if (!result) {
  1865. return false;
  1866. }
  1867.  
  1868. postCastSpell(player);
  1869. if (hasCharges && item && g_config.getBoolean(ConfigManager::REMOVE_RUNE_CHARGES)) {
  1870. int32_t newCount = std::max<int32_t>(0, item->getCharges() - 1);
  1871. g_game.transformItem(item, item->getID(), newCount);
  1872. }
  1873. return true;
  1874. }
  1875.  
  1876. bool RuneSpell::castSpell(Creature* creature)
  1877. {
  1878. LuaVariant var;
  1879. var.type = VARIANT_NUMBER;
  1880. var.number = creature->getID();
  1881. return internalCastSpell(creature, var);
  1882. }
  1883.  
  1884. bool RuneSpell::castSpell(Creature* creature, Creature* target)
  1885. {
  1886. LuaVariant var;
  1887. var.type = VARIANT_NUMBER;
  1888. var.number = target->getID();
  1889. return internalCastSpell(creature, var);
  1890. }
  1891.  
  1892. bool RuneSpell::internalCastSpell(Creature* creature, const LuaVariant& var)
  1893. {
  1894. bool result;
  1895. if (m_scripted) {
  1896. result = executeCastSpell(creature, var);
  1897. } else {
  1898. result = false;
  1899. }
  1900. return result;
  1901. }
  1902.  
  1903. bool RuneSpell::executeCastSpell(Creature* creature, const LuaVariant& var)
  1904. {
  1905. //onCastSpell(creature, var)
  1906. if (!m_scriptInterface->reserveScriptEnv()) {
  1907. std::cout << "[Error - RuneSpell::executeCastSpell] Call stack overflow" << std::endl;
  1908. return false;
  1909. }
  1910.  
  1911. ScriptEnvironment* env = m_scriptInterface->getScriptEnv();
  1912. env->setScriptId(m_scriptId, m_scriptInterface);
  1913.  
  1914. lua_State* L = m_scriptInterface->getLuaState();
  1915.  
  1916. m_scriptInterface->pushFunction(m_scriptId);
  1917.  
  1918. LuaScriptInterface::pushUserdata<Creature>(L, creature);
  1919. LuaScriptInterface::setCreatureMetatable(L, -1, creature);
  1920.  
  1921. LuaScriptInterface::pushVariant(L, var);
  1922.  
  1923. return m_scriptInterface->callFunction(2);
  1924. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement