Advertisement
Bitupx

combat.cpp

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