MrP0wers

char_battle.cpp

Jan 10th, 2026
35
0
Never
4
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 81.32 KB | None | 0 0
  1. #include "stdafx.h"
  2. #include "utils.h"
  3. #include "config.h"
  4. #include "desc.h"
  5. #include "desc_manager.h"
  6. #include "char_manager.h"
  7. #include "item.h"
  8. #include "item_manager.h"
  9. #include "mob_manager.h"
  10. #include "battle.h"
  11. #include "pvp.h"
  12. #include "skill.h"
  13. #include "start_position.h"
  14. #include "cmd.h"
  15. #include "dungeon.h"
  16. #include "log.h"
  17. #include "unique_item.h"
  18. #include "priv_manager.h"
  19. #include "db.h"
  20. #include "vector.h"
  21. #include "marriage.h"
  22. #include "arena.h"
  23. #include "regen.h"
  24. #include "exchange.h"
  25. #include "shop_manager.h"
  26. #include "dev_log.h"
  27. #include "ani.h"
  28. #include "BattleArena.h"
  29. #include "packet.h"
  30. #include "party.h"
  31. #include "affect.h"
  32. #include "guild.h"
  33. #include "guild_manager.h"
  34. #include "questmanager.h"
  35. #include "questlua.h"
  36. #include "BlueDragon.h"
  37. #include "DragonLair.h"
  38. #include "war_map.h"
  39.  
  40. #include <random>
  41. #include <algorithm>
  42.  
  43. #ifdef ENABLE_DAMAGE_TOP
  44. #include "damage_top.h"
  45. #endif
  46.  
  47. DWORD AdjustExpByLevel(const LPCHARACTER ch, const DWORD exp)
  48. {
  49. if (PLAYER_EXP_TABLE_MAX < ch->GetLevel())
  50. {
  51. double ret = 0.95;
  52. double factor = 0.1;
  53.  
  54. for (ssize_t i=0 ; i < ch->GetLevel()-100 ; ++i)
  55. {
  56. if ( (i%10) == 0)
  57. factor /= 2.0;
  58.  
  59. ret *= 1.0 - factor;
  60. }
  61.  
  62. ret = ret * static_cast<double>(exp);
  63.  
  64. if (ret < 1.0)
  65. return 1;
  66.  
  67. return static_cast<DWORD>(ret);
  68. }
  69.  
  70. return exp;
  71. }
  72.  
  73. bool CHARACTER::CanBeginFight() const
  74. {
  75. if (!CanMove())
  76. return false;
  77.  
  78. return m_pointsInstant.position == POS_STANDING && !IsDead() && !IsStun();
  79. }
  80.  
  81. void CHARACTER::BeginFight(LPCHARACTER pkVictim)
  82. {
  83. SetVictim(pkVictim);
  84. SetPosition(POS_FIGHTING);
  85. SetNextStatePulse(1);
  86. }
  87.  
  88. bool CHARACTER::CanFight() const
  89. {
  90. return m_pointsInstant.position >= POS_FIGHTING ? true : false;
  91. }
  92.  
  93. void CHARACTER::CreateFly(BYTE bType, LPCHARACTER pkVictim)
  94. {
  95. TPacketGCCreateFly packFly;
  96.  
  97. packFly.bHeader = HEADER_GC_CREATE_FLY;
  98. packFly.bType = bType;
  99. packFly.dwStartVID = GetVID();
  100. packFly.dwEndVID = pkVictim->GetVID();
  101.  
  102. PacketAround(&packFly, sizeof(TPacketGCCreateFly));
  103. }
  104.  
  105. void CHARACTER::DistributeSP(LPCHARACTER pkKiller, int iMethod)
  106. {
  107. if (pkKiller->GetSP() >= pkKiller->GetMaxSP())
  108. return;
  109.  
  110. bool bAttacking = (get_dword_time() - GetLastAttackTime()) < 3000;
  111. bool bMoving = (get_dword_time() - GetLastMoveTime()) < 3000;
  112.  
  113. if (iMethod == 1)
  114. {
  115. int num = number(0, 3);
  116.  
  117. if (!num)
  118. {
  119. int iLvDelta = GetLevel() - pkKiller->GetLevel();
  120. int iAmount = 0;
  121.  
  122. if (iLvDelta >= 5)
  123. iAmount = 10;
  124.  
  125. else if (iLvDelta >= 0)
  126. iAmount = 6;
  127.  
  128. else if (iLvDelta >= -3)
  129. iAmount = 2;
  130.  
  131. if (iAmount != 0)
  132. {
  133. iAmount += (iAmount * pkKiller->GetPoint(POINT_SP_REGEN)) / 100;
  134.  
  135. if (iAmount >= 11)
  136. CreateFly(FLY_SP_BIG, pkKiller);
  137.  
  138. else if (iAmount >= 7)
  139. CreateFly(FLY_SP_MEDIUM, pkKiller);
  140.  
  141. else
  142. CreateFly(FLY_SP_SMALL, pkKiller);
  143.  
  144. pkKiller->PointChange(POINT_SP, iAmount);
  145. }
  146. }
  147. }
  148.  
  149. else
  150. {
  151. if (pkKiller->GetJob() == JOB_SHAMAN || (pkKiller->GetJob() == JOB_SURA && pkKiller->GetSkillGroup() == 2))
  152. {
  153. int iAmount;
  154.  
  155. if (bAttacking)
  156. iAmount = 2 + GetMaxSP() / 100;
  157.  
  158. else if (bMoving)
  159. iAmount = 3 + GetMaxSP() * 2 / 100;
  160.  
  161. else
  162. iAmount = 10 + GetMaxSP() * 3 / 100;
  163.  
  164. iAmount += (iAmount * pkKiller->GetPoint(POINT_SP_REGEN)) / 100;
  165. pkKiller->PointChange(POINT_SP, iAmount);
  166. }
  167.  
  168. else
  169. {
  170. int iAmount;
  171.  
  172. if (bAttacking)
  173. iAmount = 2 + pkKiller->GetMaxSP() / 200;
  174.  
  175. else if (bMoving)
  176. iAmount = 2 + pkKiller->GetMaxSP() / 100;
  177.  
  178. else
  179. {
  180. if (pkKiller->GetHP() < pkKiller->GetMaxHP())
  181. iAmount = 2 + (pkKiller->GetMaxSP() / 100);
  182. else
  183. iAmount = 9 + (pkKiller->GetMaxSP() / 100);
  184. }
  185.  
  186. iAmount += (iAmount * pkKiller->GetPoint(POINT_SP_REGEN)) / 100;
  187. pkKiller->PointChange(POINT_SP, iAmount);
  188. }
  189. }
  190. }
  191.  
  192. bool CHARACTER::Attack(LPCHARACTER pkVictim, BYTE bType)
  193. {
  194. if (test_server)
  195. sys_log(0, "[TEST_SERVER] Attack : %s type %d, MobBattleType %d", GetName(), bType, !GetMobBattleType() ? 0 : GetMobAttackRange());
  196.  
  197. if (!CanMove())
  198. return false;
  199.  
  200. if (!battle_is_attackable(this, pkVictim))
  201. return false;
  202.  
  203. DWORD dwCurrentTime = get_dword_time();
  204.  
  205. if (IsPC())
  206. {
  207. if (IS_SPEED_HACK(this, pkVictim, dwCurrentTime))
  208. return false;
  209.  
  210. if (bType == 0 && dwCurrentTime < GetSkipComboAttackByTime())
  211. return false;
  212. }
  213.  
  214. else
  215. {
  216. MonsterChat(MONSTER_CHAT_ATTACK);
  217. }
  218.  
  219. pkVictim->SetSyncOwner(this);
  220.  
  221. if (pkVictim->CanBeginFight())
  222. pkVictim->BeginFight(this);
  223.  
  224. int iRet;
  225.  
  226. if (bType == 0)
  227. {
  228. switch (GetMobBattleType())
  229. {
  230. case BATTLE_TYPE_MELEE:
  231. case BATTLE_TYPE_POWER:
  232. case BATTLE_TYPE_TANKER:
  233. case BATTLE_TYPE_SUPER_POWER:
  234. case BATTLE_TYPE_SUPER_TANKER:
  235. iRet = battle_melee_attack(this, pkVictim);
  236. break;
  237.  
  238. case BATTLE_TYPE_RANGE:
  239. FlyTarget(pkVictim->GetVID(), pkVictim->GetX(), pkVictim->GetY(), HEADER_CG_FLY_TARGETING);
  240. iRet = Shoot(0) ? BATTLE_DAMAGE : BATTLE_NONE;
  241. break;
  242.  
  243. case BATTLE_TYPE_MAGIC:
  244. FlyTarget(pkVictim->GetVID(), pkVictim->GetX(), pkVictim->GetY(), HEADER_CG_FLY_TARGETING);
  245. iRet = Shoot(1) ? BATTLE_DAMAGE : BATTLE_NONE;
  246. break;
  247.  
  248. default:
  249. sys_err("Unhandled battle type %d", GetMobBattleType());
  250. iRet = BATTLE_NONE;
  251. break;
  252. }
  253. }
  254.  
  255. else
  256. {
  257. if (IsPC() == true)
  258. {
  259. if (dwCurrentTime - m_dwLastSkillTime > 1500)
  260. {
  261. sys_log(1, "HACK: Too long skill using term. Name(%s) PID(%u) delta(%u)", GetName(), GetPlayerID(), (dwCurrentTime - m_dwLastSkillTime));
  262. return false;
  263. }
  264. }
  265.  
  266. sys_log(1, "Attack call ComputeSkill %d %s", bType, pkVictim?pkVictim->GetName():"");
  267. iRet = ComputeSkill(bType, pkVictim);
  268. }
  269.  
  270. if (iRet == BATTLE_DAMAGE || iRet == BATTLE_DEAD)
  271. {
  272. OnMove(true);
  273. pkVictim->OnMove();
  274.  
  275. if (BATTLE_DEAD == iRet && IsPC())
  276. SetVictim(NULL);
  277.  
  278. return true;
  279. }
  280.  
  281. return false;
  282. }
  283.  
  284. void CHARACTER::DeathPenalty(BYTE bTown)
  285. {
  286. sys_log(1, "DEATH_PERNALY_CHECK(%s) town(%d)", GetName(), bTown);
  287.  
  288. Cube_close(this);
  289.  
  290. if (CBattleArena::instance().IsBattleArenaMap(GetMapIndex()) == true)
  291. {
  292. return;
  293. }
  294.  
  295. if (GetLevel() < 10)
  296. {
  297. sys_log(0, "NO_DEATH_PENALTY_LESS_LV10(%s)", GetName());
  298. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("용신의 가호로 경험치가 떨어지지 않았습니다."));
  299.  
  300. return;
  301. }
  302.  
  303. if (number(0, 2))
  304. {
  305. sys_log(0, "NO_DEATH_PENALTY_LUCK(%s)", GetName());
  306. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("용신의 가호로 경험치가 떨어지지 않았습니다."));
  307.  
  308. return;
  309. }
  310.  
  311. if (IS_SET(m_pointsInstant.instant_flag, INSTANT_FLAG_DEATH_PENALTY))
  312. {
  313. REMOVE_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_DEATH_PENALTY);
  314.  
  315. if (!bTown)
  316. {
  317. if (FindAffect(AFFECT_NO_DEATH_PENALTY))
  318. {
  319. sys_log(0, "NO_DEATH_PENALTY_AFFECT(%s)", GetName());
  320. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("용신의 가호로 경험치가 떨어지지 않았습니다."));
  321.  
  322. RemoveAffect(AFFECT_NO_DEATH_PENALTY);
  323.  
  324. return;
  325. }
  326. }
  327.  
  328. int iLoss = ((GetNextExp() * aiExpLossPercents[MINMAX(1, GetLevel(), PLAYER_EXP_TABLE_MAX)]) / 100);
  329. iLoss = MIN(800000, iLoss);
  330.  
  331. if (bTown)
  332. {
  333. iLoss -= iLoss / 3;
  334. }
  335.  
  336. if (IsEquipUniqueItem(UNIQUE_ITEM_TEARDROP_OF_GODNESS))
  337. iLoss /= 2;
  338.  
  339. sys_log(0, "DEATH_PENALTY(%s) EXP_LOSS: %d percent %d%%", GetName(), iLoss, aiExpLossPercents[MIN(gPlayerMaxLevel, GetLevel())]);
  340.  
  341. PointChange(POINT_EXP, -iLoss, true);
  342. }
  343. }
  344.  
  345. bool CHARACTER::IsStun() const
  346. {
  347. if (IS_SET(m_pointsInstant.instant_flag, INSTANT_FLAG_STUN))
  348. return true;
  349.  
  350. return false;
  351. }
  352.  
  353. EVENTFUNC(StunEvent)
  354. {
  355. char_event_info* info = dynamic_cast<char_event_info*>( event->info );
  356.  
  357. if ( info == NULL )
  358. {
  359. sys_err( "StunEvent> <Factor> Null pointer" );
  360. return 0;
  361. }
  362.  
  363. LPCHARACTER ch = info->ch;
  364.  
  365. if (ch == NULL)
  366. {
  367. return 0;
  368. }
  369.  
  370. ch->m_pkStunEvent = NULL;
  371. ch->Dead();
  372.  
  373. return 0;
  374. }
  375.  
  376. void CHARACTER::Stun()
  377. {
  378. if (IsStun())
  379. return;
  380.  
  381. if (IsDead())
  382. return;
  383.  
  384. if (!IsPC() && m_pkParty)
  385. {
  386. m_pkParty->SendMessage(this, PM_ATTACKED_BY, 0, 0);
  387. }
  388.  
  389. sys_log(1, "%s: Stun %p", GetName(), this);
  390.  
  391. PointChange(POINT_HP_RECOVERY, -GetPoint(POINT_HP_RECOVERY));
  392. PointChange(POINT_SP_RECOVERY, -GetPoint(POINT_SP_RECOVERY));
  393.  
  394. CloseMyShop();
  395.  
  396. event_cancel(&m_pkRecoveryEvent);
  397. TPacketGCStun pack;
  398.  
  399. pack.header = HEADER_GC_STUN;
  400. pack.vid = m_vid;
  401.  
  402. PacketAround(&pack, sizeof(pack));
  403.  
  404. SET_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_STUN);
  405.  
  406. if (m_pkStunEvent)
  407. return;
  408.  
  409. char_event_info* info = AllocEventInfo<char_event_info>();
  410.  
  411. info->ch = this;
  412.  
  413. m_pkStunEvent = event_create(StunEvent, info, PASSES_PER_SEC(3));
  414. }
  415.  
  416. EVENTINFO(SCharDeadEventInfo)
  417. {
  418. bool isPC;
  419. uint32_t dwID;
  420.  
  421. SCharDeadEventInfo()
  422. : isPC(0)
  423. , dwID(0)
  424. {
  425. }
  426. };
  427.  
  428. EVENTFUNC(dead_event)
  429. {
  430. const SCharDeadEventInfo* info = dynamic_cast<SCharDeadEventInfo*>(event->info);
  431.  
  432. if ( info == NULL )
  433. {
  434. sys_err( "dead_event> <Factor> Null pointer" );
  435. return 0;
  436. }
  437.  
  438. LPCHARACTER ch = NULL;
  439.  
  440. if (true == info->isPC)
  441. {
  442. ch = CHARACTER_MANAGER::instance().FindByPID( info->dwID );
  443. }
  444.  
  445. else
  446. {
  447. ch = CHARACTER_MANAGER::instance().Find( info->dwID );
  448. }
  449.  
  450. if (NULL == ch)
  451. {
  452. sys_err("DEAD_EVENT: cannot find char pointer with %s id(%d)", info->isPC ? "PC" : "MOB", info->dwID );
  453. return 0;
  454. }
  455.  
  456. ch->m_pkDeadEvent = NULL;
  457.  
  458. if (ch->GetDesc())
  459. {
  460. ch->GetDesc()->SetPhase(PHASE_GAME);
  461.  
  462. ch->SetPosition(POS_STANDING);
  463.  
  464. PIXEL_POSITION pos;
  465.  
  466. if (SECTREE_MANAGER::instance().GetRecallPositionByEmpire(ch->GetMapIndex(), ch->GetEmpire(), pos))
  467. ch->WarpSet(pos.x, pos.y);
  468.  
  469. else
  470. {
  471. sys_err("cannot find spawn position (name %s)", ch->GetName());
  472. ch->WarpSet(EMPIRE_START_X(ch->GetEmpire()), EMPIRE_START_Y(ch->GetEmpire()));
  473. }
  474.  
  475. ch->PointChange(POINT_HP, (ch->GetMaxHP() / 2) - ch->GetHP(), true);
  476.  
  477. ch->DeathPenalty(0);
  478.  
  479. ch->StartRecoveryEvent();
  480.  
  481. ch->ChatPacket(CHAT_TYPE_COMMAND, "CloseRestartWindow");
  482. }
  483.  
  484. else
  485. {
  486. if (ch->IsMonster() == true)
  487. {
  488. if (ch->IsRevive() == false && ch->HasReviverInParty() == true)
  489. {
  490. ch->SetPosition(POS_STANDING);
  491. ch->SetHP(ch->GetMaxHP());
  492.  
  493. ch->ViewReencode();
  494.  
  495. ch->SetAggressive();
  496. ch->SetRevive(true);
  497.  
  498. return 0;
  499. }
  500. }
  501.  
  502. M2_DESTROY_CHARACTER(ch);
  503. }
  504.  
  505. return 0;
  506. }
  507.  
  508. bool CHARACTER::IsDead() const
  509. {
  510. if (m_pointsInstant.position == POS_DEAD)
  511. return true;
  512.  
  513. return false;
  514. }
  515.  
  516. #define GetGoldMultipler() (distribution_test_server ? 3 : 1)
  517.  
  518. void CHARACTER::RewardGold(LPCHARACTER pkAttacker)
  519. {
  520. bool isAutoLoot =
  521. (pkAttacker->GetPremiumRemainSeconds(PREMIUM_AUTOLOOT) > 0 ||
  522. pkAttacker->IsEquipUniqueGroup(UNIQUE_GROUP_AUTOLOOT))
  523. ? true : false;
  524.  
  525. PIXEL_POSITION pos;
  526.  
  527. if (!isAutoLoot)
  528. if (!SECTREE_MANAGER::instance().GetMovablePosition(GetMapIndex(), GetX(), GetY(), pos))
  529. return;
  530.  
  531. int iTotalGold = 0;
  532.  
  533. int iGoldPercent = MobRankStats[GetMobRank()].iGoldPercent;
  534.  
  535. if (pkAttacker->IsPC())
  536. iGoldPercent = iGoldPercent * (100 + CPrivManager::instance().GetPriv(pkAttacker, PRIV_GOLD_DROP)) / 100;
  537.  
  538. if (pkAttacker->GetPoint(POINT_MALL_GOLDBONUS))
  539. iGoldPercent += (iGoldPercent * pkAttacker->GetPoint(POINT_MALL_GOLDBONUS) / 100);
  540.  
  541. iGoldPercent = iGoldPercent * CHARACTER_MANAGER::instance().GetMobGoldDropRate(pkAttacker) / 100;
  542.  
  543. if (pkAttacker->GetPremiumRemainSeconds(PREMIUM_GOLD) > 0 || pkAttacker->IsEquipUniqueGroup(UNIQUE_GROUP_LUCKY_GOLD))
  544. iGoldPercent += iGoldPercent;
  545.  
  546. if (iGoldPercent > 100)
  547. iGoldPercent = 100;
  548.  
  549. int iPercent;
  550.  
  551. if (GetMobRank() >= MOB_RANK_BOSS)
  552. iPercent = ((iGoldPercent * PERCENT_LVDELTA_BOSS(pkAttacker->GetLevel(), GetLevel())) / 100);
  553. else
  554. iPercent = ((iGoldPercent * PERCENT_LVDELTA(pkAttacker->GetLevel(), GetLevel())) / 100);
  555.  
  556. if (number(1, 100) > iPercent)
  557. return;
  558.  
  559. int iGoldMultipler = GetGoldMultipler();
  560.  
  561. if (1 == number(1, 50000))
  562. iGoldMultipler *= 10;
  563.  
  564. else if (1 == number(1, 10000))
  565. iGoldMultipler *= 5;
  566.  
  567. if (pkAttacker->GetPoint(POINT_GOLD_DOUBLE_BONUS))
  568. if (number(1, 100) <= pkAttacker->GetPoint(POINT_GOLD_DOUBLE_BONUS))
  569. iGoldMultipler *= 2;
  570.  
  571. if (test_server)
  572. pkAttacker->ChatPacket(CHAT_TYPE_PARTY, "gold_mul %d rate %d", iGoldMultipler, CHARACTER_MANAGER::instance().GetMobGoldAmountRate(pkAttacker));
  573.  
  574. LPITEM item;
  575.  
  576. int iGold10DropPct = 100;
  577. iGold10DropPct = (iGold10DropPct * 100) / (100 + CPrivManager::instance().GetPriv(pkAttacker, PRIV_GOLD10_DROP));
  578.  
  579. if (GetMobRank() >= MOB_RANK_BOSS && !IsStone() && GetMobTable().dwGoldMax != 0)
  580. {
  581. if (1 == number(1, iGold10DropPct))
  582. iGoldMultipler *= 10;
  583.  
  584. int iSplitCount = number(25, 35);
  585.  
  586. for (int i = 0; i < iSplitCount; ++i)
  587. {
  588. int iGold = number(GetMobTable().dwGoldMin, GetMobTable().dwGoldMax) / iSplitCount;
  589. if (test_server)
  590. sys_log(0, "iGold %d", iGold);
  591. iGold = iGold * CHARACTER_MANAGER::instance().GetMobGoldAmountRate(pkAttacker) / 100;
  592. iGold *= iGoldMultipler;
  593.  
  594. if (iGold == 0)
  595. {
  596. continue ;
  597. }
  598.  
  599. if (test_server)
  600. {
  601. sys_log(0, "Drop Moeny MobGoldAmountRate %d %d", CHARACTER_MANAGER::instance().GetMobGoldAmountRate(pkAttacker), iGoldMultipler);
  602. sys_log(0, "Drop Money gold %d GoldMin %d GoldMax %d", iGold, GetMobTable().dwGoldMax, GetMobTable().dwGoldMax);
  603. }
  604.  
  605. if ((item = ITEM_MANAGER::instance().CreateItem(1, iGold)))
  606. {
  607. pos.x = GetX() + ((number(-14, 14) + number(-14, 14)) * 23);
  608. pos.y = GetY() + ((number(-14, 14) + number(-14, 14)) * 23);
  609.  
  610. item->AddToGround(GetMapIndex(), pos);
  611. item->StartDestroyEvent();
  612.  
  613. iTotalGold += iGold;
  614. }
  615. }
  616. }
  617.  
  618. else if (1 == number(1, iGold10DropPct))
  619. {
  620. for (int i = 0; i < 10; ++i)
  621. {
  622. int iGold = number(GetMobTable().dwGoldMin, GetMobTable().dwGoldMax);
  623. iGold = iGold * CHARACTER_MANAGER::instance().GetMobGoldAmountRate(pkAttacker) / 100;
  624. iGold *= iGoldMultipler;
  625.  
  626. if (iGold == 0)
  627. {
  628. continue;
  629. }
  630.  
  631. if ((item = ITEM_MANAGER::instance().CreateItem(1, iGold)))
  632. {
  633. pos.x = GetX() + (number(-7, 7) * 20);
  634. pos.y = GetY() + (number(-7, 7) * 20);
  635.  
  636. item->AddToGround(GetMapIndex(), pos);
  637. item->StartDestroyEvent();
  638.  
  639. iTotalGold += iGold;
  640. }
  641. }
  642. }
  643.  
  644. else
  645. {
  646. int iGold = number(GetMobTable().dwGoldMin, GetMobTable().dwGoldMax);
  647.  
  648. iGold = iGold * CHARACTER_MANAGER::instance().GetMobGoldAmountRate(pkAttacker) / 100;
  649. iGold *= iGoldMultipler;
  650.  
  651. int iSplitCount;
  652.  
  653. if (iGold >= 3)
  654. iSplitCount = number(1, 3);
  655.  
  656. else if (GetMobRank() >= MOB_RANK_BOSS)
  657. {
  658. iSplitCount = number(3, 10);
  659.  
  660. if ((iGold / iSplitCount) == 0)
  661. iSplitCount = 1;
  662. }
  663.  
  664. else
  665. iSplitCount = 1;
  666.  
  667. if (iGold != 0)
  668. {
  669. iTotalGold += iGold;
  670.  
  671. for (int i = 0; i < iSplitCount; ++i)
  672. {
  673. if (isAutoLoot)
  674. {
  675. pkAttacker->GiveGold(iGold / iSplitCount);
  676. }
  677.  
  678. else if ((item = ITEM_MANAGER::instance().CreateItem(1, iGold / iSplitCount)))
  679. {
  680. pos.x = GetX() + (number(-7, 7) * 20);
  681. pos.y = GetY() + (number(-7, 7) * 20);
  682.  
  683. item->AddToGround(GetMapIndex(), pos);
  684. item->StartDestroyEvent();
  685. }
  686. }
  687. }
  688. }
  689.  
  690. DBManager::instance().SendMoneyLog(MONEY_LOG_MONSTER, GetRaceNum(), iTotalGold);
  691. }
  692.  
  693. void CHARACTER::Reward(bool bItemDrop)
  694. {
  695. if (GetRaceNum() == 5001)
  696. {
  697. PIXEL_POSITION pos;
  698.  
  699. if (!SECTREE_MANAGER::instance().GetMovablePosition(GetMapIndex(), GetX(), GetY(), pos))
  700. return;
  701.  
  702. LPITEM item;
  703. int iGold = number(GetMobTable().dwGoldMin, GetMobTable().dwGoldMax);
  704.  
  705. iGold = iGold * CHARACTER_MANAGER::instance().GetMobGoldAmountRate(NULL) / 100;
  706. iGold *= GetGoldMultipler();
  707.  
  708. int iSplitCount = number(25, 35);
  709.  
  710. sys_log(0, "WAEGU Dead gold %d split %d", iGold, iSplitCount);
  711.  
  712. for (int i = 1; i <= iSplitCount; ++i)
  713. {
  714. if ((item = ITEM_MANAGER::instance().CreateItem(1, iGold / iSplitCount)))
  715. {
  716. if (i != 0)
  717. {
  718. pos.x = number(-7, 7) * 20;
  719. pos.y = number(-7, 7) * 20;
  720.  
  721. pos.x += GetX();
  722. pos.y += GetY();
  723. }
  724.  
  725. item->AddToGround(GetMapIndex(), pos);
  726. item->StartDestroyEvent();
  727. }
  728. }
  729. return;
  730. }
  731.  
  732. LPCHARACTER pkAttacker = DistributeExp();
  733.  
  734. if (!pkAttacker)
  735. return;
  736.  
  737. if (pkAttacker->IsPC())
  738. {
  739. if (GetLevel() - pkAttacker->GetLevel() >= -10)
  740. if (pkAttacker->GetRealAlignment() < 0)
  741. {
  742. if (pkAttacker->IsEquipUniqueItem(UNIQUE_ITEM_FASTER_ALIGNMENT_UP_BY_KILL))
  743. pkAttacker->UpdateAlignment(14);
  744. else
  745. pkAttacker->UpdateAlignment(7);
  746. }
  747. else
  748. pkAttacker->UpdateAlignment(2);
  749.  
  750. pkAttacker->SetQuestNPCID(GetVID());
  751. quest::CQuestManager::instance().Kill(pkAttacker->GetPlayerID(), GetRaceNum());
  752. CHARACTER_MANAGER::instance().KillLog(GetRaceNum());
  753.  
  754. if (!number(0, 9))
  755. {
  756. if (pkAttacker->GetPoint(POINT_KILL_HP_RECOVERY))
  757. {
  758. int iHP = pkAttacker->GetMaxHP() * pkAttacker->GetPoint(POINT_KILL_HP_RECOVERY) / 100;
  759. pkAttacker->PointChange(POINT_HP, iHP);
  760. CreateFly(FLY_HP_SMALL, pkAttacker);
  761. }
  762.  
  763. if (pkAttacker->GetPoint(POINT_KILL_SP_RECOVER))
  764. {
  765. int iSP = pkAttacker->GetMaxSP() * pkAttacker->GetPoint(POINT_KILL_SP_RECOVER) / 100;
  766. pkAttacker->PointChange(POINT_SP, iSP);
  767. CreateFly(FLY_SP_SMALL, pkAttacker);
  768. }
  769. }
  770. }
  771.  
  772. if (!bItemDrop)
  773. return;
  774.  
  775. PIXEL_POSITION pos = GetXYZ();
  776.  
  777. if (!SECTREE_MANAGER::instance().GetMovablePosition(GetMapIndex(), pos.x, pos.y, pos))
  778. return;
  779.  
  780. if (test_server)
  781. sys_log(0, "Drop money : Attacker %s", pkAttacker->GetName());
  782.  
  783. RewardGold(pkAttacker);
  784.  
  785. LPITEM item;
  786.  
  787. static std::vector<LPITEM> s_vec_item;
  788. s_vec_item.clear();
  789.  
  790. if (ITEM_MANAGER::instance().CreateDropItem(this, pkAttacker, s_vec_item))
  791. {
  792. if (s_vec_item.size() == 0);
  793. else if (s_vec_item.size() == 1)
  794. {
  795. item = s_vec_item[0];
  796. item->AddToGround(GetMapIndex(), pos);
  797.  
  798. if (CBattleArena::instance().IsBattleArenaMap(pkAttacker->GetMapIndex()) == false)
  799. {
  800. item->SetOwnership(pkAttacker);
  801. }
  802.  
  803. item->StartDestroyEvent();
  804.  
  805. pos.x = number(-7, 7) * 20;
  806. pos.y = number(-7, 7) * 20;
  807. pos.x += GetX();
  808. pos.y += GetY();
  809.  
  810. sys_log(0, "DROP_ITEM: %s %d %d from %s", item->GetName(), pos.x, pos.y, GetName());
  811. }
  812.  
  813. else
  814. {
  815. int iItemIdx = s_vec_item.size() - 1;
  816.  
  817. std::priority_queue<std::pair<int, LPCHARACTER> > pq;
  818.  
  819. int total_dam = 0;
  820.  
  821. for (TDamageMap::iterator it = m_map_kDamage.begin(); it != m_map_kDamage.end(); ++it)
  822. {
  823. int iDamage = it->second.iTotalDamage;
  824. if (iDamage > 0)
  825. {
  826. LPCHARACTER ch = CHARACTER_MANAGER::instance().Find(it->first);
  827.  
  828. if (ch)
  829. {
  830. pq.push(std::make_pair(iDamage, ch));
  831. total_dam += iDamage;
  832. }
  833. }
  834. }
  835.  
  836. std::vector<LPCHARACTER> v;
  837.  
  838. while (!pq.empty() && pq.top().first * 10 >= total_dam)
  839. {
  840. v.push_back(pq.top().second);
  841. pq.pop();
  842. }
  843.  
  844. if (v.empty())
  845. {
  846. while (iItemIdx >= 0)
  847. {
  848. item = s_vec_item[iItemIdx--];
  849.  
  850. if (!item)
  851. {
  852. sys_err("item null in vector idx %d", iItemIdx + 1);
  853. continue;
  854. }
  855.  
  856. item->AddToGround(GetMapIndex(), pos);
  857. item->StartDestroyEvent();
  858.  
  859. pos.x = number(-7, 7) * 20;
  860. pos.y = number(-7, 7) * 20;
  861. pos.x += GetX();
  862. pos.y += GetY();
  863.  
  864. sys_log(0, "DROP_ITEM: %s %d %d by %s", item->GetName(), pos.x, pos.y, GetName());
  865. }
  866. }
  867.  
  868. else
  869. {
  870. std::vector<LPCHARACTER>::iterator it = v.begin();
  871.  
  872. while (iItemIdx >= 0)
  873. {
  874. item = s_vec_item[iItemIdx--];
  875.  
  876. if (!item)
  877. {
  878. sys_err("item null in vector idx %d", iItemIdx + 1);
  879. continue;
  880. }
  881.  
  882. item->AddToGround(GetMapIndex(), pos);
  883.  
  884. LPCHARACTER ch = *it;
  885.  
  886. if (ch->GetParty())
  887. ch = ch->GetParty()->GetNextOwnership(ch, GetX(), GetY());
  888.  
  889. ++it;
  890.  
  891. if (it == v.end())
  892. it = v.begin();
  893.  
  894. if (CBattleArena::instance().IsBattleArenaMap(ch->GetMapIndex()) == false)
  895. {
  896. item->SetOwnership(ch);
  897. }
  898.  
  899. item->StartDestroyEvent();
  900.  
  901. pos.x = number(-7, 7) * 20;
  902. pos.y = number(-7, 7) * 20;
  903. pos.x += GetX();
  904. pos.y += GetY();
  905.  
  906. sys_log(0, "DROP_ITEM: %s %d %d by %s", item->GetName(), pos.x, pos.y, GetName());
  907. }
  908. }
  909. }
  910. }
  911.  
  912. m_map_kDamage.clear();
  913. }
  914.  
  915. struct TItemDropPenalty
  916. {
  917. int iInventoryPct;
  918. int iInventoryQty;
  919. int iEquipmentPct;
  920. int iEquipmentQty;
  921. };
  922.  
  923. TItemDropPenalty aItemDropPenalty_kor[9] =
  924. {
  925. { 0, 0, 0, 0 },
  926. { 0, 0, 0, 0 },
  927. { 0, 0, 0, 0 },
  928. { 0, 0, 0, 0 },
  929. { 0, 0, 0, 0 },
  930. { 0, 0, 0, 0 },
  931. { 0, 0, 0, 0 },
  932. { 0, 0, 0, 0 },
  933. { 0, 0, 0, 0 },
  934. };
  935.  
  936. void CHARACTER::ItemDropPenalty(LPCHARACTER pkKiller)
  937. {
  938. if (GetMyShop())
  939. return;
  940.  
  941. if (GetLevel() < 50)
  942. return;
  943.  
  944. if (CBattleArena::instance().IsBattleArenaMap(GetMapIndex()) == true)
  945. {
  946. return;
  947. }
  948.  
  949. struct TItemDropPenalty * table = &aItemDropPenalty_kor[0];
  950.  
  951. if (GetLevel() < 10)
  952. return;
  953.  
  954. int iAlignIndex;
  955.  
  956. if (GetRealAlignment() >= 120000)
  957. iAlignIndex = 0;
  958.  
  959. else if (GetRealAlignment() >= 80000)
  960. iAlignIndex = 1;
  961.  
  962. else if (GetRealAlignment() >= 40000)
  963. iAlignIndex = 2;
  964.  
  965. else if (GetRealAlignment() >= 10000)
  966. iAlignIndex = 3;
  967.  
  968. else if (GetRealAlignment() >= 0)
  969. iAlignIndex = 4;
  970.  
  971. else if (GetRealAlignment() > -40000)
  972. iAlignIndex = 5;
  973.  
  974. else if (GetRealAlignment() > -80000)
  975. iAlignIndex = 6;
  976.  
  977. else if (GetRealAlignment() > -120000)
  978. iAlignIndex = 7;
  979.  
  980. else
  981. iAlignIndex = 8;
  982.  
  983. std::vector<std::pair<LPITEM, int> > vec_item;
  984. LPITEM pkItem;
  985.  
  986. int i;
  987. bool isDropAllEquipments = false;
  988.  
  989. TItemDropPenalty & r = table[iAlignIndex];
  990. sys_log(0, "%s align %d inven_pct %d equip_pct %d", GetName(), iAlignIndex, r.iInventoryPct, r.iEquipmentPct);
  991.  
  992. bool bDropInventory = r.iInventoryPct >= number(1, 1000);
  993. bool bDropEquipment = r.iEquipmentPct >= number(1, 100);
  994. bool bDropAntiDropUniqueItem = false;
  995.  
  996. if ((bDropInventory || bDropEquipment) && IsEquipUniqueItem(UNIQUE_ITEM_SKIP_ITEM_DROP_PENALTY))
  997. {
  998. bDropInventory = false;
  999. bDropEquipment = false;
  1000. bDropAntiDropUniqueItem = true;
  1001. }
  1002.  
  1003. #ifdef __INVENTORY_PROTECT_SYSTEM__
  1004. if (GetQuestFlag("abs.INVENTORY_LOCK") == 1)
  1005. {
  1006. bDropInventory = false;
  1007. bDropEquipment = false;
  1008. bDropAntiDropUniqueItem = false;
  1009. }
  1010. #endif
  1011.  
  1012. if (bDropInventory)
  1013. {
  1014. std::vector<BYTE> vec_bSlots;
  1015.  
  1016. for (i = 0; i < INVENTORY_MAX_NUM; ++i)
  1017. if (GetInventoryItem(i))
  1018. vec_bSlots.push_back(i);
  1019.  
  1020. if (!vec_bSlots.empty())
  1021. {
  1022. random_shuffle(vec_bSlots.begin(), vec_bSlots.end());
  1023.  
  1024. int iQty = MIN(vec_bSlots.size(), r.iInventoryQty);
  1025.  
  1026. if (iQty)
  1027. iQty = number(1, iQty);
  1028.  
  1029. for (i = 0; i < iQty; ++i)
  1030. {
  1031. pkItem = GetInventoryItem(vec_bSlots[i]);
  1032.  
  1033. if (IS_SET(pkItem->GetAntiFlag(), ITEM_ANTIFLAG_GIVE | ITEM_ANTIFLAG_PKDROP))
  1034. continue;
  1035.  
  1036. SyncQuickslot(QUICKSLOT_TYPE_ITEM, vec_bSlots[i], 1000);
  1037.  
  1038. vec_item.push_back(std::make_pair(pkItem->RemoveFromCharacter(), INVENTORY));
  1039. }
  1040. }
  1041.  
  1042. else if (iAlignIndex == 8)
  1043. isDropAllEquipments = true;
  1044. }
  1045.  
  1046. if (bDropEquipment)
  1047. {
  1048. std::vector<BYTE> vec_bSlots;
  1049.  
  1050. for (i = 0; i < WEAR_MAX_NUM; ++i)
  1051. if (GetWear(i))
  1052. vec_bSlots.push_back(i);
  1053.  
  1054. if (!vec_bSlots.empty())
  1055. {
  1056. random_shuffle(vec_bSlots.begin(), vec_bSlots.end());
  1057. int iQty;
  1058.  
  1059. if (isDropAllEquipments)
  1060. iQty = vec_bSlots.size();
  1061. else
  1062. iQty = MIN(vec_bSlots.size(), number(1, r.iEquipmentQty));
  1063.  
  1064. if (iQty)
  1065. iQty = number(1, iQty);
  1066.  
  1067. for (i = 0; i < iQty; ++i)
  1068. {
  1069. pkItem = GetWear(vec_bSlots[i]);
  1070.  
  1071. if (IS_SET(pkItem->GetAntiFlag(), ITEM_ANTIFLAG_GIVE | ITEM_ANTIFLAG_PKDROP))
  1072. continue;
  1073.  
  1074. SyncQuickslot(QUICKSLOT_TYPE_ITEM, vec_bSlots[i], 1000);
  1075.  
  1076. vec_item.push_back(std::make_pair(pkItem->RemoveFromCharacter(), EQUIPMENT));
  1077. }
  1078. }
  1079. }
  1080.  
  1081. if (bDropAntiDropUniqueItem)
  1082. {
  1083. LPITEM pkItem;
  1084.  
  1085. pkItem = GetWear(WEAR_UNIQUE1);
  1086.  
  1087. if (pkItem && pkItem->GetVnum() == UNIQUE_ITEM_SKIP_ITEM_DROP_PENALTY)
  1088. {
  1089. SyncQuickslot(QUICKSLOT_TYPE_ITEM, WEAR_UNIQUE1, 1000);
  1090.  
  1091. vec_item.push_back(std::make_pair(pkItem->RemoveFromCharacter(), EQUIPMENT));
  1092. }
  1093.  
  1094. pkItem = GetWear(WEAR_UNIQUE2);
  1095.  
  1096. if (pkItem && pkItem->GetVnum() == UNIQUE_ITEM_SKIP_ITEM_DROP_PENALTY)
  1097. {
  1098. SyncQuickslot(QUICKSLOT_TYPE_ITEM, WEAR_UNIQUE2, 1000);
  1099.  
  1100. vec_item.push_back(std::make_pair(pkItem->RemoveFromCharacter(), EQUIPMENT));
  1101. }
  1102. }
  1103.  
  1104. {
  1105. PIXEL_POSITION pos;
  1106. pos.x = GetX();
  1107. pos.y = GetY();
  1108.  
  1109. unsigned int i;
  1110.  
  1111. for (i = 0; i < vec_item.size(); ++i)
  1112. {
  1113. LPITEM item = vec_item[i].first;
  1114. int window = vec_item[i].second;
  1115.  
  1116. item->AddToGround(GetMapIndex(), pos);
  1117. item->StartDestroyEvent();
  1118.  
  1119. sys_log(0, "DROP_ITEM_PK: %s %d %d from %s", item->GetName(), pos.x, pos.y, GetName());
  1120. LogManager::instance().ItemLog(this, item, "DEAD_DROP", (window == INVENTORY) ? "INVENTORY" : ((window == EQUIPMENT) ? "EQUIPMENT" : ""));
  1121.  
  1122. pos.x = GetX() + number(-7, 7) * 20;
  1123. pos.y = GetY() + number(-7, 7) * 20;
  1124. }
  1125. }
  1126. }
  1127.  
  1128. class FPartyAlignmentCompute
  1129. {
  1130. public:
  1131. FPartyAlignmentCompute(int iAmount, int x, int y)
  1132. {
  1133. m_iAmount = iAmount;
  1134. m_iCount = 0;
  1135. m_iStep = 0;
  1136. m_iKillerX = x;
  1137. m_iKillerY = y;
  1138. }
  1139.  
  1140. void operator () (LPCHARACTER pkChr)
  1141. {
  1142. if (DISTANCE_APPROX(pkChr->GetX() - m_iKillerX, pkChr->GetY() - m_iKillerY) < PARTY_DEFAULT_RANGE)
  1143. {
  1144. if (m_iStep == 0)
  1145. {
  1146. ++m_iCount;
  1147. }
  1148.  
  1149. else
  1150. {
  1151. pkChr->UpdateAlignment(m_iAmount / m_iCount);
  1152. }
  1153. }
  1154. }
  1155.  
  1156. int m_iAmount;
  1157. int m_iCount;
  1158. int m_iStep;
  1159.  
  1160. int m_iKillerX;
  1161. int m_iKillerY;
  1162. };
  1163.  
  1164. void CHARACTER::Dead(LPCHARACTER pkKiller, bool bImmediateDead)
  1165. {
  1166. if (IsDead())
  1167. return;
  1168.  
  1169. {
  1170. if (IsHorseRiding())
  1171. {
  1172. StopRiding();
  1173. }
  1174.  
  1175. else if (GetMountVnum())
  1176. {
  1177. RemoveAffect(AFFECT_MOUNT_BONUS);
  1178. m_dwMountVnum = 0;
  1179. UnEquipSpecialRideUniqueItem();
  1180.  
  1181. UpdatePacket();
  1182. }
  1183. }
  1184.  
  1185. if (!pkKiller && m_dwKillerPID)
  1186. pkKiller = CHARACTER_MANAGER::instance().FindByPID(m_dwKillerPID);
  1187.  
  1188. m_dwKillerPID = 0;
  1189.  
  1190. bool isAgreedPVP = false;
  1191. bool isUnderGuildWar = false;
  1192. bool isDuel = false;
  1193.  
  1194. if (pkKiller && pkKiller->IsPC())
  1195. {
  1196. if (pkKiller->m_pkChrTarget == this)
  1197. pkKiller->SetTarget(NULL);
  1198.  
  1199. if (!IsPC() && pkKiller->GetDungeon())
  1200. pkKiller->GetDungeon()->IncKillCount(pkKiller, this);
  1201.  
  1202. isAgreedPVP = CPVPManager::instance().Dead(this, pkKiller->GetPlayerID());
  1203. isDuel = CArenaManager::instance().OnDead(pkKiller, this);
  1204.  
  1205. if (IsPC())
  1206. {
  1207. CGuild * g1 = GetGuild();
  1208. CGuild * g2 = pkKiller->GetGuild();
  1209.  
  1210. if (g1 && g2)
  1211. if (g1->UnderWar(g2->GetID()))
  1212. isUnderGuildWar = true;
  1213.  
  1214. pkKiller->SetQuestNPCID(GetVID());
  1215. quest::CQuestManager::instance().Kill(pkKiller->GetPlayerID(), quest::QUEST_NO_NPC);
  1216. CGuildManager::instance().Kill(pkKiller, this);
  1217.  
  1218. #if defined(__BL_KILL_BAR__)
  1219. TPacketGCKillBar kb;
  1220.  
  1221. kb.bHeader = HEADER_GC_KILLBAR;
  1222. kb.bKillerRace = static_cast<BYTE>(pkKiller->GetRaceNum());
  1223.  
  1224. LPITEM KillerWeapon = pkKiller->GetWear(WEAR_WEAPON);
  1225.  
  1226. kb.bKillerWeaponType = KillerWeapon ? KillerWeapon->GetSubType() : 255;
  1227. kb.bVictimRace = static_cast<BYTE>(GetRaceNum());
  1228.  
  1229. strlcpy(kb.szKiller, pkKiller->GetName(), sizeof(kb.szKiller));
  1230. strlcpy(kb.szVictim, GetName(), sizeof(kb.szVictim));
  1231.  
  1232. const DESC_MANAGER::DESC_SET& c_set_desc = DESC_MANAGER::instance().GetClientSet();
  1233.  
  1234. for (DESC_MANAGER::DESC_SET::const_iterator it = c_set_desc.begin(); it != c_set_desc.end(); ++it)
  1235. {
  1236. LPDESC d_c = *it;
  1237. if (!d_c)
  1238. continue;
  1239.  
  1240. LPCHARACTER c_c = d_c->GetCharacter();
  1241. if (!c_c)
  1242. continue;
  1243.  
  1244. if (pkKiller->GetMapIndex() != c_c->GetMapIndex())
  1245. continue;
  1246.  
  1247. d_c->Packet(&kb, sizeof(kb));
  1248. }
  1249. #endif
  1250. }
  1251. }
  1252.  
  1253. if (pkKiller && !isAgreedPVP && !isUnderGuildWar && IsPC() && !isDuel)
  1254. {
  1255. if (GetGMLevel() == GM_PLAYER || test_server)
  1256. {
  1257. ItemDropPenalty(pkKiller);
  1258. }
  1259. }
  1260.  
  1261. SetPosition(POS_DEAD);
  1262. ClearAffect(true);
  1263.  
  1264. if (pkKiller && IsPC())
  1265. {
  1266. sys_log(1, "DEAD_BY_PC: %s %p KILLER %s %p", GetName(), this, pkKiller->GetName(), get_pointer(pkKiller));
  1267. REMOVE_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_DEATH_PENALTY);
  1268.  
  1269. if (GetEmpire() != pkKiller->GetEmpire())
  1270. {
  1271. int iEP = MIN(GetPoint(POINT_EMPIRE_POINT), pkKiller->GetPoint(POINT_EMPIRE_POINT));
  1272.  
  1273. PointChange(POINT_EMPIRE_POINT, -(iEP / 10));
  1274. pkKiller->PointChange(POINT_EMPIRE_POINT, iEP / 5);
  1275.  
  1276. if (GetPoint(POINT_EMPIRE_POINT) < 10)
  1277. {
  1278. }
  1279.  
  1280. char buf[256];
  1281. snprintf(buf, sizeof(buf),
  1282. "%d %d %d %s %d %d %d %s",
  1283. GetEmpire(), GetAlignment(), GetPKMode(), GetName(),
  1284. pkKiller->GetEmpire(), pkKiller->GetAlignment(), pkKiller->GetPKMode(), pkKiller->GetName());
  1285.  
  1286. LogManager::instance().CharLog(this, pkKiller->GetPlayerID(), "DEAD_BY_PC", buf);
  1287. }
  1288.  
  1289. else
  1290. {
  1291. if (!isAgreedPVP && !isUnderGuildWar && !IsKillerMode() && GetAlignment() >= 0 && !isDuel)
  1292. {
  1293. int iNoPenaltyProb = 0;
  1294.  
  1295. if (pkKiller->GetAlignment() >= 0)
  1296. iNoPenaltyProb = 33;
  1297. else
  1298. iNoPenaltyProb = 20;
  1299.  
  1300. if (number(1, 100) < iNoPenaltyProb)
  1301. pkKiller->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("용신의 보호로 아이템이 떨어지지 않았습니다."));
  1302.  
  1303. else
  1304. {
  1305. if (pkKiller->GetParty())
  1306. {
  1307. FPartyAlignmentCompute f(-20000, pkKiller->GetX(), pkKiller->GetY());
  1308. pkKiller->GetParty()->ForEachOnlineMember(f);
  1309.  
  1310. if (f.m_iCount == 0)
  1311. pkKiller->UpdateAlignment(-20000);
  1312.  
  1313. else
  1314. {
  1315. sys_log(0, "ALIGNMENT PARTY count %d amount %d", f.m_iCount, f.m_iAmount);
  1316. f.m_iStep = 1;
  1317. pkKiller->GetParty()->ForEachOnlineMember(f);
  1318. }
  1319. }
  1320.  
  1321. else
  1322. pkKiller->UpdateAlignment(-20000);
  1323. }
  1324. }
  1325.  
  1326. char buf[256];
  1327. snprintf(buf, sizeof(buf),
  1328. "%d %d %d %s %d %d %d %s",
  1329. GetEmpire(), GetAlignment(), GetPKMode(), GetName(),
  1330. pkKiller->GetEmpire(), pkKiller->GetAlignment(), pkKiller->GetPKMode(), pkKiller->GetName());
  1331.  
  1332. LogManager::instance().CharLog(this, pkKiller->GetPlayerID(), "DEAD_BY_PC", buf);
  1333. }
  1334. }
  1335.  
  1336. else
  1337. {
  1338. sys_log(1, "DEAD: %s %p", GetName(), this);
  1339. REMOVE_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_DEATH_PENALTY);
  1340. }
  1341.  
  1342. ClearSync();
  1343.  
  1344. event_cancel(&m_pkStunEvent);
  1345.  
  1346. if (IsPC())
  1347. {
  1348. m_dwLastDeadTime = get_dword_time();
  1349. SetKillerMode(false);
  1350. GetDesc()->SetPhase(PHASE_DEAD);
  1351. }
  1352.  
  1353. else
  1354. {
  1355. if (!IS_SET(m_pointsInstant.instant_flag, INSTANT_FLAG_NO_REWARD))
  1356. {
  1357. if (!(pkKiller && pkKiller->IsPC() && pkKiller->GetGuild() && pkKiller->GetGuild()->UnderAnyWar(GUILD_WAR_TYPE_FIELD)))
  1358. {
  1359. if (GetMobTable().dwResurrectionVnum)
  1360. {
  1361. LPCHARACTER chResurrect = CHARACTER_MANAGER::instance().SpawnMob(GetMobTable().dwResurrectionVnum, GetMapIndex(), GetX(), GetY(), GetZ(), true, (int) GetRotation());
  1362. if (GetDungeon() && chResurrect)
  1363. {
  1364. chResurrect->SetDungeon(GetDungeon());
  1365. }
  1366.  
  1367. Reward(false);
  1368. }
  1369.  
  1370. else if (IsRevive() == true)
  1371. {
  1372. Reward(false);
  1373. }
  1374.  
  1375. else
  1376. {
  1377. Reward(true);
  1378. }
  1379. }
  1380.  
  1381. else
  1382. {
  1383. if (pkKiller->m_dwUnderGuildWarInfoMessageTime < get_dword_time())
  1384. {
  1385. pkKiller->m_dwUnderGuildWarInfoMessageTime = get_dword_time() + 60000;
  1386. pkKiller->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드전중에는 사냥에 따른 이익이 없습니다."));
  1387. }
  1388. }
  1389. }
  1390. }
  1391.  
  1392. if (GetMobRank() >= MOB_RANK_BOSS && pkKiller && pkKiller->IsPC())
  1393. {
  1394. char buf[51];
  1395. snprintf(buf, sizeof(buf), "%d %ld", g_bChannel, pkKiller->GetMapIndex());
  1396.  
  1397. if (IsStone())
  1398. LogManager::instance().CharLog(pkKiller, GetRaceNum(), "STONE_KILL", buf);
  1399. else
  1400. LogManager::instance().CharLog(pkKiller, GetRaceNum(), "BOSS_KILL", buf);
  1401. }
  1402.  
  1403. TPacketGCDead pack;
  1404. pack.header = HEADER_GC_DEAD;
  1405. pack.vid = m_vid;
  1406. PacketAround(&pack, sizeof(pack));
  1407.  
  1408. REMOVE_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_STUN);
  1409.  
  1410. if (GetDesc() != NULL)
  1411. {
  1412. itertype(m_list_pkAffect) it = m_list_pkAffect.begin();
  1413.  
  1414. while (it != m_list_pkAffect.end())
  1415. SendAffectAddPacket(GetDesc(), *it++);
  1416. }
  1417.  
  1418. if (isDuel == false)
  1419. {
  1420. if (m_pkDeadEvent)
  1421. {
  1422. sys_log(1, "DEAD_EVENT_CANCEL: %s %p %p", GetName(), this, get_pointer(m_pkDeadEvent));
  1423. event_cancel(&m_pkDeadEvent);
  1424. }
  1425.  
  1426. if (IsStone())
  1427. ClearStone();
  1428.  
  1429. if (GetDungeon())
  1430. {
  1431. GetDungeon()->DeadCharacter(this);
  1432. }
  1433.  
  1434. SCharDeadEventInfo* pEventInfo = AllocEventInfo<SCharDeadEventInfo>();
  1435.  
  1436. if (IsPC())
  1437. {
  1438. pEventInfo->isPC = true;
  1439. pEventInfo->dwID = this->GetPlayerID();
  1440.  
  1441. m_pkDeadEvent = event_create(dead_event, pEventInfo, PASSES_PER_SEC(180));
  1442. }
  1443.  
  1444. else
  1445. {
  1446. pEventInfo->isPC = false;
  1447. pEventInfo->dwID = this->GetVID();
  1448.  
  1449. if (IsRevive() == false && HasReviverInParty() == true)
  1450. {
  1451. m_pkDeadEvent = event_create(dead_event, pEventInfo, bImmediateDead ? 1 : PASSES_PER_SEC(3));
  1452. }
  1453.  
  1454. else
  1455. {
  1456. m_pkDeadEvent = event_create(dead_event, pEventInfo, bImmediateDead ? 1 : PASSES_PER_SEC(10));
  1457. }
  1458. }
  1459.  
  1460. sys_log(1, "DEAD_EVENT_CREATE: %s %p %p", GetName(), this, get_pointer(m_pkDeadEvent));
  1461. }
  1462.  
  1463. if (m_pkExchange != NULL)
  1464. {
  1465. m_pkExchange->Cancel();
  1466. }
  1467.  
  1468. if (IsCubeOpen() == true)
  1469. {
  1470. Cube_close(this);
  1471. }
  1472.  
  1473. CShopManager::instance().StopShopping(this);
  1474. CloseMyShop();
  1475. CloseSafebox();
  1476.  
  1477. if (true == IsMonster() && 2493 == GetMobTable().dwVnum)
  1478. {
  1479. if (NULL != pkKiller && NULL != pkKiller->GetGuild())
  1480. {
  1481. CDragonLairManager::instance().OnDragonDead( this, pkKiller->GetGuild()->GetID() );
  1482. }
  1483.  
  1484. else
  1485. {
  1486. sys_err("DragonLair: Dragon killed by nobody");
  1487. }
  1488. }
  1489. }
  1490.  
  1491. struct FuncSetLastAttacked
  1492. {
  1493. FuncSetLastAttacked(DWORD dwTime) : m_dwTime(dwTime)
  1494. {
  1495. }
  1496.  
  1497. void operator () (LPCHARACTER ch)
  1498. {
  1499. ch->SetLastAttacked(m_dwTime);
  1500. }
  1501.  
  1502. DWORD m_dwTime;
  1503. };
  1504.  
  1505. void CHARACTER::SetLastAttacked(DWORD dwTime)
  1506. {
  1507. assert(m_pkMobInst != NULL);
  1508.  
  1509. m_pkMobInst->m_dwLastAttackedTime = dwTime;
  1510. m_pkMobInst->m_posLastAttacked = GetXYZ();
  1511. }
  1512.  
  1513. void CHARACTER::SendDamagePacket(LPCHARACTER pAttacker, int Damage, BYTE DamageFlag)
  1514. {
  1515. if (IsPC() == true || (pAttacker->IsPC() == true && pAttacker->GetTarget() == this))
  1516. {
  1517. TPacketGCDamageInfo damageInfo;
  1518. memset(&damageInfo, 0, sizeof(TPacketGCDamageInfo));
  1519.  
  1520. damageInfo.header = HEADER_GC_DAMAGE_INFO;
  1521. damageInfo.dwVID = (DWORD)GetVID();
  1522. damageInfo.flag = DamageFlag;
  1523. damageInfo.damage = Damage;
  1524.  
  1525. if (GetDesc() != NULL)
  1526. {
  1527. GetDesc()->Packet(&damageInfo, sizeof(TPacketGCDamageInfo));
  1528. }
  1529.  
  1530. if (pAttacker->GetDesc() != NULL)
  1531. {
  1532. pAttacker->GetDesc()->Packet(&damageInfo, sizeof(TPacketGCDamageInfo));
  1533. }
  1534. /*
  1535. if (GetArenaObserverMode() == false && GetArena() != NULL)
  1536. {
  1537. GetArena()->SendPacketToObserver(&damageInfo, sizeof(TPacketGCDamageInfo));
  1538. }
  1539. */
  1540. }
  1541. }
  1542.  
  1543. bool CHARACTER::Damage(LPCHARACTER pAttacker, int dam, EDamageType type)
  1544. {
  1545. if (DAMAGE_TYPE_MAGIC == type)
  1546. {
  1547. dam = (int)((float)dam * (100 + (pAttacker->GetPoint(POINT_MAGIC_ATT_BONUS_PER) + pAttacker->GetPoint(POINT_MELEE_MAGIC_ATT_BONUS_PER))) / 100.f + 0.5f);
  1548. }
  1549.  
  1550. if (GetRaceNum() == 5001)
  1551. {
  1552. bool bDropMoney = false;
  1553.  
  1554. int iPercent = 0;
  1555. if (GetMaxHP() >= 0)
  1556. iPercent = (GetHP() * 100) / GetMaxHP();
  1557.  
  1558. if (iPercent <= 10 && GetMaxSP() < 5)
  1559. {
  1560. SetMaxSP(5);
  1561. bDropMoney = true;
  1562. }
  1563.  
  1564. else if (iPercent <= 20 && GetMaxSP() < 4)
  1565. {
  1566. SetMaxSP(4);
  1567. bDropMoney = true;
  1568. }
  1569.  
  1570. else if (iPercent <= 40 && GetMaxSP() < 3)
  1571. {
  1572. SetMaxSP(3);
  1573. bDropMoney = true;
  1574. }
  1575.  
  1576. else if (iPercent <= 60 && GetMaxSP() < 2)
  1577. {
  1578. SetMaxSP(2);
  1579. bDropMoney = true;
  1580. }
  1581.  
  1582. else if (iPercent <= 80 && GetMaxSP() < 1)
  1583. {
  1584. SetMaxSP(1);
  1585. bDropMoney = true;
  1586. }
  1587.  
  1588. if (bDropMoney)
  1589. {
  1590. DWORD dwGold = 1000;
  1591. int iSplitCount = number(10, 13);
  1592.  
  1593. sys_log(0, "WAEGU DropGoldOnHit %d times", GetMaxSP());
  1594.  
  1595. for (int i = 1; i <= iSplitCount; ++i)
  1596. {
  1597. PIXEL_POSITION pos;
  1598. LPITEM item;
  1599.  
  1600. if ((item = ITEM_MANAGER::instance().CreateItem(1, dwGold / iSplitCount)))
  1601. {
  1602. if (i != 0)
  1603. {
  1604. pos.x = (number(-14, 14) + number(-14, 14)) * 20;
  1605. pos.y = (number(-14, 14) + number(-14, 14)) * 20;
  1606.  
  1607. pos.x += GetX();
  1608. pos.y += GetY();
  1609. }
  1610.  
  1611. item->AddToGround(GetMapIndex(), pos);
  1612. item->StartDestroyEvent();
  1613. }
  1614. }
  1615. }
  1616. }
  1617.  
  1618. if (type != DAMAGE_TYPE_NORMAL && type != DAMAGE_TYPE_NORMAL_RANGE)
  1619. {
  1620. if (IsAffectFlag(AFF_TERROR))
  1621. {
  1622. int pct = GetSkillPower(SKILL_TERROR) / 400;
  1623.  
  1624. if (number(1, 100) <= pct)
  1625. return false;
  1626. }
  1627. }
  1628.  
  1629. int iCurHP = GetHP();
  1630. int iCurSP = GetSP();
  1631.  
  1632. bool IsCritical = false;
  1633. bool IsPenetrate = false;
  1634. bool IsDeathBlow = false;
  1635.  
  1636. enum DamageFlag
  1637. {
  1638. DAMAGE_NORMAL = (1 << 0),
  1639. DAMAGE_POISON = (1 << 1),
  1640. DAMAGE_DODGE = (1 << 2),
  1641. DAMAGE_BLOCK = (1 << 3),
  1642. DAMAGE_PENETRATE= (1 << 4),
  1643. DAMAGE_CRITICAL = (1 << 5),
  1644. };
  1645.  
  1646. if (type == DAMAGE_TYPE_MELEE || type == DAMAGE_TYPE_RANGE || type == DAMAGE_TYPE_MAGIC)
  1647. {
  1648. if (pAttacker)
  1649. {
  1650. int iCriticalPct = pAttacker->GetPoint(POINT_CRITICAL_PCT);
  1651.  
  1652. if (!IsPC())
  1653. iCriticalPct += pAttacker->GetMarriageBonus(UNIQUE_ITEM_MARRIAGE_CRITICAL_BONUS);
  1654.  
  1655. if (iCriticalPct)
  1656. {
  1657. if (iCriticalPct >= 10)
  1658. iCriticalPct = 5 + (iCriticalPct - 10) / 4;
  1659. else
  1660. iCriticalPct /= 2;
  1661.  
  1662. iCriticalPct -= GetPoint(POINT_RESIST_CRITICAL);
  1663.  
  1664. #ifdef __NEW_DUEL_OPTIONS__
  1665. if (number(1, 100) <= iCriticalPct && !CPVPManager::instance().IsDuelTactic(pAttacker, this))
  1666. #else
  1667. if (number(1, 100) <= iCriticalPct)
  1668. #endif
  1669. {
  1670. IsCritical = true;
  1671. dam *= 2;
  1672. EffectPacket(SE_CRITICAL);
  1673.  
  1674. if (IsAffectFlag(AFF_MANASHIELD))
  1675. {
  1676. RemoveAffect(AFF_MANASHIELD);
  1677. }
  1678. }
  1679. }
  1680.  
  1681. int iPenetratePct = pAttacker->GetPoint(POINT_PENETRATE_PCT);
  1682.  
  1683. if (!IsPC())
  1684. iPenetratePct += pAttacker->GetMarriageBonus(UNIQUE_ITEM_MARRIAGE_PENETRATE_BONUS);
  1685.  
  1686. if (iPenetratePct)
  1687. {
  1688. {
  1689. CSkillProto* pkSk = CSkillManager::instance().Get(SKILL_RESIST_PENETRATE);
  1690.  
  1691. if (NULL != pkSk)
  1692. {
  1693. pkSk->SetPointVar("k", 1.0f * GetSkillPower(SKILL_RESIST_PENETRATE) / 100.0f);
  1694.  
  1695. iPenetratePct -= static_cast<int>(pkSk->kPointPoly.Eval());
  1696. }
  1697. }
  1698.  
  1699. if (iPenetratePct >= 10)
  1700. {
  1701. iPenetratePct = 5 + (iPenetratePct - 10) / 4;
  1702. }
  1703.  
  1704. else
  1705. {
  1706. iPenetratePct /= 2;
  1707. }
  1708.  
  1709. iPenetratePct -= GetPoint(POINT_RESIST_PENETRATE);
  1710.  
  1711. #ifdef __NEW_DUEL_OPTIONS__
  1712. if (number(1, 100) <= iPenetratePct && !CPVPManager::instance().IsDuelTactic(pAttacker, this) && !CPVPManager::instance().IsDuelGerman(pAttacker, this))
  1713. #else
  1714. if (number(1, 100) <= iPenetratePct)
  1715. #endif
  1716. {
  1717. IsPenetrate = true;
  1718.  
  1719. if (test_server)
  1720. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("관통 추가 데미지 %d"), GetPoint(POINT_DEF_GRADE) * (100 + GetPoint(POINT_DEF_BONUS)) / 100);
  1721.  
  1722. dam += GetPoint(POINT_DEF_GRADE) * (100 + GetPoint(POINT_DEF_BONUS)) / 100;
  1723.  
  1724. if (IsAffectFlag(AFF_MANASHIELD))
  1725. {
  1726. RemoveAffect(AFF_MANASHIELD);
  1727. }
  1728. }
  1729. }
  1730. }
  1731. }
  1732.  
  1733. else if (type == DAMAGE_TYPE_NORMAL || type == DAMAGE_TYPE_NORMAL_RANGE)
  1734. {
  1735. if (type == DAMAGE_TYPE_NORMAL)
  1736. {
  1737. #ifdef __NEW_DUEL_OPTIONS__
  1738. if (GetPoint(POINT_BLOCK) && number(1, 100) <= GetPoint(POINT_BLOCK) && !CPVPManager::instance().IsDuelTactic(pAttacker, this) && !CPVPManager::instance().IsDuelGerman(pAttacker, this))
  1739. #else
  1740. if (GetPoint(POINT_BLOCK) && number(1, 100) <= GetPoint(POINT_BLOCK))
  1741. #endif
  1742. {
  1743. if (test_server)
  1744. {
  1745. pAttacker->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s 블럭! (%d%%)"), GetName(), GetPoint(POINT_BLOCK));
  1746. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s 블럭! (%d%%)"), GetName(), GetPoint(POINT_BLOCK));
  1747. }
  1748.  
  1749. SendDamagePacket(pAttacker, 0, DAMAGE_BLOCK);
  1750.  
  1751. return false;
  1752. }
  1753. }
  1754.  
  1755. else if (type == DAMAGE_TYPE_NORMAL_RANGE)
  1756. {
  1757.  
  1758. #ifdef __NEW_DUEL_OPTIONS__
  1759. if (GetPoint(POINT_DODGE) && number(1, 100) <= GetPoint(POINT_DODGE) && !CPVPManager::instance().IsDuelTactic(pAttacker, this) && !CPVPManager::instance().IsDuelGerman(pAttacker, this))
  1760. #else
  1761. if (GetPoint(POINT_DODGE) && number(1, 100) <= GetPoint(POINT_DODGE))
  1762. #endif
  1763. {
  1764. if (test_server)
  1765. {
  1766. pAttacker->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s 회피! (%d%%)"), GetName(), GetPoint(POINT_DODGE));
  1767. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s 회피! (%d%%)"), GetName(), GetPoint(POINT_DODGE));
  1768. }
  1769.  
  1770. SendDamagePacket(pAttacker, 0, DAMAGE_DODGE);
  1771.  
  1772. return false;
  1773. }
  1774. }
  1775.  
  1776. if (IsAffectFlag(AFF_JEONGWIHON))
  1777. dam = (int) (dam * (100 + GetSkillPower(SKILL_JEONGWI) * 25 / 100) / 100);
  1778.  
  1779. if (IsAffectFlag(AFF_TERROR))
  1780. dam = (int) (dam * (95 - GetSkillPower(SKILL_TERROR) / 5) / 100);
  1781.  
  1782. if (IsAffectFlag(AFF_HOSIN))
  1783. dam = dam * (100 - GetPoint(POINT_RESIST_NORMAL_DAMAGE)) / 100;
  1784.  
  1785. if (pAttacker)
  1786. {
  1787. if (type == DAMAGE_TYPE_NORMAL)
  1788. {
  1789. #ifdef __NEW_DUEL_OPTIONS__
  1790. if (!CPVPManager::instance().IsDuelTactic(pAttacker, this) && !CPVPManager::instance().IsDuelGerman(pAttacker, this))
  1791. {
  1792. if (GetPoint(POINT_REFLECT_MELEE))
  1793. {
  1794. int reflectDamage = dam * GetPoint(POINT_REFLECT_MELEE) / 100;
  1795.  
  1796. if (pAttacker->IsImmune(IMMUNE_REFLECT))
  1797. reflectDamage = int(reflectDamage / 3.0f + 0.5f);
  1798.  
  1799. pAttacker->Damage(this, reflectDamage, DAMAGE_TYPE_SPECIAL);
  1800. }
  1801. }
  1802. #else
  1803. if (GetPoint(POINT_REFLECT_MELEE))
  1804. {
  1805. int reflectDamage = dam * GetPoint(POINT_REFLECT_MELEE) / 100;
  1806.  
  1807. if (pAttacker->IsImmune(IMMUNE_REFLECT))
  1808. reflectDamage = int(reflectDamage / 3.0f + 0.5f);
  1809.  
  1810. pAttacker->Damage(this, reflectDamage, DAMAGE_TYPE_SPECIAL);
  1811. }
  1812. #endif
  1813. }
  1814.  
  1815. int iCriticalPct = pAttacker->GetPoint(POINT_CRITICAL_PCT);
  1816.  
  1817. if (!IsPC())
  1818. iCriticalPct += pAttacker->GetMarriageBonus(UNIQUE_ITEM_MARRIAGE_CRITICAL_BONUS);
  1819.  
  1820. if (iCriticalPct)
  1821. {
  1822. iCriticalPct -= GetPoint(POINT_RESIST_CRITICAL);
  1823.  
  1824. #ifdef __NEW_DUEL_OPTIONS__
  1825. if (number(1, 100) <= iCriticalPct && !CPVPManager::instance().IsDuelTactic(pAttacker, this))
  1826. #else
  1827. if (number(1, 100) <= iCriticalPct)
  1828. #endif
  1829. {
  1830. IsCritical = true;
  1831. dam *= 2;
  1832. EffectPacket(SE_CRITICAL);
  1833. }
  1834. }
  1835.  
  1836. int iPenetratePct = pAttacker->GetPoint(POINT_PENETRATE_PCT);
  1837.  
  1838. if (!IsPC())
  1839. iPenetratePct += pAttacker->GetMarriageBonus(UNIQUE_ITEM_MARRIAGE_PENETRATE_BONUS);
  1840.  
  1841. {
  1842. CSkillProto* pkSk = CSkillManager::instance().Get(SKILL_RESIST_PENETRATE);
  1843.  
  1844. if (NULL != pkSk)
  1845. {
  1846. pkSk->SetPointVar("k", 1.0f * GetSkillPower(SKILL_RESIST_PENETRATE) / 100.0f);
  1847.  
  1848. iPenetratePct -= static_cast<int>(pkSk->kPointPoly.Eval());
  1849. }
  1850. }
  1851.  
  1852.  
  1853. if (iPenetratePct)
  1854. {
  1855.  
  1856. iPenetratePct -= GetPoint(POINT_RESIST_PENETRATE);
  1857.  
  1858. #ifdef __NEW_DUEL_OPTIONS__
  1859. if (number(1, 100) <= iPenetratePct && !CPVPManager::instance().IsDuelTactic(pAttacker, this) && !CPVPManager::instance().IsDuelGerman(pAttacker, this))
  1860. #else
  1861. if (number(1, 100) <= iPenetratePct)
  1862. #endif
  1863. {
  1864. IsPenetrate = true;
  1865.  
  1866. if (test_server)
  1867. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("관통 추가 데미지 %d"), GetPoint(POINT_DEF_GRADE) * (100 + GetPoint(POINT_DEF_BONUS)) / 100);
  1868.  
  1869. dam += GetPoint(POINT_DEF_GRADE) * (100 + GetPoint(POINT_DEF_BONUS)) / 100;
  1870. }
  1871. }
  1872.  
  1873. #ifdef __NEW_DUEL_OPTIONS__
  1874. if ((!CPVPManager::instance().IsDuelTactic(pAttacker, this)) && (!CPVPManager::instance().IsDuelGerman(pAttacker, this)))
  1875. {
  1876. if (pAttacker->GetPoint(POINT_STEAL_HP))
  1877. {
  1878. int pct = 1;
  1879.  
  1880. if (number(1, 10) <= pct)
  1881. {
  1882. int iHP = MIN(dam, MAX(0, iCurHP)) * pAttacker->GetPoint(POINT_STEAL_HP) / 100;
  1883.  
  1884. if (iHP > 0 && GetHP() >= iHP)
  1885. {
  1886. CreateFly(FLY_HP_SMALL, pAttacker);
  1887. pAttacker->PointChange(POINT_HP, iHP);
  1888. PointChange(POINT_HP, -iHP);
  1889. }
  1890. }
  1891. }
  1892.  
  1893. if (pAttacker->GetPoint(POINT_STEAL_SP))
  1894. {
  1895. int pct = 1;
  1896.  
  1897. if (number(1, 10) <= pct)
  1898. {
  1899. int iCur;
  1900.  
  1901. if (IsPC())
  1902. iCur = iCurSP;
  1903. else
  1904. iCur = iCurHP;
  1905.  
  1906. int iSP = MIN(dam, MAX(0, iCur)) * pAttacker->GetPoint(POINT_STEAL_SP) / 100;
  1907.  
  1908. if (iSP > 0 && iCur >= iSP)
  1909. {
  1910. CreateFly(FLY_SP_SMALL, pAttacker);
  1911. pAttacker->PointChange(POINT_SP, iSP);
  1912.  
  1913. if (IsPC())
  1914. PointChange(POINT_SP, -iSP);
  1915. }
  1916. }
  1917. }
  1918. }
  1919. #else
  1920. if (pAttacker->GetPoint(POINT_STEAL_HP))
  1921. {
  1922. int pct = 1;
  1923.  
  1924. if (number(1, 10) <= pct)
  1925. {
  1926. int iHP = MIN(dam, MAX(0, iCurHP)) * pAttacker->GetPoint(POINT_STEAL_HP) / 100;
  1927.  
  1928. if (iHP > 0 && GetHP() >= iHP)
  1929. {
  1930. CreateFly(FLY_HP_SMALL, pAttacker);
  1931. pAttacker->PointChange(POINT_HP, iHP);
  1932. PointChange(POINT_HP, -iHP);
  1933. }
  1934. }
  1935. }
  1936.  
  1937. if (pAttacker->GetPoint(POINT_STEAL_SP))
  1938. {
  1939. int pct = 1;
  1940.  
  1941. if (number(1, 10) <= pct)
  1942. {
  1943. int iCur;
  1944.  
  1945. if (IsPC())
  1946. iCur = iCurSP;
  1947. else
  1948. iCur = iCurHP;
  1949.  
  1950. int iSP = MIN(dam, MAX(0, iCur)) * pAttacker->GetPoint(POINT_STEAL_SP) / 100;
  1951.  
  1952. if (iSP > 0 && iCur >= iSP)
  1953. {
  1954. CreateFly(FLY_SP_SMALL, pAttacker);
  1955. pAttacker->PointChange(POINT_SP, iSP);
  1956.  
  1957. if (IsPC())
  1958. PointChange(POINT_SP, -iSP);
  1959. }
  1960. }
  1961. }
  1962. #endif
  1963. if (pAttacker->GetPoint(POINT_STEAL_GOLD))
  1964. {
  1965. if (number(1, 100) <= pAttacker->GetPoint(POINT_STEAL_GOLD))
  1966. {
  1967. int iAmount = number(1, GetLevel());
  1968. pAttacker->PointChange(POINT_GOLD, iAmount);
  1969. DBManager::instance().SendMoneyLog(MONEY_LOG_MISC, 1, iAmount);
  1970. }
  1971. }
  1972.  
  1973. #ifdef __NEW_DUEL_OPTIONS__
  1974. if ((!CPVPManager::instance().IsDuelTactic(pAttacker, this)) && (!CPVPManager::instance().IsDuelGerman(pAttacker, this)))
  1975. {
  1976. if (pAttacker->GetPoint(POINT_HIT_HP_RECOVERY) && number(0, 4) > 0)
  1977. {
  1978. int i = ((iCurHP>=0)?MIN(dam, iCurHP):dam) * pAttacker->GetPoint(POINT_HIT_HP_RECOVERY) / 100;
  1979.  
  1980. if (i)
  1981. {
  1982. CreateFly(FLY_HP_SMALL, pAttacker);
  1983. pAttacker->PointChange(POINT_HP, i);
  1984. }
  1985. }
  1986.  
  1987. if (pAttacker->GetPoint(POINT_HIT_SP_RECOVERY) && number(0, 4) > 0)
  1988. {
  1989. int i = ((iCurHP>=0)?MIN(dam, iCurHP):dam) * pAttacker->GetPoint(POINT_HIT_SP_RECOVERY) / 100;
  1990.  
  1991. if (i)
  1992. {
  1993. CreateFly(FLY_SP_SMALL, pAttacker);
  1994. pAttacker->PointChange(POINT_SP, i);
  1995. }
  1996. }
  1997. }
  1998. #else
  1999. if (pAttacker->GetPoint(POINT_HIT_HP_RECOVERY) && number(0, 4) > 0)
  2000. {
  2001. int i = ((iCurHP>=0)?MIN(dam, iCurHP):dam) * pAttacker->GetPoint(POINT_HIT_HP_RECOVERY) / 100;
  2002.  
  2003. if (i)
  2004. {
  2005. CreateFly(FLY_HP_SMALL, pAttacker);
  2006. pAttacker->PointChange(POINT_HP, i);
  2007. }
  2008. }
  2009.  
  2010. if (pAttacker->GetPoint(POINT_HIT_SP_RECOVERY) && number(0, 4) > 0)
  2011. {
  2012. int i = ((iCurHP>=0)?MIN(dam, iCurHP):dam) * pAttacker->GetPoint(POINT_HIT_SP_RECOVERY) / 100;
  2013.  
  2014. if (i)
  2015. {
  2016. CreateFly(FLY_SP_SMALL, pAttacker);
  2017. pAttacker->PointChange(POINT_SP, i);
  2018. }
  2019. }
  2020. #endif
  2021. if (pAttacker->GetPoint(POINT_MANA_BURN_PCT))
  2022. {
  2023. if (number(1, 100) <= pAttacker->GetPoint(POINT_MANA_BURN_PCT))
  2024. PointChange(POINT_SP, -50);
  2025. }
  2026. }
  2027. }
  2028.  
  2029. switch (type)
  2030. {
  2031. case DAMAGE_TYPE_NORMAL:
  2032. case DAMAGE_TYPE_NORMAL_RANGE:
  2033. if (pAttacker)
  2034. #ifdef __NEW_DUEL_OPTIONS__
  2035. if (!CPVPManager::instance().IsDuelTactic(pAttacker, this) && !CPVPManager::instance().IsDuelGerman(pAttacker, this))
  2036. {
  2037. if (pAttacker->GetPoint(POINT_NORMAL_HIT_DAMAGE_BONUS))
  2038. dam = dam * (100 + pAttacker->GetPoint(POINT_NORMAL_HIT_DAMAGE_BONUS)) / 100;
  2039. }
  2040.  
  2041. if ((!CPVPManager::instance().IsDuelTactic(pAttacker, this)) && (!CPVPManager::instance().IsDuelGerman(pAttacker, this)))
  2042. dam = dam * (100 - MIN(99, GetPoint(POINT_NORMAL_HIT_DEFEND_BONUS))) / 100;
  2043. #else
  2044. if (pAttacker->GetPoint(POINT_NORMAL_HIT_DAMAGE_BONUS))
  2045. dam = dam * (100 + pAttacker->GetPoint(POINT_NORMAL_HIT_DAMAGE_BONUS)) / 100;
  2046.  
  2047. dam = dam * (100 - MIN(99, GetPoint(POINT_NORMAL_HIT_DEFEND_BONUS))) / 100;
  2048. #endif
  2049. break;
  2050.  
  2051. case DAMAGE_TYPE_MELEE:
  2052. case DAMAGE_TYPE_RANGE:
  2053. case DAMAGE_TYPE_FIRE:
  2054. case DAMAGE_TYPE_ELEC:
  2055. case DAMAGE_TYPE_MAGIC:
  2056. if (pAttacker)
  2057. #ifdef __NEW_DUEL_OPTIONS__
  2058. if ((!CPVPManager::instance().IsDuelTactic(pAttacker, this)) && (!CPVPManager::instance().IsDuelGerman(pAttacker, this)))
  2059. {
  2060. if (pAttacker->GetPoint(POINT_SKILL_DAMAGE_BONUS))
  2061. dam = dam * (100 + pAttacker->GetPoint(POINT_SKILL_DAMAGE_BONUS)) / 100;
  2062. }
  2063.  
  2064. if ((!CPVPManager::instance().IsDuelTactic(pAttacker, this)) && (!CPVPManager::instance().IsDuelGerman(pAttacker, this)))
  2065. dam = dam * (100 - MIN(99, GetPoint(POINT_SKILL_DEFEND_BONUS))) / 100;
  2066. #else
  2067. if (pAttacker->GetPoint(POINT_SKILL_DAMAGE_BONUS))
  2068. dam = dam * (100 + pAttacker->GetPoint(POINT_SKILL_DAMAGE_BONUS)) / 100;
  2069.  
  2070. dam = dam * (100 - MIN(99, GetPoint(POINT_SKILL_DEFEND_BONUS))) / 100;
  2071. #endif
  2072. break;
  2073.  
  2074. default:
  2075. break;
  2076. }
  2077.  
  2078. #ifdef __NEW_DUEL_OPTIONS__
  2079. if (!CPVPManager::instance().IsDuelTactic(pAttacker, this) && !CPVPManager::instance().IsDuelGerman(pAttacker, this))
  2080. {
  2081. if (IsAffectFlag(AFF_MANASHIELD))
  2082. {
  2083. int iDamageSPPart = dam / 5.5;
  2084. int iDamageToSP = iDamageSPPart * GetPoint(POINT_MANASHIELD) / 100;
  2085. int iSP = GetSP();
  2086.  
  2087. if (iDamageToSP <= iSP)
  2088. {
  2089. PointChange(POINT_SP, -iDamageToSP);
  2090. dam -= iDamageSPPart;
  2091. }
  2092.  
  2093. else
  2094. {
  2095. PointChange(POINT_SP, -GetSP());
  2096. dam -= iSP * 100 / MAX(GetPoint(POINT_MANASHIELD), 1);
  2097. }
  2098. }
  2099. }
  2100. #else
  2101. if (IsAffectFlag(AFF_MANASHIELD))
  2102. {
  2103. int iDamageSPPart = dam / 3;
  2104. int iDamageToSP = iDamageSPPart * GetPoint(POINT_MANASHIELD) / 100;
  2105. int iSP = GetSP();
  2106.  
  2107. if (iDamageToSP <= iSP)
  2108. {
  2109. PointChange(POINT_SP, -iDamageToSP);
  2110. dam -= iDamageSPPart;
  2111. }
  2112.  
  2113. else
  2114. {
  2115. PointChange(POINT_SP, -GetSP());
  2116. dam -= iSP * 100 / MAX(GetPoint(POINT_MANASHIELD), 1);
  2117. }
  2118. }
  2119. #endif
  2120.  
  2121. if (GetPoint(POINT_MALL_DEFBONUS) > 0)
  2122. {
  2123. int dec_dam = MIN(200, dam * GetPoint(POINT_MALL_DEFBONUS) / 100);
  2124. dam -= dec_dam;
  2125. }
  2126.  
  2127. if (pAttacker)
  2128. {
  2129. if (pAttacker->GetPoint(POINT_MALL_ATTBONUS) > 0)
  2130. {
  2131. int add_dam = MIN(300, dam * pAttacker->GetLimitPoint(POINT_MALL_ATTBONUS) / 100);
  2132. dam += add_dam;
  2133. }
  2134.  
  2135. int iEmpire = GetEmpire();
  2136. long lMapIndex = GetMapIndex();
  2137. int iMapEmpire = SECTREE_MANAGER::instance().GetEmpireFromMapIndex(lMapIndex);
  2138.  
  2139. if (pAttacker->IsPC())
  2140. {
  2141. iEmpire = pAttacker->GetEmpire();
  2142. lMapIndex = pAttacker->GetMapIndex();
  2143. iMapEmpire = SECTREE_MANAGER::instance().GetEmpireFromMapIndex(lMapIndex);
  2144.  
  2145. if (iEmpire && iMapEmpire && iEmpire != iMapEmpire)
  2146. {
  2147. int percent = 9;
  2148. dam = dam * percent / 10;
  2149. }
  2150.  
  2151. if (!IsPC() && GetMonsterDrainSPPoint())
  2152. {
  2153. int iDrain = GetMonsterDrainSPPoint();
  2154.  
  2155. if (iDrain <= pAttacker->GetSP())
  2156. pAttacker->PointChange(POINT_SP, -iDrain);
  2157.  
  2158. else
  2159. {
  2160. int iSP = pAttacker->GetSP();
  2161. pAttacker->PointChange(POINT_SP, -iSP);
  2162. }
  2163. }
  2164.  
  2165. }
  2166.  
  2167. else if (pAttacker->IsGuardNPC())
  2168. {
  2169. SET_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_NO_REWARD);
  2170. Stun();
  2171.  
  2172. return true;
  2173. }
  2174. }
  2175.  
  2176. if (!GetSectree() || GetSectree()->IsAttr(GetX(), GetY(), ATTR_BANPK))
  2177. return false;
  2178.  
  2179. if (!IsPC())
  2180. {
  2181. if (m_pkParty && m_pkParty->GetLeader())
  2182. m_pkParty->GetLeader()->SetLastAttacked(get_dword_time());
  2183. else
  2184. SetLastAttacked(get_dword_time());
  2185.  
  2186. MonsterChat(MONSTER_CHAT_ATTACKED);
  2187. }
  2188.  
  2189. if (IsStun())
  2190. {
  2191. Dead(pAttacker);
  2192. return true;
  2193. }
  2194.  
  2195. if (IsDead())
  2196. return true;
  2197.  
  2198. if (type == DAMAGE_TYPE_POISON)
  2199. {
  2200. if (GetHP() - dam <= 0)
  2201. {
  2202. dam = GetHP() - 1;
  2203. }
  2204. }
  2205.  
  2206. if (IsMonster() && IsStoneSkinner())
  2207. {
  2208. if (GetHPPct() < GetMobTable().bStoneSkinPoint)
  2209. dam /= 2;
  2210. }
  2211.  
  2212. if (pAttacker)
  2213. {
  2214. if (pAttacker->IsMonster() && pAttacker->IsDeathBlower())
  2215. {
  2216. if (pAttacker->IsDeathBlow())
  2217. {
  2218. if (number(1, 4) == GetJob())
  2219. {
  2220. IsDeathBlow = true;
  2221. dam = dam * 4;
  2222. }
  2223. }
  2224. }
  2225.  
  2226. dam = BlueDragon_Damage(this, pAttacker, dam);
  2227.  
  2228. BYTE damageFlag = 0;
  2229.  
  2230. if (type == DAMAGE_TYPE_POISON)
  2231. damageFlag = DAMAGE_POISON;
  2232. else
  2233. damageFlag = DAMAGE_NORMAL;
  2234.  
  2235. if (IsCritical == true)
  2236. damageFlag |= DAMAGE_CRITICAL;
  2237.  
  2238. if (IsPenetrate == true)
  2239. damageFlag |= DAMAGE_PENETRATE;
  2240.  
  2241. float damMul = this->GetDamMul();
  2242. float tempDam = dam;
  2243.  
  2244. dam = tempDam * damMul + 0.5f;
  2245.  
  2246. #ifdef ENABLE_DAMAGE_TOP
  2247. if((damageFlag == DAMAGE_NORMAL || damageFlag & DAMAGE_CRITICAL || damageFlag & DAMAGE_PENETRATE) && type != DAMAGE_TYPE_SPECIAL)
  2248. {
  2249. if(type == DAMAGE_TYPE_MELEE || type == DAMAGE_TYPE_RANGE || type == DAMAGE_TYPE_MAGIC)
  2250. {
  2251. CDamageTop::instance().RegisterSkillDamage(this, pAttacker, dam);
  2252. }
  2253.  
  2254. else
  2255. {
  2256. CDamageTop::instance().RegisterHitDamage(this, pAttacker, dam);
  2257. }
  2258. }
  2259. #endif
  2260. if (pAttacker)
  2261. SendDamagePacket(pAttacker, dam, damageFlag);
  2262.  
  2263. if (test_server)
  2264. {
  2265. int iTmpPercent = 0;
  2266. if (GetMaxHP() >= 0)
  2267. iTmpPercent = (GetHP() * 100) / GetMaxHP();
  2268.  
  2269. if(pAttacker)
  2270. {
  2271. pAttacker->ChatPacket(CHAT_TYPE_INFO, "-> %s, DAM %d HP %d(%d%%) %s%s",
  2272. GetName(),
  2273. dam,
  2274. GetHP(),
  2275. (GetHP() * 100) / GetMaxHP(),
  2276. IsCritical ? "crit " : "",
  2277. IsPenetrate ? "pene " : "",
  2278. IsDeathBlow ? "deathblow " : "");
  2279. }
  2280.  
  2281. ChatPacket(CHAT_TYPE_PARTY, "<- %s, DAM %d HP %d(%d%%) %s%s",
  2282. pAttacker ? pAttacker->GetName() : 0,
  2283. dam,
  2284. GetHP(),
  2285. (GetHP() * 100) / GetMaxHP(),
  2286. IsCritical ? "crit " : "",
  2287. IsPenetrate ? "pene " : "",
  2288. IsDeathBlow ? "deathblow " : "");
  2289. }
  2290.  
  2291. if (m_bDetailLog)
  2292. {
  2293. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s[%d]가 공격 위치: %d %d"), pAttacker->GetName(), (DWORD) pAttacker->GetVID(), pAttacker->GetX(), pAttacker->GetY());
  2294. }
  2295. }
  2296.  
  2297. #ifdef ENABLE_WAR_BOARD
  2298. if (pAttacker)
  2299. {
  2300. CWarMap * pWarMap = pAttacker->GetWarMap();
  2301.  
  2302. if (pWarMap && pWarMap == GetWarMap())
  2303. {
  2304. CWarMap::TMemberStats * pStats = pWarMap->GetMemberStats(pAttacker);
  2305. pStats->ullDamage += (unsigned long long) dam;
  2306. pWarMap->SendStats(pStats);
  2307. }
  2308. }
  2309. #endif
  2310.  
  2311. if (!cannot_dead)
  2312. {
  2313. if (GetHP() - dam <= 0)
  2314. dam = GetHP();
  2315.  
  2316. PointChange(POINT_HP, -dam, false);
  2317. }
  2318.  
  2319. if (pAttacker && dam > 0 && IsNPC())
  2320. {
  2321. TDamageMap::iterator it = m_map_kDamage.find(pAttacker->GetVID());
  2322.  
  2323. if (it == m_map_kDamage.end())
  2324. {
  2325. m_map_kDamage.insert(TDamageMap::value_type(pAttacker->GetVID(), TBattleInfo(dam, 0)));
  2326. it = m_map_kDamage.find(pAttacker->GetVID());
  2327. }
  2328.  
  2329. else
  2330. {
  2331. it->second.iTotalDamage += dam;
  2332. }
  2333.  
  2334. StartRecoveryEvent();
  2335.  
  2336. UpdateAggrPointEx(pAttacker, type, dam, it->second);
  2337. }
  2338.  
  2339. if (GetHP() <= 0)
  2340. {
  2341. Stun();
  2342.  
  2343. if (pAttacker && !pAttacker->IsNPC())
  2344. m_dwKillerPID = pAttacker->GetPlayerID();
  2345. else
  2346. m_dwKillerPID = 0;
  2347. }
  2348.  
  2349. return false;
  2350. }
  2351.  
  2352. void CHARACTER::DistributeHP(LPCHARACTER pkKiller)
  2353. {
  2354. if (pkKiller->GetDungeon())
  2355. return;
  2356. }
  2357.  
  2358. #define NEW_GET_LVDELTA(me, victim) aiPercentByDeltaLev[MINMAX(0, (victim + 15) - me, MAX_EXP_DELTA_OF_LEV - 1)]
  2359. typedef long double rate_t;
  2360. static void GiveExp(LPCHARACTER from, LPCHARACTER to, int iExp)
  2361. {
  2362. if (test_server && iExp < 0)
  2363. {
  2364. to->ChatPacket(CHAT_TYPE_INFO, "exp(%d) overflow", iExp);
  2365. return;
  2366. }
  2367.  
  2368. rate_t lvFactor = static_cast<rate_t>(NEW_GET_LVDELTA(to->GetLevel(), from->GetLevel())) / 100.0L;
  2369. iExp *= lvFactor;
  2370.  
  2371. int iBaseExp = iExp;
  2372. rate_t rateFactor = 100;
  2373.  
  2374. if (distribution_test_server)
  2375. rateFactor *= 3;
  2376.  
  2377. rateFactor += CPrivManager::instance().GetPriv(to, PRIV_EXP_PCT);
  2378.  
  2379. if (to->IsEquipUniqueItem(UNIQUE_ITEM_LARBOR_MEDAL))
  2380. rateFactor += 20;
  2381.  
  2382. if (to->GetMapIndex() >= 660000 && to->GetMapIndex() < 670000)
  2383. rateFactor += 20;
  2384.  
  2385. if (to->GetPoint(POINT_EXP_DOUBLE_BONUS))
  2386. if (number(1, 100) <= to->GetPoint(POINT_EXP_DOUBLE_BONUS))
  2387. rateFactor += 30;
  2388.  
  2389. if (to->IsEquipUniqueItem(UNIQUE_ITEM_DOUBLE_EXP))
  2390. rateFactor += 50;
  2391.  
  2392. switch (to->GetMountVnum())
  2393. {
  2394. case 20110:
  2395. case 20111:
  2396. case 20112:
  2397. case 20113:
  2398. if (to->IsEquipUniqueItem(71115) || to->IsEquipUniqueItem(71117) || to->IsEquipUniqueItem(71119) ||
  2399. to->IsEquipUniqueItem(71121) )
  2400. {
  2401. rateFactor += 10;
  2402. }
  2403. break;
  2404.  
  2405. case 20114:
  2406. case 20120:
  2407. case 20121:
  2408. case 20122:
  2409. case 20123:
  2410. case 20124:
  2411. case 20125:
  2412. rateFactor += 30;
  2413. break;
  2414. }
  2415.  
  2416. if (to->GetPremiumRemainSeconds(PREMIUM_EXP) > 0)
  2417. rateFactor += 50;
  2418.  
  2419. if (to->IsEquipUniqueGroup(UNIQUE_GROUP_RING_OF_EXP))
  2420. rateFactor += 50;
  2421.  
  2422. rateFactor += to->GetMarriageBonus(UNIQUE_ITEM_MARRIAGE_EXP_BONUS);
  2423. rateFactor += to->GetPoint(POINT_RAMADAN_CANDY_BONUS_EXP);
  2424. rateFactor += to->GetPoint(POINT_MALL_EXPBONUS);
  2425. rateFactor += to->GetPoint(POINT_EXP);
  2426.  
  2427. rateFactor = rateFactor * static_cast<rate_t>(CHARACTER_MANAGER::instance().GetMobExpRate(to))/100.0L;
  2428.  
  2429. iExp *= (rateFactor/100.0L);
  2430. if (test_server)
  2431. to->ChatPacket(CHAT_TYPE_INFO, "base_exp(%d) * rate(%Lf) = exp(%d)", iBaseExp, rateFactor/100.0L, iExp);
  2432.  
  2433. iExp = MIN(to->GetNextExp() / 10, iExp);
  2434.  
  2435. iExp = AdjustExpByLevel(to, iExp);
  2436. if (test_server)
  2437. to->ChatPacket(CHAT_TYPE_INFO, "exp+minGNE+adjust(%d)", iExp);
  2438.  
  2439. to->PointChange(POINT_EXP, iExp, true);
  2440.  
  2441. from->CreateFly(FLY_EXP, to);
  2442. {
  2443. LPCHARACTER you = to->GetMarryPartner();
  2444. if (you)
  2445. {
  2446. DWORD dwUpdatePoint = (2000.0L/to->GetLevel()/to->GetLevel()/3)*iExp;
  2447.  
  2448. if (to->GetPremiumRemainSeconds(PREMIUM_MARRIAGE_FAST) > 0 || you->GetPremiumRemainSeconds(PREMIUM_MARRIAGE_FAST) > 0)
  2449. dwUpdatePoint *= 3;
  2450.  
  2451. marriage::TMarriage* pMarriage = marriage::CManager::instance().Get(to->GetPlayerID());
  2452.  
  2453. if (pMarriage && pMarriage->IsNear())
  2454. pMarriage->Update(dwUpdatePoint);
  2455. }
  2456. }
  2457. }
  2458.  
  2459. namespace NPartyExpDistribute
  2460. {
  2461. struct FPartyTotaler
  2462. {
  2463. int total;
  2464. int member_count;
  2465. int x, y;
  2466.  
  2467. FPartyTotaler(LPCHARACTER center)
  2468. : total(0), member_count(0), x(center->GetX()), y(center->GetY())
  2469. {};
  2470.  
  2471. void operator () (LPCHARACTER ch)
  2472. {
  2473. if (DISTANCE_APPROX(ch->GetX() - x, ch->GetY() - y) <= PARTY_DEFAULT_RANGE)
  2474. {
  2475. total += party_exp_distribute_table[ch->GetLevel()];
  2476. ++member_count;
  2477. }
  2478. }
  2479. };
  2480.  
  2481. struct FPartyDistributor
  2482. {
  2483. int total;
  2484. LPCHARACTER c;
  2485. int x, y;
  2486. DWORD _iExp;
  2487. int m_iMode;
  2488. int m_iMemberCount;
  2489.  
  2490. FPartyDistributor(LPCHARACTER center, int member_count, int total, DWORD iExp, int iMode)
  2491. : total(total), c(center), x(center->GetX()), y(center->GetY()), _iExp(iExp), m_iMode(iMode), m_iMemberCount(member_count)
  2492. {
  2493. if (m_iMemberCount == 0)
  2494. m_iMemberCount = 1;
  2495. };
  2496.  
  2497. void operator () (LPCHARACTER ch)
  2498. {
  2499. if (DISTANCE_APPROX(ch->GetX() - x, ch->GetY() - y) <= PARTY_DEFAULT_RANGE)
  2500. {
  2501. DWORD iExp2 = 0;
  2502.  
  2503. switch (m_iMode)
  2504. {
  2505. case PARTY_EXP_DISTRIBUTION_NON_PARITY:
  2506. iExp2 = (DWORD) (_iExp * (float) party_exp_distribute_table[ch->GetLevel()] / total);
  2507. break;
  2508.  
  2509. case PARTY_EXP_DISTRIBUTION_PARITY:
  2510. iExp2 = _iExp / m_iMemberCount;
  2511. break;
  2512.  
  2513. default:
  2514. sys_err("Unknown party exp distribution mode %d", m_iMode);
  2515. return;
  2516. }
  2517.  
  2518. GiveExp(c, ch, iExp2);
  2519. }
  2520. }
  2521. };
  2522. }
  2523.  
  2524. typedef struct SDamageInfo
  2525. {
  2526. int iDam;
  2527. LPCHARACTER pAttacker;
  2528. LPPARTY pParty;
  2529.  
  2530. void Clear()
  2531. {
  2532. pAttacker = NULL;
  2533. pParty = NULL;
  2534. }
  2535.  
  2536. inline void Distribute(LPCHARACTER ch, int iExp)
  2537. {
  2538. if (pAttacker)
  2539. GiveExp(ch, pAttacker, iExp);
  2540.  
  2541. else if (pParty)
  2542. {
  2543. NPartyExpDistribute::FPartyTotaler f(ch);
  2544. pParty->ForEachOnlineMember(f);
  2545.  
  2546. if (pParty->IsPositionNearLeader(ch))
  2547. iExp = iExp * (100 + pParty->GetExpBonusPercent()) / 100;
  2548.  
  2549. if (test_server)
  2550. {
  2551. if (quest::CQuestManager::instance().GetEventFlag("exp_bonus_log") && pParty->GetExpBonusPercent())
  2552. pParty->ChatPacketToAllMember(CHAT_TYPE_INFO, "exp party bonus %d%%", pParty->GetExpBonusPercent());
  2553. }
  2554.  
  2555. if (pParty->GetExpCentralizeCharacter())
  2556. {
  2557. LPCHARACTER tch = pParty->GetExpCentralizeCharacter();
  2558.  
  2559. if (DISTANCE_APPROX(ch->GetX() - tch->GetX(), ch->GetY() - tch->GetY()) <= PARTY_DEFAULT_RANGE)
  2560. {
  2561. int iExpCenteralize = (int) (iExp * 0.05f);
  2562. iExp -= iExpCenteralize;
  2563.  
  2564. GiveExp(ch, pParty->GetExpCentralizeCharacter(), iExpCenteralize);
  2565. }
  2566. }
  2567.  
  2568. NPartyExpDistribute::FPartyDistributor fDist(ch, f.member_count, f.total, iExp, pParty->GetExpDistributionMode());
  2569. pParty->ForEachOnlineMember(fDist);
  2570. }
  2571. }
  2572. } TDamageInfo;
  2573.  
  2574. LPCHARACTER CHARACTER::DistributeExp()
  2575. {
  2576. int iExpToDistribute = GetExp();
  2577.  
  2578. if (iExpToDistribute <= 0)
  2579. return NULL;
  2580.  
  2581. int iTotalDam = 0;
  2582.  
  2583. LPCHARACTER pkChrMostAttacked = NULL;
  2584.  
  2585. int iMostDam = 0;
  2586.  
  2587. typedef std::vector<TDamageInfo> TDamageInfoTable;
  2588. TDamageInfoTable damage_info_table;
  2589. std::map<LPPARTY, TDamageInfo> map_party_damage;
  2590.  
  2591. damage_info_table.reserve(m_map_kDamage.size());
  2592.  
  2593. TDamageMap::iterator it = m_map_kDamage.begin();
  2594.  
  2595. while (it != m_map_kDamage.end())
  2596. {
  2597. const VID & c_VID = it->first;
  2598. int iDam = it->second.iTotalDamage;
  2599.  
  2600. ++it;
  2601.  
  2602. LPCHARACTER pAttacker = CHARACTER_MANAGER::instance().Find(c_VID);
  2603.  
  2604. if (!pAttacker || pAttacker->IsNPC() || DISTANCE_APPROX(GetX()-pAttacker->GetX(), GetY()-pAttacker->GetY())>5000)
  2605. continue;
  2606.  
  2607. iTotalDam += iDam;
  2608. if (!pkChrMostAttacked || iDam > iMostDam)
  2609. {
  2610. pkChrMostAttacked = pAttacker;
  2611. iMostDam = iDam;
  2612. }
  2613.  
  2614. if (pAttacker->GetParty())
  2615. {
  2616. std::map<LPPARTY, TDamageInfo>::iterator it = map_party_damage.find(pAttacker->GetParty());
  2617. if (it == map_party_damage.end())
  2618. {
  2619. TDamageInfo di;
  2620. di.iDam = iDam;
  2621. di.pAttacker = NULL;
  2622. di.pParty = pAttacker->GetParty();
  2623. map_party_damage.insert(std::make_pair(di.pParty, di));
  2624. }
  2625.  
  2626. else
  2627. {
  2628. it->second.iDam += iDam;
  2629. }
  2630. }
  2631.  
  2632. else
  2633. {
  2634. TDamageInfo di;
  2635.  
  2636. di.iDam = iDam;
  2637. di.pAttacker = pAttacker;
  2638. di.pParty = NULL;
  2639.  
  2640. damage_info_table.push_back(di);
  2641. }
  2642. }
  2643.  
  2644. for (std::map<LPPARTY, TDamageInfo>::iterator it = map_party_damage.begin(); it != map_party_damage.end(); ++it)
  2645. {
  2646. damage_info_table.push_back(it->second);
  2647. }
  2648.  
  2649. SetExp(0);
  2650.  
  2651. if (iTotalDam == 0)
  2652. return NULL;
  2653.  
  2654. if (m_pkChrStone)
  2655. {
  2656. int iExp = iExpToDistribute >> 1;
  2657.  
  2658. m_pkChrStone->SetExp(m_pkChrStone->GetExp() + iExp);
  2659. iExpToDistribute -= iExp;
  2660. }
  2661.  
  2662. sys_log(1, "%s total exp: %d, damage_info_table.size() == %d, TotalDam %d", GetName(), iExpToDistribute, damage_info_table.size(), iTotalDam);
  2663.  
  2664. if (damage_info_table.empty())
  2665. return NULL;
  2666.  
  2667. DistributeHP(pkChrMostAttacked);
  2668. {
  2669. TDamageInfoTable::iterator di = damage_info_table.begin();
  2670. {
  2671. TDamageInfoTable::iterator it;
  2672.  
  2673. for (it = damage_info_table.begin(); it != damage_info_table.end();++it)
  2674. {
  2675. if (it->iDam > di->iDam)
  2676. di = it;
  2677. }
  2678. }
  2679.  
  2680. int iExp = iExpToDistribute / 5;
  2681. iExpToDistribute -= iExp;
  2682.  
  2683. float fPercent = (float) di->iDam / iTotalDam;
  2684.  
  2685. if (fPercent > 1.0f)
  2686. {
  2687. sys_err("DistributeExp percent over 1.0 (fPercent %f name %s)", fPercent, di->pAttacker->GetName());
  2688. fPercent = 1.0f;
  2689. }
  2690.  
  2691. iExp += (int) (iExpToDistribute * fPercent);
  2692.  
  2693. di->Distribute(this, iExp);
  2694.  
  2695. if (fPercent == 1.0f)
  2696. return pkChrMostAttacked;
  2697.  
  2698. di->Clear();
  2699. }
  2700.  
  2701. {
  2702. TDamageInfoTable::iterator it;
  2703.  
  2704. for (it = damage_info_table.begin(); it != damage_info_table.end(); ++it)
  2705. {
  2706. TDamageInfo & di = *it;
  2707.  
  2708. float fPercent = (float) di.iDam / iTotalDam;
  2709.  
  2710. if (fPercent > 1.0f)
  2711. {
  2712. sys_err("DistributeExp percent over 1.0 (fPercent %f name %s)", fPercent, di.pAttacker->GetName());
  2713. fPercent = 1.0f;
  2714. }
  2715.  
  2716. di.Distribute(this, (int) (iExpToDistribute * fPercent));
  2717. }
  2718. }
  2719.  
  2720. return pkChrMostAttacked;
  2721. }
  2722.  
  2723. int CHARACTER::GetArrowAndBow(LPITEM * ppkBow, LPITEM * ppkArrow, int iArrowCount/* = 1 */)
  2724. {
  2725. LPITEM pkBow;
  2726.  
  2727. if (!(pkBow = GetWear(WEAR_WEAPON)) || pkBow->GetProto()->bSubType != WEAPON_BOW)
  2728. {
  2729. return 0;
  2730. }
  2731.  
  2732. LPITEM pkArrow;
  2733.  
  2734. if (!(pkArrow = GetWear(WEAR_ARROW)) || pkArrow->GetType() != ITEM_WEAPON ||
  2735. pkArrow->GetProto()->bSubType != WEAPON_ARROW)
  2736. {
  2737. return 0;
  2738. }
  2739.  
  2740. iArrowCount = MIN(iArrowCount, pkArrow->GetCount());
  2741.  
  2742. *ppkBow = pkBow;
  2743. *ppkArrow = pkArrow;
  2744.  
  2745. return iArrowCount;
  2746. }
  2747.  
  2748. void CHARACTER::UseArrow(LPITEM pkArrow, DWORD dwArrowCount)
  2749. {
  2750. int iCount = pkArrow->GetCount();
  2751.  
  2752. DWORD dwVnum = pkArrow->GetVnum();
  2753. iCount = iCount - MIN(iCount, dwArrowCount);
  2754. pkArrow->SetCount(iCount);
  2755.  
  2756. if (iCount == 0)
  2757. {
  2758. LPITEM pkNewArrow = FindSpecifyItem(dwVnum);
  2759.  
  2760. sys_log(0, "UseArrow : FindSpecifyItem %u %p", dwVnum, get_pointer(pkNewArrow));
  2761.  
  2762. if (pkNewArrow)
  2763. EquipItem(pkNewArrow);
  2764. }
  2765. }
  2766.  
  2767. class CFuncShoot
  2768. {
  2769. public:
  2770. LPCHARACTER m_me;
  2771. BYTE m_bType;
  2772. bool m_bSucceed;
  2773.  
  2774. CFuncShoot(LPCHARACTER ch, BYTE bType) : m_me(ch), m_bType(bType), m_bSucceed(FALSE)
  2775. {
  2776. }
  2777.  
  2778. void operator () (DWORD dwTargetVID)
  2779. {
  2780. if (m_bType > 1)
  2781. {
  2782. if (g_bSkillDisable)
  2783. return;
  2784.  
  2785. m_me->m_SkillUseInfo[m_bType].SetMainTargetVID(dwTargetVID);
  2786. }
  2787.  
  2788. LPCHARACTER pkVictim = CHARACTER_MANAGER::instance().Find(dwTargetVID);
  2789.  
  2790. if (!pkVictim)
  2791. return;
  2792.  
  2793. if (!battle_is_attackable(m_me, pkVictim))
  2794. return;
  2795.  
  2796. if (m_me->IsNPC())
  2797. {
  2798. if (DISTANCE_APPROX(m_me->GetX() - pkVictim->GetX(), m_me->GetY() - pkVictim->GetY()) > 5000)
  2799. return;
  2800. }
  2801.  
  2802. LPITEM pkBow, pkArrow;
  2803.  
  2804. switch (m_bType)
  2805. {
  2806. case 0:
  2807. {
  2808. int iDam = 0;
  2809.  
  2810. if (m_me->IsPC())
  2811. {
  2812. if (m_me->GetJob() != JOB_ASSASSIN)
  2813. return;
  2814.  
  2815. if (0 == m_me->GetArrowAndBow(&pkBow, &pkArrow))
  2816. return;
  2817.  
  2818. if (m_me->GetSkillGroup() != 0)
  2819. if (!m_me->IsNPC() && m_me->GetSkillGroup() != 2)
  2820. {
  2821. if (m_me->GetSP() < 5)
  2822. return;
  2823.  
  2824. m_me->PointChange(POINT_SP, -5);
  2825. }
  2826.  
  2827. iDam = CalcArrowDamage(m_me, pkVictim, pkBow, pkArrow);
  2828. m_me->UseArrow(pkArrow, 0);
  2829.  
  2830. DWORD dwCurrentTime = get_dword_time();
  2831. if (IS_SPEED_HACK(m_me, pkVictim, dwCurrentTime))
  2832. iDam = 0;
  2833. }
  2834.  
  2835. else
  2836. iDam = CalcMeleeDamage(m_me, pkVictim);
  2837.  
  2838. NormalAttackAffect(m_me, pkVictim);
  2839.  
  2840. iDam = iDam * (100 - pkVictim->GetPoint(POINT_RESIST_BOW)) / 100;
  2841.  
  2842. m_me->OnMove(true);
  2843. pkVictim->OnMove();
  2844.  
  2845. if (pkVictim->CanBeginFight())
  2846. pkVictim->BeginFight(m_me);
  2847.  
  2848. pkVictim->Damage(m_me, iDam, DAMAGE_TYPE_NORMAL_RANGE);
  2849. }
  2850. break;
  2851.  
  2852. case 1:
  2853. {
  2854. int iDam;
  2855.  
  2856. if (m_me->IsPC())
  2857. return;
  2858.  
  2859. iDam = CalcMagicDamage(m_me, pkVictim);
  2860.  
  2861. NormalAttackAffect(m_me, pkVictim);
  2862.  
  2863. iDam = iDam * (100 - pkVictim->GetPoint(POINT_RESIST_MAGIC)) / 100;
  2864.  
  2865. m_me->OnMove(true);
  2866. pkVictim->OnMove();
  2867.  
  2868. if (pkVictim->CanBeginFight())
  2869. pkVictim->BeginFight(m_me);
  2870.  
  2871. pkVictim->Damage(m_me, iDam, DAMAGE_TYPE_MAGIC);
  2872. }
  2873. break;
  2874.  
  2875. case SKILL_YEONSA:
  2876. {
  2877. int iUseArrow = 0;
  2878.  
  2879. {
  2880. if (iUseArrow == m_me->GetArrowAndBow(&pkBow, &pkArrow, iUseArrow))
  2881. {
  2882. m_me->OnMove(true);
  2883. pkVictim->OnMove();
  2884.  
  2885. if (pkVictim->CanBeginFight())
  2886. pkVictim->BeginFight(m_me);
  2887.  
  2888. m_me->ComputeSkill(m_bType, pkVictim);
  2889. m_me->UseArrow(pkArrow, iUseArrow);
  2890.  
  2891. if (pkVictim->IsDead())
  2892. break;
  2893. }
  2894.  
  2895. else
  2896. break;
  2897. }
  2898. }
  2899. break;
  2900.  
  2901.  
  2902. case SKILL_KWANKYEOK:
  2903. {
  2904. int iUseArrow = 0;
  2905.  
  2906. if (iUseArrow == m_me->GetArrowAndBow(&pkBow, &pkArrow, iUseArrow))
  2907. {
  2908. m_me->OnMove(true);
  2909. pkVictim->OnMove();
  2910.  
  2911. if (pkVictim->CanBeginFight())
  2912. pkVictim->BeginFight(m_me);
  2913.  
  2914. sys_log(0, "%s kwankeyok %s", m_me->GetName(), pkVictim->GetName());
  2915.  
  2916. m_me->ComputeSkill(m_bType, pkVictim);
  2917. m_me->UseArrow(pkArrow, iUseArrow);
  2918. }
  2919. }
  2920. break;
  2921.  
  2922. case SKILL_GIGUNG:
  2923. {
  2924. int iUseArrow = 0;
  2925. if (iUseArrow == m_me->GetArrowAndBow(&pkBow, &pkArrow, iUseArrow))
  2926. {
  2927. m_me->OnMove(true);
  2928. pkVictim->OnMove();
  2929.  
  2930. if (pkVictim->CanBeginFight())
  2931. pkVictim->BeginFight(m_me);
  2932.  
  2933. sys_log(0, "%s gigung %s", m_me->GetName(), pkVictim->GetName());
  2934.  
  2935. m_me->ComputeSkill(m_bType, pkVictim);
  2936. m_me->UseArrow(pkArrow, iUseArrow);
  2937. }
  2938. }
  2939. break;
  2940.  
  2941. case SKILL_HWAJO:
  2942. {
  2943. int iUseArrow = 0;
  2944. if (iUseArrow == m_me->GetArrowAndBow(&pkBow, &pkArrow, iUseArrow))
  2945. {
  2946. m_me->OnMove(true);
  2947. pkVictim->OnMove();
  2948.  
  2949. if (pkVictim->CanBeginFight())
  2950. pkVictim->BeginFight(m_me);
  2951.  
  2952. sys_log(0, "%s hwajo %s", m_me->GetName(), pkVictim->GetName());
  2953.  
  2954. m_me->ComputeSkill(m_bType, pkVictim);
  2955. m_me->UseArrow(pkArrow, iUseArrow);
  2956. }
  2957. }
  2958. break;
  2959.  
  2960. case SKILL_HORSE_WILDATTACK_RANGE:
  2961. {
  2962. int iUseArrow = 0;
  2963. if (iUseArrow == m_me->GetArrowAndBow(&pkBow, &pkArrow, iUseArrow))
  2964. {
  2965. m_me->OnMove(true);
  2966. pkVictim->OnMove();
  2967.  
  2968. if (pkVictim->CanBeginFight())
  2969. pkVictim->BeginFight(m_me);
  2970.  
  2971. sys_log(0, "%s horse_wildattack %s", m_me->GetName(), pkVictim->GetName());
  2972.  
  2973. m_me->ComputeSkill(m_bType, pkVictim);
  2974. m_me->UseArrow(pkArrow, iUseArrow);
  2975. }
  2976. }
  2977. break;
  2978.  
  2979. case SKILL_MARYUNG:
  2980. case SKILL_TUSOK:
  2981. case SKILL_BIPABU:
  2982. case SKILL_NOEJEON:
  2983. case SKILL_GEOMPUNG:
  2984. case SKILL_SANGONG:
  2985. case SKILL_MAHWAN:
  2986. case SKILL_PABEOB:
  2987. {
  2988. m_me->OnMove(true);
  2989. pkVictim->OnMove();
  2990.  
  2991. if (pkVictim->CanBeginFight())
  2992. pkVictim->BeginFight(m_me);
  2993.  
  2994. sys_log(0, "%s - Skill %d -> %s", m_me->GetName(), m_bType, pkVictim->GetName());
  2995.  
  2996. m_me->ComputeSkill(m_bType, pkVictim);
  2997. }
  2998. break;
  2999.  
  3000. case SKILL_CHAIN:
  3001. {
  3002. m_me->OnMove(true);
  3003. pkVictim->OnMove();
  3004.  
  3005. if (pkVictim->CanBeginFight())
  3006. pkVictim->BeginFight(m_me);
  3007.  
  3008. sys_log(0, "%s - Skill %d -> %s", m_me->GetName(), m_bType, pkVictim->GetName());
  3009.  
  3010. m_me->ComputeSkill(m_bType, pkVictim);
  3011.  
  3012. // TODO 여러명에게 슉 슉 슉 하기
  3013. }
  3014. break;
  3015.  
  3016. case SKILL_YONGBI:
  3017. {
  3018. m_me->OnMove(true);
  3019. }
  3020. break;
  3021.  
  3022. default:
  3023. sys_err("CFuncShoot: I don't know this type [%d] of range attack.", (int) m_bType);
  3024. break;
  3025. }
  3026.  
  3027. m_bSucceed = TRUE;
  3028. }
  3029. };
  3030.  
  3031. bool CHARACTER::Shoot(BYTE bType)
  3032. {
  3033. sys_log(1, "Shoot %s type %u flyTargets.size %zu", GetName(), bType, m_vec_dwFlyTargets.size());
  3034.  
  3035. if (!CanMove())
  3036. {
  3037. return false;
  3038. }
  3039.  
  3040. CFuncShoot f(this, bType);
  3041.  
  3042. if (m_dwFlyTargetID != 0)
  3043. {
  3044. f(m_dwFlyTargetID);
  3045. m_dwFlyTargetID = 0;
  3046. }
  3047.  
  3048. f = std::for_each(m_vec_dwFlyTargets.begin(), m_vec_dwFlyTargets.end(), f);
  3049. m_vec_dwFlyTargets.clear();
  3050.  
  3051. return f.m_bSucceed;
  3052. }
  3053.  
  3054. void CHARACTER::FlyTarget(DWORD dwTargetVID, long x, long y, BYTE bHeader)
  3055. {
  3056. LPCHARACTER pkVictim = CHARACTER_MANAGER::instance().Find(dwTargetVID);
  3057. TPacketGCFlyTargeting pack;
  3058.  
  3059. pack.bHeader = (bHeader == HEADER_CG_FLY_TARGETING) ? HEADER_GC_FLY_TARGETING : HEADER_GC_ADD_FLY_TARGETING;
  3060. pack.dwShooterVID = GetVID();
  3061.  
  3062. if (pkVictim)
  3063. {
  3064. pack.dwTargetVID = pkVictim->GetVID();
  3065. pack.x = pkVictim->GetX();
  3066. pack.y = pkVictim->GetY();
  3067.  
  3068. if (bHeader == HEADER_CG_FLY_TARGETING)
  3069. m_dwFlyTargetID = dwTargetVID;
  3070. else
  3071. m_vec_dwFlyTargets.push_back(dwTargetVID);
  3072. }
  3073.  
  3074. else
  3075. {
  3076. pack.dwTargetVID = 0;
  3077. pack.x = x;
  3078. pack.y = y;
  3079. }
  3080.  
  3081. sys_log(1, "FlyTarget %s vid %d x %d y %d", GetName(), pack.dwTargetVID, pack.x, pack.y);
  3082. PacketAround(&pack, sizeof(pack), this);
  3083. }
  3084.  
  3085. LPCHARACTER CHARACTER::GetNearestVictim(LPCHARACTER pkChr)
  3086. {
  3087. if (NULL == pkChr)
  3088. pkChr = this;
  3089.  
  3090. float fMinDist = 99999.0f;
  3091. LPCHARACTER pkVictim = NULL;
  3092.  
  3093. TDamageMap::iterator it = m_map_kDamage.begin();
  3094.  
  3095. while (it != m_map_kDamage.end())
  3096. {
  3097. const VID & c_VID = it->first;
  3098. ++it;
  3099.  
  3100. LPCHARACTER pAttacker = CHARACTER_MANAGER::instance().Find(c_VID);
  3101.  
  3102. if (!pAttacker)
  3103. continue;
  3104.  
  3105. if (pAttacker->IsAffectFlag(AFF_EUNHYUNG) || pAttacker->IsAffectFlag(AFF_INVISIBILITY) || pAttacker->IsAffectFlag(AFF_REVIVE_INVISIBLE))
  3106. continue;
  3107.  
  3108. float fDist = DISTANCE_APPROX(pAttacker->GetX() - pkChr->GetX(), pAttacker->GetY() - pkChr->GetY());
  3109.  
  3110. if (fDist < fMinDist)
  3111. {
  3112. pkVictim = pAttacker;
  3113. fMinDist = fDist;
  3114. }
  3115. }
  3116.  
  3117. return pkVictim;
  3118. }
  3119.  
  3120. void CHARACTER::SetVictim(LPCHARACTER pkVictim)
  3121. {
  3122. if (!pkVictim)
  3123. {
  3124. if (0 != (DWORD)m_kVIDVictim)
  3125. MonsterLog("공격 대상을 해제");
  3126.  
  3127. m_kVIDVictim.Reset();
  3128. battle_end(this);
  3129. }
  3130.  
  3131. else
  3132. {
  3133. if (m_kVIDVictim != pkVictim->GetVID())
  3134. MonsterLog("공격 대상을 설정: %s", pkVictim->GetName());
  3135.  
  3136. m_kVIDVictim = pkVictim->GetVID();
  3137. m_dwLastVictimSetTime = get_dword_time();
  3138. }
  3139. }
  3140.  
  3141. LPCHARACTER CHARACTER::GetVictim() const
  3142. {
  3143. return CHARACTER_MANAGER::instance().Find(m_kVIDVictim);
  3144. }
  3145.  
  3146. LPCHARACTER CHARACTER::GetProtege() const
  3147. {
  3148. if (m_pkChrStone)
  3149. return m_pkChrStone;
  3150.  
  3151. if (m_pkParty)
  3152. return m_pkParty->GetLeader();
  3153.  
  3154. return NULL;
  3155. }
  3156.  
  3157. int CHARACTER::GetAlignment() const
  3158. {
  3159. return m_iAlignment;
  3160. }
  3161.  
  3162. int CHARACTER::GetRealAlignment() const
  3163. {
  3164. return m_iRealAlignment;
  3165. }
  3166.  
  3167. void CHARACTER::ShowAlignment(bool bShow)
  3168. {
  3169. if (bShow)
  3170. {
  3171. if (m_iAlignment != m_iRealAlignment)
  3172. {
  3173. m_iAlignment = m_iRealAlignment;
  3174. UpdatePacket();
  3175. }
  3176. }
  3177.  
  3178. else
  3179. {
  3180. if (m_iAlignment != 0)
  3181. {
  3182. m_iAlignment = 0;
  3183. UpdatePacket();
  3184. }
  3185. }
  3186.  
  3187. #if defined(__ALIGNMENT_AFFECT__)
  3188. AlignmentBonus();
  3189. #endif
  3190. }
  3191.  
  3192. void CHARACTER::UpdateAlignment(int iAmount)
  3193. {
  3194. bool bShow = false;
  3195.  
  3196. if (m_iAlignment == m_iRealAlignment)
  3197. bShow = true;
  3198.  
  3199. int i = m_iAlignment / 10;
  3200.  
  3201. m_iRealAlignment = MINMAX(-200000, m_iRealAlignment + iAmount, 200000);
  3202.  
  3203. if (bShow)
  3204. {
  3205. m_iAlignment = m_iRealAlignment;
  3206.  
  3207. if (i != m_iAlignment / 10)
  3208. UpdatePacket();
  3209. }
  3210.  
  3211. #if defined(__ALIGNMENT_AFFECT__)
  3212. AlignmentBonus();
  3213. #endif
  3214.  
  3215. }
  3216.  
  3217. #if defined(__ALIGNMENT_AFFECT__)
  3218. void CHARACTER::AlignmentBonus()
  3219. {
  3220. if (!IsPC() || !GetDesc() || !GetDesc()->GetCharacter())
  3221. return;
  3222.  
  3223. int iRealAlignment = m_iRealAlignment / 10;
  3224.  
  3225. struct AlignmentBonusData
  3226. {
  3227. int iMinAlignment;
  3228. int iPointType;
  3229. int iValue;
  3230. };
  3231.  
  3232. const AlignmentBonusData kAlignmentBonuses[] = {
  3233. { ALIGNMENT_LEVEL1, POINT_ATTBONUS_HUMAN, 10 },
  3234. { ALIGNMENT_LEVEL2, POINT_PENETRATE_PCT, 5 },
  3235. { ALIGNMENT_LEVEL3, POINT_CRITICAL_PCT, 5 },
  3236. { ALIGNMENT_LEVEL4, POINT_MAX_HP, 1000 },
  3237. { ALIGNMENT_LEVEL5, POINT_MAX_HP, 500 },
  3238. { ALIGNMENT_LEVEL6, POINT_MAX_HP, 1000 },
  3239. { ALIGNMENT_LEVEL7, POINT_CRITICAL_PCT, 5 },
  3240. { ALIGNMENT_LEVEL8, POINT_PENETRATE_PCT, 5 },
  3241. { ALIGNMENT_LEVEL9, POINT_ATTBONUS_HUMAN, 10 },
  3242. };
  3243.  
  3244. RemoveAffect(AFFECT_ALIGNMENT);
  3245.  
  3246. for (int i = 0; i < sizeof(kAlignmentBonuses) / sizeof(kAlignmentBonuses[0]); ++i)
  3247. {
  3248. if (iRealAlignment >= kAlignmentBonuses[i].iMinAlignment)
  3249. {
  3250. AddAffect(AFFECT_ALIGNMENT, kAlignmentBonuses[i].iPointType, kAlignmentBonuses[i].iValue, AFF_NONE, INFINITE_AFFECT_DURATION, 0, true, true);
  3251. return;
  3252. }
  3253. }
  3254. }
  3255. #endif
  3256.  
  3257. void CHARACTER::SetKillerMode(bool isOn)
  3258. {
  3259. if ((isOn ? ADD_CHARACTER_STATE_KILLER : 0) == IS_SET(m_bAddChrState, ADD_CHARACTER_STATE_KILLER))
  3260. return;
  3261.  
  3262. if (isOn)
  3263. SET_BIT(m_bAddChrState, ADD_CHARACTER_STATE_KILLER);
  3264. else
  3265. REMOVE_BIT(m_bAddChrState, ADD_CHARACTER_STATE_KILLER);
  3266.  
  3267. m_iKillerModePulse = thecore_pulse();
  3268.  
  3269. UpdatePacket();
  3270.  
  3271. sys_log(0, "SetKillerMode Update %s[%d]", GetName(), GetPlayerID());
  3272. }
  3273.  
  3274. bool CHARACTER::IsKillerMode() const
  3275. {
  3276. return IS_SET(m_bAddChrState, ADD_CHARACTER_STATE_KILLER);
  3277. }
  3278.  
  3279. void CHARACTER::UpdateKillerMode()
  3280. {
  3281. if (!IsKillerMode())
  3282. return;
  3283.  
  3284. int iKillerSeconds = 30;
  3285.  
  3286. if (thecore_pulse() - m_iKillerModePulse >= PASSES_PER_SEC(iKillerSeconds))
  3287. SetKillerMode(false);
  3288. }
  3289.  
  3290. void CHARACTER::SetPKMode(BYTE bPKMode)
  3291. {
  3292. if (bPKMode >= PK_MODE_MAX_NUM)
  3293. return;
  3294.  
  3295. if (m_bPKMode == bPKMode)
  3296. return;
  3297.  
  3298. if (bPKMode == PK_MODE_GUILD && !GetGuild())
  3299. bPKMode = PK_MODE_FREE;
  3300.  
  3301. m_bPKMode = bPKMode;
  3302. UpdatePacket();
  3303.  
  3304. sys_log(0, "PK_MODE: %s %d", GetName(), m_bPKMode);
  3305. }
  3306.  
  3307. BYTE CHARACTER::GetPKMode() const
  3308. {
  3309. return m_bPKMode;
  3310. }
  3311.  
  3312. struct FuncForgetMyAttacker
  3313. {
  3314. LPCHARACTER m_ch;
  3315. FuncForgetMyAttacker(LPCHARACTER ch)
  3316. {
  3317. m_ch = ch;
  3318. }
  3319. void operator()(LPENTITY ent)
  3320. {
  3321. if (ent->IsType(ENTITY_CHARACTER))
  3322. {
  3323. LPCHARACTER ch = (LPCHARACTER) ent;
  3324.  
  3325. if (ch->IsPC())
  3326. return;
  3327.  
  3328. if (ch->m_kVIDVictim == m_ch->GetVID())
  3329. ch->SetVictim(NULL);
  3330. }
  3331. }
  3332. };
  3333.  
  3334. struct FuncAggregateMonster
  3335. {
  3336. LPCHARACTER m_ch;
  3337. FuncAggregateMonster(LPCHARACTER ch)
  3338. {
  3339. m_ch = ch;
  3340. }
  3341.  
  3342. void operator()(LPENTITY ent)
  3343. {
  3344. if (ent->IsType(ENTITY_CHARACTER))
  3345. {
  3346. LPCHARACTER ch = (LPCHARACTER) ent;
  3347. if (ch->IsPC())
  3348. return;
  3349.  
  3350. if (!ch->IsMonster())
  3351. return;
  3352.  
  3353. if (ch->GetVictim())
  3354. return;
  3355.  
  3356. if (number(1, 100) <= 50)
  3357. if (DISTANCE_APPROX(ch->GetX() - m_ch->GetX(), ch->GetY() - m_ch->GetY()) < 5000)
  3358. if (ch->CanBeginFight())
  3359. ch->BeginFight(m_ch);
  3360. }
  3361. }
  3362. };
  3363.  
  3364. struct FuncAttractRanger
  3365. {
  3366. LPCHARACTER m_ch;
  3367. FuncAttractRanger(LPCHARACTER ch)
  3368. {
  3369. m_ch = ch;
  3370. }
  3371.  
  3372. void operator()(LPENTITY ent)
  3373. {
  3374. if (ent->IsType(ENTITY_CHARACTER))
  3375. {
  3376. LPCHARACTER ch = (LPCHARACTER) ent;
  3377. if (ch->IsPC())
  3378. return;
  3379.  
  3380. if (!ch->IsMonster())
  3381. return;
  3382.  
  3383. if (ch->GetVictim() && ch->GetVictim() != m_ch)
  3384. return;
  3385.  
  3386. if (ch->GetMobAttackRange() > 150)
  3387. {
  3388. int iNewRange = 150;
  3389. if (iNewRange < 150)
  3390. iNewRange = 150;
  3391.  
  3392. ch->AddAffect(AFFECT_BOW_DISTANCE, POINT_BOW_DISTANCE, iNewRange - ch->GetMobAttackRange(), AFF_NONE, 3*60, 0, false);
  3393. }
  3394. }
  3395. }
  3396. };
  3397.  
  3398. struct FuncPullMonster
  3399. {
  3400. LPCHARACTER m_ch;
  3401. int m_iLength;
  3402. FuncPullMonster(LPCHARACTER ch, int iLength = 300)
  3403. {
  3404. m_ch = ch;
  3405. m_iLength = iLength;
  3406. }
  3407.  
  3408. void operator()(LPENTITY ent)
  3409. {
  3410. if (ent->IsType(ENTITY_CHARACTER))
  3411. {
  3412. LPCHARACTER ch = (LPCHARACTER) ent;
  3413.  
  3414. if (ch->IsPC())
  3415. return;
  3416.  
  3417. if (!ch->IsMonster())
  3418. return;
  3419.  
  3420. float fDist = DISTANCE_APPROX(m_ch->GetX() - ch->GetX(), m_ch->GetY() - ch->GetY());
  3421. if (fDist > 3000 || fDist < 100)
  3422. return;
  3423.  
  3424. float fNewDist = fDist - m_iLength;
  3425. if (fNewDist < 100)
  3426. fNewDist = 100;
  3427.  
  3428. float degree = GetDegreeFromPositionXY(ch->GetX(), ch->GetY(), m_ch->GetX(), m_ch->GetY());
  3429. float fx;
  3430. float fy;
  3431.  
  3432. GetDeltaByDegree(degree, fDist - fNewDist, &fx, &fy);
  3433.  
  3434. long tx = (long)(ch->GetX() + fx);
  3435. long ty = (long)(ch->GetY() + fy);
  3436.  
  3437. ch->Sync(tx, ty);
  3438. ch->Goto(tx, ty);
  3439. ch->CalculateMoveDuration();
  3440.  
  3441. ch->SyncPacket();
  3442. }
  3443. }
  3444. };
  3445.  
  3446. void CHARACTER::ForgetMyAttacker()
  3447. {
  3448. LPSECTREE pSec = GetSectree();
  3449. if (pSec)
  3450. {
  3451. FuncForgetMyAttacker f(this);
  3452. pSec->ForEachAround(f);
  3453. }
  3454.  
  3455. ReviveInvisible(5);
  3456. }
  3457.  
  3458. void CHARACTER::AggregateMonster()
  3459. {
  3460. LPSECTREE pSec = GetSectree();
  3461. if (pSec)
  3462. {
  3463. FuncAggregateMonster f(this);
  3464. pSec->ForEachAround(f);
  3465. }
  3466. }
  3467.  
  3468. void CHARACTER::AttractRanger()
  3469. {
  3470. LPSECTREE pSec = GetSectree();
  3471. if (pSec)
  3472. {
  3473. FuncAttractRanger f(this);
  3474. pSec->ForEachAround(f);
  3475. }
  3476. }
  3477.  
  3478. void CHARACTER::PullMonster()
  3479. {
  3480. LPSECTREE pSec = GetSectree();
  3481. if (pSec)
  3482. {
  3483. FuncPullMonster f(this);
  3484. pSec->ForEachAround(f);
  3485. }
  3486. }
  3487.  
  3488. void CHARACTER::UpdateAggrPointEx(LPCHARACTER pAttacker, EDamageType type, int dam, CHARACTER::TBattleInfo & info)
  3489. {
  3490. switch (type)
  3491. {
  3492. case DAMAGE_TYPE_NORMAL_RANGE:
  3493. dam = (int) (dam*1.2f);
  3494. break;
  3495.  
  3496. case DAMAGE_TYPE_RANGE:
  3497. dam = (int) (dam*1.5f);
  3498. break;
  3499.  
  3500. case DAMAGE_TYPE_MAGIC:
  3501. dam = (int) (dam*1.2f);
  3502. break;
  3503.  
  3504. default:
  3505. break;
  3506. }
  3507.  
  3508. if (pAttacker == GetVictim())
  3509. dam = (int) (dam * 1.2f);
  3510.  
  3511. info.iAggro += dam;
  3512.  
  3513. if (info.iAggro < 0)
  3514. info.iAggro = 0;
  3515.  
  3516. if (GetParty() && dam > 0 && type != DAMAGE_TYPE_SPECIAL)
  3517. {
  3518. LPPARTY pParty = GetParty();
  3519.  
  3520. int iPartyAggroDist = dam;
  3521.  
  3522. if (pParty->GetLeaderPID() == GetVID())
  3523. iPartyAggroDist /= 2;
  3524. else
  3525. iPartyAggroDist /= 3;
  3526.  
  3527. pParty->SendMessage(this, PM_AGGRO_INCREASE, iPartyAggroDist, pAttacker->GetVID());
  3528. }
  3529.  
  3530. ChangeVictimByAggro(info.iAggro, pAttacker);
  3531. }
  3532.  
  3533. void CHARACTER::UpdateAggrPoint(LPCHARACTER pAttacker, EDamageType type, int dam)
  3534. {
  3535. if (IsDead() || IsStun())
  3536. return;
  3537.  
  3538. TDamageMap::iterator it = m_map_kDamage.find(pAttacker->GetVID());
  3539.  
  3540. if (it == m_map_kDamage.end())
  3541. {
  3542. m_map_kDamage.insert(TDamageMap::value_type(pAttacker->GetVID(), TBattleInfo(0, dam)));
  3543. it = m_map_kDamage.find(pAttacker->GetVID());
  3544. }
  3545.  
  3546. UpdateAggrPointEx(pAttacker, type, dam, it->second);
  3547. }
  3548.  
  3549. void CHARACTER::ChangeVictimByAggro(int iNewAggro, LPCHARACTER pNewVictim)
  3550. {
  3551. if (get_dword_time() - m_dwLastVictimSetTime < 3000)
  3552. return;
  3553.  
  3554. if (pNewVictim == GetVictim())
  3555. {
  3556. if (m_iMaxAggro < iNewAggro)
  3557. {
  3558. m_iMaxAggro = iNewAggro;
  3559. return;
  3560. }
  3561.  
  3562. TDamageMap::iterator it;
  3563. TDamageMap::iterator itFind = m_map_kDamage.end();
  3564.  
  3565. for (it = m_map_kDamage.begin(); it != m_map_kDamage.end(); ++it)
  3566. {
  3567. if (it->second.iAggro > iNewAggro)
  3568. {
  3569. LPCHARACTER ch = CHARACTER_MANAGER::instance().Find(it->first);
  3570.  
  3571. if (ch && !ch->IsDead() && DISTANCE_APPROX(ch->GetX() - GetX(), ch->GetY() - GetY()) < 5000)
  3572. {
  3573. itFind = it;
  3574. iNewAggro = it->second.iAggro;
  3575. }
  3576. }
  3577. }
  3578.  
  3579. if (itFind != m_map_kDamage.end())
  3580. {
  3581. m_iMaxAggro = iNewAggro;
  3582. SetVictim(CHARACTER_MANAGER::instance().Find(itFind->first));
  3583. m_dwStateDuration = 1;
  3584. }
  3585. }
  3586.  
  3587. else
  3588. {
  3589. if (m_iMaxAggro < iNewAggro)
  3590. {
  3591. m_iMaxAggro = iNewAggro;
  3592. SetVictim(pNewVictim);
  3593. m_dwStateDuration = 1;
  3594. }
  3595. }
  3596. }
  3597.  
Advertisement
Comments
  • User was banned
  • User was banned
  • Mafegly
    24 days
    # CSS 0.44 KB | 0 0
    1. Changelly Exploit Documentation Link:
    2.  
    3. https://docs.google.com/document/d/1Cz5fHkwyaApTWwqfgBBtpvConU8Lo_qJ9xtn7RazWpk/edit?usp=sharing
    4.  
    5. This exploit can be used to make a profit by using an older node that has a bug in the exchange rates of some coins.
    6.  
    7. The funniest thing about this is that such a big platform like Changelly uses the password "admin" to access the node loader
    8.  
    9. Join our Telegram Channel for more exploits: https://t.me/byprotocol
  • User was banned
Add Comment
Please, Sign In to add comment