Advertisement
Guest User

Untitled

a guest
May 1st, 2018
243
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 38.55 KB | None | 0 0
  1. /**
  2. * The Forgotten Server - a free and open-source MMORPG server emulator
  3. * Copyright (C) 2016 Mark Samman <mark.samman@gmail.com>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License along
  16. * with this program; if not, write to the Free Software Foundation, Inc.,
  17. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  18. */
  19.  
  20. #include "otpch.h"
  21.  
  22. #include "combat.h"
  23.  
  24. #include "game.h"
  25. #include "weapons.h"
  26. #include "configmanager.h"
  27. #include "events.h"
  28.  
  29. extern Game g_game;
  30. extern Weapons* g_weapons;
  31. extern ConfigManager g_config;
  32. extern Events* g_events;
  33.  
  34. Combat::Combat() :
  35. formulaType(COMBAT_FORMULA_UNDEFINED),
  36. mina(0.0), minb(0.0), maxa(0.0), maxb(0.0),
  37. area(nullptr)
  38. {
  39. //
  40. }
  41.  
  42. CombatDamage Combat::getCombatDamage(Creature* creature, Creature* target) const
  43. {
  44. CombatDamage damage;
  45. damage.origin = params.origin;
  46. damage.primary.type = params.combatType;
  47. if (formulaType == COMBAT_FORMULA_DAMAGE) {
  48. damage.primary.value = normal_random(
  49. static_cast<int32_t>(mina),
  50. static_cast<int32_t>(maxa)
  51. );
  52. } else if (creature) {
  53. int32_t min, max;
  54. if (creature->getCombatValues(min, max)) {
  55. damage.primary.value = normal_random(min, max);
  56. } else if (Player* player = creature->getPlayer()) {
  57. if (params.valueCallback) {
  58. params.valueCallback->getMinMaxValues(player, damage, params.useCharges);
  59. } else if (formulaType == COMBAT_FORMULA_LEVELMAGIC) {
  60. int32_t levelFormula = player->getLevel() * 2 + player->getMagicLevel() * 3;
  61. damage.primary.value = normal_random(
  62. static_cast<int32_t>(levelFormula * mina + minb),
  63. static_cast<int32_t>(levelFormula * maxa + maxb)
  64. );
  65. } else if (formulaType == COMBAT_FORMULA_SKILL) {
  66. Item* tool = player->getWeapon();
  67. const Weapon* weapon = g_weapons->getWeapon(tool);
  68. if (weapon) {
  69. damage.primary.value = normal_random(
  70. static_cast<int32_t>(minb),
  71. static_cast<int32_t>(weapon->getWeaponDamage(player, target, tool, true) * maxa + maxb)
  72. );
  73.  
  74. damage.secondary.type = weapon->getElementType();
  75. damage.secondary.value = weapon->getElementDamage(player, target, tool);
  76. if (params.useCharges) {
  77. uint16_t charges = tool->getCharges();
  78. if (charges != 0) {
  79. g_game.transformItem(tool, tool->getID(), charges - 1);
  80. }
  81. }
  82. } else {
  83. damage.primary.value = normal_random(
  84. static_cast<int32_t>(minb),
  85. static_cast<int32_t>(maxb)
  86. );
  87. }
  88. }
  89. }
  90. }
  91. return damage;
  92. }
  93.  
  94. void Combat::getCombatArea(const Position& centerPos, const Position& targetPos, const AreaCombat* area, std::forward_list<Tile*>& list)
  95. {
  96. if (targetPos.z >= MAP_MAX_LAYERS) {
  97. return;
  98. }
  99.  
  100. if (area) {
  101. area->getList(centerPos, targetPos, list);
  102. } else {
  103. Tile* tile = g_game.map.getTile(targetPos);
  104. if (!tile) {
  105. tile = new StaticTile(targetPos.x, targetPos.y, targetPos.z);
  106. g_game.map.setTile(targetPos, tile);
  107. }
  108. list.push_front(tile);
  109. }
  110. }
  111.  
  112. CombatType_t Combat::ConditionToDamageType(ConditionType_t type)
  113. {
  114. switch (type) {
  115. case CONDITION_FIRE:
  116. return COMBAT_FIREDAMAGE;
  117.  
  118. case CONDITION_ENERGY:
  119. return COMBAT_ENERGYDAMAGE;
  120.  
  121. case CONDITION_BLEEDING:
  122. return COMBAT_PHYSICALDAMAGE;
  123.  
  124. case CONDITION_DROWN:
  125. return COMBAT_DROWNDAMAGE;
  126.  
  127. case CONDITION_POISON:
  128. return COMBAT_EARTHDAMAGE;
  129.  
  130. case CONDITION_FREEZING:
  131. return COMBAT_ICEDAMAGE;
  132.  
  133. case CONDITION_DAZZLED:
  134. return COMBAT_HOLYDAMAGE;
  135.  
  136. case CONDITION_CURSED:
  137. return COMBAT_DEATHDAMAGE;
  138.  
  139. default:
  140. break;
  141. }
  142.  
  143. return COMBAT_NONE;
  144. }
  145.  
  146. ConditionType_t Combat::DamageToConditionType(CombatType_t type)
  147. {
  148. switch (type) {
  149. case COMBAT_FIREDAMAGE:
  150. return CONDITION_FIRE;
  151.  
  152. case COMBAT_ENERGYDAMAGE:
  153. return CONDITION_ENERGY;
  154.  
  155. case COMBAT_DROWNDAMAGE:
  156. return CONDITION_DROWN;
  157.  
  158. case COMBAT_EARTHDAMAGE:
  159. return CONDITION_POISON;
  160.  
  161. case COMBAT_ICEDAMAGE:
  162. return CONDITION_FREEZING;
  163.  
  164. case COMBAT_HOLYDAMAGE:
  165. return CONDITION_DAZZLED;
  166.  
  167. case COMBAT_DEATHDAMAGE:
  168. return CONDITION_CURSED;
  169.  
  170. case COMBAT_PHYSICALDAMAGE:
  171. return CONDITION_BLEEDING;
  172.  
  173. default:
  174. return CONDITION_NONE;
  175. }
  176. }
  177.  
  178. bool Combat::isPlayerCombat(const Creature* target)
  179. {
  180. if (target->getPlayer()) {
  181. return true;
  182. }
  183.  
  184. if (target->isSummon() && target->getMaster()->getPlayer()) {
  185. return true;
  186. }
  187.  
  188. return false;
  189. }
  190.  
  191. ReturnValue Combat::canTargetCreature(Player* player, Creature* target)
  192. {
  193. if (player == target) {
  194. return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER;
  195. }
  196.  
  197. if (!player->hasFlag(PlayerFlag_IgnoreProtectionZone)) {
  198. //pz-zone
  199. if (player->getZone() == ZONE_PROTECTION) {
  200. return RETURNVALUE_YOUMAYNOTATTACKAPERSONWHILEINPROTECTIONZONE;
  201. }
  202.  
  203. if (target->getZone() == ZONE_PROTECTION) {
  204. return RETURNVALUE_YOUMAYNOTATTACKAPERSONINPROTECTIONZONE;
  205. }
  206.  
  207. //nopvp-zone
  208. if (isPlayerCombat(target)) {
  209. if (player->getZone() == ZONE_NOPVP) {
  210. return RETURNVALUE_ACTIONNOTPERMITTEDINANOPVPZONE;
  211. }
  212.  
  213. if (target->getZone() == ZONE_NOPVP) {
  214. return RETURNVALUE_YOUMAYNOTATTACKAPERSONINPROTECTIONZONE;
  215. }
  216. }
  217. }
  218.  
  219. if (player->hasFlag(PlayerFlag_CannotUseCombat) || !target->isAttackable()) {
  220. if (target->getPlayer()) {
  221. return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER;
  222. } else {
  223. return RETURNVALUE_YOUMAYNOTATTACKTHISCREATURE;
  224. }
  225. }
  226.  
  227. if (target->getPlayer()) {
  228. if (isProtected(player, target->getPlayer())) {
  229. return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER;
  230. }
  231.  
  232. if (player->hasSecureMode() && !Combat::isInPvpZone(player, target) && player->getSkullClient(target->getPlayer()) == SKULL_NONE) {
  233. return RETURNVALUE_TURNSECUREMODETOATTACKUNMARKEDPLAYERS;
  234. }
  235. }
  236.  
  237. return Combat::canDoCombat(player, target);
  238. }
  239.  
  240. ReturnValue Combat::canDoCombat(Creature* caster, Tile* tile, bool aggressive)
  241. {
  242. if (tile->hasProperty(CONST_PROP_BLOCKPROJECTILE)) {
  243. return RETURNVALUE_NOTENOUGHROOM;
  244. }
  245.  
  246. if (tile->hasFlag(TILESTATE_FLOORCHANGE)) {
  247. return RETURNVALUE_NOTENOUGHROOM;
  248. }
  249.  
  250. if (tile->getTeleportItem()) {
  251. return RETURNVALUE_NOTENOUGHROOM;
  252. }
  253.  
  254. if (caster) {
  255. const Position& casterPosition = caster->getPosition();
  256. const Position& tilePosition = tile->getPosition();
  257. if (casterPosition.z < tilePosition.z) {
  258. return RETURNVALUE_FIRSTGODOWNSTAIRS;
  259. } else if (casterPosition.z > tilePosition.z) {
  260. return RETURNVALUE_FIRSTGOUPSTAIRS;
  261. }
  262.  
  263. if (const Player* player = caster->getPlayer()) {
  264. if (player->hasFlag(PlayerFlag_IgnoreProtectionZone)) {
  265. return RETURNVALUE_NOERROR;
  266. }
  267. }
  268. }
  269.  
  270. //pz-zone
  271. if (aggressive && tile->hasFlag(TILESTATE_PROTECTIONZONE)) {
  272. return RETURNVALUE_ACTIONNOTPERMITTEDINPROTECTIONZONE;
  273. }
  274.  
  275. return g_events->eventCreatureOnAreaCombat(caster, tile, aggressive);
  276. }
  277.  
  278. bool Combat::isInPvpZone(const Creature* attacker, const Creature* target)
  279. {
  280. return attacker->getZone() == ZONE_PVP && target->getZone() == ZONE_PVP;
  281. }
  282.  
  283. bool Combat::isProtected(const Player* attacker, const Player* target)
  284. {
  285. uint32_t protectionLevel = g_config.getNumber(ConfigManager::PROTECTION_LEVEL);
  286. if (target->getLevel() < protectionLevel || attacker->getLevel() < protectionLevel) {
  287. return true;
  288. }
  289.  
  290. if (attacker->getVocationId() == VOCATION_NONE || target->getVocationId() == VOCATION_NONE) {
  291. return true;
  292. }
  293.  
  294. if (attacker->getSkull() == SKULL_BLACK && attacker->getSkullClient(target) == SKULL_NONE) {
  295. return true;
  296. }
  297.  
  298. return false;
  299. }
  300.  
  301. ReturnValue Combat::canDoCombat(Creature* attacker, Creature* target)
  302. {
  303. if (attacker) {
  304. if (const Player* targetPlayer = target->getPlayer()) {
  305. if (targetPlayer->hasFlag(PlayerFlag_CannotBeAttacked)) {
  306. return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER;
  307. }
  308.  
  309. if (const Player* attackerPlayer = attacker->getPlayer()) {
  310. if (attackerPlayer->hasFlag(PlayerFlag_CannotAttackPlayer)) {
  311. return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER;
  312. }
  313.  
  314. if (isProtected(attackerPlayer, targetPlayer)) {
  315. return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER;
  316. }
  317.  
  318. //nopvp-zone
  319. const Tile* targetPlayerTile = targetPlayer->getTile();
  320. if (targetPlayerTile->hasFlag(TILESTATE_NOPVPZONE)) {
  321. return RETURNVALUE_ACTIONNOTPERMITTEDINANOPVPZONE;
  322. } else if (attackerPlayer->getTile()->hasFlag(TILESTATE_NOPVPZONE) && !targetPlayerTile->hasFlag(TILESTATE_NOPVPZONE | TILESTATE_PROTECTIONZONE)) {
  323. return RETURNVALUE_ACTIONNOTPERMITTEDINANOPVPZONE;
  324. }
  325. }
  326.  
  327. if (attacker->isSummon()) {
  328. if (const Player* masterAttackerPlayer = attacker->getMaster()->getPlayer()) {
  329. if (masterAttackerPlayer->hasFlag(PlayerFlag_CannotAttackPlayer)) {
  330. return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER;
  331. }
  332.  
  333. if (targetPlayer->getTile()->hasFlag(TILESTATE_NOPVPZONE)) {
  334. return RETURNVALUE_ACTIONNOTPERMITTEDINANOPVPZONE;
  335. }
  336.  
  337. if (isProtected(masterAttackerPlayer, targetPlayer)) {
  338. return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER;
  339. }
  340. }
  341. }
  342. } else if (target->getMonster()) {
  343. if (const Player* attackerPlayer = attacker->getPlayer()) {
  344. if (attackerPlayer->hasFlag(PlayerFlag_CannotAttackMonster)) {
  345. return RETURNVALUE_YOUMAYNOTATTACKTHISCREATURE;
  346. }
  347.  
  348. if (target->isSummon() && target->getMaster()->getPlayer() && target->getZone() == ZONE_NOPVP) {
  349. return RETURNVALUE_ACTIONNOTPERMITTEDINANOPVPZONE;
  350. }
  351. } else if (attacker->getMonster()) {
  352. const Creature* targetMaster = target->getMaster();
  353.  
  354. if (!targetMaster || !targetMaster->getPlayer()) {
  355. const Creature* attackerMaster = attacker->getMaster();
  356.  
  357. if (!attackerMaster || !attackerMaster->getPlayer()) {
  358. return RETURNVALUE_YOUMAYNOTATTACKTHISCREATURE;
  359. }
  360. }
  361. }
  362. }
  363.  
  364. if (g_game.getWorldType() == WORLD_TYPE_NO_PVP) {
  365. if (attacker->getPlayer() || (attacker->isSummon() && attacker->getMaster()->getPlayer())) {
  366. if (target->getPlayer()) {
  367. if (!isInPvpZone(attacker, target)) {
  368. return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER;
  369. }
  370. }
  371.  
  372. if (target->isSummon() && target->getMaster()->getPlayer()) {
  373. if (!isInPvpZone(attacker, target)) {
  374. return RETURNVALUE_YOUMAYNOTATTACKTHISCREATURE;
  375. }
  376. }
  377. }
  378. }
  379. }
  380. return g_events->eventCreatureOnTargetCombat(attacker, target);
  381. }
  382.  
  383. void Combat::setPlayerCombatValues(formulaType_t _type, double _mina, double _minb, double _maxa, double _maxb)
  384. {
  385. formulaType = _type;
  386. mina = _mina;
  387. minb = _minb;
  388. maxa = _maxa;
  389. maxb = _maxb;
  390. }
  391.  
  392. bool Combat::setParam(CombatParam_t param, uint32_t value)
  393. {
  394. switch (param) {
  395. case COMBAT_PARAM_TYPE: {
  396. params.combatType = static_cast<CombatType_t>(value);
  397. return true;
  398. }
  399.  
  400. case COMBAT_PARAM_EFFECT: {
  401. params.impactEffect = static_cast<uint8_t>(value);
  402. return true;
  403. }
  404.  
  405. case COMBAT_PARAM_DISTANCEEFFECT: {
  406. params.distanceEffect = static_cast<uint8_t>(value);
  407. return true;
  408. }
  409.  
  410. case COMBAT_PARAM_BLOCKARMOR: {
  411. params.blockedByArmor = (value != 0);
  412. return true;
  413. }
  414.  
  415. case COMBAT_PARAM_BLOCKSHIELD: {
  416. params.blockedByShield = (value != 0);
  417. return true;
  418. }
  419.  
  420. case COMBAT_PARAM_TARGETCASTERORTOPMOST: {
  421. params.targetCasterOrTopMost = (value != 0);
  422. return true;
  423. }
  424.  
  425. case COMBAT_PARAM_CREATEITEM: {
  426. params.itemId = value;
  427. return true;
  428. }
  429.  
  430. case COMBAT_PARAM_AGGRESSIVE: {
  431. params.aggressive = (value != 0);
  432. return true;
  433. }
  434.  
  435. case COMBAT_PARAM_DISPEL: {
  436. params.dispelType = static_cast<ConditionType_t>(value);
  437. return true;
  438. }
  439.  
  440. case COMBAT_PARAM_USECHARGES: {
  441. params.useCharges = (value != 0);
  442. return true;
  443. }
  444. }
  445. return false;
  446. }
  447.  
  448. bool Combat::setCallback(CallBackParam_t key)
  449. {
  450. switch (key) {
  451. case CALLBACK_PARAM_LEVELMAGICVALUE: {
  452. params.valueCallback.reset(new ValueCallback(COMBAT_FORMULA_LEVELMAGIC));
  453. return true;
  454. }
  455.  
  456. case CALLBACK_PARAM_SKILLVALUE: {
  457. params.valueCallback.reset(new ValueCallback(COMBAT_FORMULA_SKILL));
  458. return true;
  459. }
  460.  
  461. case CALLBACK_PARAM_TARGETTILE: {
  462. params.tileCallback.reset(new TileCallback());
  463. return true;
  464. }
  465.  
  466. case CALLBACK_PARAM_TARGETCREATURE: {
  467. params.targetCallback.reset(new TargetCallback());
  468. return true;
  469. }
  470. }
  471. return false;
  472. }
  473.  
  474. CallBack* Combat::getCallback(CallBackParam_t key)
  475. {
  476. switch (key) {
  477. case CALLBACK_PARAM_LEVELMAGICVALUE:
  478. case CALLBACK_PARAM_SKILLVALUE: {
  479. return params.valueCallback.get();
  480. }
  481.  
  482. case CALLBACK_PARAM_TARGETTILE: {
  483. return params.tileCallback.get();
  484. }
  485.  
  486. case CALLBACK_PARAM_TARGETCREATURE: {
  487. return params.targetCallback.get();
  488. }
  489. }
  490. return nullptr;
  491. }
  492.  
  493. void Combat::CombatHealthFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data)
  494. {
  495. assert(data);
  496. CombatDamage damage = *data;
  497. if (g_game.combatBlockHit(damage, caster, target, params.blockedByShield, params.blockedByArmor, params.itemId != 0)) {
  498. return;
  499. }
  500.  
  501. if ((damage.primary.value < 0 || damage.secondary.value < 0) && caster) {
  502. Player* targetPlayer = target->getPlayer();
  503. if (targetPlayer && caster->getPlayer() && targetPlayer->getSkull() != SKULL_BLACK) {
  504. damage.primary.value /= 2;
  505. damage.secondary.value /= 2;
  506. }
  507. }
  508.  
  509. if (g_game.combatChangeHealth(caster, target, damage)) {
  510. CombatConditionFunc(caster, target, params, nullptr);
  511. CombatDispelFunc(caster, target, params, nullptr);
  512. }
  513. }
  514.  
  515. void Combat::CombatManaFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data)
  516. {
  517. assert(data);
  518. CombatDamage damage = *data;
  519. if (damage.primary.value < 0) {
  520. if (caster && caster->getPlayer() && target->getPlayer()) {
  521. damage.primary.value /= 2;
  522. }
  523. }
  524.  
  525. if (g_game.combatChangeMana(caster, target, damage.primary.value, damage.origin)) {
  526. CombatConditionFunc(caster, target, params, nullptr);
  527. CombatDispelFunc(caster, target, params, nullptr);
  528. }
  529. }
  530.  
  531. void Combat::CombatConditionFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage*)
  532. {
  533. for (const auto& condition : params.conditionList) {
  534. if (caster == target || !target->isImmune(condition->getType())) {
  535. Condition* conditionCopy = condition->clone();
  536. if (caster) {
  537. conditionCopy->setParam(CONDITION_PARAM_OWNER, caster->getID());
  538. }
  539.  
  540. //TODO: infight condition until all aggressive conditions has ended
  541. target->addCombatCondition(conditionCopy);
  542. }
  543. }
  544. }
  545.  
  546. void Combat::CombatDispelFunc(Creature*, Creature* target, const CombatParams& params, CombatDamage*)
  547. {
  548. target->removeCombatCondition(params.dispelType);
  549. }
  550.  
  551. void Combat::CombatNullFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage*)
  552. {
  553. CombatConditionFunc(caster, target, params, nullptr);
  554. CombatDispelFunc(caster, target, params, nullptr);
  555. }
  556.  
  557. void Combat::combatTileEffects(const SpectatorVec& list, Creature* caster, Tile* tile, const CombatParams& params)
  558. {
  559. if (params.itemId != 0) {
  560. uint16_t itemId = params.itemId;
  561. switch (itemId) {
  562. case ITEM_FIREFIELD_PERSISTENT_FULL:
  563. itemId = ITEM_FIREFIELD_PVP_FULL;
  564. break;
  565.  
  566. case ITEM_FIREFIELD_PERSISTENT_MEDIUM:
  567. itemId = ITEM_FIREFIELD_PVP_MEDIUM;
  568. break;
  569.  
  570. case ITEM_FIREFIELD_PERSISTENT_SMALL:
  571. itemId = ITEM_FIREFIELD_PVP_SMALL;
  572. break;
  573.  
  574. case ITEM_ENERGYFIELD_PERSISTENT:
  575. itemId = ITEM_ENERGYFIELD_PVP;
  576. break;
  577.  
  578. case ITEM_POISONFIELD_PERSISTENT:
  579. itemId = ITEM_POISONFIELD_PVP;
  580. break;
  581.  
  582. case ITEM_MAGICWALL_PERSISTENT:
  583. itemId = ITEM_MAGICWALL;
  584. break;
  585.  
  586. case ITEM_WILDGROWTH_PERSISTENT:
  587. itemId = ITEM_WILDGROWTH;
  588. break;
  589.  
  590. default:
  591. break;
  592. }
  593.  
  594. if (caster) {
  595. Player* casterPlayer;
  596. if (caster->isSummon()) {
  597. casterPlayer = caster->getMaster()->getPlayer();
  598. } else {
  599. casterPlayer = caster->getPlayer();
  600. }
  601.  
  602. if (casterPlayer) {
  603. if (g_game.getWorldType() == WORLD_TYPE_NO_PVP || tile->hasFlag(TILESTATE_NOPVPZONE)) {
  604. if (itemId == ITEM_FIREFIELD_PVP_FULL) {
  605. itemId = ITEM_FIREFIELD_NOPVP;
  606. } else if (itemId == ITEM_POISONFIELD_PVP) {
  607. itemId = ITEM_POISONFIELD_NOPVP;
  608. } else if (itemId == ITEM_ENERGYFIELD_PVP) {
  609. itemId = ITEM_ENERGYFIELD_NOPVP;
  610. }
  611. } else if (itemId == ITEM_FIREFIELD_PVP_FULL || itemId == ITEM_POISONFIELD_PVP || itemId == ITEM_ENERGYFIELD_PVP) {
  612. casterPlayer->addInFightTicks();
  613. }
  614. }
  615. }
  616.  
  617. Item* item = Item::CreateItem(itemId);
  618. if (caster) {
  619. item->setOwner(caster->getID());
  620. }
  621.  
  622. ReturnValue ret = g_game.internalAddItem(tile, item);
  623. if (ret == RETURNVALUE_NOERROR) {
  624. g_game.startDecay(item);
  625. } else {
  626. delete item;
  627. }
  628. }
  629.  
  630. if (params.tileCallback) {
  631. params.tileCallback->onTileCombat(caster, tile);
  632. }
  633.  
  634. if (params.impactEffect != CONST_ME_NONE) {
  635. Game::addMagicEffect(list, tile->getPosition(), params.impactEffect);
  636. }
  637. }
  638.  
  639. void Combat::postCombatEffects(Creature* caster, const Position& pos, const CombatParams& params)
  640. {
  641. if (caster && params.distanceEffect != CONST_ANI_NONE) {
  642. addDistanceEffect(caster, caster->getPosition(), pos, params.distanceEffect);
  643. }
  644. }
  645.  
  646. void Combat::addDistanceEffect(Creature* caster, const Position& fromPos, const Position& toPos, uint8_t effect)
  647. {
  648. if (effect == CONST_ANI_WEAPONTYPE) {
  649. if (!caster) {
  650. return;
  651. }
  652.  
  653. Player* player = caster->getPlayer();
  654. if (!player) {
  655. return;
  656. }
  657.  
  658. switch (player->getWeaponType()) {
  659. case WEAPON_AXE:
  660. effect = CONST_ANI_WHIRLWINDAXE;
  661. break;
  662. case WEAPON_SWORD:
  663. effect = CONST_ANI_WHIRLWINDSWORD;
  664. break;
  665. case WEAPON_CLUB:
  666. effect = CONST_ANI_WHIRLWINDCLUB;
  667. break;
  668. default:
  669. effect = CONST_ANI_NONE;
  670. break;
  671. }
  672. }
  673.  
  674. if (effect != CONST_ANI_NONE) {
  675. g_game.addDistanceEffect(fromPos, toPos, effect);
  676. }
  677. }
  678.  
  679. void Combat::CombatFunc(Creature* caster, const Position& pos, const AreaCombat* area, const CombatParams& params, COMBATFUNC func, CombatDamage* data)
  680. {
  681. std::forward_list<Tile*> tileList;
  682.  
  683. if (caster) {
  684. getCombatArea(caster->getPosition(), pos, area, tileList);
  685. } else {
  686. getCombatArea(pos, pos, area, tileList);
  687. }
  688.  
  689. SpectatorVec list;
  690. uint32_t maxX = 0;
  691. uint32_t maxY = 0;
  692.  
  693. //calculate the max viewable range
  694. for (Tile* tile : tileList) {
  695. const Position& tilePos = tile->getPosition();
  696.  
  697. uint32_t diff = Position::getDistanceX(tilePos, pos);
  698. if (diff > maxX) {
  699. maxX = diff;
  700. }
  701.  
  702. diff = Position::getDistanceY(tilePos, pos);
  703. if (diff > maxY) {
  704. maxY = diff;
  705. }
  706. }
  707.  
  708. const int32_t rangeX = maxX + Map::maxViewportX;
  709. const int32_t rangeY = maxY + Map::maxViewportY;
  710. g_game.map.getSpectators(list, pos, true, true, rangeX, rangeX, rangeY, rangeY);
  711.  
  712. for (Tile* tile : tileList) {
  713. if (canDoCombat(caster, tile, params.aggressive) != RETURNVALUE_NOERROR) {
  714. continue;
  715. }
  716.  
  717. if (CreatureVector* creatures = tile->getCreatures()) {
  718. const Creature* topCreature = tile->getTopCreature();
  719. for (Creature* creature : *creatures) {
  720. if (params.targetCasterOrTopMost) {
  721. if (caster && caster->getTile() == tile) {
  722. if (creature != caster) {
  723. continue;
  724. }
  725. } else if (creature != topCreature) {
  726. continue;
  727. }
  728. }
  729.  
  730. if (!params.aggressive || (caster != creature && Combat::canDoCombat(caster, creature) == RETURNVALUE_NOERROR)) {
  731. func(caster, creature, params, data);
  732. if (params.targetCallback) {
  733. params.targetCallback->onTargetCombat(caster, creature);
  734. }
  735.  
  736. if (params.targetCasterOrTopMost) {
  737. break;
  738. }
  739. }
  740. }
  741. }
  742. combatTileEffects(list, caster, tile, params);
  743. }
  744. postCombatEffects(caster, pos, params);
  745. }
  746.  
  747. void Combat::doCombat(Creature* caster, Creature* target) const
  748. {
  749. //target combat callback function
  750. if (params.combatType != COMBAT_NONE) {
  751. CombatDamage damage = getCombatDamage(caster, target);
  752. if (damage.primary.type != COMBAT_MANADRAIN) {
  753. doCombatHealth(caster, target, damage, params);
  754. } else {
  755. doCombatMana(caster, target, damage, params);
  756. }
  757. } else {
  758. doCombatDefault(caster, target, params);
  759. }
  760. }
  761.  
  762. void Combat::doCombat(Creature* caster, const Position& position) const
  763. {
  764. //area combat callback function
  765. if (params.combatType != COMBAT_NONE) {
  766. CombatDamage damage = getCombatDamage(caster, nullptr);
  767. if (damage.primary.type != COMBAT_MANADRAIN) {
  768. doCombatHealth(caster, position, area.get(), damage, params);
  769. } else {
  770. doCombatMana(caster, position, area.get(), damage, params);
  771. }
  772. } else {
  773. CombatFunc(caster, position, area.get(), params, CombatNullFunc, nullptr);
  774. }
  775. }
  776.  
  777. void Combat::doCombatHealth(Creature* caster, Creature* target, CombatDamage& damage, const CombatParams& params)
  778. {
  779. bool canCombat = !params.aggressive || (caster != target && Combat::canDoCombat(caster, target) == RETURNVALUE_NOERROR);
  780. if ((caster == target || canCombat) && params.impactEffect != CONST_ME_NONE) {
  781. g_game.addMagicEffect(target->getPosition(), params.impactEffect);
  782. }
  783.  
  784. if (canCombat) {
  785. CombatHealthFunc(caster, target, params, &damage);
  786. if (params.targetCallback) {
  787. params.targetCallback->onTargetCombat(caster, target);
  788. }
  789.  
  790. if (caster && params.distanceEffect != CONST_ANI_NONE) {
  791. addDistanceEffect(caster, caster->getPosition(), target->getPosition(), params.distanceEffect);
  792. }
  793. }
  794. }
  795.  
  796. void Combat::doCombatHealth(Creature* caster, const Position& position, const AreaCombat* area, CombatDamage& damage, const CombatParams& params)
  797. {
  798. CombatFunc(caster, position, area, params, CombatHealthFunc, &damage);
  799. }
  800.  
  801. void Combat::doCombatMana(Creature* caster, Creature* target, CombatDamage& damage, const CombatParams& params)
  802. {
  803. bool canCombat = !params.aggressive || (caster != target && Combat::canDoCombat(caster, target) == RETURNVALUE_NOERROR);
  804. if ((caster == target || canCombat) && params.impactEffect != CONST_ME_NONE) {
  805. g_game.addMagicEffect(target->getPosition(), params.impactEffect);
  806. }
  807.  
  808. if (canCombat) {
  809. CombatManaFunc(caster, target, params, &damage);
  810. if (params.targetCallback) {
  811. params.targetCallback->onTargetCombat(caster, target);
  812. }
  813.  
  814. if (caster && params.distanceEffect != CONST_ANI_NONE) {
  815. addDistanceEffect(caster, caster->getPosition(), target->getPosition(), params.distanceEffect);
  816. }
  817. }
  818. }
  819.  
  820. void Combat::doCombatMana(Creature* caster, const Position& position, const AreaCombat* area, CombatDamage& damage, const CombatParams& params)
  821. {
  822. CombatFunc(caster, position, area, params, CombatManaFunc, &damage);
  823. }
  824.  
  825. void Combat::doCombatCondition(Creature* caster, const Position& position, const AreaCombat* area, const CombatParams& params)
  826. {
  827. CombatFunc(caster, position, area, params, CombatConditionFunc, nullptr);
  828. }
  829.  
  830. void Combat::doCombatCondition(Creature* caster, Creature* target, const CombatParams& params)
  831. {
  832. bool canCombat = !params.aggressive || (caster != target && Combat::canDoCombat(caster, target) == RETURNVALUE_NOERROR);
  833. if ((caster == target || canCombat) && params.impactEffect != CONST_ME_NONE) {
  834. g_game.addMagicEffect(target->getPosition(), params.impactEffect);
  835. }
  836.  
  837. if (canCombat) {
  838. CombatConditionFunc(caster, target, params, nullptr);
  839. if (params.targetCallback) {
  840. params.targetCallback->onTargetCombat(caster, target);
  841. }
  842.  
  843. if (caster && params.distanceEffect != CONST_ANI_NONE) {
  844. addDistanceEffect(caster, caster->getPosition(), target->getPosition(), params.distanceEffect);
  845. }
  846. }
  847. }
  848.  
  849. void Combat::doCombatDispel(Creature* caster, const Position& position, const AreaCombat* area, const CombatParams& params)
  850. {
  851. CombatFunc(caster, position, area, params, CombatDispelFunc, nullptr);
  852. }
  853.  
  854. void Combat::doCombatDispel(Creature* caster, Creature* target, const CombatParams& params)
  855. {
  856. bool canCombat = !params.aggressive || (caster != target && Combat::canDoCombat(caster, target) == RETURNVALUE_NOERROR);
  857. if ((caster == target || canCombat) && params.impactEffect != CONST_ME_NONE) {
  858. g_game.addMagicEffect(target->getPosition(), params.impactEffect);
  859. }
  860.  
  861. if (canCombat) {
  862. CombatDispelFunc(caster, target, params, nullptr);
  863. if (params.targetCallback) {
  864. params.targetCallback->onTargetCombat(caster, target);
  865. }
  866.  
  867. if (caster && params.distanceEffect != CONST_ANI_NONE) {
  868. addDistanceEffect(caster, caster->getPosition(), target->getPosition(), params.distanceEffect);
  869. }
  870. }
  871. }
  872.  
  873. void Combat::doCombatDefault(Creature* caster, Creature* target, const CombatParams& params)
  874. {
  875. if (!params.aggressive || (caster != target && Combat::canDoCombat(caster, target) == RETURNVALUE_NOERROR)) {
  876. SpectatorVec list;
  877. g_game.map.getSpectators(list, target->getPosition(), true, true);
  878.  
  879. CombatNullFunc(caster, target, params, nullptr);
  880. combatTileEffects(list, caster, target->getTile(), params);
  881.  
  882. if (params.targetCallback) {
  883. params.targetCallback->onTargetCombat(caster, target);
  884. }
  885.  
  886. /*
  887. if (params.impactEffect != CONST_ME_NONE) {
  888. g_game.addMagicEffect(target->getPosition(), params.impactEffect);
  889. }
  890. */
  891.  
  892. if (caster && params.distanceEffect != CONST_ANI_NONE) {
  893. addDistanceEffect(caster, caster->getPosition(), target->getPosition(), params.distanceEffect);
  894. }
  895. }
  896. }
  897.  
  898. //**********************************************************//
  899.  
  900. void ValueCallback::getMinMaxValues(Player* player, CombatDamage& damage, bool useCharges) const
  901. {
  902. //onGetPlayerMinMaxValues(...)
  903. if (!scriptInterface->reserveScriptEnv()) {
  904. std::cout << "[Error - ValueCallback::getMinMaxValues] Call stack overflow" << std::endl;
  905. return;
  906. }
  907.  
  908. ScriptEnvironment* env = scriptInterface->getScriptEnv();
  909. if (!env->setCallbackId(scriptId, scriptInterface)) {
  910. scriptInterface->resetScriptEnv();
  911. return;
  912. }
  913.  
  914. lua_State* L = scriptInterface->getLuaState();
  915.  
  916. scriptInterface->pushFunction(scriptId);
  917.  
  918. LuaScriptInterface::pushUserdata<Player>(L, player);
  919. LuaScriptInterface::setMetatable(L, -1, "Player");
  920.  
  921. int parameters = 1;
  922. switch (type) {
  923. case COMBAT_FORMULA_LEVELMAGIC: {
  924. //onGetPlayerMinMaxValues(player, level, maglevel)
  925. lua_pushnumber(L, player->getLevel());
  926. lua_pushnumber(L, player->getMagicLevel());
  927. parameters += 2;
  928. break;
  929. }
  930.  
  931. case COMBAT_FORMULA_SKILL: {
  932. //onGetPlayerMinMaxValues(player, attackSkill, attackValue, attackFactor)
  933. Item* tool = player->getWeapon();
  934. const Weapon* weapon = g_weapons->getWeapon(tool);
  935.  
  936. int32_t attackValue = 7;
  937. if (weapon) {
  938. attackValue = tool->getAttack();
  939. if (tool->getWeaponType() == WEAPON_AMMO) {
  940. Item* item = player->getWeapon(true);
  941. if (item) {
  942. attackValue += item->getAttack();
  943. }
  944. }
  945.  
  946. damage.secondary.type = weapon->getElementType();
  947. damage.secondary.value = weapon->getElementDamage(player, nullptr, tool);
  948. if (useCharges) {
  949. uint16_t charges = tool->getCharges();
  950. if (charges != 0) {
  951. g_game.transformItem(tool, tool->getID(), charges - 1);
  952. }
  953. }
  954. }
  955.  
  956. lua_pushnumber(L, player->getWeaponSkill(tool));
  957. lua_pushnumber(L, attackValue);
  958. lua_pushnumber(L, player->getAttackFactor());
  959. parameters += 3;
  960. break;
  961. }
  962.  
  963. default: {
  964. std::cout << "ValueCallback::getMinMaxValues - unknown callback type" << std::endl;
  965. scriptInterface->resetScriptEnv();
  966. return;
  967. }
  968. }
  969.  
  970. int size0 = lua_gettop(L);
  971. if (lua_pcall(L, parameters, 2, 0) != 0) {
  972. LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
  973. } else {
  974. damage.primary.value = normal_random(
  975. LuaScriptInterface::getNumber<int32_t>(L, -2),
  976. LuaScriptInterface::getNumber<int32_t>(L, -1)
  977. );
  978. lua_pop(L, 2);
  979. }
  980.  
  981. if ((lua_gettop(L) + parameters + 1) != size0) {
  982. LuaScriptInterface::reportError(nullptr, "Stack size changed!");
  983. }
  984.  
  985. scriptInterface->resetScriptEnv();
  986. }
  987.  
  988. //**********************************************************//
  989.  
  990. void TileCallback::onTileCombat(Creature* creature, Tile* tile) const
  991. {
  992. //onTileCombat(creature, pos)
  993. if (!scriptInterface->reserveScriptEnv()) {
  994. std::cout << "[Error - TileCallback::onTileCombat] Call stack overflow" << std::endl;
  995. return;
  996. }
  997.  
  998. ScriptEnvironment* env = scriptInterface->getScriptEnv();
  999. if (!env->setCallbackId(scriptId, scriptInterface)) {
  1000. scriptInterface->resetScriptEnv();
  1001. return;
  1002. }
  1003.  
  1004. lua_State* L = scriptInterface->getLuaState();
  1005.  
  1006. scriptInterface->pushFunction(scriptId);
  1007. if (creature) {
  1008. LuaScriptInterface::pushUserdata<Creature>(L, creature);
  1009. LuaScriptInterface::setCreatureMetatable(L, -1, creature);
  1010. } else {
  1011. lua_pushnil(L);
  1012. }
  1013. LuaScriptInterface::pushPosition(L, tile->getPosition());
  1014.  
  1015. scriptInterface->callFunction(2);
  1016. }
  1017.  
  1018. //**********************************************************//
  1019.  
  1020. void TargetCallback::onTargetCombat(Creature* creature, Creature* target) const
  1021. {
  1022. //onTargetCombat(creature, target)
  1023. if (!scriptInterface->reserveScriptEnv()) {
  1024. std::cout << "[Error - TargetCallback::onTargetCombat] Call stack overflow" << std::endl;
  1025. return;
  1026. }
  1027.  
  1028. ScriptEnvironment* env = scriptInterface->getScriptEnv();
  1029. if (!env->setCallbackId(scriptId, scriptInterface)) {
  1030. scriptInterface->resetScriptEnv();
  1031. return;
  1032. }
  1033.  
  1034. lua_State* L = scriptInterface->getLuaState();
  1035.  
  1036. scriptInterface->pushFunction(scriptId);
  1037.  
  1038. if (creature) {
  1039. LuaScriptInterface::pushUserdata<Creature>(L, creature);
  1040. LuaScriptInterface::setCreatureMetatable(L, -1, creature);
  1041. } else {
  1042. lua_pushnil(L);
  1043. }
  1044.  
  1045. if (target) {
  1046. LuaScriptInterface::pushUserdata<Creature>(L, target);
  1047. LuaScriptInterface::setCreatureMetatable(L, -1, target);
  1048. } else {
  1049. lua_pushnil(L);
  1050. }
  1051.  
  1052. int size0 = lua_gettop(L);
  1053.  
  1054. if (lua_pcall(L, 2, 0 /*nReturnValues*/, 0) != 0) {
  1055. LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
  1056. }
  1057.  
  1058. if ((lua_gettop(L) + 2 /*nParams*/ + 1) != size0) {
  1059. LuaScriptInterface::reportError(nullptr, "Stack size changed!");
  1060. }
  1061.  
  1062. scriptInterface->resetScriptEnv();
  1063. }
  1064.  
  1065. //**********************************************************//
  1066.  
  1067. void AreaCombat::clear()
  1068. {
  1069. for (const auto& it : areas) {
  1070. delete it.second;
  1071. }
  1072. areas.clear();
  1073. }
  1074.  
  1075. AreaCombat::AreaCombat(const AreaCombat& rhs)
  1076. {
  1077. hasExtArea = rhs.hasExtArea;
  1078. for (const auto& it : rhs.areas) {
  1079. areas[it.first] = new MatrixArea(*it.second);
  1080. }
  1081. }
  1082.  
  1083. void AreaCombat::getList(const Position& centerPos, const Position& targetPos, std::forward_list<Tile*>& list) const
  1084. {
  1085. const MatrixArea* area = getArea(centerPos, targetPos);
  1086. if (!area) {
  1087. return;
  1088. }
  1089.  
  1090. uint32_t centerY, centerX;
  1091. area->getCenter(centerY, centerX);
  1092.  
  1093. Position tmpPos(targetPos.x - centerX, targetPos.y - centerY, targetPos.z);
  1094. uint32_t cols = area->getCols();
  1095. for (uint32_t y = 0, rows = area->getRows(); y < rows; ++y) {
  1096. for (uint32_t x = 0; x < cols; ++x) {
  1097. if (area->getValue(y, x) != 0) {
  1098. if (g_game.isSightClear(targetPos, tmpPos, true)) {
  1099. Tile* tile = g_game.map.getTile(tmpPos);
  1100. if (!tile) {
  1101. tile = new StaticTile(tmpPos.x, tmpPos.y, tmpPos.z);
  1102. g_game.map.setTile(tmpPos, tile);
  1103. }
  1104. list.push_front(tile);
  1105. }
  1106. }
  1107. tmpPos.x++;
  1108. }
  1109. tmpPos.x -= cols;
  1110. tmpPos.y++;
  1111. }
  1112. }
  1113.  
  1114. void AreaCombat::copyArea(const MatrixArea* input, MatrixArea* output, MatrixOperation_t op) const
  1115. {
  1116. uint32_t centerY, centerX;
  1117. input->getCenter(centerY, centerX);
  1118.  
  1119. if (op == MATRIXOPERATION_COPY) {
  1120. for (uint32_t y = 0; y < input->getRows(); ++y) {
  1121. for (uint32_t x = 0; x < input->getCols(); ++x) {
  1122. (*output)[y][x] = (*input)[y][x];
  1123. }
  1124. }
  1125.  
  1126. output->setCenter(centerY, centerX);
  1127. } else if (op == MATRIXOPERATION_MIRROR) {
  1128. for (uint32_t y = 0; y < input->getRows(); ++y) {
  1129. uint32_t rx = 0;
  1130. for (int32_t x = input->getCols(); --x >= 0;) {
  1131. (*output)[y][rx++] = (*input)[y][x];
  1132. }
  1133. }
  1134.  
  1135. output->setCenter(centerY, (input->getRows() - 1) - centerX);
  1136. } else if (op == MATRIXOPERATION_FLIP) {
  1137. for (uint32_t x = 0; x < input->getCols(); ++x) {
  1138. uint32_t ry = 0;
  1139. for (int32_t y = input->getRows(); --y >= 0;) {
  1140. (*output)[ry++][x] = (*input)[y][x];
  1141. }
  1142. }
  1143.  
  1144. output->setCenter((input->getCols() - 1) - centerY, centerX);
  1145. } else {
  1146. // rotation
  1147. int32_t rotateCenterX = (output->getCols() / 2) - 1;
  1148. int32_t rotateCenterY = (output->getRows() / 2) - 1;
  1149. int32_t angle;
  1150.  
  1151. switch (op) {
  1152. case MATRIXOPERATION_ROTATE90:
  1153. angle = 90;
  1154. break;
  1155.  
  1156. case MATRIXOPERATION_ROTATE180:
  1157. angle = 180;
  1158. break;
  1159.  
  1160. case MATRIXOPERATION_ROTATE270:
  1161. angle = 270;
  1162. break;
  1163.  
  1164. default:
  1165. angle = 0;
  1166. break;
  1167. }
  1168.  
  1169. double angleRad = M_PI * angle / 180.0;
  1170.  
  1171. double a = std::cos(angleRad);
  1172. double b = -std::sin(angleRad);
  1173. double c = std::sin(angleRad);
  1174. double d = std::cos(angleRad);
  1175.  
  1176. const uint32_t rows = input->getRows();
  1177. for (uint32_t x = 0, cols = input->getCols(); x < cols; ++x) {
  1178. for (uint32_t y = 0; y < rows; ++y) {
  1179. //calculate new coordinates using rotation center
  1180. int32_t newX = x - centerX;
  1181. int32_t newY = y - centerY;
  1182.  
  1183. //perform rotation
  1184. int32_t rotatedX = static_cast<int32_t>(round(newX * a + newY * b));
  1185. int32_t rotatedY = static_cast<int32_t>(round(newX * c + newY * d));
  1186.  
  1187. //write in the output matrix using rotated coordinates
  1188. (*output)[rotatedY + rotateCenterY][rotatedX + rotateCenterX] = (*input)[y][x];
  1189. }
  1190. }
  1191.  
  1192. output->setCenter(rotateCenterY, rotateCenterX);
  1193. }
  1194. }
  1195.  
  1196. MatrixArea* AreaCombat::createArea(const std::list<uint32_t>& list, uint32_t rows)
  1197. {
  1198. uint32_t cols;
  1199. if (rows == 0) {
  1200. cols = 0;
  1201. } else {
  1202. cols = list.size() / rows;
  1203. }
  1204.  
  1205. MatrixArea* area = new MatrixArea(rows, cols);
  1206.  
  1207. uint32_t x = 0;
  1208. uint32_t y = 0;
  1209.  
  1210. for (uint32_t value : list) {
  1211. if (value == 1 || value == 3) {
  1212. area->setValue(y, x, true);
  1213. }
  1214.  
  1215. if (value == 2 || value == 3) {
  1216. area->setCenter(y, x);
  1217. }
  1218.  
  1219. ++x;
  1220.  
  1221. if (cols == x) {
  1222. x = 0;
  1223. ++y;
  1224. }
  1225. }
  1226. return area;
  1227. }
  1228.  
  1229. void AreaCombat::setupArea(const std::list<uint32_t>& list, uint32_t rows)
  1230. {
  1231. MatrixArea* area = createArea(list, rows);
  1232.  
  1233. //NORTH
  1234. areas[DIRECTION_NORTH] = area;
  1235.  
  1236. uint32_t maxOutput = std::max<uint32_t>(area->getCols(), area->getRows()) * 2;
  1237.  
  1238. //SOUTH
  1239. MatrixArea* southArea = new MatrixArea(maxOutput, maxOutput);
  1240. copyArea(area, southArea, MATRIXOPERATION_ROTATE180);
  1241. areas[DIRECTION_SOUTH] = southArea;
  1242.  
  1243. //EAST
  1244. MatrixArea* eastArea = new MatrixArea(maxOutput, maxOutput);
  1245. copyArea(area, eastArea, MATRIXOPERATION_ROTATE90);
  1246. areas[DIRECTION_EAST] = eastArea;
  1247.  
  1248. //WEST
  1249. MatrixArea* westArea = new MatrixArea(maxOutput, maxOutput);
  1250. copyArea(area, westArea, MATRIXOPERATION_ROTATE270);
  1251. areas[DIRECTION_WEST] = westArea;
  1252. }
  1253.  
  1254. void AreaCombat::setupArea(int32_t length, int32_t spread)
  1255. {
  1256. std::list<uint32_t> list;
  1257.  
  1258. uint32_t rows = length;
  1259. int32_t cols = 1;
  1260.  
  1261. if (spread != 0) {
  1262. cols = ((length - (length % spread)) / spread) * 2 + 1;
  1263. }
  1264.  
  1265. int32_t colSpread = cols;
  1266.  
  1267. for (uint32_t y = 1; y <= rows; ++y) {
  1268. int32_t mincol = cols - colSpread + 1;
  1269. int32_t maxcol = cols - (cols - colSpread);
  1270.  
  1271. for (int32_t x = 1; x <= cols; ++x) {
  1272. if (y == rows && x == ((cols - (cols % 2)) / 2) + 1) {
  1273. list.push_back(3);
  1274. } else if (x >= mincol && x <= maxcol) {
  1275. list.push_back(1);
  1276. } else {
  1277. list.push_back(0);
  1278. }
  1279. }
  1280.  
  1281. if (spread > 0 && y % spread == 0) {
  1282. --colSpread;
  1283. }
  1284. }
  1285.  
  1286. setupArea(list, rows);
  1287. }
  1288.  
  1289. void AreaCombat::setupArea(int32_t radius)
  1290. {
  1291. int32_t area[13][13] = {
  1292. {0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0},
  1293. {0, 0, 0, 0, 8, 8, 7, 8, 8, 0, 0, 0, 0},
  1294. {0, 0, 0, 8, 7, 6, 6, 6, 7, 8, 0, 0, 0},
  1295. {0, 0, 8, 7, 6, 5, 5, 5, 6, 7, 8, 0, 0},
  1296. {0, 8, 7, 6, 5, 4, 4, 4, 5, 6, 7, 8, 0},
  1297. {0, 8, 6, 5, 4, 3, 2, 3, 4, 5, 6, 8, 0},
  1298. {8, 7, 6, 5, 4, 2, 1, 2, 4, 5, 6, 7, 8},
  1299. {0, 8, 6, 5, 4, 3, 2, 3, 4, 5, 6, 8, 0},
  1300. {0, 8, 7, 6, 5, 4, 4, 4, 5, 6, 7, 8, 0},
  1301. {0, 0, 8, 7, 6, 5, 5, 5, 6, 7, 8, 0, 0},
  1302. {0, 0, 0, 8, 7, 6, 6, 6, 7, 8, 0, 0, 0},
  1303. {0, 0, 0, 0, 8, 8, 7, 8, 8, 0, 0, 0, 0},
  1304. {0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0}
  1305. };
  1306.  
  1307. std::list<uint32_t> list;
  1308.  
  1309. for (int32_t y = 0; y < 13; ++y) {
  1310. for (int32_t x = 0; x < 13; ++x) {
  1311. if (area[y][x] == 1) {
  1312. list.push_back(3);
  1313. } else if (area[y][x] > 0 && area[y][x] <= radius) {
  1314. list.push_back(1);
  1315. } else {
  1316. list.push_back(0);
  1317. }
  1318. }
  1319. }
  1320.  
  1321. setupArea(list, 13);
  1322. }
  1323.  
  1324. void AreaCombat::setupExtArea(const std::list<uint32_t>& list, uint32_t rows)
  1325. {
  1326. if (list.empty()) {
  1327. return;
  1328. }
  1329.  
  1330. hasExtArea = true;
  1331. MatrixArea* area = createArea(list, rows);
  1332.  
  1333. //NORTH-WEST
  1334. areas[DIRECTION_NORTHWEST] = area;
  1335.  
  1336. uint32_t maxOutput = std::max<uint32_t>(area->getCols(), area->getRows()) * 2;
  1337.  
  1338. //NORTH-EAST
  1339. MatrixArea* neArea = new MatrixArea(maxOutput, maxOutput);
  1340. copyArea(area, neArea, MATRIXOPERATION_MIRROR);
  1341. areas[DIRECTION_NORTHEAST] = neArea;
  1342.  
  1343. //SOUTH-WEST
  1344. MatrixArea* swArea = new MatrixArea(maxOutput, maxOutput);
  1345. copyArea(area, swArea, MATRIXOPERATION_FLIP);
  1346. areas[DIRECTION_SOUTHWEST] = swArea;
  1347.  
  1348. //SOUTH-EAST
  1349. MatrixArea* seArea = new MatrixArea(maxOutput, maxOutput);
  1350. copyArea(swArea, seArea, MATRIXOPERATION_MIRROR);
  1351. areas[DIRECTION_SOUTHEAST] = seArea;
  1352. }
  1353.  
  1354. //**********************************************************//
  1355.  
  1356. void MagicField::onStepInField(Creature* creature)
  1357. {
  1358. //remove magic walls/wild growth
  1359. if (id == ITEM_MAGICWALL || id == ITEM_WILDGROWTH || id == ITEM_MAGICWALL_SAFE || id == ITEM_WILDGROWTH_SAFE || isBlocking()) {
  1360. if (!creature->isInGhostMode()) {
  1361. g_game.internalRemoveItem(this, 1);
  1362. }
  1363.  
  1364. return;
  1365. }
  1366.  
  1367. const ItemType& it = items[getID()];
  1368. if (it.conditionDamage) {
  1369. Condition* conditionCopy = it.conditionDamage->clone();
  1370. uint32_t ownerId = getOwner();
  1371. if (ownerId) {
  1372. bool harmfulField = true;
  1373.  
  1374. if (g_game.getWorldType() == WORLD_TYPE_NO_PVP || getTile()->hasFlag(TILESTATE_NOPVPZONE)) {
  1375. Creature* owner = g_game.getCreatureByID(ownerId);
  1376. if (owner) {
  1377. if (owner->getPlayer() || (owner->isSummon() && owner->getMaster()->getPlayer())) {
  1378. harmfulField = false;
  1379. }
  1380. }
  1381. }
  1382.  
  1383. Player* targetPlayer = creature->getPlayer();
  1384. if (targetPlayer) {
  1385. Player* attackerPlayer = g_game.getPlayerByID(ownerId);
  1386. if (attackerPlayer) {
  1387. if (Combat::isProtected(attackerPlayer, targetPlayer)) {
  1388. harmfulField = false;
  1389. }
  1390. }
  1391. }
  1392.  
  1393. if (!harmfulField || (OTSYS_TIME() - createTime <= 5000) || creature->hasBeenAttacked(ownerId)) {
  1394. conditionCopy->setParam(CONDITION_PARAM_OWNER, ownerId);
  1395. }
  1396. }
  1397.  
  1398. creature->addCondition(conditionCopy);
  1399. }
  1400. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement