Guest User

char_battle

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