Oskar1121

Untitled

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