Advertisement
Guest User

Weapons.cpp

a guest
Mar 29th, 2018
102
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 25.60 KB | None | 0 0
  1. ////////////////////////////////////////////////////////////////////////
  2. // OpenTibia - an opensource roleplaying game
  3. ////////////////////////////////////////////////////////////////////////
  4. // This program is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. ////////////////////////////////////////////////////////////////////////
  17. #include "otpch.h"
  18. #include "weapons.h"
  19.  
  20. #include <libxml/xmlmemory.h>
  21. #include <libxml/parser.h>
  22.  
  23. #include "game.h"
  24. #include "configmanager.h"
  25. #include "tools.h"
  26.  
  27. extern Game g_game;
  28. extern ConfigManager g_config;
  29. extern Weapons* g_weapons;
  30.  
  31. Weapons::Weapons():
  32. m_interface("Weapon Interface")
  33. {
  34. m_interface.initState();
  35. }
  36.  
  37. const Weapon* Weapons::getWeapon(const Item* item) const
  38. {
  39. if(!item)
  40. return NULL;
  41.  
  42. WeaponMap::const_iterator it = weapons.find(item->getID());
  43. if(it != weapons.end())
  44. return it->second;
  45.  
  46. return NULL;
  47. }
  48.  
  49. void Weapons::clear()
  50. {
  51. for(WeaponMap::iterator it = weapons.begin(); it != weapons.end(); ++it)
  52. delete it->second;
  53.  
  54. weapons.clear();
  55. m_interface.reInitState();
  56. }
  57.  
  58. bool Weapons::loadDefaults()
  59. {
  60. for(uint32_t i = 0; i <= Item::items.size(); ++i)
  61. {
  62. const ItemType* it = Item::items.getElement(i);
  63. if(!it || weapons.find(it->id) != weapons.end())
  64. continue;
  65.  
  66. if(it->weaponType != WEAPON_NONE)
  67. {
  68. switch(it->weaponType)
  69. {
  70. case WEAPON_AXE:
  71. case WEAPON_SWORD:
  72. case WEAPON_CLUB:
  73. case WEAPON_FIST:
  74. {
  75. if(WeaponMelee* weapon = new WeaponMelee(&m_interface))
  76. {
  77. weapon->configureWeapon(*it);
  78. weapons[it->id] = weapon;
  79. }
  80.  
  81. break;
  82. }
  83.  
  84. case WEAPON_DIST:
  85. if(it->ammoType != AMMO_NONE)
  86. break;
  87.  
  88. case WEAPON_AMMO:
  89. {
  90. if(WeaponDistance* weapon = new WeaponDistance(&m_interface))
  91. {
  92. weapon->configureWeapon(*it);
  93. weapons[it->id] = weapon;
  94. }
  95.  
  96. break;
  97. }
  98.  
  99. default:
  100. break;
  101. }
  102. }
  103. }
  104.  
  105. return true;
  106. }
  107.  
  108. Event* Weapons::getEvent(const std::string& nodeName)
  109. {
  110. std::string tmpNodeName = asLowerCaseString(nodeName);
  111. if(tmpNodeName == "melee")
  112. return new WeaponMelee(&m_interface);
  113.  
  114. if(tmpNodeName == "distance" || tmpNodeName == "ammunition" || tmpNodeName == "ammo")
  115. return new WeaponDistance(&m_interface);
  116.  
  117. if(tmpNodeName == "wand" || tmpNodeName == "rod")
  118. return new WeaponWand(&m_interface);
  119.  
  120. return NULL;
  121. }
  122.  
  123. bool Weapons::registerEvent(Event* event, xmlNodePtr, bool override)
  124. {
  125. Weapon* weapon = dynamic_cast<Weapon*>(event);
  126. if(!weapon)
  127. return false;
  128.  
  129. WeaponMap::iterator it = weapons.find(weapon->getID());
  130. if(it == weapons.end())
  131. {
  132. weapons[weapon->getID()] = weapon;
  133. return true;
  134. }
  135.  
  136. if(override)
  137. {
  138. delete it->second;
  139. it->second = weapon;
  140. return true;
  141. }
  142.  
  143. std::clog << "[Warning - Weapons::registerEvent] Duplicate registered item with id: " << weapon->getID() << std::endl;
  144. return false;
  145. }
  146.  
  147. int64_t Weapons::getMaxMeleeDamage(int64_t attackSkill, int64_t attackValue)
  148. {
  149. return (int64_t)std::ceil((attackSkill * (attackValue * 0.05)) + (attackValue * 0.5));
  150. }
  151.  
  152. int64_t Weapons::getMaxWeaponDamage(int64_t level, int64_t attackSkill, int64_t attackValue, float attackFactor)
  153. {
  154. return (int64_t)std::ceil((2 * (attackValue * (attackSkill + 5.8) / 25 + (level - 1) / 10.)) / attackFactor);
  155. }
  156.  
  157. Weapon::Weapon(LuaInterface* _interface):
  158. Event(_interface)
  159. {
  160. id = 0;
  161. level = 0;
  162. magLevel = 0;
  163. mana = 0;
  164. manaPercent = 0;
  165. soul = 0;
  166. exhaustion = 0;
  167. premium = false;
  168. enabled = true;
  169. wieldUnproperly = false;
  170. swing = true;
  171. ammoAction = AMMOACTION_NONE;
  172. params.blockedByArmor = true;
  173. params.blockedByShield = true;
  174. params.combatType = COMBAT_PHYSICALDAMAGE;
  175. }
  176.  
  177. bool Weapon::configureEvent(xmlNodePtr p)
  178. {
  179. int32_t intValue, wieldInfo = 0;
  180. std::string strValue;
  181. if(!readXMLInteger(p, "id", intValue))
  182. {
  183. std::clog << "Error: [Weapon::configureEvent] Weapon without id." << std::endl;
  184. return false;
  185. }
  186.  
  187. id = intValue;
  188. if(readXMLInteger(p, "lv", intValue) || readXMLInteger(p, "lvl", intValue) || readXMLInteger(p, "level", intValue))
  189. {
  190. level = intValue;
  191. if(level > 0)
  192. wieldInfo |= WIELDINFO_LEVEL;
  193. }
  194.  
  195. if(readXMLInteger(p, "maglv", intValue) || readXMLInteger(p, "maglvl", intValue) || readXMLInteger(p, "maglevel", intValue))
  196. {
  197. magLevel = intValue;
  198. if(magLevel > 0)
  199. wieldInfo |= WIELDINFO_MAGLV;
  200. }
  201.  
  202. if(readXMLInteger(p, "mana", intValue))
  203. mana = intValue;
  204.  
  205. if(readXMLInteger(p, "manapercent", intValue))
  206. manaPercent = intValue;
  207.  
  208. if(readXMLInteger(p, "soul", intValue))
  209. soul = intValue;
  210.  
  211. if(readXMLInteger(p, "exhaust", intValue) || readXMLInteger(p, "exhaustion", intValue))
  212. exhaustion = intValue;
  213.  
  214. if(readXMLString(p, "prem", strValue) || readXMLString(p, "premium", strValue))
  215. {
  216. premium = booleanString(strValue);
  217. if(premium)
  218. wieldInfo |= WIELDINFO_PREMIUM;
  219. }
  220.  
  221. if(readXMLString(p, "enabled", strValue))
  222. enabled = booleanString(strValue);
  223.  
  224. if(readXMLString(p, "unproperly", strValue))
  225. wieldUnproperly = booleanString(strValue);
  226.  
  227. if(readXMLString(p, "swing", strValue))
  228. swing = booleanString(strValue);
  229.  
  230. if(readXMLString(p, "type", strValue))
  231. params.combatType = getCombatType(strValue);
  232.  
  233. std::string error;
  234. StringVec vocStringVec;
  235.  
  236. xmlNodePtr vocationNode = p->children;
  237. while(vocationNode)
  238. {
  239. if(!parseVocationNode(vocationNode, vocWeaponMap, vocStringVec, error))
  240. std::clog << "[Warning - Weapon::configureEvent] " << error << std::endl;
  241.  
  242. vocationNode = vocationNode->next;
  243. }
  244.  
  245. if(!vocWeaponMap.empty())
  246. wieldInfo |= WIELDINFO_VOCREQ;
  247.  
  248. if(wieldInfo)
  249. {
  250. ItemType& it = Item::items.getItemType(id);
  251. it.minReqMagicLevel = getReqMagLv();
  252. it.minReqLevel = getReqLevel();
  253.  
  254. it.wieldInfo = wieldInfo;
  255. it.vocationString = parseVocationString(vocStringVec);
  256. }
  257.  
  258. return configureWeapon(Item::items[getID()]);
  259. }
  260.  
  261. bool Weapon::loadFunction(const std::string& functionName)
  262. {
  263. std::string tmpFunctionName = asLowerCaseString(functionName);
  264. if(tmpFunctionName == "internalloadweapon" || tmpFunctionName == "default")
  265. {
  266. m_scripted = EVENT_SCRIPT_FALSE;
  267. return configureWeapon(Item::items[getID()]);
  268. }
  269.  
  270. return false;
  271. }
  272.  
  273. bool Weapon::configureWeapon(const ItemType& it)
  274. {
  275. id = it.id;
  276. return true;
  277. }
  278.  
  279. int64_t Weapon::playerWeaponCheck(Player* player, Creature* target) const
  280. {
  281. const Position& playerPos = player->getPosition();
  282. const Position& targetPos = target->getPosition();
  283. if(playerPos.z != targetPos.z)
  284. return 0;
  285.  
  286. const ItemType& it = Item::items[id];
  287. int32_t range = it.shootRange;
  288. if(it.weaponType == WEAPON_AMMO)
  289. {
  290. if(Item* item = player->getWeapon(true))
  291. range = item->getShootRange();
  292. }
  293.  
  294. if(std::max(std::abs(playerPos.x - targetPos.x), std::abs(playerPos.y - targetPos.y)) > range)
  295. return 0;
  296.  
  297. if(player->hasFlag(PlayerFlag_IgnoreEquipCheck))
  298. return 100;
  299.  
  300. if(!enabled)
  301. return 0;
  302.  
  303. if(player->getMana() < getManaCost(player))
  304. return 0;
  305.  
  306. if(player->getSoul() < soul)
  307. return 0;
  308.  
  309. if(isPremium() && !player->isPremium())
  310. return 0;
  311.  
  312. if(!vocWeaponMap.empty() && vocWeaponMap.find(player->getVocationId()) == vocWeaponMap.end())
  313. return 0;
  314.  
  315. int64_t modifier = 100;
  316. if(player->getLevel() < getReqLevel())
  317. {
  318. if(!isWieldedUnproperly())
  319. return 0;
  320.  
  321. double penalty = (getReqLevel() - player->getLevel()) * 0.02;
  322. if(penalty > 0.5)
  323. penalty = 0.5;
  324.  
  325. modifier -= (int64_t)(modifier * penalty);
  326. }
  327.  
  328. if(player->getMagicLevel() < getReqMagLv())
  329. {
  330. if(!isWieldedUnproperly())
  331. return 0;
  332.  
  333. double penalty = (getReqMagLv() - player->getMagicLevel()) * 0.02;
  334. if(penalty > 0.5)
  335. penalty = 0.5;
  336.  
  337. modifier -= (int32_t)(modifier * penalty);
  338. }
  339.  
  340. return modifier;
  341. }
  342.  
  343. bool Weapon::useWeapon(Player* player, Item* item, Creature* target) const
  344. {
  345. int64_t modifier = playerWeaponCheck(player, target);
  346. if(!modifier)
  347. return false;
  348.  
  349. return internalUseWeapon(player, item, target, modifier);
  350. }
  351.  
  352. bool Weapon::useFist(Player* player, Creature* target)
  353. {
  354. const Position& playerPos = player->getPosition();
  355. const Position& targetPos = target->getPosition();
  356. if(!Position::areInRange<1,1>(playerPos, targetPos))
  357. return false;
  358.  
  359. float attackFactor = player->getAttackFactor();
  360. int64_t attackSkill = player->getSkill(SKILL_FIST, SKILL_LEVEL), attackValue = g_config.getNumber(ConfigManager::FIST_BASE_ATTACK);
  361.  
  362. double maxDamage = Weapons::getMaxWeaponDamage(player->getLevel(), attackSkill, attackValue, attackFactor);
  363. if(g_config.getNumber(ConfigManager::CRITICAL_HIT_CHANCE) >= random_range(1, 100))
  364. {
  365. maxDamage = std::pow(maxDamage, g_config.getDouble(ConfigManager::CRITICAL_HIT_MUL));
  366. player->sendCritical();
  367. }
  368.  
  369. Vocation* vocation = player->getVocation();
  370. if(vocation && vocation->getMultiplier(MULTIPLIER_MELEE) != 1.0)
  371. maxDamage *= vocation->getMultiplier(MULTIPLIER_MELEE);
  372.  
  373. maxDamage = std::floor(maxDamage);
  374. int64_t damage = -random_range(0, (int64_t)maxDamage, DISTRO_NORMAL);
  375.  
  376. CombatParams fist;
  377. fist.blockedByArmor = true;
  378. fist.blockedByShield = true;
  379. fist.combatType = COMBAT_PHYSICALDAMAGE;
  380.  
  381. Combat::doCombatHealth(player, target, damage, damage, fist);
  382. if(!player->hasFlag(PlayerFlag_NotGainSkill) && player->getAddAttackSkill())
  383. player->addSkillAdvance(SKILL_FIST, 1);
  384.  
  385. return true;
  386. }
  387.  
  388. bool Weapon::internalUseWeapon(Player* player, Item* item, Creature* target, int64_t modifier) const
  389. {
  390. if(isScripted())
  391. {
  392. LuaVariant var;
  393. var.type = VARIANT_NUMBER;
  394. var.number = target->getID();
  395. executeUseWeapon(player, var);
  396. }
  397. else
  398. {
  399. CombatParams _params = params;
  400. _params.element.type = item->getElementType();
  401. _params.element.damage = getWeaponElementDamage(player, item);
  402.  
  403. int64_t damage = (getWeaponDamage(player, target, item) * modifier) / 100;
  404. Combat::doCombatHealth(player, target, damage, damage, _params);
  405. }
  406.  
  407. onUsedAmmo(player, item, target->getTile());
  408. onUsedWeapon(player, item, target->getTile());
  409. return true;
  410. }
  411.  
  412. bool Weapon::internalUseWeapon(Player* player, Item* item, Tile* tile) const
  413. {
  414. if(isScripted())
  415. {
  416. LuaVariant var;
  417. var.type = VARIANT_TARGETPOSITION;
  418. var.pos = tile->getPosition();
  419. executeUseWeapon(player, var);
  420. }
  421. else
  422. {
  423. Combat::postCombatEffects(player, tile->getPosition(), params);
  424. g_game.addMagicEffect(tile->getPosition(), MAGIC_EFFECT_POFF);
  425. }
  426.  
  427. onUsedAmmo(player, item, tile);
  428. onUsedWeapon(player, item, tile);
  429. return true;
  430. }
  431.  
  432. void Weapon::onUsedWeapon(Player* player, Item* item, Tile*) const
  433. {
  434. if(!player->hasFlag(PlayerFlag_NotGainSkill))
  435. {
  436. skills_t skillType;
  437. uint64_t skillPoint = 0;
  438. if(getSkillType(player, item, skillType, skillPoint))
  439. player->addSkillAdvance(skillType, skillPoint);
  440. }
  441.  
  442. if(!player->hasFlag(PlayerFlag_HasNoExhaustion) && exhaustion > 0)
  443. player->addExhaust(exhaustion, EXHAUST_MELEE);
  444.  
  445. int64_t manaCost = getManaCost(player);
  446. if(manaCost > 0)
  447. {
  448. player->changeMana(-manaCost);
  449. if(!player->hasFlag(PlayerFlag_NotGainMana) && (player->getZone() != ZONE_HARDCORE
  450. || g_config.getBool(ConfigManager::PVPZONE_ADDMANASPENT)))
  451. player->addManaSpent(manaCost);
  452. }
  453.  
  454. if(!player->hasFlag(PlayerFlag_HasInfiniteSoul) && soul > 0)
  455. player->changeSoul(-soul);
  456. }
  457.  
  458. void Weapon::onUsedAmmo(Player* player, Item* item, Tile* destTile) const
  459. {
  460. if(!g_config.getBool(ConfigManager::REMOVE_WEAPON_AMMO))
  461. return;
  462.  
  463. switch(ammoAction)
  464. {
  465. case AMMOACTION_REMOVECOUNT:
  466. g_game.transformItem(item, item->getID(), std::max((int32_t)0, ((int32_t)item->getItemCount()) - 1));
  467. break;
  468.  
  469. case AMMOACTION_REMOVECHARGE:
  470. g_game.transformItem(item, item->getID(), std::max((int32_t)0, ((int32_t)item->getCharges()) - 1));
  471. break;
  472.  
  473. case AMMOACTION_MOVE:
  474. g_game.internalMoveItem(player, item->getParent(), destTile, INDEX_WHEREEVER, item, 1, NULL, FLAG_NOLIMIT);
  475. break;
  476.  
  477. case AMMOACTION_MOVEBACK:
  478. break;
  479.  
  480. default:
  481. if(item->hasCharges())
  482. g_game.transformItem(item, item->getID(), std::max((int32_t)0, ((int32_t)item->getCharges()) - 1));
  483.  
  484. break;
  485. }
  486. }
  487.  
  488. int64_t Weapon::getManaCost(const Player* player) const
  489. {
  490. if(mana)
  491. return mana;
  492.  
  493. return manaPercent ? (player->getMaxMana() * manaPercent) / 100 : 0;
  494. }
  495.  
  496. bool Weapon::executeUseWeapon(Player* player, const LuaVariant& var) const
  497. {
  498. //onUseWeapon(cid, var)
  499. if(m_interface->reserveEnv())
  500. {
  501. ScriptEnviroment* env = m_interface->getEnv();
  502. if(m_scripted == EVENT_SCRIPT_BUFFER)
  503. {
  504. env->setRealPos(player->getPosition());
  505. std::stringstream scriptstream;
  506.  
  507. scriptstream << "local cid = " << env->addThing(player) << std::endl;
  508. env->streamVariant(scriptstream, "var", var);
  509.  
  510. if(m_scriptData)
  511. scriptstream << *m_scriptData;
  512.  
  513. bool result = true;
  514. if(m_interface->loadBuffer(scriptstream.str()))
  515. {
  516. lua_State* L = m_interface->getState();
  517. result = m_interface->getGlobalBool(L, "_result", true);
  518. }
  519.  
  520. m_interface->releaseEnv();
  521. return result;
  522. }
  523. else
  524. {
  525. #ifdef __DEBUG_LUASCRIPTS__
  526. char desc[60];
  527. sprintf(desc, "onUseWeapon - %s", player->getName().c_str());
  528. env->setEvent(desc);
  529. #endif
  530.  
  531. env->setScriptId(m_scriptId, m_interface);
  532. env->setRealPos(player->getPosition());
  533.  
  534. lua_State* L = m_interface->getState();
  535. m_interface->pushFunction(m_scriptId);
  536.  
  537. lua_pushnumber(L, env->addThing(player));
  538. m_interface->pushVariant(L, var);
  539.  
  540. bool result = m_interface->callFunction(2);
  541. m_interface->releaseEnv();
  542. return result;
  543. }
  544. }
  545. else
  546. {
  547. std::clog << "[Error - Weapon::executeUseWeapon] Call stack overflow" << std::endl;
  548. return false;
  549. }
  550. }
  551.  
  552. WeaponMelee::WeaponMelee(LuaInterface* _interface):
  553. Weapon(_interface) {}
  554.  
  555. bool WeaponMelee::useWeapon(Player* player, Item* item, Creature* target) const
  556. {
  557. int64_t modifier = playerWeaponCheck(player, target);
  558. if(!modifier)
  559. return false;
  560.  
  561. return internalUseWeapon(player, item, target, modifier);
  562. }
  563.  
  564. bool WeaponMelee::getSkillType(const Player* player, const Item* item,
  565. skills_t& skill, uint64_t& skillPoint) const
  566. {
  567. skillPoint = 0;
  568. if(player->getAddAttackSkill())
  569. {
  570. switch(player->getLastAttackBlockType())
  571. {
  572. case BLOCK_ARMOR:
  573. case BLOCK_NONE:
  574. skillPoint = 1;
  575. break;
  576.  
  577. case BLOCK_DEFENSE:
  578. default:
  579. break;
  580. }
  581. }
  582.  
  583. switch(item->getWeaponType())
  584. {
  585. case WEAPON_SWORD:
  586. {
  587. skill = SKILL_SWORD;
  588. return true;
  589. }
  590.  
  591. case WEAPON_CLUB:
  592. {
  593. skill = SKILL_CLUB;
  594. return true;
  595. }
  596.  
  597. case WEAPON_AXE:
  598. {
  599. skill = SKILL_AXE;
  600. return true;
  601. }
  602.  
  603. case WEAPON_FIST:
  604. {
  605. skill = SKILL_FIST;
  606. return true;
  607. }
  608.  
  609. default:
  610. break;
  611. }
  612.  
  613. return false;
  614. }
  615.  
  616. int64_t WeaponMelee::getWeaponDamage(const Player* player, const Creature*, const Item* item, bool maxDamage /*= false*/) const
  617. {
  618. int64_t attackSkill = player->getWeaponSkill(item), attackValue = std::max((int64_t)0,
  619. (int64_t(item->getAttack() + item->getExtraAttack()) - item->getElementDamage()));
  620. float attackFactor = player->getAttackFactor();
  621.  
  622. double maxValue = Weapons::getMaxWeaponDamage(player->getLevel(), attackSkill, attackValue, attackFactor);
  623. if(g_config.getNumber(ConfigManager::CRITICAL_HIT_CHANCE) >= random_range(1, 100))
  624. {
  625. maxValue = std::pow(maxValue, g_config.getDouble(ConfigManager::CRITICAL_HIT_MUL));
  626. player->sendCritical();
  627. }
  628.  
  629. Vocation* vocation = player->getVocation();
  630. if(vocation && vocation->getMultiplier(MULTIPLIER_MELEE) != 1.0)
  631. maxValue *= vocation->getMultiplier(MULTIPLIER_MELEE);
  632.  
  633. int32_t ret = (int32_t)std::floor(maxValue);
  634. if(maxDamage)
  635. return -ret;
  636.  
  637. return -random_range(0, ret, DISTRO_NORMAL);
  638. }
  639.  
  640. int64_t WeaponMelee::getWeaponElementDamage(const Player* player, const Item* item, bool maxDamage/* = false*/) const
  641. {
  642. int64_t attackSkill = player->getWeaponSkill(item), attackValue = item->getElementDamage();
  643. float attackFactor = player->getAttackFactor();
  644.  
  645. double maxValue = Weapons::getMaxWeaponDamage(player->getLevel(), attackSkill, attackValue, attackFactor);
  646.  
  647. Vocation* vocation = player->getVocation();
  648. if(vocation && vocation->getMultiplier(MULTIPLIER_MELEE) != 1.0)
  649. maxValue *= vocation->getMultiplier(MULTIPLIER_MELEE);
  650.  
  651. int64_t ret = (int64_t)std::floor(maxValue);
  652. if(maxDamage)
  653. return -ret;
  654.  
  655. return -random_range(0, ret, DISTRO_NORMAL);
  656. }
  657.  
  658. WeaponDistance::WeaponDistance(LuaInterface* _interface):
  659. Weapon(_interface)
  660. {
  661. hitChance = -1;
  662. maxHitChance = breakChance = attack = 0;
  663. swing = params.blockedByShield = false;
  664. }
  665.  
  666. bool WeaponDistance::configureWeapon(const ItemType& it)
  667. {
  668. if(it.ammoType != AMMO_NONE) //hit chance on two-handed weapons is limited to 90%
  669. maxHitChance = 90;
  670. else //one-handed is set to 75%
  671. maxHitChance = 75;
  672.  
  673. if(it.hitChance > 0)
  674. hitChance = it.hitChance;
  675.  
  676. if(it.maxHitChance > 0)
  677. maxHitChance = it.maxHitChance;
  678.  
  679. if(it.breakChance > 0)
  680. breakChance = it.breakChance;
  681.  
  682. if(it.ammoAction != AMMOACTION_NONE)
  683. ammoAction = it.ammoAction;
  684.  
  685. params.effects.distance = it.shootType;
  686. attack = it.attack;
  687. return Weapon::configureWeapon(it);
  688. }
  689.  
  690. int64_t WeaponDistance::playerWeaponCheck(Player* player, Creature* target) const
  691. {
  692. const ItemType& it = Item::items[id];
  693. if(it.weaponType == WEAPON_AMMO)
  694. {
  695. if(Item* item = player->getWeapon(true))
  696. {
  697. if(const Weapon* weapon = g_weapons->getWeapon(item))
  698. return weapon->playerWeaponCheck(player, target);
  699. }
  700. }
  701.  
  702. return Weapon::playerWeaponCheck(player, target);
  703. }
  704.  
  705. bool WeaponDistance::useWeapon(Player* player, Item* item, Creature* target) const
  706. {
  707. int64_t modifier = playerWeaponCheck(player, target);
  708. if(!modifier)
  709. return false;
  710.  
  711. int64_t chance = hitChance;
  712. if(chance == -1)
  713. {
  714. //hit chance is based on distance to target and distance skill
  715. const Position& playerPos = player->getPosition();
  716. const Position& targetPos = target->getPosition();
  717.  
  718. uint64_t distance = std::max(std::abs(playerPos.x - targetPos.x), std::abs(
  719. playerPos.y - targetPos.y)), skill = player->getSkill(SKILL_DIST, SKILL_LEVEL);
  720. if(maxHitChance == 75)
  721. {
  722. //chance for one-handed weapons
  723. switch(distance)
  724. {
  725. case 1:
  726. chance = (uint64_t)((float)std::min(skill, (uint64_t)74)) + 1;
  727. break;
  728. case 2:
  729. chance = (uint64_t)((float)2.4 * std::min(skill, (uint64_t)28)) + 8;
  730. break;
  731. case 3:
  732. chance = (uint64_t)((float)1.55 * std::min(skill, (uint64_t)45)) + 6;
  733. break;
  734. case 4:
  735. chance = (uint64_t)((float)1.25 * std::min(skill, (uint64_t)58)) + 3;
  736. break;
  737. case 5:
  738. chance = (uint64_t)((float)std::min(skill, (uint64_t)74)) + 1;
  739. break;
  740. case 6:
  741. chance = (uint64_t)((float)0.8 * std::min(skill, (uint64_t)90)) + 3;
  742. break;
  743. case 7:
  744. chance = (uint64_t)((float)0.7 * std::min(skill, (uint64_t)104)) + 2;
  745. break;
  746. default:
  747. chance = hitChance;
  748. break;
  749. }
  750. }
  751. else if(maxHitChance == 90)
  752. {
  753. //formula for two-handed weapons
  754. switch(distance)
  755. {
  756. case 1:
  757. chance = (uint64_t)((float)1.2 * std::min(skill, (uint64_t)74)) + 1;
  758. break;
  759. case 2:
  760. chance = (uint64_t)((float)3.2 * std::min(skill, (uint64_t)28));
  761. break;
  762. case 3:
  763. chance = (uint64_t)((float)2.0 * std::min(skill, (uint64_t)45));
  764. break;
  765. case 4:
  766. chance = (uint64_t)((float)1.55 * std::min(skill, (uint64_t)58));
  767. break;
  768. case 5:
  769. chance = (uint64_t)((float)1.2 * std::min(skill, (uint64_t)74)) + 1;
  770. break;
  771. case 6:
  772. chance = (uint64_t)((float)1.0 * std::min(skill, (uint64_t)90));
  773. break;
  774. case 7:
  775. chance = (uint64_t)((float)1.0 * std::min(skill, (uint64_t)90));
  776. break;
  777. default:
  778. chance = hitChance;
  779. break;
  780. }
  781. }
  782. else if(maxHitChance == 100)
  783. {
  784. switch(distance)
  785. {
  786. case 1:
  787. chance = (uint64_t)((float)1.35 * std::min(skill, (uint64_t)73)) + 1;
  788. break;
  789. case 2:
  790. chance = (uint64_t)((float)3.2 * std::min(skill, (uint64_t)30)) + 4;
  791. break;
  792. case 3:
  793. chance = (uint64_t)((float)2.05 * std::min(skill, (uint64_t)48)) + 2;
  794. break;
  795. case 4:
  796. chance = (uint64_t)((float)1.5 * std::min(skill, (uint64_t)65)) + 2;
  797. break;
  798. case 5:
  799. chance = (uint64_t)((float)1.35 * std::min(skill, (uint64_t)73)) + 1;
  800. break;
  801. case 6:
  802. chance = (uint64_t)((float)1.2 * std::min(skill, (uint64_t)87)) - 4;
  803. break;
  804. case 7:
  805. chance = (uint64_t)((float)1.1 * std::min(skill, (uint64_t)90)) + 1;
  806. break;
  807. default:
  808. chance = hitChance;
  809. break;
  810. }
  811. }
  812. else
  813. chance = maxHitChance;
  814. }
  815.  
  816. if(item->getWeaponType() == WEAPON_AMMO)
  817. {
  818. Item* bow = player->getWeapon(true);
  819. if(bow && bow->getHitChance() != -1)
  820. chance += bow->getHitChance();
  821. }
  822.  
  823. if(random_range(1, 100) > chance)
  824. {
  825. //we failed attack, miss!
  826. Tile* destTile = target->getTile();
  827. if(!Position::areInRange<1,1,0>(player->getPosition(), target->getPosition()))
  828. {
  829. std::vector<std::pair<int32_t, int32_t> > destList;
  830. destList.push_back(std::make_pair(-1, -1));
  831. destList.push_back(std::make_pair(-1, 0));
  832. destList.push_back(std::make_pair(-1, 1));
  833. destList.push_back(std::make_pair(0, -1));
  834. destList.push_back(std::make_pair(0, 0));
  835. destList.push_back(std::make_pair(0, 1));
  836. destList.push_back(std::make_pair(1, -1));
  837. destList.push_back(std::make_pair(1, 0));
  838. destList.push_back(std::make_pair(1, 1));
  839.  
  840. std::random_shuffle(destList.begin(), destList.end());
  841. Position destPos = target->getPosition();
  842.  
  843. Tile* tmpTile = NULL;
  844. for(std::vector<std::pair<int32_t, int32_t> >::iterator it = destList.begin(); it != destList.end(); ++it)
  845. {
  846. if(!(tmpTile = g_game.getTile(destPos.x + it->first, destPos.y + it->second, destPos.z))
  847. || tmpTile->hasProperty(IMMOVABLEBLOCKSOLID) || !tmpTile->ground)
  848. continue;
  849.  
  850. destTile = tmpTile;
  851. break;
  852. }
  853. }
  854.  
  855. Weapon::internalUseWeapon(player, item, destTile);
  856. }
  857. else
  858. Weapon::internalUseWeapon(player, item, target, modifier);
  859.  
  860. return true;
  861. }
  862.  
  863. void WeaponDistance::onUsedAmmo(Player* player, Item* item, Tile* destTile) const
  864. {
  865. if(!g_config.getBool(ConfigManager::REMOVE_WEAPON_AMMO))
  866. return;
  867.  
  868. if(ammoAction == AMMOACTION_MOVEBACK && breakChance > 0 && random_range(1, 100) <= breakChance)
  869. g_game.transformItem(item, item->getID(), std::max((int32_t)0, (int32_t)item->getItemCount() - 1));
  870. else
  871. Weapon::onUsedAmmo(player, item, destTile);
  872. }
  873.  
  874. int64_t WeaponDistance::getWeaponDamage(const Player* player, const Creature* target, const Item* item, bool maxDamage /*= false*/) const
  875. {
  876. int64_t attackValue = attack;
  877. if(item->getWeaponType() == WEAPON_AMMO)
  878. {
  879. if(Item* bow = const_cast<Player*>(player)->getWeapon(true))
  880. attackValue += bow->getAttack() + bow->getExtraAttack();
  881. }
  882.  
  883. int64_t attackSkill = player->getSkill(SKILL_DIST, SKILL_LEVEL);
  884. float attackFactor = player->getAttackFactor();
  885.  
  886. double maxValue = Weapons::getMaxWeaponDamage(player->getLevel(), attackSkill, attackValue, attackFactor);
  887. if(g_config.getNumber(ConfigManager::CRITICAL_HIT_CHANCE) >= random_range(1, 100))
  888. {
  889. maxValue *= g_config.getDouble(ConfigManager::CRITICAL_HIT_MUL);
  890. player->sendCritical();
  891. }
  892.  
  893. Vocation* vocation = player->getVocation();
  894. if(vocation && vocation->getMultiplier(MULTIPLIER_DISTANCE) != 1.0)
  895. maxValue *= vocation->getMultiplier(MULTIPLIER_DISTANCE);
  896.  
  897. int64_t ret = (int64_t)std::floor(maxValue);
  898. if(maxDamage)
  899. return -ret;
  900.  
  901. int64_t minValue = 0;
  902. if(target)
  903. {
  904. if(target->getPlayer())
  905. minValue = (int64_t)std::ceil(player->getLevel() * 0.1);
  906. else
  907. minValue = (int64_t)std::ceil(player->getLevel() * 0.2);
  908. }
  909.  
  910. return -random_range(minValue, ret, DISTRO_NORMAL);
  911. }
  912.  
  913. bool WeaponDistance::getSkillType(const Player* player, const Item*,
  914. skills_t& skill, uint64_t& skillPoint) const
  915. {
  916. skill = SKILL_DIST;
  917. skillPoint = 0;
  918. if(player->getAddAttackSkill())
  919. {
  920. switch(player->getLastAttackBlockType())
  921. {
  922. case BLOCK_NONE:
  923. skillPoint = 2;
  924. break;
  925.  
  926. case BLOCK_ARMOR:
  927. skillPoint = 1;
  928. break;
  929.  
  930. case BLOCK_DEFENSE:
  931. default:
  932. break;
  933. }
  934. }
  935.  
  936. return true;
  937. }
  938.  
  939. WeaponWand::WeaponWand(LuaInterface* _interface):
  940. Weapon(_interface)
  941. {
  942. minChange = 0;
  943. maxChange = 0;
  944. params.blockedByArmor = false;
  945. params.blockedByShield = false;
  946. }
  947.  
  948. bool WeaponWand::configureEvent(xmlNodePtr p)
  949. {
  950. if(!Weapon::configureEvent(p))
  951. return false;
  952.  
  953. int32_t intValue;
  954. if(readXMLInteger(p, "min", intValue))
  955. minChange = intValue;
  956.  
  957. if(readXMLInteger(p, "max", intValue))
  958. maxChange = intValue;
  959.  
  960. return true;
  961. }
  962.  
  963. bool WeaponWand::configureWeapon(const ItemType& it)
  964. {
  965. params.effects.distance = it.shootType;
  966. return Weapon::configureWeapon(it);
  967. }
  968.  
  969. int64_t WeaponWand::getWeaponDamage(const Player* player, const Creature*, const Item*, bool maxDamage /* = false*/) const
  970. {
  971. float multiplier = 1.0f;
  972. if(Vocation* vocation = player->getVocation())
  973. multiplier = vocation->getMultiplier(MULTIPLIER_WAND);
  974.  
  975. int64_t maxValue = (int64_t)(maxChange * multiplier);
  976. if(maxDamage)
  977. {
  978. player->sendCritical();
  979. return -maxValue;
  980. }
  981.  
  982. int64_t minValue = (int64_t)(minChange * multiplier);
  983. return random_range(-minValue, -maxValue, DISTRO_NORMAL);
  984. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement