Advertisement
Guest User

Untitled

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