Advertisement
Guest User

Untitled

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