Advertisement
Guest User

combat.cpp

a guest
Aug 31st, 2014
267
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 42.36 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 "const.h"
  19.  
  20. #include "combat.h"
  21. #include "tools.h"
  22.  
  23. #include "game.h"
  24. #include "configmanager.h"
  25.  
  26. #include "creature.h"
  27. #include "player.h"
  28. #include "weapons.h"
  29.  
  30. extern Game g_game;
  31. extern Weapons* g_weapons;
  32. extern ConfigManager g_config;
  33.  
  34. Combat::Combat()
  35. {
  36.     params.valueCallback = NULL;
  37.     params.tileCallback = NULL;
  38.     params.targetCallback = NULL;
  39.     area = NULL;
  40.  
  41.     formulaType = FORMULA_UNDEFINED;
  42.     mina = minb = maxa = maxb = minl = maxl = minm = maxm = minc = maxc = 0;
  43. }
  44.  
  45. Combat::~Combat()
  46. {
  47.     for(std::list<const Condition*>::iterator it = params.conditionList.begin(); it != params.conditionList.end(); ++it)
  48.         delete (*it);
  49.  
  50.     params.conditionList.clear();
  51.     delete area;
  52.  
  53.     delete params.valueCallback;
  54.     delete params.tileCallback;
  55.     delete params.targetCallback;
  56. }
  57.  
  58. bool Combat::getMinMaxValues(Creature* creature, Creature* target, CombatParams& _params, int32_t& min, int32_t& max) const
  59. {
  60.     if(creature)
  61.     {
  62.         if(creature->getCombatValues(min, max))
  63.             return true;
  64.  
  65.         if(Player* player = creature->getPlayer())
  66.         {
  67.             if(params.valueCallback)
  68.             {
  69.                 params.valueCallback->getMinMaxValues(player, _params, min, max);
  70.                 return true;
  71.             }
  72.  
  73.             min = max = 0;
  74.             switch(formulaType)
  75.             {
  76.                 case FORMULA_LEVELMAGIC:
  77.                 {
  78.                     min = (int32_t)((player->getLevel() / minl + player->getMagicLevel() * minm) * 1. * mina + minb);
  79.                     max = (int32_t)((player->getLevel() / maxl + player->getMagicLevel() * maxm) * 1. * maxa + maxb);
  80.                     if(minc && std::abs(min) < std::abs(minc))
  81.                         min = minc;
  82.  
  83.                     if(maxc && std::abs(max) < std::abs(maxc))
  84.                         max = maxc;
  85.  
  86.                     player->increaseCombatValues(min, max, params.useCharges, true);
  87.                     return true;
  88.                 }
  89.  
  90.                 case FORMULA_SKILL:
  91.                 {
  92.                     Item* item = player->getWeapon(false);
  93.                     if(const Weapon* weapon = g_weapons->getWeapon(item))
  94.                     {
  95.                         _params.element.type = item->getElementType();
  96.                         if(_params.element.type != COMBAT_NONE)
  97.                         {
  98.                             _params.element.damage = weapon->getWeaponElementDamage(player, item, true);
  99.                             _params.element.damage = random_range((int32_t)0, (int32_t)(_params.element.damage * maxa + maxb), DISTRO_NORMAL);
  100.                         }
  101.  
  102.                         max = (int32_t)(weapon->getWeaponDamage(player, target, item, true) * maxa + maxb);
  103.                         if(params.useCharges && item->hasCharges() && g_config.getBool(ConfigManager::REMOVE_WEAPON_CHARGES))
  104.                             g_game.transformItem(item, item->getID(), std::max((int32_t)0, ((int32_t)item->getCharges()) - 1));
  105.                     }
  106.                     else
  107.                         max = (int32_t)maxb;
  108.  
  109.                     min = (int32_t)minb;
  110.                     if(maxc && std::abs(max) < std::abs(maxc))
  111.                         max = maxc;
  112.  
  113.                     return true;
  114.                 }
  115.  
  116.                 case FORMULA_VALUE:
  117.                 {
  118.                     min = (int32_t)minb;
  119.                     max = (int32_t)maxb;
  120.                     return true;
  121.                 }
  122.  
  123.                 default:
  124.                     break;
  125.             }
  126.  
  127.             return false;
  128.         }
  129.     }
  130.  
  131.     if(formulaType != FORMULA_VALUE)
  132.         return false;
  133.  
  134.     min = (int32_t)mina;
  135.     max = (int32_t)maxa;
  136.     return true;
  137. }
  138.  
  139. void Combat::getCombatArea(const Position& centerPos, const Position& targetPos, const CombatArea* area, std::list<Tile*>& list)
  140. {
  141.     if(area)
  142.         area->getList(centerPos, targetPos, list);
  143.     else if(targetPos.z < MAP_MAX_LAYERS)
  144.     {
  145.         Tile* tile = g_game.getTile(targetPos);
  146.         if(!tile)
  147.         {
  148.             tile = new StaticTile(targetPos.x, targetPos.y, targetPos.z);
  149.             g_game.setTile(tile);
  150.         }
  151.  
  152.         list.push_back(tile);
  153.     }
  154. }
  155.  
  156. CombatType_t Combat::ConditionToDamageType(ConditionType_t type)
  157. {
  158.     switch(type)
  159.     {
  160.         case CONDITION_FIRE:
  161.             return COMBAT_FIREDAMAGE;
  162.  
  163.         case CONDITION_ENERGY:
  164.             return COMBAT_ENERGYDAMAGE;
  165.  
  166.         case CONDITION_POISON:
  167.             return COMBAT_EARTHDAMAGE;
  168.  
  169.         case CONDITION_FREEZING:
  170.             return COMBAT_ICEDAMAGE;
  171.  
  172.         case CONDITION_DAZZLED:
  173.             return COMBAT_HOLYDAMAGE;
  174.  
  175.         case CONDITION_CURSED:
  176.             return COMBAT_DEATHDAMAGE;
  177.  
  178.         case CONDITION_DROWN:
  179.             return COMBAT_DROWNDAMAGE;
  180.  
  181.         case CONDITION_BLEEDING:
  182.             return COMBAT_PHYSICALDAMAGE;
  183.  
  184.         default:
  185.             break;
  186.     }
  187.  
  188.     return COMBAT_NONE;
  189. }
  190.  
  191. ConditionType_t Combat::DamageToConditionType(CombatType_t type)
  192. {
  193.     switch(type)
  194.     {
  195.         case COMBAT_FIREDAMAGE:
  196.             return CONDITION_FIRE;
  197.  
  198.         case COMBAT_ENERGYDAMAGE:
  199.             return CONDITION_ENERGY;
  200.  
  201.         case COMBAT_EARTHDAMAGE:
  202.             return CONDITION_POISON;
  203.  
  204.         case COMBAT_ICEDAMAGE:
  205.             return CONDITION_FREEZING;
  206.  
  207.         case COMBAT_HOLYDAMAGE:
  208.             return CONDITION_DAZZLED;
  209.  
  210.         case COMBAT_DEATHDAMAGE:
  211.             return CONDITION_CURSED;
  212.  
  213.         case COMBAT_PHYSICALDAMAGE:
  214.             return CONDITION_BLEEDING;
  215.  
  216.         default:
  217.             break;
  218.     }
  219.  
  220.     return CONDITION_NONE;
  221. }
  222.  
  223. ReturnValue Combat::canDoCombat(const Creature* caster, const Tile* tile, bool isAggressive, bool/* createItem*/)
  224. {
  225.     if(tile->hasProperty(BLOCKPROJECTILE) || tile->floorChange() || tile->getTeleportItem())
  226.         return RET_NOTENOUGHROOM;
  227.  
  228.     if(caster)
  229.     {
  230.         bool success = true;
  231.         CreatureEventList combatAreaEvents = const_cast<Creature*>(caster)->getCreatureEvents(CREATURE_EVENT_COMBAT_AREA);
  232.         for(CreatureEventList::iterator it = combatAreaEvents.begin(); it != combatAreaEvents.end(); ++it)
  233.         {
  234.             if(!(*it)->executeCombatArea(const_cast<Creature*>(caster), const_cast<Tile*>(tile), isAggressive) && success)
  235.                 success = false;
  236.         }
  237.  
  238.         if(!success)
  239.             return RET_NOTPOSSIBLE;
  240.  
  241.         if(caster->getPosition().z < tile->getPosition().z)
  242.             return RET_FIRSTGODOWNSTAIRS;
  243.  
  244.         if(caster->getPosition().z > tile->getPosition().z)
  245.             return RET_FIRSTGOUPSTAIRS;
  246.  
  247.         if(!isAggressive)
  248.             return RET_NOERROR;
  249.  
  250.         const Player* player = caster->getPlayer();
  251.         if(player && player->hasFlag(PlayerFlag_IgnoreProtectionZone))
  252.             return RET_NOERROR;
  253.     }
  254.  
  255.     return isAggressive && tile->hasFlag(TILESTATE_PROTECTIONZONE) ?
  256.         RET_ACTIONNOTPERMITTEDINPROTECTIONZONE : RET_NOERROR;
  257. }
  258.  
  259. ReturnValue Combat::canDoCombat(const Creature* attacker, const Creature* target, bool isAggressive)
  260. {
  261.     if(!attacker)
  262.         return RET_NOERROR;
  263.  
  264.     bool success = true;
  265.     CreatureEventList combatEvents = const_cast<Creature*>(attacker)->getCreatureEvents(CREATURE_EVENT_COMBAT);
  266.     for(CreatureEventList::iterator it = combatEvents.begin(); it != combatEvents.end(); ++it)
  267.     {
  268.         if(!(*it)->executeCombat(const_cast<Creature*>(attacker), const_cast<Creature*>(target), isAggressive) && success)
  269.             success = false;
  270.     }
  271.  
  272.     if(!success)
  273.         return RET_NOTPOSSIBLE;
  274.  
  275.     bool checkZones = false;
  276.     if(const Player* targetPlayer = target->getPlayer())
  277.     {
  278.         if(!targetPlayer->isAttackable())
  279.             return RET_YOUMAYNOTATTACKTHISPLAYER;
  280.  
  281.         const Player* attackerPlayer = NULL;
  282.         if((attackerPlayer = attacker->getPlayer()) || (attackerPlayer = attacker->getPlayerMaster()))
  283.         {
  284.             checkZones = true;
  285.             if((g_game.getWorldType() == WORLDTYPE_OPTIONAL && !Combat::isInPvpZone(attacker, target)
  286.                 && !attackerPlayer->isEnemy(targetPlayer, true)) || isProtected(const_cast<Player*>(attackerPlayer),
  287.                 const_cast<Player*>(targetPlayer)) || (g_config.getBool(ConfigManager::CANNOT_ATTACK_SAME_LOOKFEET)
  288.                 && attackerPlayer->getDefaultOutfit().lookFeet == targetPlayer->getDefaultOutfit().lookFeet)
  289.                 || !attackerPlayer->canSeeCreature(targetPlayer))
  290.                 return RET_YOUMAYNOTATTACKTHISPLAYER;
  291.         }
  292.     }
  293.     else if(target->getMonster())
  294.     {
  295.         if(attacker->getMonster())
  296.             return RET_YOUMAYNOTATTACKTHISCREATURE;
  297.  
  298.         if(!target->isAttackable())
  299.             return RET_YOUMAYNOTATTACKTHISCREATURE;
  300.  
  301.         const Player* attackerPlayer = NULL;
  302.         if((attackerPlayer = attacker->getPlayer()) || (attackerPlayer = attacker->getPlayerMaster()))
  303.         {
  304.             if(attackerPlayer->hasFlag(PlayerFlag_CannotAttackMonster))
  305.                 return RET_YOUMAYNOTATTACKTHISCREATURE;
  306.  
  307.             if(target->isPlayerSummon())
  308.             {
  309.                 checkZones = true;
  310.                 if(g_game.getWorldType() == WORLDTYPE_OPTIONAL && !Combat::isInPvpZone(attacker, target)
  311.                     && !attackerPlayer->isEnemy(target->getPlayerMaster(), true))
  312.                     return RET_YOUMAYNOTATTACKTHISCREATURE;
  313.             }
  314.         }
  315.     }
  316.     else if(target->getNpc() && !target->isAttackable())
  317.         return RET_YOUMAYNOTATTACKTHISCREATURE;
  318.  
  319.     return checkZones && (target->getTile()->hasFlag(TILESTATE_OPTIONALZONE) ||
  320.         (attacker->getTile()->hasFlag(TILESTATE_OPTIONALZONE)
  321.         && !target->getTile()->hasFlag(TILESTATE_OPTIONALZONE) &&
  322.         !target->getTile()->hasFlag(TILESTATE_PROTECTIONZONE))) ?
  323.         RET_ACTIONNOTPERMITTEDINANOPVPZONE : RET_NOERROR;
  324. }
  325.  
  326. ReturnValue Combat::canTargetCreature(const Player* player, const Creature* target)
  327. {
  328.     if(player == target)
  329.         return RET_YOUMAYNOTATTACKTHISPLAYER;
  330.  
  331.     Player* tmpPlayer = const_cast<Player*>(player);
  332.     bool deny = false;
  333.  
  334.     CreatureEventList targetEvents = tmpPlayer->getCreatureEvents(CREATURE_EVENT_TARGET);
  335.     for(CreatureEventList::iterator it = targetEvents.begin(); it != targetEvents.end(); ++it)
  336.     {
  337.         if(!(*it)->executeAction(tmpPlayer, const_cast<Creature*>(target)) && !deny)
  338.             deny = true;
  339.     }
  340.  
  341.     if(deny)
  342.         return RET_NEEDEXCHANGE;
  343.  
  344.     if(!player->hasFlag(PlayerFlag_IgnoreProtectionZone))
  345.     {
  346.         if(player->getZone() == ZONE_PROTECTION)
  347.             return RET_YOUMAYNOTATTACKAPERSONWHILEINPROTECTIONZONE;
  348.  
  349.         if(target->getZone() == ZONE_PROTECTION)
  350.             return RET_YOUMAYNOTATTACKAPERSONINPROTECTIONZONE;
  351.  
  352.         if(target->getPlayer() || target->isPlayerSummon())
  353.         {
  354.             if(player->getZone() == ZONE_OPTIONAL)
  355.                 return RET_ACTIONNOTPERMITTEDINANOPVPZONE;
  356.  
  357.             if(target->getZone() == ZONE_OPTIONAL)
  358.                 return RET_YOUMAYNOTATTACKAPERSONINPROTECTIONZONE;
  359.         }
  360.     }
  361.  
  362.     if(player->hasFlag(PlayerFlag_CannotUseCombat))
  363.         return target->getPlayer() ? RET_YOUMAYNOTATTACKTHISPLAYER : RET_YOUMAYNOTATTACKTHISCREATURE;
  364.  
  365.     if(target->getPlayer() && !Combat::isInPvpZone(player, target) && player->getSkullType(target->getPlayer()) == SKULL_NONE)
  366.     {
  367.         if(player->getSecureMode() == SECUREMODE_ON)
  368.             return RET_TURNSECUREMODETOATTACKUNMARKEDPLAYERS;
  369.  
  370.         if(player->getSkull() == SKULL_BLACK)
  371.             return RET_YOUMAYNOTATTACKTHISPLAYER;
  372.     }
  373.    
  374.     if(player->checkLoginDelay())
  375.         return RET_YOUMAYNOTATTACKIMMEDIATELYAFTERLOGGINGIN;
  376.    
  377.     return Combat::canDoCombat(player, target, true);
  378. }
  379.  
  380. bool Combat::isInPvpZone(const Creature* attacker, const Creature* target)
  381. {
  382.     return attacker->getZone() == ZONE_HARDCORE && target->getZone() == ZONE_HARDCORE;
  383. }
  384.  
  385. bool Combat::isProtected(Player* attacker, Player* target)
  386. {
  387.     if(attacker->hasFlag(PlayerFlag_CannotAttackPlayer))
  388.         return true;
  389.  
  390.     if(attacker->hasCustomFlag(PlayerCustomFlag_GamemasterPrivileges))
  391.         return false;
  392.  
  393.     if(attacker->getZone() == ZONE_HARDCORE && target->getZone() == ZONE_HARDCORE && g_config.getBool(ConfigManager::PVP_TILE_IGNORE_PROTECTION))
  394.         return false;
  395.  
  396.     return target->isProtected() || attacker->isProtected() || (attacker->checkLoginDelay() && !attacker->hasBeenAttacked(target->getID()));
  397. }
  398.  
  399. void Combat::setPlayerCombatValues(formulaType_t _type, double _mina, double _minb, double _maxa, double _maxb, double _minl, double _maxl, double _minm, double _maxm, int32_t _minc, int32_t _maxc)
  400. {
  401.     formulaType = _type; mina = _mina; minb = _minb; maxa = _maxa; maxb = _maxb;
  402.     minl = _minl; maxl = _maxl; minm = _minm; maxm = _maxm; minc = _minc; maxc = _maxc;
  403. }
  404.  
  405. bool Combat::setParam(CombatParam_t param, uint32_t value)
  406. {
  407.     switch(param)
  408.     {
  409.         case COMBATPARAM_COMBATTYPE:
  410.             params.combatType = (CombatType_t)value;
  411.             return true;
  412.  
  413.         case COMBATPARAM_EFFECT:
  414.             params.effects.impact = (MagicEffect_t)value;
  415.             return true;
  416.  
  417.         case COMBATPARAM_DISTANCEEFFECT:
  418.             params.effects.distance = (ShootEffect_t)value;
  419.             return true;
  420.  
  421.         case COMBATPARAM_BLOCKEDBYARMOR:
  422.             params.blockedByArmor = (value != 0);
  423.             return true;
  424.  
  425.         case COMBATPARAM_BLOCKEDBYSHIELD:
  426.             params.blockedByShield = (value != 0);
  427.             return true;
  428.  
  429.         case COMBATPARAM_TARGETCASTERORTOPMOST:
  430.             params.targetCasterOrTopMost = (value != 0);
  431.             return true;
  432.  
  433.         case COMBATPARAM_TARGETPLAYERSORSUMMONS:
  434.             params.targetPlayersOrSummons = (value != 0);
  435.             return true;
  436.  
  437.         case COMBATPARAM_DIFFERENTAREADAMAGE:
  438.             params.differentAreaDamage = (value != 0);
  439.             return true;
  440.  
  441.         case COMBATPARAM_CREATEITEM:
  442.             params.itemId = value;
  443.             return true;
  444.  
  445.         case COMBATPARAM_AGGRESSIVE:
  446.             params.isAggressive = (value != 0);
  447.             return true;
  448.  
  449.         case COMBATPARAM_DISPEL:
  450.             params.dispelType = (ConditionType_t)value;
  451.             return true;
  452.  
  453.         case COMBATPARAM_USECHARGES:
  454.             params.useCharges = (value != 0);
  455.             return true;
  456.  
  457.         case COMBATPARAM_HITEFFECT:
  458.             params.effects.hit = (MagicEffect_t)value;
  459.             return true;
  460.  
  461.         case COMBATPARAM_HITCOLOR:
  462.             params.effects.color = (Color_t)value;
  463.             return true;
  464.  
  465.         case COMBATPARAM_ELEMENTDAMAGE:
  466.             params.element.damage = value;
  467.             break;
  468.  
  469.         case COMBATPARAM_ELEMENTTYPE:
  470.             params.element.type = (CombatType_t)value;
  471.             break;
  472.  
  473.         default:
  474.             break;
  475.     }
  476.  
  477.     return false;
  478. }
  479.  
  480. bool Combat::setCallback(CallBackParam_t key)
  481. {
  482.     switch(key)
  483.     {
  484.         case CALLBACKPARAM_LEVELMAGICVALUE:
  485.         {
  486.             delete params.valueCallback;
  487.             params.valueCallback = new ValueCallback(FORMULA_LEVELMAGIC);
  488.             return true;
  489.         }
  490.  
  491.         case CALLBACKPARAM_SKILLVALUE:
  492.         {
  493.             delete params.valueCallback;
  494.             params.valueCallback = new ValueCallback(FORMULA_SKILL);
  495.             return true;
  496.         }
  497.  
  498.         case CALLBACKPARAM_TARGETTILECALLBACK:
  499.         {
  500.             delete params.tileCallback;
  501.             params.tileCallback = new TileCallback();
  502.             break;
  503.         }
  504.  
  505.         case CALLBACKPARAM_TARGETCREATURECALLBACK:
  506.         {
  507.             delete params.targetCallback;
  508.             params.targetCallback = new TargetCallback();
  509.             break;
  510.         }
  511.  
  512.         default:
  513.             std::clog << "Combat::setCallback - Unknown callback type: " << (uint32_t)key << std::endl;
  514.             break;
  515.     }
  516.  
  517.     return false;
  518. }
  519.  
  520. CallBack* Combat::getCallback(CallBackParam_t key)
  521. {
  522.     switch(key)
  523.     {
  524.         case CALLBACKPARAM_LEVELMAGICVALUE:
  525.         case CALLBACKPARAM_SKILLVALUE:
  526.             return params.valueCallback;
  527.  
  528.         case CALLBACKPARAM_TARGETTILECALLBACK:
  529.             return params.tileCallback;
  530.  
  531.         case CALLBACKPARAM_TARGETCREATURECALLBACK:
  532.             return params.targetCallback;
  533.  
  534.         default:
  535.             break;
  536.     }
  537.  
  538.     return NULL;
  539. }
  540.  
  541. bool Combat::CombatHealthFunc(Creature* caster, Creature* target, const CombatParams& params, void* data)
  542. {
  543.     int32_t change = 0;
  544.     if(Combat2Var* var = (Combat2Var*)data)
  545.     {
  546.         change = var->change;
  547.         if(!change)
  548.             change = random_range(var->minChange, var->maxChange, DISTRO_NORMAL);
  549.     }
  550.  
  551.     if(g_game.combatBlockHit(params.combatType, caster, target, change, params.blockedByShield, params.blockedByArmor, params.itemId != 0))
  552.         return false;
  553.  
  554.     CombatParams _params = params;
  555.     if(_params.element.damage && _params.element.type != COMBAT_NONE)
  556.         g_game.combatBlockHit(_params.element.type, caster, target, _params.element.damage, params.blockedByShield, params.blockedByArmor, params.itemId != 0, true);
  557.  
  558.     if(caster && caster->getPlayer() && target->getPlayer() && target->getSkull() != SKULL_BLACK)
  559.     {
  560.         _params.element.damage /= 2;
  561.         if(change < 0)
  562.             change /= 2;
  563.     }
  564.  
  565.     if(!g_game.combatChangeHealth(_params, caster, target, change, false))
  566.         return false;
  567.  
  568.     CombatConditionFunc(caster, target, params, NULL);
  569.     CombatDispelFunc(caster, target, params, NULL);
  570.     return true;
  571. }
  572.  
  573. bool Combat::CombatManaFunc(Creature* caster, Creature* target, const CombatParams& params, void* data)
  574. {
  575.     int32_t change = 0;
  576.     if(Combat2Var* var = (Combat2Var*)data)
  577.     {
  578.         change = var->change;
  579.         if(!change)
  580.             change = random_range(var->minChange, var->maxChange, DISTRO_NORMAL);
  581.     }
  582.  
  583.     if(g_game.combatBlockHit(COMBAT_MANADRAIN, caster, target, change, false, false, params.itemId != 0))
  584.         return false;
  585.  
  586.     if(change < 0 && caster && caster->getPlayer() && target->getPlayer() && target->getSkull() != SKULL_BLACK)
  587.         change /= 2;
  588.  
  589.     if(!g_game.combatChangeMana(caster, target, change))
  590.         return false;
  591.  
  592.     CombatConditionFunc(caster, target, params, NULL);
  593.     CombatDispelFunc(caster, target, params, NULL);
  594.     return true;
  595. }
  596.  
  597. bool Combat::CombatConditionFunc(Creature* caster, Creature* target, const CombatParams& params, void*)
  598. {
  599.     if(params.conditionList.empty())
  600.         return false;
  601.  
  602.     bool result = true;
  603.     for(std::list<const Condition*>::const_iterator it = params.conditionList.begin(); it != params.conditionList.end(); ++it)
  604.     {
  605.         if(caster != target && target->isImmune((*it)->getType()))
  606.             continue;
  607.  
  608.         Condition* tmp = (*it)->clone();
  609.         if(caster)
  610.         {
  611.             tmp->setParam(CONDITIONPARAM_OWNER, caster->getID());
  612.             if(params.isAggressive)
  613.                 caster->onTargetDrain(target, 0);
  614.             else
  615.                 caster->onTargetGain(target, 0);
  616.         }
  617.  
  618.         //TODO: infight condition until all aggressive conditions has ended [?]
  619.         if(!target->addCombatCondition(tmp) && result)
  620.             result = false;
  621.     }
  622.  
  623.     return result;
  624. }
  625.  
  626. bool Combat::CombatDispelFunc(Creature* caster, Creature* target, const CombatParams& params, void*)
  627. {
  628.     if(!target->hasCondition(params.dispelType, -1, false))
  629.         return false;
  630.  
  631.     if(params.dispelType == CONDITION_INVISIBLE)
  632.     {
  633.         if(Player* player = target->getPlayer())
  634.         {
  635.             Item* item = player->getEquippedItem(SLOT_RING);
  636.             if(item && item->getID() == ITEM_STEALTH_RING && (g_game.getWorldType() == WORLDTYPE_HARDCORE
  637.                 || player->getTile()->hasFlag(TILESTATE_HARDCOREZONE)) && random_range(1, 100) <= 10)
  638.                 g_game.internalRemoveItem(NULL, item);
  639.         }
  640.     }
  641.  
  642.     target->removeCondition(caster, params.dispelType);
  643.     return true;
  644. }
  645.  
  646. bool Combat::CombatNullFunc(Creature* caster, Creature* target, const CombatParams& params, void*)
  647. {
  648.     CombatConditionFunc(caster, target, params, NULL);
  649.     CombatDispelFunc(caster, target, params, NULL);
  650.     return true;
  651. }
  652.  
  653. void Combat::combatTileEffects(const SpectatorVec& list, Creature* caster, Tile* tile, const CombatParams& params)
  654. {
  655.     if(params.itemId)
  656.     {
  657.         Player* player = NULL;
  658.         if(caster)
  659.         {
  660.             if(caster->getPlayer())
  661.                 player = caster->getPlayer();
  662.             else if(caster->isPlayerSummon())
  663.                 player = caster->getPlayerMaster();
  664.         }
  665.  
  666.         uint32_t itemId = params.itemId;
  667.         if(player)
  668.         {
  669.             bool pzLock = false;
  670.             if((g_game.getWorldType() == WORLDTYPE_OPTIONAL && !tile->hasFlag(
  671.                 TILESTATE_HARDCOREZONE)) || tile->hasFlag(TILESTATE_OPTIONALZONE))
  672.             {
  673.                 switch(itemId)
  674.                 {
  675.                     case ITEM_FIREFIELD:
  676.                         itemId = ITEM_FIREFIELD_SAFE;
  677.                         break;
  678.                     case ITEM_POISONFIELD:
  679.                         itemId = ITEM_POISONFIELD_SAFE;
  680.                         break;
  681.                     case ITEM_ENERGYFIELD:
  682.                         itemId = ITEM_ENERGYFIELD_SAFE;
  683.                         break;
  684.                     case ITEM_MAGICWALL:
  685.                         itemId = ITEM_MAGICWALL_SAFE;
  686.                         break;
  687.                     case ITEM_WILDGROWTH:
  688.                         itemId = ITEM_WILDGROWTH_SAFE;
  689.                         break;
  690.                     default:
  691.                         break;
  692.                 }
  693.             }
  694.             else if(params.isAggressive && !Item::items[itemId].blockPathFind)
  695.                 pzLock = true;
  696.  
  697.             player->addInFightTicks(pzLock);
  698.         }
  699.  
  700.         if(Item* item = Item::CreateItem(itemId))
  701.         {
  702.             if(caster)
  703.                 item->setOwner(caster->getID());
  704.  
  705.             if(g_game.internalAddItem(caster, tile, item) == RET_NOERROR)
  706.                 g_game.startDecay(item);
  707.             else
  708.                 delete item;
  709.         }
  710.     }
  711.  
  712.     if(params.tileCallback)
  713.         params.tileCallback->onTileCombat(caster, tile);
  714.  
  715.     if(params.effects.impact != MAGIC_EFFECT_NONE && (!caster || !caster->isGhost()
  716.         || g_config.getBool(ConfigManager::GHOST_SPELL_EFFECTS)))
  717.         g_game.addMagicEffect(list, tile->getPosition(), params.effects.impact);
  718. }
  719.  
  720. void Combat::postCombatEffects(Creature* caster, const Position& pos, const CombatParams& params)
  721. {
  722.     if(caster && params.effects.distance != SHOOT_EFFECT_NONE)
  723.         addDistanceEffect(caster, caster->getPosition(), pos, params.effects.distance);
  724. }
  725.  
  726. void Combat::addDistanceEffect(Creature* caster, const Position& fromPos, const Position& toPos, ShootEffect_t effect)
  727. {
  728.     if(effect == SHOOT_EFFECT_WEAPONTYPE)
  729.     {
  730.         switch(caster->getWeaponType())
  731.         {
  732.             case WEAPON_AXE:
  733.                 effect = SHOOT_EFFECT_WHIRLWINDAXE;
  734.                 break;
  735.  
  736.             case WEAPON_SWORD:
  737.                 effect = SHOOT_EFFECT_WHIRLWINDSWORD;
  738.                 break;
  739.  
  740.             case WEAPON_CLUB:
  741.                 effect = SHOOT_EFFECT_WHIRLWINDCLUB;
  742.                 break;
  743.  
  744.             case WEAPON_FIST:
  745.                 effect = SHOOT_EFFECT_LARGEROCK;
  746.                 break;
  747.  
  748.             default:
  749.                 effect = SHOOT_EFFECT_NONE;
  750.                 break;
  751.         }
  752.     }
  753.  
  754.     if(caster && effect != SHOOT_EFFECT_NONE)
  755.         g_game.addDistanceEffect(fromPos, toPos, effect);
  756. }
  757.  
  758. void Combat::CombatFunc(Creature* caster, const Position& pos, const CombatArea* area,
  759.     const CombatParams& params, COMBATFUNC func, void* data)
  760. {
  761.     std::list<Tile*> tileList;
  762.     if(caster)
  763.         getCombatArea(caster->getPosition(), pos, area, tileList);
  764.     else
  765.         getCombatArea(pos, pos, area, tileList);
  766.  
  767.     Combat2Var* var = (Combat2Var*)data;
  768.     if(var && !params.differentAreaDamage)
  769.         var->change = random_range(var->minChange, var->maxChange, DISTRO_NORMAL);
  770.  
  771.     uint32_t maxX = 0, maxY = 0, diff;
  772.     //calculate the max viewable range
  773.     for(std::list<Tile*>::iterator it = tileList.begin(); it != tileList.end(); ++it)
  774.     {
  775.         diff = std::abs((*it)->getPosition().x - pos.x);
  776.         if(diff > maxX)
  777.             maxX = diff;
  778.  
  779.         diff = std::abs((*it)->getPosition().y - pos.y);
  780.         if(diff > maxY)
  781.             maxY = diff;
  782.     }
  783.  
  784.     SpectatorVec list;
  785.     g_game.getSpectators(list, pos, false, true, maxX + Map::maxViewportX, maxX + Map::maxViewportX,
  786.         maxY + Map::maxViewportY, maxY + Map::maxViewportY);
  787.  
  788.     Tile* tile = NULL;
  789.     for(std::list<Tile*>::iterator it = tileList.begin(); it != tileList.end(); ++it)
  790.     {
  791.         if(!(tile = (*it)) || canDoCombat(caster, (*it), params.isAggressive, params.itemId != 0) != RET_NOERROR)
  792.             continue;
  793.  
  794.         bool skip = true;
  795.         if(CreatureVector* creatures = tile->getCreatures())
  796.         {
  797.             for(CreatureVector::iterator cit = creatures->begin(), cend = creatures->end(); skip && cit != cend; ++cit)
  798.             {
  799.                 if(params.targetPlayersOrSummons && !(*cit)->getPlayer() && !(*cit)->isPlayerSummon())
  800.                     continue;
  801.  
  802.                 if(params.targetCasterOrTopMost)
  803.                 {
  804.                     if(caster && caster->getTile() == tile)
  805.                     {
  806.                         if((*cit) == caster)
  807.                             skip = false;
  808.                     }
  809.                     else if((*cit) == tile->getTopCreature())
  810.                         skip = false;
  811.  
  812.                     if(skip)
  813.                         continue;
  814.                 }
  815.  
  816.                 if(!params.isAggressive || (caster != (*cit) && Combat::canDoCombat(caster, (*cit), true) == RET_NOERROR))
  817.                 {
  818.                     func(caster, (*cit), params, (void*)var);
  819.                     if(params.targetCallback)
  820.                         params.targetCallback->onTargetCombat(caster, (*cit));
  821.                 }
  822.             }
  823.         }
  824.  
  825.         combatTileEffects(list, caster, tile, params);
  826.     }
  827.  
  828.     postCombatEffects(caster, pos, params);
  829. }
  830.  
  831. void Combat::doCombat(Creature* caster, Creature* target) const
  832. {
  833.     //target combat callback function
  834.     if(params.combatType != COMBAT_NONE)
  835.     {
  836.         if(params.isAggressive && (caster == target || Combat::canDoCombat(caster, target, true) != RET_NOERROR))
  837.             return;
  838.  
  839.         int32_t minChange = 0, maxChange = 0;
  840.         CombatParams _params = params;
  841.  
  842.         getMinMaxValues(caster, target, _params, minChange, maxChange);
  843.         if(params.combatType != COMBAT_MANADRAIN)
  844.             doCombatHealth(caster, target, minChange, maxChange, _params, false);
  845.         else
  846.             doCombatMana(caster, target, minChange, maxChange, _params, false);
  847.     }
  848.     else
  849.         doCombatDefault(caster, target, params);
  850. }
  851.  
  852. void Combat::doCombat(Creature* caster, const Position& pos) const
  853. {
  854.     //area combat callback function
  855.     if(params.combatType != COMBAT_NONE)
  856.     {
  857.         int32_t minChange = 0, maxChange = 0;
  858.         CombatParams _params = params;
  859.  
  860.         getMinMaxValues(caster, NULL, _params, minChange, maxChange);
  861.         if(params.combatType != COMBAT_MANADRAIN)
  862.             doCombatHealth(caster, pos, area, minChange, maxChange, _params);
  863.         else
  864.             doCombatMana(caster, pos, area, minChange, maxChange, _params);
  865.     }
  866.     else
  867.         CombatFunc(caster, pos, area, params, CombatNullFunc, NULL);
  868. }
  869.  
  870. void Combat::doCombatHealth(Creature* caster, Creature* target, int32_t minChange, int32_t maxChange, const CombatParams& params, bool check/* = true*/)
  871. {
  872.     if(check && params.isAggressive && (caster == target || Combat::canDoCombat(caster, target, true) != RET_NOERROR))
  873.         return;
  874.  
  875.     Combat2Var var;
  876.     var.minChange = minChange;
  877.     var.maxChange = maxChange;
  878.  
  879.     CombatHealthFunc(caster, target, params, (void*)&var);
  880.     if(params.targetCallback)
  881.         params.targetCallback->onTargetCombat(caster, target);
  882.  
  883.     if(params.effects.impact != MAGIC_EFFECT_NONE && (!caster || !caster->isGhost()
  884.         || g_config.getBool(ConfigManager::GHOST_SPELL_EFFECTS)))
  885.         g_game.addMagicEffect(target->getPosition(), params.effects.impact);
  886.  
  887.     if(caster && params.effects.distance != SHOOT_EFFECT_NONE)
  888.         addDistanceEffect(caster, caster->getPosition(), target->getPosition(), params.effects.distance);
  889. }
  890.  
  891. void Combat::doCombatHealth(Creature* caster, const Position& pos, const CombatArea* area,
  892.     int32_t minChange, int32_t maxChange, const CombatParams& params)
  893. {
  894.     Combat2Var var;
  895.     var.minChange = minChange;
  896.     var.maxChange = maxChange;
  897.     CombatFunc(caster, pos, area, params, CombatHealthFunc, (void*)&var);
  898. }
  899.  
  900. void Combat::doCombatMana(Creature* caster, Creature* target, int32_t minChange, int32_t maxChange, const CombatParams& params, bool check/* = true*/)
  901. {
  902.     if(check && params.isAggressive && (caster == target || Combat::canDoCombat(caster, target, true) != RET_NOERROR))
  903.         return;
  904.  
  905.     Combat2Var var;
  906.     var.minChange = minChange;
  907.     var.maxChange = maxChange;
  908.  
  909.     CombatManaFunc(caster, target, params, (void*)&var);
  910.     if(params.targetCallback)
  911.         params.targetCallback->onTargetCombat(caster, target);
  912.  
  913.     if(params.effects.impact != MAGIC_EFFECT_NONE && (!caster || !caster->isGhost()
  914.         || g_config.getBool(ConfigManager::GHOST_SPELL_EFFECTS)))
  915.         g_game.addMagicEffect(target->getPosition(), params.effects.impact);
  916.  
  917.     if(caster && params.effects.distance != SHOOT_EFFECT_NONE)
  918.         addDistanceEffect(caster, caster->getPosition(), target->getPosition(), params.effects.distance);
  919. }
  920.  
  921. void Combat::doCombatMana(Creature* caster, const Position& pos, const CombatArea* area,
  922.     int32_t minChange, int32_t maxChange, const CombatParams& params)
  923. {
  924.     Combat2Var var;
  925.     var.minChange = minChange;
  926.     var.maxChange = maxChange;
  927.     CombatFunc(caster, pos, area, params, CombatManaFunc, (void*)&var);
  928. }
  929.  
  930. void Combat::doCombatCondition(Creature* caster, const Position& pos, const CombatArea* area,
  931.     const CombatParams& params)
  932. {
  933.     CombatFunc(caster, pos, area, params, CombatConditionFunc, NULL);
  934. }
  935.  
  936. void Combat::doCombatCondition(Creature* caster, Creature* target, const CombatParams& params, bool check/* = true*/)
  937. {
  938.     if(check && params.isAggressive && (caster == target || Combat::canDoCombat(caster, target, true) != RET_NOERROR))
  939.         return;
  940.  
  941.     CombatConditionFunc(caster, target, params, NULL);
  942.     if(params.targetCallback)
  943.         params.targetCallback->onTargetCombat(caster, target);
  944.  
  945.     if(params.effects.impact != MAGIC_EFFECT_NONE && (!caster || !caster->isGhost()
  946.         || g_config.getBool(ConfigManager::GHOST_SPELL_EFFECTS)))
  947.         g_game.addMagicEffect(target->getPosition(), params.effects.impact);
  948.  
  949.     if(caster && params.effects.distance != SHOOT_EFFECT_NONE)
  950.         addDistanceEffect(caster, caster->getPosition(), target->getPosition(), params.effects.distance);
  951. }
  952.  
  953. void Combat::doCombatDispel(Creature* caster, const Position& pos, const CombatArea* area,
  954.     const CombatParams& params)
  955. {
  956.     CombatFunc(caster, pos, area, params, CombatDispelFunc, NULL);
  957. }
  958.  
  959. void Combat::doCombatDispel(Creature* caster, Creature* target, const CombatParams& params, bool check/* = true*/)
  960. {
  961.     if(check && params.isAggressive && (caster == target || Combat::canDoCombat(caster, target, true) != RET_NOERROR))
  962.         return;
  963.  
  964.     CombatDispelFunc(caster, target, params, NULL);
  965.     if(params.targetCallback)
  966.         params.targetCallback->onTargetCombat(caster, target);
  967.  
  968.     if(params.effects.impact != MAGIC_EFFECT_NONE && (!caster || !caster->isGhost()
  969.         || g_config.getBool(ConfigManager::GHOST_SPELL_EFFECTS)))
  970.         g_game.addMagicEffect(target->getPosition(), params.effects.impact);
  971.  
  972.     if(caster && params.effects.distance != SHOOT_EFFECT_NONE)
  973.         addDistanceEffect(caster, caster->getPosition(), target->getPosition(), params.effects.distance);
  974. }
  975.  
  976. void Combat::doCombatDefault(Creature* caster, Creature* target, const CombatParams& params)
  977. {
  978.     if(params.isAggressive && (caster == target || Combat::canDoCombat(caster, target, true) != RET_NOERROR))
  979.         return;
  980.  
  981.     const SpectatorVec& list = g_game.getSpectators(target->getTile()->getPosition());
  982.     CombatNullFunc(caster, target, params, NULL);
  983.  
  984.     combatTileEffects(list, caster, target->getTile(), params);
  985.     if(params.targetCallback)
  986.         params.targetCallback->onTargetCombat(caster, target);
  987.  
  988.     if(params.effects.impact != MAGIC_EFFECT_NONE && (!caster || !caster->isGhost()
  989.         || g_config.getBool(ConfigManager::GHOST_SPELL_EFFECTS)))
  990.         g_game.addMagicEffect(target->getPosition(), params.effects.impact);
  991.  
  992.     if(caster && params.effects.distance != SHOOT_EFFECT_NONE)
  993.         addDistanceEffect(caster, caster->getPosition(), target->getPosition(), params.effects.distance);
  994. }
  995.  
  996. //**********************************************************
  997.  
  998. void ValueCallback::getMinMaxValues(Player* player, CombatParams& params, int32_t& min, int32_t& max) const
  999. {
  1000.     //"onGetPlayerMinMaxValues"(cid, ...)
  1001.     if(!m_interface->reserveEnv())
  1002.     {
  1003.         std::clog << "[Error - ValueCallback::getMinMaxValues] Callstack overflow." << std::endl;
  1004.         return;
  1005.     }
  1006.  
  1007.     ScriptEnviroment* env = m_interface->getEnv();
  1008.     if(!env->setCallbackId(m_scriptId, m_interface))
  1009.         return;
  1010.  
  1011.     m_interface->pushFunction(m_scriptId);
  1012.     lua_State* L = m_interface->getState();
  1013.     lua_pushnumber(L, env->addThing(player));
  1014.  
  1015.     int32_t parameters = 1;
  1016.     switch(type)
  1017.     {
  1018.         case FORMULA_LEVELMAGIC:
  1019.         {
  1020.             //"onGetPlayerMinMaxValues"(cid, level, magLevel)
  1021.             lua_pushnumber(L, player->getLevel());
  1022.             lua_pushnumber(L, player->getMagicLevel());
  1023.  
  1024.             parameters += 2;
  1025.             break;
  1026.         }
  1027.  
  1028.         case FORMULA_SKILL:
  1029.         {
  1030.             //"onGetPlayerMinMaxValues"(cid, level, skill, attack, element, factor)
  1031.             lua_pushnumber(L, player->getLevel());
  1032.             if(Item* weapon = player->getWeapon(false))
  1033.             {
  1034.                 lua_pushnumber(L, player->getWeaponSkill(weapon));
  1035.                 if(params.useCharges && weapon->hasCharges() && g_config.getBool(ConfigManager::REMOVE_WEAPON_CHARGES))
  1036.                     g_game.transformItem(weapon, weapon->getID(), std::max(0, weapon->getCharges() - 1));
  1037.  
  1038.                 uint32_t attack = weapon->getAttack() + weapon->getExtraAttack();
  1039.                 if(weapon->getWeaponType() == WEAPON_AMMO)
  1040.                 {
  1041.                     if(Item* bow = player->getWeapon(true))
  1042.                         attack += bow->getAttack() + bow->getExtraAttack();
  1043.                 }
  1044.  
  1045.                 if(weapon->getElementType() != COMBAT_NONE)
  1046.                 {
  1047.                     attack -= weapon->getElementDamage();
  1048.                     lua_pushnumber(L, attack);
  1049.  
  1050.                     lua_pushnumber(L, weapon->getElementDamage());
  1051.                     params.element.type = weapon->getElementType();
  1052.                 }
  1053.                 else
  1054.                 {
  1055.                     lua_pushnumber(L, attack);
  1056.                     lua_pushnumber(L, 0);
  1057.                 }
  1058.             }
  1059.             else
  1060.             {
  1061.                 lua_pushnumber(L, player->getSkill(SKILL_FIST, SKILL_LEVEL));
  1062.                 lua_pushnumber(L, g_config.getNumber(ConfigManager::FIST_BASE_ATTACK));
  1063.                 lua_pushnumber(L, 0);
  1064.             }
  1065.  
  1066.             lua_pushnumber(L, player->getAttackFactor());
  1067.             parameters += 5;
  1068.             break;
  1069.         }
  1070.  
  1071.         default:
  1072.         {
  1073.             std::clog << "[Warning - ValueCallback::getMinMaxValues] Unknown callback type" << std::endl;
  1074.             return;
  1075.         }
  1076.     }
  1077.  
  1078.     int32_t args = lua_gettop(L);
  1079.     if(!lua_pcall(L, parameters, 3, 0))
  1080.     {
  1081.         params.element.damage = LuaInterface::popNumber(L);
  1082.         max = LuaInterface::popNumber(L);
  1083.         min = LuaInterface::popNumber(L);
  1084.         player->increaseCombatValues(min, max, params.useCharges, type != FORMULA_SKILL);
  1085.     }
  1086.     else
  1087.         LuaInterface::error(NULL, std::string(LuaInterface::popString(L)));
  1088.  
  1089.     if((lua_gettop(L) + parameters + 1) != args)
  1090.         LuaInterface::error(__FUNCTION__, "Stack size changed!");
  1091.  
  1092.     env->resetCallback();
  1093.     m_interface->releaseEnv();
  1094. }
  1095.  
  1096. //**********************************************************
  1097.  
  1098. void TileCallback::onTileCombat(Creature* creature, Tile* tile) const
  1099. {
  1100.     //"onTileCombat"(cid, pos)
  1101.     if(m_interface->reserveEnv())
  1102.     {
  1103.         ScriptEnviroment* env = m_interface->getEnv();
  1104.         if(!env->setCallbackId(m_scriptId, m_interface))
  1105.             return;
  1106.  
  1107.         m_interface->pushFunction(m_scriptId);
  1108.         lua_State* L = m_interface->getState();
  1109.  
  1110.         lua_pushnumber(L, creature ? env->addThing(creature) : 0);
  1111.         m_interface->pushPosition(L, tile->getPosition(), 0);
  1112.  
  1113.         m_interface->callFunction(2);
  1114.         env->resetCallback();
  1115.         m_interface->releaseEnv();
  1116.     }
  1117.     else
  1118.         std::clog << "[Error - TileCallback::onTileCombat] Call stack overflow." << std::endl;
  1119. }
  1120.  
  1121. //**********************************************************
  1122.  
  1123. void TargetCallback::onTargetCombat(Creature* creature, Creature* target) const
  1124. {
  1125.     //"onTargetCombat"(cid, target)
  1126.     if(m_interface->reserveEnv())
  1127.     {
  1128.         ScriptEnviroment* env = m_interface->getEnv();
  1129.         if(!env->setCallbackId(m_scriptId, m_interface))
  1130.             return;
  1131.  
  1132.         uint32_t cid = 0;
  1133.         if(creature)
  1134.             cid = env->addThing(creature);
  1135.  
  1136.         m_interface->pushFunction(m_scriptId);
  1137.         lua_State* L = m_interface->getState();
  1138.  
  1139.         lua_pushnumber(L, cid);
  1140.         lua_pushnumber(L, env->addThing(target));
  1141.  
  1142.         int32_t size = lua_gettop(L);
  1143.         if(lua_pcall(L, 2, 0 /*nReturnValues*/, 0) != 0)
  1144.             LuaInterface::error(NULL, std::string(LuaInterface::popString(L)));
  1145.  
  1146.         if((lua_gettop(L) + 2 /*nParams*/ + 1) != size)
  1147.             LuaInterface::error(__FUNCTION__, "Stack size changed!");
  1148.  
  1149.         env->resetCallback();
  1150.         m_interface->releaseEnv();
  1151.     }
  1152.     else
  1153.     {
  1154.         std::clog << "[Error - TargetCallback::onTargetCombat] Call stack overflow." << std::endl;
  1155.         return;
  1156.     }
  1157. }
  1158.  
  1159. //**********************************************************
  1160.  
  1161. void CombatArea::clear()
  1162. {
  1163.     for(CombatAreas::iterator it = areas.begin(); it != areas.end(); ++it)
  1164.         delete it->second;
  1165.  
  1166.     areas.clear();
  1167. }
  1168.  
  1169. CombatArea::CombatArea(const CombatArea& rhs)
  1170. {
  1171.     hasExtArea = rhs.hasExtArea;
  1172.     for(CombatAreas::const_iterator it = rhs.areas.begin(); it != rhs.areas.end(); ++it)
  1173.         areas[it->first] = new MatrixArea(*it->second);
  1174. }
  1175.  
  1176. bool CombatArea::getList(const Position& centerPos, const Position& targetPos, std::list<Tile*>& list) const
  1177. {
  1178.     Tile* tile = g_game.getTile(targetPos);
  1179.     const MatrixArea* area = getArea(centerPos, targetPos);
  1180.     if(!area)
  1181.         return false;
  1182.  
  1183.     uint16_t tmpX = targetPos.x, tmpY = targetPos.y, centerY = 0, centerX = 0;
  1184.     size_t cols = area->getCols(), rows = area->getRows();
  1185.     area->getCenter(centerY, centerX);
  1186.  
  1187.     tmpX -= centerX;
  1188.     tmpY -= centerY;
  1189.     for(size_t y = 0; y < rows; ++y)
  1190.     {
  1191.         for(size_t x = 0; x < cols; ++x)
  1192.         {
  1193.             if(area->getValue(y, x) != 0)
  1194.             {
  1195.                 if(targetPos.z < MAP_MAX_LAYERS && g_game.isSightClear(targetPos, Position(tmpX, tmpY, targetPos.z), true))
  1196.                 {
  1197.                     if(!(tile = g_game.getTile(tmpX, tmpY, targetPos.z)))
  1198.                     {
  1199.                         tile = new StaticTile(tmpX, tmpY, targetPos.z);
  1200.                         g_game.setTile(tile);
  1201.                     }
  1202.  
  1203.                     list.push_back(tile);
  1204.                 }
  1205.             }
  1206.  
  1207.             tmpX++;
  1208.         }
  1209.  
  1210.         tmpX -= cols;
  1211.         tmpY++;
  1212.     }
  1213.  
  1214.     return true;
  1215. }
  1216.  
  1217. void CombatArea::copyArea(const MatrixArea* input, MatrixArea* output, MatrixOperation_t op) const
  1218. {
  1219.     uint16_t centerY, centerX;
  1220.     input->getCenter(centerY, centerX);
  1221.     if(op == MATRIXOPERATION_COPY)
  1222.     {
  1223.         for(uint32_t y = 0; y < input->getRows(); ++y)
  1224.         {
  1225.             for(uint32_t x = 0; x < input->getCols(); ++x)
  1226.                 (*output)[y][x] = (*input)[y][x];
  1227.         }
  1228.  
  1229.         output->setCenter(centerY, centerX);
  1230.     }
  1231.     else if(op == MATRIXOPERATION_MIRROR)
  1232.     {
  1233.         for(uint32_t y = 0; y < input->getRows(); ++y)
  1234.         {
  1235.             int32_t rx = 0;
  1236.             for(int32_t x = input->getCols() - 1; x >= 0; --x)
  1237.                 (*output)[y][rx++] = (*input)[y][x];
  1238.         }
  1239.  
  1240.         output->setCenter(centerY, (input->getRows() - 1) - centerX);
  1241.     }
  1242.     else if(op == MATRIXOPERATION_FLIP)
  1243.     {
  1244.         for(uint32_t x = 0; x < input->getCols(); ++x)
  1245.         {
  1246.             int32_t ry = 0;
  1247.             for(int32_t y = input->getRows() - 1; y >= 0; --y)
  1248.                 (*output)[ry++][x] = (*input)[y][x];
  1249.         }
  1250.  
  1251.         output->setCenter((input->getCols() - 1) - centerY, centerX);
  1252.     }
  1253.     else //rotation
  1254.     {
  1255.         uint16_t centerX, centerY;
  1256.         input->getCenter(centerY, centerX);
  1257.  
  1258.         int32_t rotateCenterX = (output->getCols() / 2) - 1, rotateCenterY = (output->getRows() / 2) - 1, angle = 0;
  1259.         switch(op)
  1260.         {
  1261.             case MATRIXOPERATION_ROTATE90:
  1262.                 angle = 90;
  1263.                 break;
  1264.  
  1265.             case MATRIXOPERATION_ROTATE180:
  1266.                 angle = 180;
  1267.                 break;
  1268.  
  1269.             case MATRIXOPERATION_ROTATE270:
  1270.                 angle = 270;
  1271.                 break;
  1272.  
  1273.             default:
  1274.                 angle = 0;
  1275.                 break;
  1276.         }
  1277.  
  1278.         double _angle = 3.1416 * angle / 180.0;
  1279.         float a = std::cos(_angle), b = std::sin(_angle);
  1280.         for(int32_t x = 0; x < (int32_t)input->getCols(); ++x)
  1281.         {
  1282.             for(int32_t y = 0; y < (int32_t)input->getRows(); ++y)
  1283.             {
  1284.                 //calculate new coordinates using rotation center
  1285.                 int32_t newX = x - centerX, newY = y - centerY,
  1286.                     rotatedX = round(newX * a + newY * -b),
  1287.                     rotatedY = round(newX * b + newY * a);
  1288.                 //write in the output matrix using rotated coordinates
  1289.                 (*output)[rotatedY + rotateCenterY][rotatedX + rotateCenterX] = (*input)[y][x];
  1290.             }
  1291.         }
  1292.  
  1293.         output->setCenter(rotateCenterY, rotateCenterX);
  1294.     }
  1295. }
  1296.  
  1297. MatrixArea* CombatArea::createArea(const std::list<uint32_t>& list, uint32_t rows)
  1298. {
  1299.     uint32_t cols = list.size() / rows;
  1300.     MatrixArea* area = new MatrixArea(rows, cols);
  1301.  
  1302.     uint16_t x = 0, y = 0;
  1303.     for(std::list<uint32_t>::const_iterator it = list.begin(); it != list.end(); ++it)
  1304.     {
  1305.         if(*it == 1 || *it == 3)
  1306.             area->setValue(y, x, true);
  1307.  
  1308.         if(*it == 2 || *it == 3)
  1309.             area->setCenter(y, x);
  1310.  
  1311.         ++x;
  1312.         if(cols != x)
  1313.             continue;
  1314.  
  1315.         x = 0;
  1316.         ++y;
  1317.     }
  1318.  
  1319.     return area;
  1320. }
  1321.  
  1322. void CombatArea::setupArea(const std::list<uint32_t>& list, uint32_t rows)
  1323. {
  1324.     //NORTH
  1325.     MatrixArea* area = createArea(list, rows);
  1326.     areas[NORTH] = area;
  1327.     uint32_t maxOutput = std::max(area->getCols(), area->getRows()) << 1;
  1328.  
  1329.     //SOUTH
  1330.     MatrixArea* southArea = new MatrixArea(maxOutput, maxOutput);
  1331.     copyArea(area, southArea, MATRIXOPERATION_ROTATE180);
  1332.     areas[SOUTH] = southArea;
  1333.  
  1334.     //EAST
  1335.     MatrixArea* eastArea = new MatrixArea(maxOutput, maxOutput);
  1336.     copyArea(area, eastArea, MATRIXOPERATION_ROTATE90);
  1337.     areas[EAST] = eastArea;
  1338.  
  1339.     //WEST
  1340.     MatrixArea* westArea = new MatrixArea(maxOutput, maxOutput);
  1341.     copyArea(area, westArea, MATRIXOPERATION_ROTATE270);
  1342.     areas[WEST] = westArea;
  1343. }
  1344.  
  1345. void CombatArea::setupArea(int32_t length, int32_t spread)
  1346. {
  1347.     std::list<uint32_t> list;
  1348.     uint32_t rows = length;
  1349.  
  1350.     int32_t cols = 1;
  1351.     if(spread != 0)
  1352.         cols = (((length - length % spread) / spread) << 1) + 1;
  1353.  
  1354.     int32_t colSpread = cols;
  1355.     for(uint32_t y = 1; y <= rows; ++y)
  1356.     {
  1357.         int32_t mincol = cols - colSpread + 1, maxcol = cols - (cols - colSpread);
  1358.         for(int32_t x = 1; x <= cols; ++x)
  1359.         {
  1360.             if(y == rows && x == ((cols - cols % 2) / 2) + 1)
  1361.                 list.push_back(3);
  1362.             else if(x >= mincol && x <= maxcol)
  1363.                 list.push_back(1);
  1364.             else
  1365.                 list.push_back(0);
  1366.         }
  1367.  
  1368.         if(spread > 0 && y % spread == 0)
  1369.             --colSpread;
  1370.     }
  1371.  
  1372.     setupArea(list, rows);
  1373. }
  1374.  
  1375. void CombatArea::setupArea(int32_t radius)
  1376. {
  1377.     int32_t area[13][13] =
  1378.     {
  1379.         {0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0},
  1380.         {0, 0, 0, 0, 8, 8, 7, 8, 8, 0, 0, 0, 0},
  1381.         {0, 0, 0, 8, 7, 6, 6, 6, 7, 8, 0, 0, 0},
  1382.         {0, 0, 8, 7, 6, 5, 5, 5, 6, 7, 8, 0, 0},
  1383.         {0, 8, 7, 6, 5, 4, 4, 4, 5, 6, 7, 8, 0},
  1384.         {0, 8, 6, 5, 4, 3, 2, 3, 4, 5, 6, 8, 0},
  1385.         {8, 7, 6, 5, 4, 2, 1, 2, 4, 5, 6, 7, 8},
  1386.         {0, 8, 6, 5, 4, 3, 2, 3, 4, 5, 6, 8, 0},
  1387.         {0, 8, 7, 6, 5, 4, 4, 4, 5, 6, 7, 8, 0},
  1388.         {0, 0, 8, 7, 6, 5, 5, 5, 6, 7, 8, 0, 0},
  1389.         {0, 0, 0, 8, 7, 6, 6, 6, 7, 8, 0, 0, 0},
  1390.         {0, 0, 0, 0, 8, 8, 7, 8, 8, 0, 0, 0, 0},
  1391.         {0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0}
  1392.     };
  1393.  
  1394.     std::list<uint32_t> list;
  1395.     for(int32_t y = 0; y < 13; ++y)
  1396.     {
  1397.         for(int32_t x = 0; x < 13; ++x)
  1398.         {
  1399.             if(area[y][x] == 1)
  1400.                 list.push_back(3);
  1401.             else if(area[y][x] > 0 && area[y][x] <= radius)
  1402.                 list.push_back(1);
  1403.             else
  1404.                 list.push_back(0);
  1405.         }
  1406.     }
  1407.  
  1408.     setupArea(list, 13);
  1409. }
  1410.  
  1411. void CombatArea::setupExtArea(const std::list<uint32_t>& list, uint32_t rows)
  1412. {
  1413.     if(list.empty())
  1414.         return;
  1415.  
  1416.     //NORTH-WEST
  1417.     MatrixArea* area = createArea(list, rows);
  1418.     areas[NORTHWEST] = area;
  1419.     uint32_t maxOutput = std::max(area->getCols(), area->getRows()) << 1;
  1420.  
  1421.     //NORTH-EAST
  1422.     MatrixArea* neArea = new MatrixArea(maxOutput, maxOutput);
  1423.     copyArea(area, neArea, MATRIXOPERATION_MIRROR);
  1424.     areas[NORTHEAST] = neArea;
  1425.  
  1426.     //SOUTH-WEST
  1427.     MatrixArea* swArea = new MatrixArea(maxOutput, maxOutput);
  1428.     copyArea(area, swArea, MATRIXOPERATION_FLIP);
  1429.     areas[SOUTHWEST] = swArea;
  1430.  
  1431.     //SOUTH-EAST
  1432.     MatrixArea* seArea = new MatrixArea(maxOutput, maxOutput);
  1433.     copyArea(swArea, seArea, MATRIXOPERATION_MIRROR);
  1434.     areas[SOUTHEAST] = seArea;
  1435.  
  1436.     hasExtArea = true;
  1437. }
  1438.  
  1439. //**********************************************************
  1440.  
  1441. bool MagicField::isBlocking(const Creature* creature) const
  1442. {
  1443.     if(!isUnstepable())
  1444.         return Item::isBlocking(creature);
  1445.  
  1446.     if(!creature || !creature->getPlayer())
  1447.         return true;
  1448.  
  1449.     uint32_t ownerId = getOwner();
  1450.     if(!ownerId)
  1451.         return false;
  1452.  
  1453.     if(Creature* owner = g_game.getCreatureByID(ownerId))
  1454.         return creature->getPlayer()->getGuildEmblem(owner) != GUILDEMBLEM_NONE;
  1455.  
  1456.     return false;
  1457. }
  1458.  
  1459. void MagicField::onStepInField(Creature* creature, bool purposeful/* = true*/)
  1460. {
  1461.     if(!creature)
  1462.         return;
  1463.  
  1464.     if(isUnstepable() || isBlocking(creature))
  1465.     {
  1466.         if(!creature->isGhost())
  1467.             g_game.internalRemoveItem(creature, this, 1);
  1468.  
  1469.         return;
  1470.     }
  1471.  
  1472.     if(!purposeful || !creature->isAttackable())
  1473.         return;
  1474.  
  1475.     const ItemType& it = items[id];
  1476.     if(!it.condition)
  1477.         return;
  1478.  
  1479.     uint32_t ownerId = getOwner();
  1480.     Tile* tile = getTile();
  1481.  
  1482.     Condition* condition = it.condition->clone();
  1483.     if(ownerId && !tile->hasFlag(TILESTATE_HARDCOREZONE))
  1484.     {
  1485.         if(Creature* owner = g_game.getCreatureByID(ownerId))
  1486.         {
  1487.             Player* ownerPlayer = owner->getPlayer();
  1488.             if(!ownerPlayer && owner->isPlayerSummon())
  1489.                 ownerPlayer = owner->getPlayerMaster();
  1490.  
  1491.             bool harmful = true;
  1492.             if((g_game.getWorldType() == WORLDTYPE_OPTIONAL || tile->hasFlag(TILESTATE_OPTIONALZONE)) && ownerPlayer)
  1493.                 harmful = false;
  1494.             else if(Player* player = creature->getPlayer())
  1495.             {
  1496.                 if(ownerPlayer && Combat::isProtected(ownerPlayer, player))
  1497.                     harmful = false;
  1498.             }
  1499.  
  1500.             if(!harmful || (OTSYS_TIME() - createTime) <= (uint32_t)g_config.getNumber(
  1501.                 ConfigManager::FIELD_OWNERSHIP) || creature->hasBeenAttacked(ownerId))
  1502.                 condition->setParam(CONDITIONPARAM_OWNER, ownerId);
  1503.         }
  1504.     }
  1505.  
  1506.     creature->addCondition(condition);
  1507. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement