Guest User

combat.cpp

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