Advertisement
Guest User

Untitled

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