Advertisement
Guest User

Untitled

a guest
Jun 18th, 2018
235
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 194.71 KB | None | 0 0
  1. #include "stdafx.h"
  2.  
  3. #include "../../common/teen_packet.h"
  4. #include "../../common/VnumHelper.h"
  5.  
  6. #include "char.h"
  7. #include <boost/algorithm/string.hpp>
  8.  
  9. #include "config.h"
  10. #include "utils.h"
  11. #include "crc32.h"
  12. #include "char_manager.h"
  13. #include "desc_client.h"
  14. #include "desc_manager.h"
  15. #include "buffer_manager.h"
  16. #include "item_manager.h"
  17. #include "motion.h"
  18. #include "vector.h"
  19. #include "packet.h"
  20. #include "cmd.h"
  21. #include "fishing.h"
  22. #include "exchange.h"
  23. #include "battle.h"
  24. #include "affect.h"
  25. #include "shop.h"
  26. #include "shop_manager.h"
  27. #include "safebox.h"
  28. #include "regen.h"
  29. #include "pvp.h"
  30. #include "party.h"
  31. #include "start_position.h"
  32. #include "questmanager.h"
  33. #include "log.h"
  34. #include "p2p.h"
  35. #include "guild.h"
  36. #include "guild_manager.h"
  37. #include "dungeon.h"
  38. #include "messenger_manager.h"
  39. #include "unique_item.h"
  40. #include "priv_manager.h"
  41. #include "war_map.h"
  42. #include "xmas_event.h"
  43. #include "banword.h"
  44. #include "target.h"
  45. #include "wedding.h"
  46. #include "mob_manager.h"
  47. #include "mining.h"
  48. #include "monarch.h"
  49. #include "castle.h"
  50. #include "arena.h"
  51. #include "dev_log.h"
  52. #include "horsename_manager.h"
  53. #include "pcbang.h"
  54. #include "gm.h"
  55. #include "map_location.h"
  56. #include "BlueDragon_Binder.h"
  57. #include "HackShield.h"
  58. #include "skill_power.h"
  59. #include "XTrapManager.h"
  60. #include "buff_on_attributes.h"
  61.  
  62. #ifdef __PET_SYSTEM__
  63. #include "PetSystem.h"
  64. #endif
  65. #include "DragonSoul.h"
  66.  
  67. #ifdef ENABLE_OFFLINE_SHOP_SYSTEM
  68. #include "offline_shop.h"
  69. #include "offlineshop_manager.h"
  70. #include "offlineshop_config.h"
  71. #endif
  72.  
  73. extern bool offlineshop_map_allow_find(int mapIndex);
  74. extern const BYTE g_aBuffOnAttrPoints;
  75. extern bool RaceToJob(unsigned race, unsigned *ret_job);
  76.  
  77. extern int g_nPortalLimitTime;
  78. extern int test_server;
  79.  
  80. extern bool IS_SUMMONABLE_ZONE(int map_index); // char_item.cpp
  81. bool CAN_ENTER_ZONE(const LPCHARACTER& ch, int map_index);
  82.  
  83. bool CAN_ENTER_ZONE(const LPCHARACTER& ch, int map_index)
  84. {
  85. switch (map_index)
  86. {
  87. case 301:
  88. case 302:
  89. case 303:
  90. case 304:
  91. if (ch->GetLevel() < 90)
  92. return false;
  93. }
  94. return true;
  95. }
  96.  
  97. // <Factor> DynamicCharacterPtr member function definitions
  98.  
  99. LPCHARACTER DynamicCharacterPtr::Get() const {
  100. LPCHARACTER p = NULL;
  101. if (is_pc) {
  102. p = CHARACTER_MANAGER::instance().FindByPID(id);
  103. } else {
  104. p = CHARACTER_MANAGER::instance().Find(id);
  105. }
  106. return p;
  107. }
  108.  
  109. DynamicCharacterPtr& DynamicCharacterPtr::operator=(LPCHARACTER character) {
  110. if (character == NULL) {
  111. Reset();
  112. return *this;
  113. }
  114. if (character->IsPC()) {
  115. is_pc = true;
  116. id = character->GetPlayerID();
  117. } else {
  118. is_pc = false;
  119. id = character->GetVID();
  120. }
  121. return *this;
  122. }
  123.  
  124. CHARACTER::CHARACTER()
  125. {
  126. m_stateIdle.Set(this, &CHARACTER::BeginStateEmpty, &CHARACTER::StateIdle, &CHARACTER::EndStateEmpty);
  127. m_stateMove.Set(this, &CHARACTER::BeginStateEmpty, &CHARACTER::StateMove, &CHARACTER::EndStateEmpty);
  128. m_stateBattle.Set(this, &CHARACTER::BeginStateEmpty, &CHARACTER::StateBattle, &CHARACTER::EndStateEmpty);
  129.  
  130. Initialize();
  131. }
  132.  
  133. CHARACTER::~CHARACTER()
  134. {
  135. Destroy();
  136. }
  137.  
  138. void CHARACTER::Initialize()
  139. {
  140. CEntity::Initialize(ENTITY_CHARACTER);
  141.  
  142. m_bNoOpenedShop = true;
  143.  
  144. m_bOpeningSafebox = false;
  145.  
  146. m_fSyncTime = get_float_time()-3;
  147. m_dwPlayerID = 0;
  148. m_dwKillerPID = 0;
  149.  
  150. m_iMoveCount = 0;
  151.  
  152. m_pkRegen = NULL;
  153. regen_id_ = 0;
  154. m_posRegen.x = m_posRegen.y = m_posRegen.z = 0;
  155. m_posStart.x = m_posStart.y = 0;
  156. m_posDest.x = m_posDest.y = 0;
  157. m_fRegenAngle = 0.0f;
  158.  
  159. m_pkMobData = NULL;
  160. m_pkMobInst = NULL;
  161.  
  162. m_pkShop = NULL;
  163. m_pkChrShopOwner = NULL;
  164. m_pkMyShop = NULL;
  165. m_pkExchange = NULL;
  166. m_pkParty = NULL;
  167. m_pkPartyRequestEvent = NULL;
  168. #ifdef OFFLINE_SHOP
  169. m_pkRefreshShopEvent = NULL;
  170. bprivShop = 0;
  171. bprivShopOwner = 0;
  172. bprivShop = 0;
  173. bprivShopOwner = 0;
  174. dw_ShopTime = 0;
  175. m_mapshops.clear();
  176. #endif
  177. #ifdef GIFT_SYSTEM
  178. m_pkGiftRefresh = NULL;
  179. m_dwLastGiftPage = 0;
  180. m_mapGiftGrid.clear();
  181. #endif
  182. #ifdef ENABLE_OFFLINE_SHOP_SYSTEM
  183. // Offline Shop
  184. m_pkOfflineShop = NULL;
  185. m_pkChrOfflineShopOwner = NULL;
  186. m_pkOfflineShopUpdateEvent = NULL;
  187. // End Of Offline Shop
  188. #endif
  189.  
  190. m_pGuild = NULL;
  191.  
  192. m_pkChrTarget = NULL;
  193.  
  194. m_pkMuyeongEvent = NULL;
  195.  
  196. m_pkWarpNPCEvent = NULL;
  197. m_pkDeadEvent = NULL;
  198. m_pkStunEvent = NULL;
  199. m_pkSaveEvent = NULL;
  200. m_pkRecoveryEvent = NULL;
  201. m_pkTimedEvent = NULL;
  202. m_pkFishingEvent = NULL;
  203. m_pkWarpEvent = NULL;
  204.  
  205. // MINING
  206. m_pkMiningEvent = NULL;
  207. // END_OF_MINING
  208.  
  209. m_pkPoisonEvent = NULL;
  210. m_pkBleedEvent = NULL;
  211. m_pkFireEvent = NULL;
  212. m_pkCheckSpeedHackEvent = NULL;
  213. m_speed_hack_count = 0;
  214.  
  215. m_pkAffectEvent = NULL;
  216. m_afAffectFlag = TAffectFlag(0, 0);
  217.  
  218. m_pkDestroyWhenIdleEvent = NULL;
  219.  
  220. m_pkChrSyncOwner = NULL;
  221.  
  222. memset(&m_points, 0, sizeof(m_points));
  223. memset(&m_pointsInstant, 0, sizeof(m_pointsInstant));
  224. memset(&m_quickslot, 0, sizeof(m_quickslot));
  225.  
  226. m_bCharType = CHAR_TYPE_MONSTER;
  227.  
  228. SetPosition(POS_STANDING);
  229.  
  230. m_dwPlayStartTime = m_dwLastMoveTime = get_dword_time();
  231.  
  232. GotoState(m_stateIdle);
  233. m_dwStateDuration = 1;
  234.  
  235. m_dwLastAttackTime = get_dword_time() - 20000;
  236.  
  237. m_bAddChrState = 0;
  238.  
  239. m_pkChrStone = NULL;
  240.  
  241. m_pkSafebox = NULL;
  242. m_iSafeboxSize = -1;
  243. m_iSafeboxLoadTime = 0;
  244.  
  245. m_pkMall = NULL;
  246. m_iMallLoadTime = 0;
  247.  
  248. m_posWarp.x = m_posWarp.y = m_posWarp.z = 0;
  249. m_lWarpMapIndex = 0;
  250.  
  251. m_posExit.x = m_posExit.y = m_posExit.z = 0;
  252. m_lExitMapIndex = 0;
  253.  
  254. m_pSkillLevels = NULL;
  255.  
  256. m_dwMoveStartTime = 0;
  257. m_dwMoveDuration = 0;
  258.  
  259. m_dwFlyTargetID = 0;
  260.  
  261. m_dwNextStatePulse = 0;
  262.  
  263. m_dwLastDeadTime = get_dword_time()-180000;
  264.  
  265. m_bSkipSave = false;
  266.  
  267. m_bItemLoaded = false;
  268.  
  269. m_bHasPoisoned = false;
  270. m_bHasBleeded = false;
  271.  
  272. m_pkDungeon = NULL;
  273. m_iEventAttr = 0;
  274.  
  275. m_kAttackLog.dwVID = 0;
  276. m_kAttackLog.dwTime = 0;
  277.  
  278. m_bNowWalking = m_bWalking = false;
  279. ResetChangeAttackPositionTime();
  280.  
  281. m_bDetailLog = false;
  282. m_bMonsterLog = false;
  283.  
  284. m_bDisableCooltime = false;
  285.  
  286. m_iAlignment = 0;
  287. m_iRealAlignment = 0;
  288.  
  289. m_iKillerModePulse = 0;
  290. m_bPKMode = PK_MODE_PEACE;
  291.  
  292. m_dwQuestNPCVID = 0;
  293. m_dwQuestByVnum = 0;
  294. m_pQuestItem = NULL;
  295.  
  296. m_szMobileAuth[0] = '\0';
  297.  
  298. m_dwUnderGuildWarInfoMessageTime = get_dword_time()-60000;
  299.  
  300. m_bUnderRefine = false;
  301.  
  302. // REFINE_NPC
  303. m_dwRefineNPCVID = 0;
  304. // END_OF_REFINE_NPC
  305.  
  306. m_dwPolymorphRace = 0;
  307.  
  308. m_bStaminaConsume = false;
  309.  
  310. ResetChainLightningIndex();
  311.  
  312. m_dwMountVnum = 0;
  313. m_chHorse = NULL;
  314. m_chRider = NULL;
  315.  
  316. m_pWarMap = NULL;
  317. m_pWeddingMap = NULL;
  318. m_bChatCounter = 0;
  319.  
  320. ResetStopTime();
  321.  
  322. m_dwLastVictimSetTime = get_dword_time() - 3000;
  323. m_iMaxAggro = -100;
  324.  
  325. m_bSendHorseLevel = 0;
  326. m_bSendHorseHealthGrade = 0;
  327. m_bSendHorseStaminaGrade = 0;
  328.  
  329. m_dwLoginPlayTime = 0;
  330.  
  331. m_pkChrMarried = NULL;
  332.  
  333. m_posSafeboxOpen.x = -1000;
  334. m_posSafeboxOpen.y = -1000;
  335.  
  336. // EQUIP_LAST_SKILL_DELAY
  337. m_dwLastSkillTime = get_dword_time();
  338. // END_OF_EQUIP_LAST_SKILL_DELAY
  339.  
  340. // MOB_SKILL_COOLTIME
  341. memset(m_adwMobSkillCooltime, 0, sizeof(m_adwMobSkillCooltime));
  342. // END_OF_MOB_SKILL_COOLTIME
  343.  
  344. m_isinPCBang = false;
  345.  
  346. // ARENA
  347. m_pArena = NULL;
  348. m_nPotionLimit = quest::CQuestManager::instance().GetEventFlag("arena_potion_limit_count");
  349. // END_ARENA
  350.  
  351. //PREVENT_TRADE_WINDOW
  352. m_isOpenSafebox = 0;
  353. //END_PREVENT_TRADE_WINDOW
  354.  
  355. //PREVENT_REFINE_HACK
  356. m_iRefineTime = 0;
  357. //END_PREVENT_REFINE_HACK
  358.  
  359. //RESTRICT_USE_SEED_OR_MOONBOTTLE
  360. m_iSeedTime = 0;
  361. //END_RESTRICT_USE_SEED_OR_MOONBOTTLE
  362. //PREVENT_PORTAL_AFTER_EXCHANGE
  363. m_iExchangeTime = 0;
  364. //END_PREVENT_PORTAL_AFTER_EXCHANGE
  365. //
  366. m_iSafeboxLoadTime = 0;
  367.  
  368. m_iMyShopTime = 0;
  369.  
  370. InitMC();
  371.  
  372. m_deposit_pulse = 0;
  373.  
  374. SET_OVER_TIME(this, OT_NONE);
  375.  
  376. m_strNewName = "";
  377.  
  378. m_known_guild.clear();
  379.  
  380. m_dwLogOffInterval = 0;
  381.  
  382. m_bComboSequence = 0;
  383. m_dwLastComboTime = 0;
  384. m_bComboIndex = 0;
  385. m_iComboHackCount = 0;
  386. m_dwSkipComboAttackByTime = 0;
  387.  
  388. m_dwMountTime = 0;
  389.  
  390. m_dwLastGoldDropTime = 0;
  391.  
  392. m_HackShieldCheckEvent = NULL;
  393. m_HackShieldCheckMode = false;
  394.  
  395. m_bIsLoadedAffect = false;
  396. cannot_dead = false;
  397.  
  398. #ifdef __PET_SYSTEM__
  399. m_petSystem = 0;
  400. m_bIsPet = false;
  401. #endif
  402.  
  403. m_fAttMul = 1.0f;
  404. m_fDamMul = 1.0f;
  405.  
  406. m_pointsInstant.iDragonSoulActiveDeck = -1;
  407.  
  408. memset(&m_tvLastSyncTime, 0, sizeof(m_tvLastSyncTime));
  409. m_iSyncHackCount = 0;
  410. }
  411.  
  412. void CHARACTER::Create(const char * c_pszName, DWORD vid, bool isPC)
  413. {
  414. static int s_crc = 172814;
  415.  
  416. char crc_string[128+1];
  417. snprintf(crc_string, sizeof(crc_string), "%s%p%d", c_pszName, this, ++s_crc);
  418. m_vid = VID(vid, GetCRC32(crc_string, strlen(crc_string)));
  419.  
  420. if (isPC)
  421. m_stName = c_pszName;
  422. }
  423.  
  424. void CHARACTER::Destroy()
  425. {
  426. CloseMyShop();
  427.  
  428. if (m_pkRegen)
  429. {
  430. if (m_pkDungeon) {
  431. // Dungeon regen may not be valid at this point
  432. if (m_pkDungeon->IsValidRegen(m_pkRegen, regen_id_)) {
  433. --m_pkRegen->count;
  434. }
  435. } else {
  436. // Is this really safe?
  437. --m_pkRegen->count;
  438. }
  439. m_pkRegen = NULL;
  440. }
  441.  
  442. if (m_pkDungeon)
  443. {
  444. SetDungeon(NULL);
  445. }
  446. #ifdef GIFT_SYSTEM
  447. event_cancel(&m_pkGiftRefresh);
  448. m_dwLastGiftPage = 0;
  449. m_mapGiftGrid.clear();
  450. #endif
  451. #ifdef OFFLINE_SHOP
  452. event_cancel(&m_pkRefreshShopEvent);
  453. bprivShop = 0;
  454. bprivShopOwner = 0;
  455. dw_ShopTime = 0;
  456. m_mapshops.clear();
  457. #endif
  458. #ifdef __PET_SYSTEM__
  459. if (m_petSystem)
  460. {
  461. m_petSystem->Destroy();
  462. delete m_petSystem;
  463.  
  464. m_petSystem = 0;
  465. }
  466. #endif
  467.  
  468. HorseSummon(false);
  469.  
  470. if (GetRider())
  471. GetRider()->ClearHorseInfo();
  472.  
  473. if( IsPC() )
  474. {
  475. if (isHackShieldEnable)
  476. {
  477. CHackShieldManager::instance().DeleteClientHandle(GetPlayerID());
  478. }
  479. }
  480.  
  481. if (GetDesc())
  482. {
  483. GetDesc()->BindCharacter(NULL);
  484. // BindDesc(NULL);
  485. }
  486.  
  487. if (m_pkExchange)
  488. m_pkExchange->Cancel();
  489.  
  490. SetVictim(NULL);
  491.  
  492. if (GetShop())
  493. {
  494. GetShop()->RemoveGuest(this);
  495. SetShop(NULL);
  496. }
  497.  
  498. ClearStone();
  499. ClearSync();
  500. ClearTarget();
  501.  
  502. if (NULL == m_pkMobData)
  503. {
  504. DragonSoul_CleanUp();
  505. ClearItem();
  506. }
  507.  
  508. // <Factor> m_pkParty becomes NULL after CParty destructor call!
  509. LPPARTY party = m_pkParty;
  510. if (party)
  511. {
  512. if (party->GetLeaderPID() == GetVID() && !IsPC())
  513. {
  514. M2_DELETE(party);
  515. }
  516. else
  517. {
  518. party->Unlink(this);
  519.  
  520. if (!IsPC())
  521. party->Quit(GetVID());
  522. }
  523.  
  524. SetParty(NULL); // ¾ÈÇصµ µÇÁö¸¸ ¾ÈÀüÇÏ°Ô.
  525. }
  526.  
  527. if (m_pkMobInst)
  528. {
  529. M2_DELETE(m_pkMobInst);
  530. m_pkMobInst = NULL;
  531. }
  532.  
  533. m_pkMobData = NULL;
  534.  
  535. if (m_pkSafebox)
  536. {
  537. M2_DELETE(m_pkSafebox);
  538. m_pkSafebox = NULL;
  539. }
  540.  
  541. if (m_pkMall)
  542. {
  543. M2_DELETE(m_pkMall);
  544. m_pkMall = NULL;
  545. }
  546.  
  547. for (TMapBuffOnAttrs::iterator it = m_map_buff_on_attrs.begin(); it != m_map_buff_on_attrs.end(); it++)
  548. {
  549. if (NULL != it->second)
  550. {
  551. M2_DELETE(it->second);
  552. }
  553. }
  554. m_map_buff_on_attrs.clear();
  555.  
  556. m_set_pkChrSpawnedBy.clear();
  557.  
  558. StopMuyeongEvent();
  559. event_cancel(&m_pkWarpNPCEvent);
  560. event_cancel(&m_pkRecoveryEvent);
  561. event_cancel(&m_pkDeadEvent);
  562. event_cancel(&m_pkSaveEvent);
  563. event_cancel(&m_pkTimedEvent);
  564. event_cancel(&m_pkStunEvent);
  565. event_cancel(&m_pkFishingEvent);
  566. event_cancel(&m_pkPoisonEvent);
  567. event_cancel(&m_pkBleedEvent);
  568. event_cancel(&m_pkFireEvent);
  569. event_cancel(&m_pkPartyRequestEvent);
  570. //DELAYED_WARP
  571. event_cancel(&m_pkWarpEvent);
  572. event_cancel(&m_pkCheckSpeedHackEvent);
  573. //END_DELAYED_WARP
  574.  
  575. // RECALL_DELAY
  576. //event_cancel(&m_pkRecallEvent);
  577. // END_OF_RECALL_DELAY
  578.  
  579. // MINING
  580. event_cancel(&m_pkMiningEvent);
  581. // END_OF_MINING
  582.  
  583. StopHackShieldCheckCycle();
  584.  
  585. for (itertype(m_mapMobSkillEvent) it = m_mapMobSkillEvent.begin(); it != m_mapMobSkillEvent.end(); ++it)
  586. {
  587. LPEVENT pkEvent = it->second;
  588. event_cancel(&pkEvent);
  589. }
  590. m_mapMobSkillEvent.clear();
  591.  
  592. //event_cancel(&m_pkAffectEvent);
  593. ClearAffect();
  594.  
  595. event_cancel(&m_pkDestroyWhenIdleEvent);
  596.  
  597. if (m_pSkillLevels)
  598. {
  599. M2_DELETE_ARRAY(m_pSkillLevels);
  600. m_pSkillLevels = NULL;
  601. }
  602.  
  603. CEntity::Destroy();
  604.  
  605. if (GetSectree())
  606. GetSectree()->RemoveEntity(this);
  607.  
  608. if (m_bMonsterLog)
  609. CHARACTER_MANAGER::instance().UnregisterForMonsterLog(this);
  610. }
  611.  
  612. const char * CHARACTER::GetName() const
  613. {
  614. return m_stName.empty() ? (m_pkMobData ? m_pkMobData->m_table.szLocaleName : "") : m_stName.c_str();
  615. }
  616.  
  617. bool CHARACTER::IsRestricted()
  618. {
  619. return GetQuestFlag("restrict.player");
  620. }
  621.  
  622. void CHARACTER::OpenMyShop(const char * c_pszSign, TShopItemTable * pTable, BYTE bItemCount)
  623. {
  624. if (GetPart(PART_MAIN) > 2)
  625. {
  626. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("°©¿ÊÀ» ¹þ¾î¾ß °³ÀÎ »óÁ¡À» ¿­ ¼ö ÀÖ½À´Ï´Ù."));
  627. return;
  628. }
  629.  
  630. if (GetMyShop()) // ÀÌ¹Ì ¼¥ÀÌ ¿­·Á ÀÖÀ¸¸é ´Ý´Â´Ù.
  631. {
  632. CloseMyShop();
  633. return;
  634. }
  635.  
  636. if (IsRestricted())
  637. {
  638. ChatPacket(CHAT_TYPE_INFO, "Nu ai permisiunea sa deschizi un magazin personal.");
  639. return;
  640. }
  641.  
  642. // ÁøÇàÁßÀÎ Äù½ºÆ®°¡ ÀÖÀ¸¸é »óÁ¡À» ¿­ ¼ö ¾ø´Ù.
  643. quest::PC * pPC = quest::CQuestManager::instance().GetPCForce(GetPlayerID());
  644.  
  645. // GetPCForce´Â NULLÀÏ ¼ö ¾øÀ¸¹Ç·Î µû·Î È®ÀÎÇÏÁö ¾ÊÀ½
  646. if (pPC->IsRunning())
  647. return;
  648.  
  649. if (bItemCount == 0)
  650. return;
  651.  
  652. long long nTotalMoney = 0;
  653.  
  654. for (int n = 0; n < bItemCount; ++n)
  655. {
  656. nTotalMoney += static_cast<long long>((pTable+n)->price);
  657. }
  658.  
  659. nTotalMoney += static_cast<long long>(GetGold());
  660.  
  661. if (GOLD_MAX <= nTotalMoney)
  662. {
  663. sys_err("[OVERFLOW_GOLD] Overflow (GOLD_MAX) id %u name %s", GetPlayerID(), GetName());
  664. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("20? ?? ???? ??? ??? ????"));
  665. return;
  666. }
  667.  
  668. char szSign[SHOP_SIGN_MAX_LEN+1];
  669. strlcpy(szSign, c_pszSign, sizeof(szSign));
  670.  
  671. m_stShopSign = szSign;
  672.  
  673. if (m_stShopSign.length() == 0)
  674. return;
  675.  
  676. if (LC_IsCanada() == false)
  677. {
  678. if (CBanwordManager::instance().CheckString(m_stShopSign.c_str(), m_stShopSign.length()))
  679. {
  680. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("ºñ¼Ó¾î³ª Àº¾î°¡ Æ÷ÇÔµÈ »óÁ¡ À̸§À¸·Î »óÁ¡À» ¿­ ¼ö ¾ø½À´Ï´Ù."));
  681. return;
  682. }
  683. }
  684.  
  685. // MYSHOP_PRICE_LIST
  686. std::map<DWORD, DWORD> itemkind; // ¾ÆÀÌÅÛ Á¾·ùº° °¡°Ý, first: vnum, second: ´ÜÀÏ ¼ö·® °¡°Ý
  687. // END_OF_MYSHOP_PRICE_LIST
  688.  
  689. std::set<TItemPos> cont;
  690. for (BYTE i = 0; i < bItemCount; ++i)
  691. {
  692. if (cont.find((pTable + i)->pos) != cont.end())
  693. {
  694. sys_err("MYSHOP: duplicate shop item detected! (name: %s)", GetName());
  695. return;
  696. }
  697.  
  698. // ANTI_GIVE, ANTI_MYSHOP check
  699. LPITEM pkItem = GetItem((pTable + i)->pos);
  700.  
  701. if (pkItem)
  702. {
  703. const TItemTable * item_table = pkItem->GetProto();
  704.  
  705. if (item_table && (IS_SET(item_table->dwAntiFlags, ITEM_ANTIFLAG_GIVE | ITEM_ANTIFLAG_MYSHOP)))
  706. {
  707. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("À¯·áÈ­ ¾ÆÀÌÅÛÀº °³ÀλóÁ¡¿¡¼­ ÆǸÅÇÒ ¼ö ¾ø½À´Ï´Ù."));
  708. return;
  709. }
  710.  
  711. if (pkItem->IsEquipped() == true)
  712. {
  713. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("ÀåºñÁßÀÎ ¾ÆÀÌÅÛÀº °³ÀλóÁ¡¿¡¼­ ÆǸÅÇÒ ¼ö ¾ø½À´Ï´Ù."));
  714. return;
  715. }
  716.  
  717. if (true == pkItem->isLocked())
  718. {
  719. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("»ç¿ëÁßÀÎ ¾ÆÀÌÅÛÀº °³ÀλóÁ¡¿¡¼­ ÆǸÅÇÒ ¼ö ¾ø½À´Ï´Ù."));
  720. return;
  721. }
  722.  
  723. // MYSHOP_PRICE_LIST
  724. itemkind[pkItem->GetVnum()] = (pTable + i)->price / pkItem->GetCount();
  725. // END_OF_MYSHOP_PRICE_LIST
  726. }
  727.  
  728. cont.insert((pTable + i)->pos);
  729. }
  730.  
  731. // MYSHOP_PRICE_LIST
  732. // º¸µû¸® °³¼ö¸¦ °¨¼Ò½ÃŲ´Ù.
  733. if (CountSpecifyItem(71049)) { // ºñ´Ü º¸µû¸®´Â ¾ø¾ÖÁö ¾Ê°í °¡°ÝÁ¤º¸¸¦ ÀúÀåÇÑ´Ù.
  734.  
  735. //
  736. // ¾ÆÀÌÅÛ °¡°ÝÁ¤º¸¸¦ ÀúÀåÇϱâ À§ÇØ ¾ÆÀÌÅÛ °¡°ÝÁ¤º¸ ÆÐŶÀ» ¸¸µé¾î DB ij½Ã¿¡ º¸³½´Ù.
  737. //
  738. TPacketMyshopPricelistHeader header;
  739. TItemPriceInfo info;
  740.  
  741. header.dwOwnerID = GetPlayerID();
  742. header.byCount = itemkind.size();
  743.  
  744. TEMP_BUFFER buf;
  745. buf.write(&header, sizeof(header));
  746.  
  747. for (itertype(itemkind) it = itemkind.begin(); it != itemkind.end(); ++it)
  748. {
  749. info.dwVnum = it->first;
  750. info.dwPrice = it->second;
  751.  
  752. buf.write(&info, sizeof(info));
  753. }
  754.  
  755. db_clientdesc->DBPacket(HEADER_GD_MYSHOP_PRICELIST_UPDATE, 0, buf.read_peek(), buf.size());
  756. }
  757. // END_OF_MYSHOP_PRICE_LIST
  758. else if (CountSpecifyItem(50200))
  759. RemoveSpecifyItem(50200, 1);
  760. else
  761. return; // º¸µû¸®°¡ ¾øÀ¸¸é Áß´Ü.
  762.  
  763. if (m_pkExchange)
  764. m_pkExchange->Cancel();
  765.  
  766. TPacketGCShopSign p;
  767.  
  768. p.bHeader = HEADER_GC_SHOP_SIGN;
  769. p.dwVID = GetVID();
  770. strlcpy(p.szSign, c_pszSign, sizeof(p.szSign));
  771.  
  772. PacketAround(&p, sizeof(TPacketGCShopSign));
  773.  
  774. m_pkMyShop = CShopManager::instance().CreatePCShop(this, pTable, bItemCount);
  775.  
  776. if (IsPolymorphed() == true)
  777. {
  778. RemoveAffect(AFFECT_POLYMORPH);
  779. }
  780.  
  781. if (GetHorse())
  782. {
  783. HorseSummon( false, true );
  784. }
  785. // new mount ÀÌ¿ë Áß¿¡, °³ÀÎ »óÁ¡ ¿­¸é ÀÚµ¿ unmount
  786. // StopRidingÀ¸·Î ´º¸¶¿îÆ®±îÁö ó¸®Çϸé ÁÁÀºµ¥ ¿Ö ±×·¸°Ô ¾ÈÇسù´ÂÁö ¾Ë ¼ö ¾ø´Ù.
  787. else if (GetMountVnum())
  788. {
  789. RemoveAffect(AFFECT_MOUNT);
  790. RemoveAffect(AFFECT_MOUNT_BONUS);
  791. }
  792. //if (!LC_IsNewCIBN())
  793. SetPolymorph(30000, true);
  794.  
  795. }
  796.  
  797. void CHARACTER::CloseMyShop()
  798. {
  799. if (GetMyShop())
  800. {
  801.  
  802. m_stShopSign.clear();
  803. CShopManager::instance().DestroyPCShop(this);
  804. m_pkMyShop = NULL;
  805.  
  806. TPacketGCShopSign p;
  807.  
  808. p.bHeader = HEADER_GC_SHOP_SIGN;
  809. p.dwVID = GetVID();
  810. p.szSign[0] = '\0';
  811.  
  812. PacketAround(&p, sizeof(p));
  813.  
  814. #ifdef OFFLINE_SHOP
  815. if (IsPrivShop())
  816. {
  817. M2_DESTROY_CHARACTER(this);
  818. return;
  819. }
  820. #endif
  821. SetPolymorph(GetJob(), true);
  822. }
  823. }
  824.  
  825. void EncodeMovePacket(TPacketGCMove & pack, DWORD dwVID, BYTE bFunc, BYTE bArg, DWORD x, DWORD y, DWORD dwDuration, DWORD dwTime, BYTE bRot)
  826. {
  827. pack.bHeader = HEADER_GC_MOVE;
  828. pack.bFunc = bFunc;
  829. pack.bArg = bArg;
  830. pack.dwVID = dwVID;
  831. pack.dwTime = dwTime ? dwTime : get_dword_time();
  832. pack.bRot = bRot;
  833. pack.lX = x;
  834. pack.lY = y;
  835. pack.dwDuration = dwDuration;
  836. }
  837.  
  838. void CHARACTER::RestartAtSamePos()
  839. {
  840. if (m_bIsObserver)
  841. return;
  842.  
  843. EncodeRemovePacket(this);
  844. EncodeInsertPacket(this);
  845.  
  846. ENTITY_MAP::iterator it = m_map_view.begin();
  847.  
  848. while (it != m_map_view.end())
  849. {
  850. LPENTITY entity = (it++)->first;
  851.  
  852. EncodeRemovePacket(entity);
  853. if (!m_bIsObserver)
  854. EncodeInsertPacket(entity);
  855.  
  856. if( entity->IsType(ENTITY_CHARACTER) )
  857. {
  858. LPCHARACTER lpChar = (LPCHARACTER)entity;
  859. if( lpChar->IsPC() || lpChar->IsNPC() || lpChar->IsMonster() )
  860. {
  861. if (!entity->IsObserverMode())
  862. entity->EncodeInsertPacket(this);
  863. }
  864. }
  865. else
  866. {
  867. if( !entity->IsObserverMode())
  868. {
  869. entity->EncodeInsertPacket(this);
  870. }
  871. }
  872. }
  873. }
  874.  
  875.  
  876. // Entity¿¡ ³»°¡ ³ªÅ¸³µ´Ù°í ÆÐŶÀ» º¸³½´Ù.
  877. void CHARACTER::EncodeInsertPacket(LPENTITY entity)
  878. {
  879.  
  880. LPDESC d;
  881.  
  882. if (!(d = entity->GetDesc()))
  883. return;
  884.  
  885. // ±æµåÀ̸§ ¹ö±× ¼öÁ¤ ÄÚµå
  886. LPCHARACTER ch = (LPCHARACTER) entity;
  887. ch->SendGuildName(GetGuild());
  888. // ±æµåÀ̸§ ¹ö±× ¼öÁ¤ ÄÚµå
  889.  
  890. TPacketGCCharacterAdd pack;
  891.  
  892. pack.header = HEADER_GC_CHARACTER_ADD;
  893. pack.dwVID = m_vid;
  894. pack.bType = GetCharType();
  895. pack.angle = GetRotation();
  896. pack.x = GetX();
  897. pack.y = GetY();
  898. pack.z = GetZ();
  899. pack.wRaceNum = GetRaceNum();
  900. if (IsPet())
  901. {
  902. pack.bMovingSpeed = 150;
  903. }
  904. else
  905. {
  906. pack.bMovingSpeed = GetLimitPoint(POINT_MOV_SPEED);
  907. }
  908. pack.bAttackSpeed = GetLimitPoint(POINT_ATT_SPEED);
  909. pack.dwAffectFlag[0] = m_afAffectFlag.bits[0];
  910. pack.dwAffectFlag[1] = m_afAffectFlag.bits[1];
  911.  
  912. pack.bStateFlag = m_bAddChrState;
  913.  
  914. int iDur = 0;
  915.  
  916. if (m_posDest.x != pack.x || m_posDest.y != pack.y)
  917. {
  918. iDur = (m_dwMoveStartTime + m_dwMoveDuration) - get_dword_time();
  919.  
  920. if (iDur <= 0)
  921. {
  922. pack.x = m_posDest.x;
  923. pack.y = m_posDest.y;
  924. }
  925. }
  926.  
  927. d->Packet(&pack, sizeof(pack));
  928.  
  929. if (IsPC() == true || m_bCharType == CHAR_TYPE_NPC)
  930. {
  931. TPacketGCCharacterAdditionalInfo addPacket;
  932. memset(&addPacket, 0, sizeof(TPacketGCCharacterAdditionalInfo));
  933.  
  934. addPacket.header = HEADER_GC_CHAR_ADDITIONAL_INFO;
  935. addPacket.dwVID = m_vid;
  936.  
  937. addPacket.awPart[CHR_EQUIPPART_ARMOR] = GetPart(PART_MAIN);
  938. addPacket.awPart[CHR_EQUIPPART_WEAPON] = GetPart(PART_WEAPON);
  939. addPacket.awPart[CHR_EQUIPPART_HEAD] = GetPart(PART_HEAD);
  940. addPacket.awPart[CHR_EQUIPPART_HAIR] = GetPart(PART_HAIR);
  941. addPacket.awPart[CHR_EQUIPPART_ACCE] = GetPart(PART_ACCE);
  942.  
  943. addPacket.bPKMode = m_bPKMode;
  944. addPacket.dwMountVnum = GetMountVnum();
  945. addPacket.bEmpire = m_bEmpire;
  946.  
  947. if (IsPC() == true && (LC_IsEurope() == true || LC_IsCanada() == true || LC_IsSingapore() == true))
  948. {
  949. addPacket.dwLevel = GetLevel();
  950. }
  951. else
  952. {
  953. addPacket.dwLevel = 0;
  954. }
  955.  
  956. if (false)
  957. {
  958. LPCHARACTER ch = (LPCHARACTER) entity;
  959.  
  960. if (GetEmpire() == ch->GetEmpire() || ch->GetGMLevel() > GM_PLAYER || m_bCharType == CHAR_TYPE_NPC)
  961. {
  962. goto show_all_info;
  963. }
  964. else
  965. {
  966. memset(addPacket.name, 0, CHARACTER_NAME_MAX_LEN);
  967. addPacket.dwGuildID = 0;
  968. addPacket.sAlignment = 0;
  969. }
  970. }
  971. else
  972. {
  973. show_all_info:
  974. #if defined(SHOP_HIDE_NAME) && defined(OFFLINE_SHOP)
  975. if (IsPC() || GetRaceNum() != 30000 && !IsPrivShop())
  976. #endif
  977. strlcpy(addPacket.name, GetName(), sizeof(addPacket.name));
  978.  
  979.  
  980. if (GetGuild() != NULL)
  981. {
  982. addPacket.dwGuildID = GetGuild()->GetID();
  983. }
  984. else
  985. {
  986. addPacket.dwGuildID = 0;
  987. }
  988.  
  989. addPacket.sAlignment = m_iAlignment / 10;
  990. }
  991.  
  992. d->Packet(&addPacket, sizeof(TPacketGCCharacterAdditionalInfo));
  993. }
  994.  
  995. if (iDur)
  996. {
  997. TPacketGCMove pack;
  998. EncodeMovePacket(pack, GetVID(), FUNC_MOVE, 0, m_posDest.x, m_posDest.y, iDur, 0, (BYTE) (GetRotation() / 5));
  999. d->Packet(&pack, sizeof(pack));
  1000.  
  1001. TPacketGCWalkMode p;
  1002. p.vid = GetVID();
  1003. p.header = HEADER_GC_WALK_MODE;
  1004. p.mode = m_bNowWalking ? WALKMODE_WALK : WALKMODE_RUN;
  1005.  
  1006. d->Packet(&p, sizeof(p));
  1007. }
  1008.  
  1009. if (entity->IsType(ENTITY_CHARACTER) && GetDesc())
  1010. {
  1011. LPCHARACTER ch = (LPCHARACTER) entity;
  1012. if (ch->IsWalking())
  1013. {
  1014. TPacketGCWalkMode p;
  1015. p.vid = ch->GetVID();
  1016. p.header = HEADER_GC_WALK_MODE;
  1017. p.mode = ch->m_bNowWalking ? WALKMODE_WALK : WALKMODE_RUN;
  1018. GetDesc()->Packet(&p, sizeof(p));
  1019. }
  1020. }
  1021.  
  1022. if (GetMyShop())
  1023. {
  1024. TPacketGCShopSign p;
  1025.  
  1026. p.bHeader = HEADER_GC_SHOP_SIGN;
  1027. p.dwVID = GetVID();
  1028. strlcpy(p.szSign, m_stShopSign.c_str(), sizeof(p.szSign));
  1029.  
  1030. d->Packet(&p, sizeof(TPacketGCShopSign));
  1031. }
  1032.  
  1033. #ifdef ENABLE_OFFLINE_SHOP_SYSTEM
  1034. if (IsOfflineShopNPC() && GetRaceNum() == 30000)
  1035. {
  1036. TPacketGCShopSign p;
  1037.  
  1038. p.bHeader = HEADER_GC_OFFLINE_SHOP_SIGN;
  1039. p.dwVID = GetVID();
  1040. if (m_stOfflineShopSign.empty())
  1041. {
  1042. std::auto_ptr<SQLMsg> pMsg(DBManager::instance().DirectQuery("SELECT sign FROM player.offline_shop_npc WHERE owner_id = %u", GetOfflineShopRealOwner()));
  1043. if (pMsg->Get()->uiNumRows > 0)
  1044. {
  1045. MYSQL_ROW row = mysql_fetch_row(pMsg->Get()->pSQLResult);
  1046. strlcpy(p.szSign, row[0], sizeof(p.szSign));
  1047. }
  1048. }
  1049. else
  1050. {
  1051. strlcpy(p.szSign, m_stOfflineShopSign.c_str(), sizeof(p.szSign));
  1052. }
  1053.  
  1054. d->Packet(&p, sizeof(TPacketGCShopSign));
  1055. }
  1056. #endif
  1057.  
  1058. if (entity->IsType(ENTITY_CHARACTER))
  1059. {
  1060. sys_log(3, "EntityInsert %s (RaceNum %d) (%d %d) TO %s",
  1061. GetName(), GetRaceNum(), GetX() / SECTREE_SIZE, GetY() / SECTREE_SIZE, ((LPCHARACTER)entity)->GetName());
  1062. }
  1063. }
  1064.  
  1065. void CHARACTER::EncodeRemovePacket(LPENTITY entity)
  1066. {
  1067. if (entity->GetType() != ENTITY_CHARACTER)
  1068. return;
  1069.  
  1070. LPDESC d;
  1071.  
  1072. if (!(d = entity->GetDesc()))
  1073. return;
  1074.  
  1075. TPacketGCCharacterDelete pack;
  1076.  
  1077. pack.header = HEADER_GC_CHARACTER_DEL;
  1078. pack.id = m_vid;
  1079.  
  1080. d->Packet(&pack, sizeof(TPacketGCCharacterDelete));
  1081.  
  1082. if (entity->IsType(ENTITY_CHARACTER))
  1083. sys_log(3, "EntityRemove %s(%d) FROM %s", GetName(), (DWORD) m_vid, ((LPCHARACTER) entity)->GetName());
  1084. }
  1085.  
  1086. void CHARACTER::UpdatePacket()
  1087. {
  1088. if (GetSectree() == NULL) return;
  1089.  
  1090. TPacketGCCharacterUpdate pack;
  1091. TPacketGCCharacterUpdate pack2;
  1092.  
  1093. pack.header = HEADER_GC_CHARACTER_UPDATE;
  1094. pack.dwVID = m_vid;
  1095.  
  1096. pack.awPart[CHR_EQUIPPART_ARMOR] = GetPart(PART_MAIN);
  1097. pack.awPart[CHR_EQUIPPART_WEAPON] = GetPart(PART_WEAPON);
  1098. pack.awPart[CHR_EQUIPPART_HEAD] = GetPart(PART_HEAD);
  1099. pack.awPart[CHR_EQUIPPART_HAIR] = GetPart(PART_HAIR);
  1100. pack.awPart[CHR_EQUIPPART_ACCE] = GetPart(PART_ACCE);
  1101.  
  1102. pack.bMovingSpeed = GetLimitPoint(POINT_MOV_SPEED);
  1103. pack.bAttackSpeed = GetLimitPoint(POINT_ATT_SPEED);
  1104. pack.bStateFlag = m_bAddChrState;
  1105. pack.dwAffectFlag[0] = m_afAffectFlag.bits[0];
  1106. pack.dwAffectFlag[1] = m_afAffectFlag.bits[1];
  1107. pack.dwGuildID = 0;
  1108. pack.sAlignment = m_iAlignment / 10;
  1109. pack.bPKMode = m_bPKMode;
  1110.  
  1111. if (GetGuild())
  1112. pack.dwGuildID = GetGuild()->GetID();
  1113.  
  1114. pack.dwMountVnum = GetMountVnum();
  1115.  
  1116. pack2 = pack;
  1117. pack2.dwGuildID = 0;
  1118. pack2.sAlignment = 0;
  1119.  
  1120. if (false)
  1121. {
  1122. if (m_bIsObserver != true)
  1123. {
  1124. for (ENTITY_MAP::iterator iter = m_map_view.begin(); iter != m_map_view.end(); iter++)
  1125. {
  1126. LPENTITY pEntity = iter->first;
  1127.  
  1128. if (pEntity != NULL)
  1129. {
  1130. if (pEntity->IsType(ENTITY_CHARACTER) == true)
  1131. {
  1132. if (pEntity->GetDesc() != NULL)
  1133. {
  1134. LPCHARACTER pChar = (LPCHARACTER)pEntity;
  1135.  
  1136. if (GetEmpire() == pChar->GetEmpire() || pChar->GetGMLevel() > GM_PLAYER)
  1137. {
  1138. pEntity->GetDesc()->Packet(&pack, sizeof(pack));
  1139. }
  1140. else
  1141. {
  1142. pEntity->GetDesc()->Packet(&pack2, sizeof(pack2));
  1143. }
  1144. }
  1145. }
  1146. else
  1147. {
  1148. if (pEntity->GetDesc() != NULL)
  1149. {
  1150. pEntity->GetDesc()->Packet(&pack, sizeof(pack));
  1151. }
  1152. }
  1153. }
  1154. }
  1155. }
  1156.  
  1157. if (GetDesc() != NULL)
  1158. {
  1159. GetDesc()->Packet(&pack, sizeof(pack));
  1160. }
  1161. }
  1162. else
  1163. {
  1164. PacketAround(&pack, sizeof(pack));
  1165. }
  1166. }
  1167.  
  1168. LPCHARACTER CHARACTER::FindCharacterInView(const char * c_pszName, bool bFindPCOnly)
  1169. {
  1170. ENTITY_MAP::iterator it = m_map_view.begin();
  1171.  
  1172. for (; it != m_map_view.end(); ++it)
  1173. {
  1174. if (!it->first->IsType(ENTITY_CHARACTER))
  1175. continue;
  1176.  
  1177. LPCHARACTER tch = (LPCHARACTER) it->first;
  1178.  
  1179. if (bFindPCOnly && tch->IsNPC())
  1180. continue;
  1181.  
  1182. if (!strcasecmp(tch->GetName(), c_pszName))
  1183. return (tch);
  1184. }
  1185.  
  1186. return NULL;
  1187. }
  1188.  
  1189. void CHARACTER::SetPosition(int pos)
  1190. {
  1191. if (pos == POS_STANDING)
  1192. {
  1193. REMOVE_BIT(m_bAddChrState, ADD_CHARACTER_STATE_DEAD);
  1194. REMOVE_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_STUN);
  1195.  
  1196. event_cancel(&m_pkDeadEvent);
  1197. event_cancel(&m_pkStunEvent);
  1198. }
  1199. else if (pos == POS_DEAD)
  1200. SET_BIT(m_bAddChrState, ADD_CHARACTER_STATE_DEAD);
  1201.  
  1202. if (!IsStone())
  1203. {
  1204. switch (pos)
  1205. {
  1206. case POS_FIGHTING:
  1207. if (!IsState(m_stateBattle))
  1208. MonsterLog("[BATTLE] ½Î¿ì´Â »óÅÂ");
  1209.  
  1210. GotoState(m_stateBattle);
  1211. break;
  1212.  
  1213. default:
  1214. if (!IsState(m_stateIdle))
  1215. MonsterLog("[IDLE] ½¬´Â »óÅÂ");
  1216.  
  1217. GotoState(m_stateIdle);
  1218. break;
  1219. }
  1220. }
  1221.  
  1222. m_pointsInstant.position = pos;
  1223. }
  1224.  
  1225. void CHARACTER::Save()
  1226. {
  1227. if (!m_bSkipSave)
  1228. CHARACTER_MANAGER::instance().DelayedSave(this);
  1229. }
  1230.  
  1231. void CHARACTER::CreatePlayerProto(TPlayerTable & tab)
  1232. {
  1233. memset(&tab, 0, sizeof(TPlayerTable));
  1234.  
  1235. if (GetNewName().empty())
  1236. {
  1237. strlcpy(tab.name, GetName(), sizeof(tab.name));
  1238. }
  1239. else
  1240. {
  1241. strlcpy(tab.name, GetNewName().c_str(), sizeof(tab.name));
  1242. }
  1243.  
  1244. strlcpy(tab.ip, GetDesc()->GetHostName(), sizeof(tab.ip));
  1245.  
  1246. tab.id = m_dwPlayerID;
  1247. tab.voice = GetPoint(POINT_VOICE);
  1248. tab.level = GetLevel();
  1249. tab.level_step = GetPoint(POINT_LEVEL_STEP);
  1250. tab.exp = GetExp();
  1251. tab.gold = GetGold();
  1252. tab.job = m_points.job;
  1253. tab.part_base = m_pointsInstant.bBasePart;
  1254. tab.skill_group = m_points.skill_group;
  1255.  
  1256. DWORD dwPlayedTime = (get_dword_time() - m_dwPlayStartTime);
  1257.  
  1258. if (dwPlayedTime > 60000)
  1259. {
  1260. if (GetSectree() && !GetSectree()->IsAttr(GetX(), GetY(), ATTR_BANPK))
  1261. {
  1262. if (GetRealAlignment() < 0)
  1263. {
  1264. if (IsEquipUniqueItem(UNIQUE_ITEM_FASTER_ALIGNMENT_UP_BY_TIME))
  1265. UpdateAlignment(120 * (dwPlayedTime / 60000));
  1266. else
  1267. UpdateAlignment(60 * (dwPlayedTime / 60000));
  1268. }
  1269. else
  1270. UpdateAlignment(5 * (dwPlayedTime / 60000));
  1271. }
  1272.  
  1273. SetRealPoint(POINT_PLAYTIME, GetRealPoint(POINT_PLAYTIME) + dwPlayedTime / 60000);
  1274. ResetPlayTime(dwPlayedTime % 60000);
  1275. }
  1276.  
  1277. tab.playtime = GetRealPoint(POINT_PLAYTIME);
  1278. tab.lAlignment = m_iRealAlignment;
  1279.  
  1280. if (m_posWarp.x != 0 || m_posWarp.y != 0)
  1281. {
  1282. tab.x = m_posWarp.x;
  1283. tab.y = m_posWarp.y;
  1284. tab.z = 0;
  1285. tab.lMapIndex = m_lWarpMapIndex;
  1286. }
  1287. else
  1288. {
  1289. tab.x = GetX();
  1290. tab.y = GetY();
  1291. tab.z = GetZ();
  1292. tab.lMapIndex = GetMapIndex();
  1293. }
  1294.  
  1295. if (m_lExitMapIndex == 0)
  1296. {
  1297. tab.lExitMapIndex = tab.lMapIndex;
  1298. tab.lExitX = tab.x;
  1299. tab.lExitY = tab.y;
  1300. }
  1301. else
  1302. {
  1303. tab.lExitMapIndex = m_lExitMapIndex;
  1304. tab.lExitX = m_posExit.x;
  1305. tab.lExitY = m_posExit.y;
  1306. }
  1307.  
  1308. sys_log(0, "SAVE: %s %dx%d", GetName(), tab.x, tab.y);
  1309.  
  1310. tab.st = GetRealPoint(POINT_ST);
  1311. tab.ht = GetRealPoint(POINT_HT);
  1312. tab.dx = GetRealPoint(POINT_DX);
  1313. tab.iq = GetRealPoint(POINT_IQ);
  1314.  
  1315. tab.stat_point = GetPoint(POINT_STAT);
  1316. tab.skill_point = GetPoint(POINT_SKILL);
  1317. tab.sub_skill_point = GetPoint(POINT_SUB_SKILL);
  1318. tab.horse_skill_point = GetPoint(POINT_HORSE_SKILL);
  1319.  
  1320. tab.stat_reset_count = GetPoint(POINT_STAT_RESET_COUNT);
  1321.  
  1322. tab.hp = GetHP();
  1323. tab.sp = GetSP();
  1324.  
  1325. tab.stamina = GetStamina();
  1326.  
  1327. tab.sRandomHP = m_points.iRandomHP;
  1328. tab.sRandomSP = m_points.iRandomSP;
  1329.  
  1330. for (int i = 0; i < QUICKSLOT_MAX_NUM; ++i)
  1331. tab.quickslot[i] = m_quickslot[i];
  1332.  
  1333. if (m_stMobile.length() && !*m_szMobileAuth)
  1334. strlcpy(tab.szMobile, m_stMobile.c_str(), sizeof(tab.szMobile));
  1335.  
  1336. thecore_memcpy(tab.parts, m_pointsInstant.parts, sizeof(tab.parts));
  1337.  
  1338. // REMOVE_REAL_SKILL_LEVLES
  1339. thecore_memcpy(tab.skills, m_pSkillLevels, sizeof(TPlayerSkill) * SKILL_MAX_NUM);
  1340. // END_OF_REMOVE_REAL_SKILL_LEVLES
  1341.  
  1342. tab.horse = GetHorseData();
  1343. }
  1344.  
  1345.  
  1346. void CHARACTER::SaveReal()
  1347. {
  1348. if (m_bSkipSave)
  1349. return;
  1350.  
  1351. if (!GetDesc())
  1352. {
  1353. sys_err("Character::Save : no descriptor when saving (name: %s)", GetName());
  1354. return;
  1355. }
  1356.  
  1357. TPlayerTable table;
  1358. CreatePlayerProto(table);
  1359.  
  1360. db_clientdesc->DBPacket(HEADER_GD_PLAYER_SAVE, GetDesc()->GetHandle(), &table, sizeof(TPlayerTable));
  1361.  
  1362. quest::PC * pkQuestPC = quest::CQuestManager::instance().GetPCForce(GetPlayerID());
  1363.  
  1364. if (!pkQuestPC)
  1365. sys_err("CHARACTER::Save : null quest::PC pointer! (name %s)", GetName());
  1366. else
  1367. {
  1368. pkQuestPC->Save();
  1369. }
  1370.  
  1371. marriage::TMarriage* pMarriage = marriage::CManager::instance().Get(GetPlayerID());
  1372. if (pMarriage)
  1373. pMarriage->Save();
  1374. }
  1375.  
  1376. void CHARACTER::FlushDelayedSaveItem()
  1377. {
  1378. // ÀúÀå ¾ÈµÈ ¼ÒÁöÇ°À» ÀüºÎ ÀúÀå½ÃŲ´Ù.
  1379. LPITEM item;
  1380.  
  1381. for (int i = 0; i < INVENTORY_AND_EQUIP_SLOT_MAX; ++i)
  1382. if ((item = GetInventoryItem(i)))
  1383. ITEM_MANAGER::instance().FlushDelayedSave(item);
  1384. }
  1385.  
  1386. #ifdef ENABLE_FUNCTION_VEGAS_VIP
  1387. void CHARACTER::RefreshVip()
  1388. {
  1389. m_afAffectFlag.Set(AFF_VIP); // Not will be used all time, only one time for refresh logo vip, no need relog or warp etc, in real time will be display you when you accept vip grade.
  1390. }
  1391. #endif
  1392.  
  1393. void CHARACTER::Disconnect(const char * c_pszReason)
  1394. {
  1395. assert(GetDesc() != NULL);
  1396.  
  1397. sys_log(0, "DISCONNECT: %s (%s)", GetName(), c_pszReason ? c_pszReason : "unset" );
  1398.  
  1399. if (GetShop())
  1400. {
  1401. GetShop()->RemoveGuest(this);
  1402. SetShop(NULL);
  1403. }
  1404.  
  1405. #ifdef ENABLE_OFFLINE_SHOP_SYSTEM
  1406. if (GetOfflineShop())
  1407. {
  1408. GetOfflineShop()->RemoveGuest(this);
  1409. SetOfflineShop(NULL);
  1410. }
  1411. #endif
  1412.  
  1413. if (GetArena() != NULL)
  1414. {
  1415. GetArena()->OnDisconnect(GetPlayerID());
  1416. }
  1417.  
  1418. if (GetParty() != NULL)
  1419. {
  1420. GetParty()->UpdateOfflineState(GetPlayerID());
  1421. }
  1422.  
  1423. marriage::CManager::instance().Logout(this);
  1424.  
  1425. // P2P Logout
  1426. TPacketGGLogout p;
  1427. p.bHeader = HEADER_GG_LOGOUT;
  1428. strlcpy(p.szName, GetName(), sizeof(p.szName));
  1429. P2P_MANAGER::instance().Send(&p, sizeof(TPacketGGLogout));
  1430. char buf[51];
  1431. snprintf(buf, sizeof(buf), "%s %lld %d %ld %d",
  1432. inet_ntoa(GetDesc()->GetAddr().sin_addr), GetGold(), g_bChannel, GetMapIndex(), GetAlignment());
  1433.  
  1434. LogManager::instance().CharLog(this, 0, "LOGOUT", buf);
  1435.  
  1436. if (LC_IsYMIR() || LC_IsKorea() || LC_IsBrazil())
  1437. {
  1438. long playTime = GetRealPoint(POINT_PLAYTIME) - m_dwLoginPlayTime;
  1439. LogManager::instance().LoginLog(false, GetDesc()->GetAccountTable().id, GetPlayerID(), GetLevel(), GetJob(), playTime);
  1440.  
  1441. if (LC_IsBrazil() != true)
  1442. CPCBangManager::instance().Log(GetDesc()->GetHostName(), GetPlayerID(), playTime);
  1443. }
  1444.  
  1445. if (m_pWarMap)
  1446. SetWarMap(NULL);
  1447.  
  1448. if (m_pWeddingMap)
  1449. {
  1450. SetWeddingMap(NULL);
  1451. }
  1452.  
  1453. if (GetGuild())
  1454. GetGuild()->LogoutMember(this);
  1455.  
  1456. quest::CQuestManager::instance().LogoutPC(this);
  1457.  
  1458. if (GetParty())
  1459. GetParty()->Unlink(this);
  1460.  
  1461. // Á×¾úÀ» ¶§ Á¢¼Ó²÷À¸¸é °æÇèÄ¡ ÁÙ°Ô Çϱâ
  1462. if (IsStun() || IsDead())
  1463. {
  1464. DeathPenalty(0);
  1465. PointChange(POINT_HP, 50 - GetHP());
  1466. }
  1467.  
  1468.  
  1469. if (!CHARACTER_MANAGER::instance().FlushDelayedSave(this))
  1470. {
  1471. SaveReal();
  1472. }
  1473.  
  1474. FlushDelayedSaveItem();
  1475.  
  1476. SaveAffect();
  1477. m_bIsLoadedAffect = false;
  1478.  
  1479. m_bSkipSave = true; // ÀÌ ÀÌÈÄ¿¡´Â ´õÀÌ»ó ÀúÀåÇÏ¸é ¾ÈµÈ´Ù.
  1480.  
  1481. quest::CQuestManager::instance().DisconnectPC(this);
  1482.  
  1483. CloseSafebox();
  1484.  
  1485. CloseMall();
  1486.  
  1487. CPVPManager::instance().Disconnect(this);
  1488.  
  1489. CTargetManager::instance().Logout(GetPlayerID());
  1490.  
  1491. MessengerManager::instance().Logout(GetName());
  1492.  
  1493. if (g_TeenDesc)
  1494. {
  1495. int offset = 0;
  1496. char buf[245] = {0};
  1497.  
  1498. buf[0] = HEADER_GT_LOGOUT;
  1499. offset += 1;
  1500.  
  1501. memset(buf+offset, 0x00, 2);
  1502. offset += 2;
  1503.  
  1504. TAccountTable &acc_table = GetDesc()->GetAccountTable();
  1505. memcpy(buf+offset, &acc_table.id, 4);
  1506. offset += 4;
  1507.  
  1508. g_TeenDesc->Packet(buf, offset);
  1509. }
  1510.  
  1511. if (GetDesc())
  1512. {
  1513. GetDesc()->BindCharacter(NULL);
  1514. // BindDesc(NULL);
  1515. }
  1516.  
  1517. CXTrapManager::instance().DestroyClientSession(this);
  1518.  
  1519. M2_DESTROY_CHARACTER(this);
  1520. }
  1521.  
  1522. bool CHARACTER::Show(long lMapIndex, long x, long y, long z, bool bShowSpawnMotion/* = false */)
  1523. {
  1524. LPSECTREE sectree = SECTREE_MANAGER::instance().Get(lMapIndex, x, y);
  1525.  
  1526. if (!sectree)
  1527. {
  1528. sys_log(0, "cannot find sectree by %dx%d mapindex %d", x, y, lMapIndex);
  1529. return false;
  1530. }
  1531.  
  1532. SetMapIndex(lMapIndex);
  1533.  
  1534. bool bChangeTree = false;
  1535.  
  1536. if (!GetSectree() || GetSectree() != sectree)
  1537. bChangeTree = true;
  1538.  
  1539. if (bChangeTree)
  1540. {
  1541. if (GetSectree())
  1542. GetSectree()->RemoveEntity(this);
  1543.  
  1544. ViewCleanup();
  1545. }
  1546.  
  1547. if (!IsNPC())
  1548. {
  1549. sys_log(0, "SHOW: %s %dx%dx%d", GetName(), x, y, z);
  1550. if (GetStamina() < GetMaxStamina())
  1551. StartAffectEvent();
  1552. }
  1553. else if (m_pkMobData)
  1554. {
  1555. m_pkMobInst->m_posLastAttacked.x = x;
  1556. m_pkMobInst->m_posLastAttacked.y = y;
  1557. m_pkMobInst->m_posLastAttacked.z = z;
  1558. }
  1559.  
  1560. if (bShowSpawnMotion)
  1561. {
  1562. SET_BIT(m_bAddChrState, ADD_CHARACTER_STATE_SPAWN);
  1563. m_afAffectFlag.Set(AFF_SPAWN);
  1564. }
  1565.  
  1566. SetXYZ(x, y, z);
  1567.  
  1568. m_posDest.x = x;
  1569. m_posDest.y = y;
  1570. m_posDest.z = z;
  1571.  
  1572. m_posStart.x = x;
  1573. m_posStart.y = y;
  1574. m_posStart.z = z;
  1575.  
  1576. if (bChangeTree)
  1577. {
  1578. EncodeInsertPacket(this);
  1579. sectree->InsertEntity(this);
  1580.  
  1581. UpdateSectree();
  1582. }
  1583. else
  1584. {
  1585. ViewReencode();
  1586. sys_log(0, " in same sectree");
  1587. }
  1588.  
  1589. REMOVE_BIT(m_bAddChrState, ADD_CHARACTER_STATE_SPAWN);
  1590.  
  1591. SetValidComboInterval(0);
  1592. return true;
  1593. }
  1594.  
  1595. // BGM_INFO
  1596. struct BGMInfo
  1597. {
  1598. std::string name;
  1599. float vol;
  1600. };
  1601.  
  1602. typedef std::map<unsigned, BGMInfo> BGMInfoMap;
  1603.  
  1604. static BGMInfoMap gs_bgmInfoMap;
  1605. static bool gs_bgmVolEnable = false;
  1606.  
  1607. void CHARACTER_SetBGMVolumeEnable()
  1608. {
  1609. gs_bgmVolEnable = true;
  1610. sys_log(0, "bgm_info.set_bgm_volume_enable");
  1611. }
  1612.  
  1613. void CHARACTER_AddBGMInfo(unsigned mapIndex, const char* name, float vol)
  1614. {
  1615. BGMInfo newInfo;
  1616. newInfo.name = name;
  1617. newInfo.vol = vol;
  1618.  
  1619. gs_bgmInfoMap[mapIndex] = newInfo;
  1620.  
  1621. //sys_log(0, "bgm_info.add_info(%d, '%s', %f)", mapIndex, name, vol);
  1622. }
  1623.  
  1624. const BGMInfo& CHARACTER_GetBGMInfo(unsigned mapIndex)
  1625. {
  1626. BGMInfoMap::iterator f = gs_bgmInfoMap.find(mapIndex);
  1627. if (gs_bgmInfoMap.end() == f)
  1628. {
  1629. static BGMInfo s_empty = {"", 0.0f};
  1630. return s_empty;
  1631. }
  1632. return f->second;
  1633. }
  1634.  
  1635. bool CHARACTER_IsBGMVolumeEnable()
  1636. {
  1637. return gs_bgmVolEnable;
  1638. }
  1639. // END_OF_BGM_INFO
  1640.  
  1641. void CHARACTER::MainCharacterPacket()
  1642. {
  1643. const unsigned mapIndex = GetMapIndex();
  1644. const BGMInfo& bgmInfo = CHARACTER_GetBGMInfo(mapIndex);
  1645.  
  1646. // SUPPORT_BGM
  1647. if (!bgmInfo.name.empty())
  1648. {
  1649. if (CHARACTER_IsBGMVolumeEnable())
  1650. {
  1651. sys_log(1, "bgm_info.play_bgm_vol(%d, name='%s', vol=%f)", mapIndex, bgmInfo.name.c_str(), bgmInfo.vol);
  1652. TPacketGCMainCharacter4_BGM_VOL mainChrPacket;
  1653. mainChrPacket.header = HEADER_GC_MAIN_CHARACTER4_BGM_VOL;
  1654. mainChrPacket.dwVID = m_vid;
  1655. mainChrPacket.wRaceNum = GetRaceNum();
  1656. mainChrPacket.lx = GetX();
  1657. mainChrPacket.ly = GetY();
  1658. mainChrPacket.lz = GetZ();
  1659. mainChrPacket.empire = GetDesc()->GetEmpire();
  1660. mainChrPacket.skill_group = GetSkillGroup();
  1661. strlcpy(mainChrPacket.szChrName, GetName(), sizeof(mainChrPacket.szChrName));
  1662.  
  1663. mainChrPacket.fBGMVol = bgmInfo.vol;
  1664. strlcpy(mainChrPacket.szBGMName, bgmInfo.name.c_str(), sizeof(mainChrPacket.szBGMName));
  1665. GetDesc()->Packet(&mainChrPacket, sizeof(TPacketGCMainCharacter4_BGM_VOL));
  1666. }
  1667. else
  1668. {
  1669. sys_log(1, "bgm_info.play(%d, '%s')", mapIndex, bgmInfo.name.c_str());
  1670. TPacketGCMainCharacter3_BGM mainChrPacket;
  1671. mainChrPacket.header = HEADER_GC_MAIN_CHARACTER3_BGM;
  1672. mainChrPacket.dwVID = m_vid;
  1673. mainChrPacket.wRaceNum = GetRaceNum();
  1674. mainChrPacket.lx = GetX();
  1675. mainChrPacket.ly = GetY();
  1676. mainChrPacket.lz = GetZ();
  1677. mainChrPacket.empire = GetDesc()->GetEmpire();
  1678. mainChrPacket.skill_group = GetSkillGroup();
  1679. strlcpy(mainChrPacket.szChrName, GetName(), sizeof(mainChrPacket.szChrName));
  1680. strlcpy(mainChrPacket.szBGMName, bgmInfo.name.c_str(), sizeof(mainChrPacket.szBGMName));
  1681. GetDesc()->Packet(&mainChrPacket, sizeof(TPacketGCMainCharacter3_BGM));
  1682. }
  1683. //if (m_stMobile.length())
  1684. // ChatPacket(CHAT_TYPE_COMMAND, "sms");
  1685. }
  1686. // END_OF_SUPPORT_BGM
  1687. else
  1688. {
  1689. sys_log(0, "bgm_info.play(%d, DEFAULT_BGM_NAME)", mapIndex);
  1690.  
  1691. TPacketGCMainCharacter pack;
  1692. pack.header = HEADER_GC_MAIN_CHARACTER;
  1693. pack.dwVID = m_vid;
  1694. pack.wRaceNum = GetRaceNum();
  1695. pack.lx = GetX();
  1696. pack.ly = GetY();
  1697. pack.lz = GetZ();
  1698. pack.empire = GetDesc()->GetEmpire();
  1699. pack.skill_group = GetSkillGroup();
  1700. strlcpy(pack.szName, GetName(), sizeof(pack.szName));
  1701. GetDesc()->Packet(&pack, sizeof(TPacketGCMainCharacter));
  1702.  
  1703. if (m_stMobile.length())
  1704. ChatPacket(CHAT_TYPE_COMMAND, "sms");
  1705. }
  1706. }
  1707.  
  1708. void CHARACTER::PointsPacket()
  1709. {
  1710. if (!GetDesc())
  1711. return;
  1712.  
  1713. TPacketGCPoints pack;
  1714. pack.header = HEADER_GC_CHARACTER_POINTS;
  1715. pack.points[POINT_LEVEL] = GetLevel();
  1716. pack.points[POINT_EXP] = GetExp();
  1717. pack.points[POINT_NEXT_EXP] = GetNextExp();
  1718. pack.points[POINT_HP] = GetHP();
  1719. pack.points[POINT_MAX_HP] = GetMaxHP();
  1720. pack.points[POINT_SP] = GetSP();
  1721. pack.points[POINT_MAX_SP] = GetMaxSP();
  1722. pack.points[POINT_GOLD] = GetGold();
  1723. pack.points[POINT_STAMINA] = GetStamina();
  1724. pack.points[POINT_MAX_STAMINA] = GetMaxStamina();
  1725. for (int i = POINT_ST; i < POINT_MAX_NUM; ++i)
  1726. pack.points[i] = GetPoint(i);
  1727.  
  1728. GetDesc()->Packet(&pack, sizeof(TPacketGCPoints));
  1729.  
  1730. if (!IsAcceOpen())
  1731. {
  1732. LPITEM item;
  1733. for (int j = 0; j < INVENTORY_AND_EQUIP_SLOT_MAX; ++j)
  1734. {
  1735. if ((item = GetInventoryItem(j)))
  1736. if (item->GetType() == ITEM_COSTUME && item->GetSubType() == COSTUME_ACCE && item->GetSocket(0) == 1)
  1737. item->SetSocket(0, 0);
  1738. }
  1739. }
  1740. }
  1741.  
  1742. bool CHARACTER::ChangeSex()
  1743. {
  1744. int src_race = GetRaceNum();
  1745.  
  1746. switch (src_race)
  1747. {
  1748. case MAIN_RACE_WARRIOR_M:
  1749. m_points.job = MAIN_RACE_WARRIOR_W;
  1750. break;
  1751.  
  1752. case MAIN_RACE_WARRIOR_W:
  1753. m_points.job = MAIN_RACE_WARRIOR_M;
  1754. break;
  1755.  
  1756. case MAIN_RACE_ASSASSIN_M:
  1757. m_points.job = MAIN_RACE_ASSASSIN_W;
  1758. break;
  1759.  
  1760. case MAIN_RACE_ASSASSIN_W:
  1761. m_points.job = MAIN_RACE_ASSASSIN_M;
  1762. break;
  1763.  
  1764. case MAIN_RACE_SURA_M:
  1765. m_points.job = MAIN_RACE_SURA_W;
  1766. break;
  1767.  
  1768. case MAIN_RACE_SURA_W:
  1769. m_points.job = MAIN_RACE_SURA_M;
  1770. break;
  1771.  
  1772. case MAIN_RACE_SHAMAN_M:
  1773. m_points.job = MAIN_RACE_SHAMAN_W;
  1774. break;
  1775.  
  1776. case MAIN_RACE_SHAMAN_W:
  1777. m_points.job = MAIN_RACE_SHAMAN_M;
  1778. break;
  1779.  
  1780. case MAIN_RACE_WOLFMAN_M:
  1781. m_points.job = MAIN_RACE_WOLFMAN_M;
  1782. break;
  1783.  
  1784. default:
  1785. sys_err("CHANGE_SEX: %s unknown race %d", GetName(), src_race);
  1786. return false;
  1787. }
  1788.  
  1789. sys_log(0, "CHANGE_SEX: %s (%d -> %d)", GetName(), src_race, m_points.job);
  1790. return true;
  1791. }
  1792.  
  1793. WORD CHARACTER::GetRaceNum() const
  1794. {
  1795. if (m_dwPolymorphRace)
  1796. return m_dwPolymorphRace;
  1797.  
  1798. if (m_pkMobData)
  1799. return m_pkMobData->m_table.dwVnum;
  1800.  
  1801. return m_points.job;
  1802. }
  1803.  
  1804. void CHARACTER::SetRace(BYTE race)
  1805. {
  1806. if (race >= MAIN_RACE_MAX_NUM)
  1807. {
  1808. sys_err("CHARACTER::SetRace(name=%s, race=%d).OUT_OF_RACE_RANGE", GetName(), race);
  1809. return;
  1810. }
  1811.  
  1812. m_points.job = race;
  1813. }
  1814.  
  1815. BYTE CHARACTER::GetJob() const
  1816. {
  1817. unsigned race = m_points.job;
  1818. unsigned job;
  1819.  
  1820. if (RaceToJob(race, &job))
  1821. return job;
  1822.  
  1823. sys_err("CHARACTER::GetJob(name=%s, race=%d).OUT_OF_RACE_RANGE", GetName(), race);
  1824. return JOB_WARRIOR;
  1825. }
  1826.  
  1827. void CHARACTER::SetLevel(BYTE level)
  1828. {
  1829. m_points.level = level;
  1830.  
  1831. if (IsPC())
  1832. {
  1833. if (level < PK_PROTECT_LEVEL)
  1834. SetPKMode(PK_MODE_PROTECT);
  1835. else if (GetGMLevel() > GM_VIP)
  1836. SetPKMode(PK_MODE_PROTECT);
  1837. else if (m_bPKMode == PK_MODE_PROTECT)
  1838. SetPKMode(PK_MODE_PEACE);
  1839. }
  1840. }
  1841.  
  1842. void CHARACTER::SetEmpire(BYTE bEmpire)
  1843. {
  1844. m_bEmpire = bEmpire;
  1845. }
  1846.  
  1847. void CHARACTER::SetPlayerProto(const TPlayerTable * t)
  1848. {
  1849. if (!GetDesc() || !*GetDesc()->GetHostName())
  1850. sys_err("cannot get desc or hostname");
  1851. else
  1852. SetGMLevel();
  1853.  
  1854. m_bCharType = CHAR_TYPE_PC;
  1855.  
  1856. m_dwPlayerID = t->id;
  1857.  
  1858. m_iAlignment = t->lAlignment;
  1859. m_iRealAlignment = t->lAlignment;
  1860.  
  1861. m_points.voice = t->voice;
  1862.  
  1863. m_points.skill_group = t->skill_group;
  1864.  
  1865. m_pointsInstant.bBasePart = t->part_base;
  1866. SetPart(PART_HAIR, t->parts[PART_HAIR]);
  1867. SetPart(PART_ACCE, t->parts[PART_ACCE]);
  1868.  
  1869. m_points.iRandomHP = t->sRandomHP;
  1870. m_points.iRandomSP = t->sRandomSP;
  1871.  
  1872. // REMOVE_REAL_SKILL_LEVLES
  1873. if (m_pSkillLevels)
  1874. M2_DELETE_ARRAY(m_pSkillLevels);
  1875.  
  1876. m_pSkillLevels = M2_NEW TPlayerSkill[SKILL_MAX_NUM];
  1877. thecore_memcpy(m_pSkillLevels, t->skills, sizeof(TPlayerSkill) * SKILL_MAX_NUM);
  1878. // END_OF_REMOVE_REAL_SKILL_LEVLES
  1879.  
  1880. if (t->lMapIndex >= 10000)
  1881. {
  1882. m_posWarp.x = t->lExitX;
  1883. m_posWarp.y = t->lExitY;
  1884. m_lWarpMapIndex = t->lExitMapIndex;
  1885. }
  1886.  
  1887. SetRealPoint(POINT_PLAYTIME, t->playtime);
  1888. m_dwLoginPlayTime = t->playtime;
  1889. SetRealPoint(POINT_ST, t->st);
  1890. SetRealPoint(POINT_HT, t->ht);
  1891. SetRealPoint(POINT_DX, t->dx);
  1892. SetRealPoint(POINT_IQ, t->iq);
  1893.  
  1894. SetPoint(POINT_ST, t->st);
  1895. SetPoint(POINT_HT, t->ht);
  1896. SetPoint(POINT_DX, t->dx);
  1897. SetPoint(POINT_IQ, t->iq);
  1898.  
  1899. SetPoint(POINT_STAT, t->stat_point);
  1900. SetPoint(POINT_SKILL, t->skill_point);
  1901. SetPoint(POINT_SUB_SKILL, t->sub_skill_point);
  1902. SetPoint(POINT_HORSE_SKILL, t->horse_skill_point);
  1903.  
  1904. SetPoint(POINT_STAT_RESET_COUNT, t->stat_reset_count);
  1905.  
  1906. SetPoint(POINT_LEVEL_STEP, t->level_step);
  1907. SetRealPoint(POINT_LEVEL_STEP, t->level_step);
  1908.  
  1909. SetRace(t->job);
  1910.  
  1911. SetLevel(t->level);
  1912. SetExp(t->exp);
  1913. SetGold(t->gold);
  1914.  
  1915. SetMapIndex(t->lMapIndex);
  1916. SetXYZ(t->x, t->y, t->z);
  1917.  
  1918. ComputePoints();
  1919.  
  1920. SetHP(t->hp);
  1921. SetSP(t->sp);
  1922. SetStamina(t->stamina);
  1923.  
  1924. //GMÀ϶§ º¸È£¸ðµå
  1925. if (!test_server)
  1926. {
  1927. if (GetGMLevel() > GM_LOW_WIZARD)
  1928. {
  1929. m_afAffectFlag.Set(AFF_YMIR);
  1930. m_bPKMode = PK_MODE_PROTECT;
  1931. }
  1932.  
  1933. else if (GetGMLevel() == GM_VIP)
  1934. {
  1935. m_afAffectFlag.Set(AFF_VIP);
  1936. }
  1937. }
  1938.  
  1939. if (GetGMLevel() == GM_VIP)
  1940. m_afAffectFlag.Set(AFF_VIP);
  1941.  
  1942. if (GetLevel() < PK_PROTECT_LEVEL)
  1943. m_bPKMode = PK_MODE_PROTECT;
  1944.  
  1945.  
  1946. m_stMobile = t->szMobile;
  1947.  
  1948. SetHorseData(t->horse);
  1949.  
  1950. if (GetHorseLevel() > 0)
  1951. UpdateHorseDataByLogoff(t->logoff_interval);
  1952.  
  1953. thecore_memcpy(m_aiPremiumTimes, t->aiPremiumTimes, sizeof(t->aiPremiumTimes));
  1954.  
  1955. m_dwLogOffInterval = t->logoff_interval;
  1956.  
  1957. sys_log(0, "PLAYER_LOAD: %s PREMIUM %d %d, LOGGOFF_INTERVAL %u PTR: %p", t->name, m_aiPremiumTimes[0], m_aiPremiumTimes[1], t->logoff_interval, this);
  1958.  
  1959. if (GetGMLevel() != GM_PLAYER)
  1960. {
  1961. LogManager::instance().CharLog(this, GetGMLevel(), "GM_LOGIN", "");
  1962. sys_log(0, "GM_LOGIN(gmlevel=%d, name=%s(%d), pos=(%d, %d)", GetGMLevel(), GetName(), GetPlayerID(), GetX(), GetY());
  1963. }
  1964.  
  1965. #ifdef __PET_SYSTEM__
  1966. // NOTE: ÀÏ´Ü Ä³¸¯ÅÍ°¡ PCÀÎ °æ¿ì¿¡¸¸ PetSystemÀ» °®µµ·Ï ÇÔ. À¯·´ ¸Ó½Å´ç ¸Þ¸ð¸® »ç¿ë·ü¶§¹®¿¡ NPC±îÁö Çϱä Á»..
  1967. if (m_petSystem)
  1968. {
  1969. m_petSystem->Destroy();
  1970. delete m_petSystem;
  1971. }
  1972.  
  1973. m_petSystem = M2_NEW CPetSystem(this);
  1974. #endif
  1975. }
  1976.  
  1977. EVENTFUNC(kill_ore_load_event)
  1978. {
  1979. char_event_info* info = dynamic_cast<char_event_info*>( event->info );
  1980. if ( info == NULL )
  1981. {
  1982. sys_err( "kill_ore_load_even> <Factor> Null pointer" );
  1983. return 0;
  1984. }
  1985.  
  1986. LPCHARACTER ch = info->ch;
  1987. if (ch == NULL) { // <Factor>
  1988. return 0;
  1989. }
  1990.  
  1991. ch->m_pkMiningEvent = NULL;
  1992. M2_DESTROY_CHARACTER(ch);
  1993. return 0;
  1994. }
  1995.  
  1996. void CHARACTER::SetProto(const CMob * pkMob)
  1997. {
  1998. if (m_pkMobInst)
  1999. M2_DELETE(m_pkMobInst);
  2000.  
  2001. m_pkMobData = pkMob;
  2002. m_pkMobInst = M2_NEW CMobInstance;
  2003.  
  2004. m_bPKMode = PK_MODE_FREE;
  2005.  
  2006. const TMobTable * t = &m_pkMobData->m_table;
  2007.  
  2008. m_bCharType = t->bType;
  2009.  
  2010. SetLevel(t->bLevel);
  2011. SetEmpire(t->bEmpire);
  2012.  
  2013. SetExp(t->dwExp);
  2014. SetRealPoint(POINT_ST, t->bStr);
  2015. SetRealPoint(POINT_DX, t->bDex);
  2016. SetRealPoint(POINT_HT, t->bCon);
  2017. SetRealPoint(POINT_IQ, t->bInt);
  2018.  
  2019. ComputePoints();
  2020.  
  2021. SetHP(GetMaxHP());
  2022. SetSP(GetMaxSP());
  2023.  
  2024. ////////////////////
  2025. m_pointsInstant.dwAIFlag = t->dwAIFlag;
  2026. SetImmuneFlag(t->dwImmuneFlag);
  2027.  
  2028. AssignTriggers(t);
  2029.  
  2030. ApplyMobAttribute(t);
  2031.  
  2032. if (IsStone())
  2033. {
  2034. DetermineDropMetinStone();
  2035. }
  2036.  
  2037. if (IsWarp() || IsGoto())
  2038. {
  2039. StartWarpNPCEvent();
  2040. }
  2041.  
  2042. CHARACTER_MANAGER::instance().RegisterRaceNumMap(this);
  2043.  
  2044. // XXX X-mas santa hardcoding
  2045. if (GetRaceNum() == xmas::MOB_SANTA_VNUM)
  2046. {
  2047. SetPoint(POINT_ATT_GRADE_BONUS, 10);
  2048. if (g_iUseLocale)
  2049. SetPoint(POINT_DEF_GRADE_BONUS, 6);
  2050. else
  2051. SetPoint(POINT_DEF_GRADE_BONUS, 15);
  2052.  
  2053. //»êŸ¿ë
  2054. //m_dwPlayStartTime = get_dword_time() + 10 * 60 * 1000;
  2055. //½Å¼±ÀÚ ³ëÇØ
  2056. m_dwPlayStartTime = get_dword_time() + 30 * 1000;
  2057. if (test_server)
  2058. m_dwPlayStartTime = get_dword_time() + 30 * 1000;
  2059. }
  2060.  
  2061. // XXX CTF GuildWar hardcoding
  2062. if (warmap::IsWarFlag(GetRaceNum()))
  2063. {
  2064. m_stateIdle.Set(this, &CHARACTER::BeginStateEmpty, &CHARACTER::StateFlag, &CHARACTER::EndStateEmpty);
  2065. m_stateMove.Set(this, &CHARACTER::BeginStateEmpty, &CHARACTER::StateFlag, &CHARACTER::EndStateEmpty);
  2066. m_stateBattle.Set(this, &CHARACTER::BeginStateEmpty, &CHARACTER::StateFlag, &CHARACTER::EndStateEmpty);
  2067. }
  2068.  
  2069. if (warmap::IsWarFlagBase(GetRaceNum()))
  2070. {
  2071. m_stateIdle.Set(this, &CHARACTER::BeginStateEmpty, &CHARACTER::StateFlagBase, &CHARACTER::EndStateEmpty);
  2072. m_stateMove.Set(this, &CHARACTER::BeginStateEmpty, &CHARACTER::StateFlagBase, &CHARACTER::EndStateEmpty);
  2073. m_stateBattle.Set(this, &CHARACTER::BeginStateEmpty, &CHARACTER::StateFlagBase, &CHARACTER::EndStateEmpty);
  2074. }
  2075.  
  2076. if (m_bCharType == CHAR_TYPE_HORSE ||
  2077. GetRaceNum() == 20101 ||
  2078. GetRaceNum() == 20102 ||
  2079. GetRaceNum() == 20103 ||
  2080. GetRaceNum() == 20104 ||
  2081. GetRaceNum() == 20105 ||
  2082. GetRaceNum() == 20106 ||
  2083. GetRaceNum() == 20107 ||
  2084. GetRaceNum() == 20108 ||
  2085. GetRaceNum() == 20109
  2086. )
  2087. {
  2088. m_stateIdle.Set(this, &CHARACTER::BeginStateEmpty, &CHARACTER::StateHorse, &CHARACTER::EndStateEmpty);
  2089. m_stateMove.Set(this, &CHARACTER::BeginStateEmpty, &CHARACTER::StateMove, &CHARACTER::EndStateEmpty);
  2090. m_stateBattle.Set(this, &CHARACTER::BeginStateEmpty, &CHARACTER::StateHorse, &CHARACTER::EndStateEmpty);
  2091. }
  2092.  
  2093. // MINING
  2094. if (mining::IsVeinOfOre (GetRaceNum()))
  2095. {
  2096. char_event_info* info = AllocEventInfo<char_event_info>();
  2097.  
  2098. info->ch = this;
  2099.  
  2100. m_pkMiningEvent = event_create(kill_ore_load_event, info, PASSES_PER_SEC(number(7 * 60, 15 * 60)));
  2101. }
  2102. // END_OF_MINING
  2103. SetOfflineShopVID(COfflineShopManager::instance().FindMyOfflineShop(GetPlayerID()));
  2104. }
  2105.  
  2106. const TMobTable & CHARACTER::GetMobTable() const
  2107. {
  2108. return m_pkMobData->m_table;
  2109. }
  2110.  
  2111. bool CHARACTER::IsRaceFlag(DWORD dwBit) const
  2112. {
  2113. return m_pkMobData ? IS_SET(m_pkMobData->m_table.dwRaceFlag, dwBit) : 0;
  2114. }
  2115.  
  2116. DWORD CHARACTER::GetMobDamageMin() const
  2117. {
  2118. return m_pkMobData->m_table.dwDamageRange[0];
  2119. }
  2120.  
  2121. DWORD CHARACTER::GetMobDamageMax() const
  2122. {
  2123. return m_pkMobData->m_table.dwDamageRange[1];
  2124. }
  2125.  
  2126. float CHARACTER::GetMobDamageMultiply() const
  2127. {
  2128. float fDamMultiply = GetMobTable().fDamMultiply;
  2129.  
  2130. if (IsBerserk())
  2131. fDamMultiply = fDamMultiply * 2.0f; // BALANCE: ±¤ÆøÈ­ ½Ã µÎ¹è
  2132.  
  2133. return fDamMultiply;
  2134. }
  2135.  
  2136. DWORD CHARACTER::GetMobDropItemVnum() const
  2137. {
  2138. return m_pkMobData->m_table.dwDropItemVnum;
  2139. }
  2140.  
  2141. bool CHARACTER::IsSummonMonster() const
  2142. {
  2143. return GetSummonVnum() != 0;
  2144. }
  2145.  
  2146. DWORD CHARACTER::GetSummonVnum() const
  2147. {
  2148. return m_pkMobData ? m_pkMobData->m_table.dwSummonVnum : 0;
  2149. }
  2150.  
  2151. DWORD CHARACTER::GetPolymorphItemVnum() const
  2152. {
  2153. return m_pkMobData ? m_pkMobData->m_table.dwPolymorphItemVnum : 0;
  2154. }
  2155.  
  2156. DWORD CHARACTER::GetMonsterDrainSPPoint() const
  2157. {
  2158. return m_pkMobData ? m_pkMobData->m_table.dwDrainSP : 0;
  2159. }
  2160.  
  2161. BYTE CHARACTER::GetMobRank() const
  2162. {
  2163. if (!m_pkMobData)
  2164. return MOB_RANK_KNIGHT; // PCÀÏ °æ¿ì KNIGHT±Þ
  2165.  
  2166. return m_pkMobData->m_table.bRank;
  2167. }
  2168.  
  2169. BYTE CHARACTER::GetMobSize() const
  2170. {
  2171. if (!m_pkMobData)
  2172. return MOBSIZE_MEDIUM;
  2173.  
  2174. return m_pkMobData->m_table.bSize;
  2175. }
  2176.  
  2177. WORD CHARACTER::GetMobAttackRange() const
  2178. {
  2179. switch (GetMobBattleType())
  2180. {
  2181. case BATTLE_TYPE_RANGE:
  2182. case BATTLE_TYPE_MAGIC:
  2183. return m_pkMobData->m_table.wAttackRange + GetPoint(POINT_BOW_DISTANCE);
  2184. default:
  2185. return m_pkMobData->m_table.wAttackRange;
  2186. }
  2187. }
  2188.  
  2189. BYTE CHARACTER::GetMobBattleType() const
  2190. {
  2191. if (!m_pkMobData)
  2192. return BATTLE_TYPE_MELEE;
  2193.  
  2194. return (m_pkMobData->m_table.bBattleType);
  2195. }
  2196.  
  2197. void CHARACTER::ComputeBattlePoints()
  2198. {
  2199. //if (IsPolymorphed())
  2200. //{
  2201. //DWORD dwMobVnum = GetPolymorphVnum();
  2202. //const CMob * pMob = CMobManager::instance().Get(dwMobVnum);
  2203. //int iAtt = 0;
  2204. //int iDef = 0;
  2205.  
  2206. //if (pMob)
  2207. //{
  2208. //iAtt = GetLevel() * 2 + GetPolymorphPoint(POINT_ST) * 2;
  2209. //iDef = GetLevel() + GetPolymorphPoint(POINT_HT) + pMob->m_table.wDef;
  2210. //}
  2211.  
  2212. //SetPoint(POINT_ATT_GRADE, iAtt);
  2213. //SetPoint(POINT_DEF_GRADE, iDef);
  2214. //SetPoint(POINT_MAGIC_ATT_GRADE, GetPoint(POINT_ATT_GRADE));
  2215. //SetPoint(POINT_MAGIC_DEF_GRADE, GetPoint(POINT_DEF_GRADE));
  2216. //}
  2217. //else if (IsPC())
  2218. if (IsPC())
  2219. {
  2220. SetPoint(POINT_ATT_GRADE, 0);
  2221. SetPoint(POINT_DEF_GRADE, 0);
  2222. SetPoint(POINT_CLIENT_DEF_GRADE, 0);
  2223. SetPoint(POINT_MAGIC_ATT_GRADE, GetPoint(POINT_ATT_GRADE));
  2224. SetPoint(POINT_MAGIC_DEF_GRADE, GetPoint(POINT_DEF_GRADE));
  2225.  
  2226. int iAtk = GetLevel() * 2;
  2227. int iStatAtk = 0;
  2228. switch (GetJob())
  2229. {
  2230. case JOB_WARRIOR:
  2231. case JOB_SURA:
  2232. iStatAtk = (2 * GetPoint(POINT_ST));
  2233. break;
  2234.  
  2235. case JOB_ASSASSIN:
  2236. iStatAtk = (4 * GetPoint(POINT_ST) + 2 * GetPoint(POINT_DX)) / 3;
  2237. break;
  2238.  
  2239. case JOB_SHAMAN:
  2240. iStatAtk = (4 * GetPoint(POINT_ST) + 2 * GetPoint(POINT_IQ)) / 3;
  2241. break;
  2242.  
  2243. case JOB_WOLFMAN:
  2244. iStatAtk = (2 * GetPoint(POINT_ST));
  2245. break;
  2246.  
  2247. default:
  2248. sys_err("invalid job %d", GetJob());
  2249. iStatAtk = (2 * GetPoint(POINT_ST));
  2250. break;
  2251. }
  2252.  
  2253. if (GetMountVnum() && iStatAtk < 2 * GetPoint(POINT_ST))
  2254. iStatAtk = (2 * GetPoint(POINT_ST));
  2255.  
  2256. iAtk += iStatAtk;
  2257. if (GetMountVnum())
  2258. {
  2259. if (GetJob() == JOB_SURA && GetSkillGroup() == 1)
  2260. {
  2261. iAtk += (iAtk * GetHorseLevel()) / 60;
  2262. }
  2263. else
  2264. {
  2265. iAtk += (iAtk * GetHorseLevel()) / 30;
  2266. }
  2267. }
  2268.  
  2269. iAtk += GetPoint(POINT_ATT_GRADE_BONUS);
  2270. PointChange(POINT_ATT_GRADE, iAtk);
  2271.  
  2272. int iShowDef = GetLevel() + GetPoint(POINT_HT);
  2273. int iDef = GetLevel() + (int) (GetPoint(POINT_HT) / 1.25);
  2274. int iArmor = 0;
  2275.  
  2276. LPITEM pkItem;
  2277. for (int i = 0; i < WEAR_MAX_NUM; ++i)
  2278. if ((pkItem = GetWear(i)) && pkItem->GetType() == ITEM_ARMOR)
  2279. {
  2280. if (pkItem->GetSubType() == ARMOR_BODY || pkItem->GetSubType() == ARMOR_HEAD || pkItem->GetSubType() == ARMOR_FOOTS || pkItem->GetSubType() == ARMOR_SHIELD)
  2281. {
  2282. iArmor += pkItem->GetValue(1);
  2283. iArmor += (2 * pkItem->GetValue(5));
  2284. }
  2285. }
  2286.  
  2287. if( true == IsHorseRiding() )
  2288. {
  2289. if (iArmor < GetHorseArmor())
  2290. iArmor = GetHorseArmor();
  2291.  
  2292. const char* pHorseName = CHorseNameManager::instance().GetHorseName(GetPlayerID());
  2293. if (pHorseName != NULL && strlen(pHorseName))
  2294. {
  2295. iArmor += 20;
  2296. }
  2297. }
  2298.  
  2299. iArmor += GetPoint(POINT_DEF_GRADE_BONUS);
  2300. iArmor += GetPoint(POINT_PARTY_DEFENDER_BONUS);
  2301. if (LC_IsYMIR())
  2302. {
  2303. PointChange(POINT_DEF_GRADE, iShowDef + iArmor);
  2304. }
  2305. else
  2306. {
  2307. PointChange(POINT_DEF_GRADE, iDef + iArmor);
  2308. PointChange(POINT_CLIENT_DEF_GRADE, (iShowDef + iArmor) - GetPoint(POINT_DEF_GRADE));
  2309. }
  2310.  
  2311. PointChange(POINT_MAGIC_ATT_GRADE, GetLevel() * 2 + GetPoint(POINT_IQ) * 2 + GetPoint(POINT_MAGIC_ATT_GRADE_BONUS));
  2312. PointChange(POINT_MAGIC_DEF_GRADE, GetLevel() + (GetPoint(POINT_IQ) * 3 + GetPoint(POINT_HT)) / 3 + iArmor / 2 + GetPoint(POINT_MAGIC_DEF_GRADE_BONUS));
  2313. }
  2314. else
  2315. {
  2316. int iAtt = GetLevel() * 2 + GetPoint(POINT_ST) * 2;
  2317. int iDef = GetLevel() + GetPoint(POINT_HT) + GetMobTable().wDef;
  2318.  
  2319. SetPoint(POINT_ATT_GRADE, iAtt);
  2320. SetPoint(POINT_DEF_GRADE, iDef);
  2321. SetPoint(POINT_MAGIC_ATT_GRADE, GetPoint(POINT_ATT_GRADE));
  2322. SetPoint(POINT_MAGIC_DEF_GRADE, GetPoint(POINT_DEF_GRADE));
  2323. }
  2324. }
  2325.  
  2326. void CHARACTER::ComputePoints()
  2327. {
  2328. long lStat = GetPoint(POINT_STAT);
  2329. long lStatResetCount = GetPoint(POINT_STAT_RESET_COUNT);
  2330. long lSkillActive = GetPoint(POINT_SKILL);
  2331. long lSkillSub = GetPoint(POINT_SUB_SKILL);
  2332. long lSkillHorse = GetPoint(POINT_HORSE_SKILL);
  2333. long lLevelStep = GetPoint(POINT_LEVEL_STEP);
  2334.  
  2335. long lAttackerBonus = GetPoint(POINT_PARTY_ATTACKER_BONUS);
  2336. long lTankerBonus = GetPoint(POINT_PARTY_TANKER_BONUS);
  2337. long lBufferBonus = GetPoint(POINT_PARTY_BUFFER_BONUS);
  2338. long lSkillMasterBonus = GetPoint(POINT_PARTY_SKILL_MASTER_BONUS);
  2339. long lHasteBonus = GetPoint(POINT_PARTY_HASTE_BONUS);
  2340. long lDefenderBonus = GetPoint(POINT_PARTY_DEFENDER_BONUS);
  2341.  
  2342. long lHPRecovery = GetPoint(POINT_HP_RECOVERY);
  2343. long lSPRecovery = GetPoint(POINT_SP_RECOVERY);
  2344.  
  2345. memset(m_pointsInstant.points, 0, sizeof(m_pointsInstant.points));
  2346. BuffOnAttr_ClearAll();
  2347. m_SkillDamageBonus.clear();
  2348.  
  2349. SetPoint(POINT_STAT, lStat);
  2350. SetPoint(POINT_SKILL, lSkillActive);
  2351. SetPoint(POINT_SUB_SKILL, lSkillSub);
  2352. SetPoint(POINT_HORSE_SKILL, lSkillHorse);
  2353. SetPoint(POINT_LEVEL_STEP, lLevelStep);
  2354. SetPoint(POINT_STAT_RESET_COUNT, lStatResetCount);
  2355.  
  2356. SetPoint(POINT_ST, GetRealPoint(POINT_ST));
  2357. SetPoint(POINT_HT, GetRealPoint(POINT_HT));
  2358. SetPoint(POINT_DX, GetRealPoint(POINT_DX));
  2359. SetPoint(POINT_IQ, GetRealPoint(POINT_IQ));
  2360.  
  2361. SetPart(PART_MAIN, GetOriginalPart(PART_MAIN));
  2362. SetPart(PART_WEAPON, GetOriginalPart(PART_WEAPON));
  2363. SetPart(PART_HEAD, GetOriginalPart(PART_HEAD));
  2364. SetPart(PART_HAIR, GetOriginalPart(PART_HAIR));
  2365. SetPart(PART_ACCE, GetOriginalPart(PART_ACCE));
  2366.  
  2367. SetPoint(POINT_PARTY_ATTACKER_BONUS, lAttackerBonus);
  2368. SetPoint(POINT_PARTY_TANKER_BONUS, lTankerBonus);
  2369. SetPoint(POINT_PARTY_BUFFER_BONUS, lBufferBonus);
  2370. SetPoint(POINT_PARTY_SKILL_MASTER_BONUS, lSkillMasterBonus);
  2371. SetPoint(POINT_PARTY_HASTE_BONUS, lHasteBonus);
  2372. SetPoint(POINT_PARTY_DEFENDER_BONUS, lDefenderBonus);
  2373.  
  2374. SetPoint(POINT_HP_RECOVERY, lHPRecovery);
  2375. SetPoint(POINT_SP_RECOVERY, lSPRecovery);
  2376.  
  2377. // PC_BANG_ITEM_ADD
  2378. SetPoint(POINT_PC_BANG_EXP_BONUS, 0);
  2379. SetPoint(POINT_PC_BANG_DROP_BONUS, 0);
  2380. // END_PC_BANG_ITEM_ADD
  2381.  
  2382. int iMaxHP, iMaxSP;
  2383. int iMaxStamina;
  2384.  
  2385. if (IsPC())
  2386. {
  2387. // ÃÖ´ë »ý¸í·Â/Á¤½Å·Â
  2388. iMaxHP = JobInitialPoints[GetJob()].max_hp + m_points.iRandomHP + GetPoint(POINT_HT) * JobInitialPoints[GetJob()].hp_per_ht;
  2389. iMaxSP = JobInitialPoints[GetJob()].max_sp + m_points.iRandomSP + GetPoint(POINT_IQ) * JobInitialPoints[GetJob()].sp_per_iq;
  2390. iMaxStamina = JobInitialPoints[GetJob()].max_stamina + GetPoint(POINT_HT) * JobInitialPoints[GetJob()].stamina_per_con;
  2391.  
  2392. {
  2393. CSkillProto* pkSk = CSkillManager::instance().Get(SKILL_ADD_HP);
  2394.  
  2395. if (NULL != pkSk)
  2396. {
  2397. pkSk->SetPointVar("k", 1.0f * GetSkillPower(SKILL_ADD_HP) / 100.0f);
  2398.  
  2399. iMaxHP += static_cast<int>(pkSk->kPointPoly.Eval());
  2400. }
  2401. }
  2402.  
  2403. // ±âº» °ªµé
  2404. SetPoint(POINT_MOV_SPEED, 100);
  2405. SetPoint(POINT_ATT_SPEED, 100);
  2406. PointChange(POINT_ATT_SPEED, GetPoint(POINT_PARTY_HASTE_BONUS));
  2407. SetPoint(POINT_CASTING_SPEED, 100);
  2408. }
  2409. else
  2410. {
  2411. iMaxHP = m_pkMobData->m_table.dwMaxHP;
  2412. iMaxSP = 0;
  2413. iMaxStamina = 0;
  2414.  
  2415. SetPoint(POINT_ATT_SPEED, m_pkMobData->m_table.sAttackSpeed);
  2416. SetPoint(POINT_MOV_SPEED, m_pkMobData->m_table.sMovingSpeed);
  2417. SetPoint(POINT_CASTING_SPEED, m_pkMobData->m_table.sAttackSpeed);
  2418. }
  2419.  
  2420. if (IsPC())
  2421. {
  2422. // ¸» Ÿ°í ÀÖÀ» ¶§´Â ±âº» ½ºÅÈÀÌ ¸»ÀÇ ±âÁØ ½ºÅȺ¸´Ù ³·À¸¸é ³ô°Ô ¸¸µç´Ù.
  2423. // µû¶ó¼­ ¸»ÀÇ ±âÁØ ½ºÅÈÀÌ ¹«»ç ±âÁØÀ̹ǷÎ, ¼ö¶ó/¹«´çÀº Àüü ½ºÅÈ ÇÕÀÌ
  2424. // ´ëäÀûÀ¸·Î ´õ ¿Ã¶ó°¡°Ô µÉ °ÍÀÌ´Ù.
  2425. if (GetMountVnum())
  2426. {
  2427. if (GetHorseST() > GetPoint(POINT_ST))
  2428. PointChange(POINT_ST, GetHorseST() - GetPoint(POINT_ST));
  2429.  
  2430. if (GetHorseDX() > GetPoint(POINT_DX))
  2431. PointChange(POINT_DX, GetHorseDX() - GetPoint(POINT_DX));
  2432.  
  2433. if (GetHorseHT() > GetPoint(POINT_HT))
  2434. PointChange(POINT_HT, GetHorseHT() - GetPoint(POINT_HT));
  2435.  
  2436. if (GetHorseIQ() > GetPoint(POINT_IQ))
  2437. PointChange(POINT_IQ, GetHorseIQ() - GetPoint(POINT_IQ));
  2438. }
  2439.  
  2440. }
  2441.  
  2442. ComputeBattlePoints();
  2443.  
  2444. // ±âº» HP/SP ¼³Á¤
  2445. if (iMaxHP != GetMaxHP())
  2446. {
  2447. SetRealPoint(POINT_MAX_HP, iMaxHP); // ±âº»HP¸¦ RealPoint¿¡ ÀúÀåÇØ ³õ´Â´Ù.
  2448. }
  2449.  
  2450. PointChange(POINT_MAX_HP, 0);
  2451.  
  2452. if (iMaxSP != GetMaxSP())
  2453. {
  2454. SetRealPoint(POINT_MAX_SP, iMaxSP); // ±âº»SP¸¦ RealPoint¿¡ ÀúÀåÇØ ³õ´Â´Ù.
  2455. }
  2456.  
  2457. PointChange(POINT_MAX_SP, 0);
  2458.  
  2459. SetMaxStamina(iMaxStamina);
  2460.  
  2461. m_pointsInstant.dwImmuneFlag = 0;
  2462.  
  2463. for (int i = 0 ; i < WEAR_MAX_NUM; i++)
  2464. {
  2465. LPITEM pItem = GetWear(i);
  2466. if (pItem)
  2467. {
  2468. pItem->ModifyPoints(true);
  2469. SET_BIT(m_pointsInstant.dwImmuneFlag, GetWear(i)->GetImmuneFlag());
  2470. }
  2471. }
  2472.  
  2473. // ¿ëÈ¥¼® ½Ã½ºÅÛ
  2474. // ComputePoints¿¡¼­´Â Äɸ¯ÅÍÀÇ ¸ðµç ¼Ó¼º°ªÀ» ÃʱâÈ­ÇÏ°í,
  2475. // ¾ÆÀÌÅÛ, ¹öÇÁ µî¿¡ °ü·ÃµÈ ¸ðµç ¼Ó¼º°ªÀ» Àç°è»êÇϱ⠶§¹®¿¡,
  2476. // ¿ëÈ¥¼® ½Ã½ºÅÛµµ ActiveDeck¿¡ ÀÖ´Â ¸ðµç ¿ëÈ¥¼®ÀÇ ¼Ó¼º°ªÀ» ´Ù½Ã Àû¿ë½ÃÄÑ¾ß ÇÑ´Ù.
  2477. if (DragonSoul_IsDeckActivated())
  2478. {
  2479. for (int i = WEAR_MAX_NUM + DS_SLOT_MAX * DragonSoul_GetActiveDeck();
  2480. i < WEAR_MAX_NUM + DS_SLOT_MAX * (DragonSoul_GetActiveDeck() + 1); i++)
  2481. {
  2482. LPITEM pItem = GetWear(i);
  2483. if (pItem)
  2484. {
  2485. if (DSManager::instance().IsTimeLeftDragonSoul(pItem))
  2486. pItem->ModifyPoints(true);
  2487. }
  2488. }
  2489. }
  2490.  
  2491. if (GetHP() > GetMaxHP())
  2492. PointChange(POINT_HP, GetMaxHP() - GetHP());
  2493.  
  2494. if (GetSP() > GetMaxSP())
  2495. PointChange(POINT_SP, GetMaxSP() - GetSP());
  2496.  
  2497. ComputeSkillPoints();
  2498.  
  2499. RefreshAffect();
  2500. CPetSystem* pPetSystem = GetPetSystem();
  2501. if (NULL != pPetSystem)
  2502. {
  2503. pPetSystem->RefreshBuff();
  2504. }
  2505.  
  2506. UpdatePacket();
  2507. }
  2508.  
  2509. // m_dwPlayStartTimeÀÇ ´ÜÀ§´Â milisecond´Ù. µ¥ÀÌÅͺ£À̽º¿¡´Â ºÐ´ÜÀ§·Î ±â·ÏÇϱâ
  2510. // ¶§¹®¿¡ Ç÷¹À̽ð£À» °è»êÇÒ ¶§ / 60000 À¸·Î ³ª´²¼­ Çϴµ¥, ±× ³ª¸ÓÁö °ªÀÌ ³²¾Ò
  2511. // À» ¶§ ¿©±â¿¡ dwTimeRemainÀ¸·Î ³Ö¾î¼­ Á¦´ë·Î °è»êµÇµµ·Ï ÇØÁÖ¾î¾ß ÇÑ´Ù.
  2512. void CHARACTER::ResetPlayTime(DWORD dwTimeRemain)
  2513. {
  2514. m_dwPlayStartTime = get_dword_time() - dwTimeRemain;
  2515. }
  2516.  
  2517. const int aiRecoveryPercents[10] = { 1, 5, 5, 5, 5, 5, 5, 5, 5, 5 };
  2518.  
  2519. EVENTFUNC(recovery_event)
  2520. {
  2521. char_event_info* info = dynamic_cast<char_event_info*>( event->info );
  2522. if ( info == NULL )
  2523. {
  2524. sys_err( "recovery_event> <Factor> Null pointer" );
  2525. return 0;
  2526. }
  2527.  
  2528. LPCHARACTER ch = info->ch;
  2529.  
  2530. if (ch == NULL) { // <Factor>
  2531. return 0;
  2532. }
  2533.  
  2534. if (!ch->IsPC())
  2535. {
  2536. //
  2537. // ¸ó½ºÅÍ È¸º¹
  2538. //
  2539. if (ch->IsAffectFlag(AFF_POISON) || ch->IsAffectFlag(AFF_BLEEDING))
  2540. return PASSES_PER_SEC(MAX(1, ch->GetMobTable().bRegenCycle));
  2541.  
  2542. if (2493 == ch->GetMobTable().dwVnum)
  2543. {
  2544. int regenPct = BlueDragon_GetRangeFactor("hp_regen", ch->GetHPPct());
  2545. regenPct += ch->GetMobTable().bRegenPercent;
  2546.  
  2547. for (int i=1 ; i <= 4 ; ++i)
  2548. {
  2549. if (REGEN_PECT_BONUS == BlueDragon_GetIndexFactor("DragonStone", i, "effect_type"))
  2550. {
  2551. DWORD dwDragonStoneID = BlueDragon_GetIndexFactor("DragonStone", i, "vnum");
  2552. size_t val = BlueDragon_GetIndexFactor("DragonStone", i, "val");
  2553. size_t cnt = SECTREE_MANAGER::instance().GetMonsterCountInMap( ch->GetMapIndex(), dwDragonStoneID );
  2554.  
  2555. regenPct += (val*cnt);
  2556.  
  2557. break;
  2558. }
  2559. }
  2560.  
  2561. ch->PointChange(POINT_HP, MAX(1, (ch->GetMaxHP() * regenPct) / 100));
  2562. }
  2563. else if (!ch->IsDoor())
  2564. {
  2565. ch->MonsterLog("HP_REGEN +%d", MAX(1, (ch->GetMaxHP() * ch->GetMobTable().bRegenPercent) / 100));
  2566. ch->PointChange(POINT_HP, MAX(1, (ch->GetMaxHP() * ch->GetMobTable().bRegenPercent) / 100));
  2567. }
  2568.  
  2569. if (ch->GetHP() >= ch->GetMaxHP())
  2570. {
  2571. ch->m_pkRecoveryEvent = NULL;
  2572. return 0;
  2573. }
  2574.  
  2575. if (2493 == ch->GetMobTable().dwVnum)
  2576. {
  2577. for (int i=1 ; i <= 4 ; ++i)
  2578. {
  2579. if (REGEN_TIME_BONUS == BlueDragon_GetIndexFactor("DragonStone", i, "effect_type"))
  2580. {
  2581. DWORD dwDragonStoneID = BlueDragon_GetIndexFactor("DragonStone", i, "vnum");
  2582. size_t val = BlueDragon_GetIndexFactor("DragonStone", i, "val");
  2583. size_t cnt = SECTREE_MANAGER::instance().GetMonsterCountInMap( ch->GetMapIndex(), dwDragonStoneID );
  2584.  
  2585. return PASSES_PER_SEC(MAX(1, (ch->GetMobTable().bRegenCycle - (val*cnt))));
  2586. }
  2587. }
  2588. }
  2589.  
  2590. return PASSES_PER_SEC(MAX(1, ch->GetMobTable().bRegenCycle));
  2591. }
  2592. else
  2593. {
  2594. //
  2595. // PC ȸº¹
  2596. //
  2597. ch->CheckTarget();
  2598. //ch->UpdateSectree(); // ¿©±â¼­ ÀÌ°É ¿ÖÇÏÁö?
  2599. ch->UpdateKillerMode();
  2600.  
  2601. if (ch->IsAffectFlag(AFF_POISON) == true || ch->IsAffectFlag(AFF_BLEEDING))
  2602. {
  2603. // Áßµ¶ÀÎ °æ¿ì ÀÚµ¿È¸º¹ ±ÝÁö
  2604. // ÆĹý¼úÀÎ °æ¿ì ÀÚµ¿È¸º¹ ±ÝÁö
  2605. return 3;
  2606. }
  2607.  
  2608. int iSec = (get_dword_time() - ch->GetLastMoveTime()) / 3000;
  2609.  
  2610. // SP ȸº¹ ·çƾ.
  2611. // ¿Ö ÀÌ°É·Î Çؼ­ ÇÔ¼ö·Î »©³ù´Â°¡ ?!
  2612. ch->DistributeSP(ch);
  2613.  
  2614. if (ch->GetMaxHP() <= ch->GetHP())
  2615. return PASSES_PER_SEC(3);
  2616.  
  2617. int iPercent = 0;
  2618. int iAmount = 0;
  2619.  
  2620. {
  2621. iPercent = aiRecoveryPercents[MIN(9, iSec)];
  2622. iAmount = 15 + (ch->GetMaxHP() * iPercent) / 100;
  2623. }
  2624.  
  2625. iAmount += (iAmount * ch->GetPoint(POINT_HP_REGEN)) / 100;
  2626.  
  2627. sys_log(1, "RECOVERY_EVENT: %s %d HP_REGEN %d HP +%d", ch->GetName(), iPercent, ch->GetPoint(POINT_HP_REGEN), iAmount);
  2628.  
  2629. ch->PointChange(POINT_HP, iAmount, false);
  2630. return PASSES_PER_SEC(3);
  2631. }
  2632. }
  2633.  
  2634. void CHARACTER::StartRecoveryEvent()
  2635. {
  2636. if (m_pkRecoveryEvent)
  2637. return;
  2638.  
  2639. if (IsDead() || IsStun())
  2640. return;
  2641.  
  2642. if (IsNPC() && GetHP() >= GetMaxHP()) // ¸ó½ºÅʹ ü·ÂÀÌ ´Ù Â÷ÀÖÀ¸¸é ½ÃÀÛ ¾ÈÇÑ´Ù.
  2643. return;
  2644.  
  2645. char_event_info* info = AllocEventInfo<char_event_info>();
  2646.  
  2647. info->ch = this;
  2648.  
  2649. int iSec = IsPC() ? 3 : (MAX(1, GetMobTable().bRegenCycle));
  2650. m_pkRecoveryEvent = event_create(recovery_event, info, PASSES_PER_SEC(iSec));
  2651. }
  2652.  
  2653. void CHARACTER::Standup()
  2654. {
  2655. struct packet_position pack_position;
  2656.  
  2657. if (!IsPosition(POS_SITTING))
  2658. return;
  2659.  
  2660. SetPosition(POS_STANDING);
  2661.  
  2662. sys_log(1, "STANDUP: %s", GetName());
  2663.  
  2664. pack_position.header = HEADER_GC_CHARACTER_POSITION;
  2665. pack_position.vid = GetVID();
  2666. pack_position.position = POSITION_GENERAL;
  2667.  
  2668. PacketAround(&pack_position, sizeof(pack_position));
  2669. }
  2670.  
  2671. void CHARACTER::Sitdown(int is_ground)
  2672. {
  2673. struct packet_position pack_position;
  2674.  
  2675. if (IsPosition(POS_SITTING))
  2676. return;
  2677.  
  2678. SetPosition(POS_SITTING);
  2679. sys_log(1, "SITDOWN: %s", GetName());
  2680.  
  2681. pack_position.header = HEADER_GC_CHARACTER_POSITION;
  2682. pack_position.vid = GetVID();
  2683. pack_position.position = POSITION_SITTING_GROUND;
  2684. PacketAround(&pack_position, sizeof(pack_position));
  2685. }
  2686.  
  2687. void CHARACTER::SetRotation(float fRot)
  2688. {
  2689. m_pointsInstant.fRot = fRot;
  2690. }
  2691.  
  2692. // x, y ¹æÇâÀ¸·Î º¸°í ¼±´Ù.
  2693. void CHARACTER::SetRotationToXY(long x, long y)
  2694. {
  2695. SetRotation(GetDegreeFromPositionXY(GetX(), GetY(), x, y));
  2696. }
  2697.  
  2698. bool CHARACTER::CannotMoveByAffect() const
  2699. {
  2700. return (IsAffectFlag(AFF_STUN));
  2701. }
  2702.  
  2703. bool CHARACTER::CanMove() const
  2704. {
  2705. if (CannotMoveByAffect())
  2706. return false;
  2707.  
  2708. if (GetMyShop()) // »óÁ¡ ¿¬ »óÅ¿¡¼­´Â ¿òÁ÷ÀÏ ¼ö ¾øÀ½
  2709. return false;
  2710.  
  2711. // 0.2ÃÊ ÀüÀ̶ó¸é ¿òÁ÷ÀÏ ¼ö ¾ø´Ù.
  2712. /*
  2713. if (get_float_time() - m_fSyncTime < 0.2f)
  2714. return false;
  2715. */
  2716. return true;
  2717. }
  2718.  
  2719. // ¹«Á¶°Ç x, y À§Ä¡·Î À̵¿ ½ÃŲ´Ù.
  2720. bool CHARACTER::Sync(long x, long y)
  2721. {
  2722. if (!GetSectree())
  2723. return false;
  2724.  
  2725. LPSECTREE new_tree = SECTREE_MANAGER::instance().Get(GetMapIndex(), x, y);
  2726.  
  2727. if (!new_tree)
  2728. {
  2729. if (GetDesc())
  2730. {
  2731. sys_err("cannot find tree at %d %d (name: %s)", x, y, GetName());
  2732. GetDesc()->SetPhase(PHASE_CLOSE);
  2733. }
  2734. else
  2735. {
  2736. sys_err("no tree: %s %d %d %d", GetName(), x, y, GetMapIndex());
  2737. Dead();
  2738. }
  2739.  
  2740. return false;
  2741. }
  2742.  
  2743. SetRotationToXY(x, y);
  2744. SetXYZ(x, y, 0);
  2745.  
  2746. if (GetDungeon())
  2747. {
  2748. // ´øÁ¯¿ë À̺¥Æ® ¼Ó¼º º¯È­
  2749. int iLastEventAttr = m_iEventAttr;
  2750. m_iEventAttr = new_tree->GetEventAttribute(x, y);
  2751.  
  2752. if (m_iEventAttr != iLastEventAttr)
  2753. {
  2754. if (GetParty())
  2755. {
  2756. quest::CQuestManager::instance().AttrOut(GetParty()->GetLeaderPID(), this, iLastEventAttr);
  2757. quest::CQuestManager::instance().AttrIn(GetParty()->GetLeaderPID(), this, m_iEventAttr);
  2758. }
  2759. else
  2760. {
  2761. quest::CQuestManager::instance().AttrOut(GetPlayerID(), this, iLastEventAttr);
  2762. quest::CQuestManager::instance().AttrIn(GetPlayerID(), this, m_iEventAttr);
  2763. }
  2764. }
  2765. }
  2766.  
  2767. if (GetSectree() != new_tree)
  2768. {
  2769. if (!IsNPC())
  2770. {
  2771. SECTREEID id = new_tree->GetID();
  2772. SECTREEID old_id = GetSectree()->GetID();
  2773.  
  2774. sys_log(0, "SECTREE DIFFER: %s %dx%d was %dx%d",
  2775. GetName(),
  2776. id.coord.x,
  2777. id.coord.y,
  2778. old_id.coord.x,
  2779. old_id.coord.y);
  2780. }
  2781.  
  2782. new_tree->InsertEntity(this);
  2783. }
  2784.  
  2785. return true;
  2786. }
  2787.  
  2788. void CHARACTER::Stop()
  2789. {
  2790. if (!IsState(m_stateIdle))
  2791. MonsterLog("[IDLE] Á¤Áö");
  2792.  
  2793. GotoState(m_stateIdle);
  2794.  
  2795. m_posDest.x = m_posStart.x = GetX();
  2796. m_posDest.y = m_posStart.y = GetY();
  2797. }
  2798.  
  2799. bool CHARACTER::Goto(long x, long y)
  2800. {
  2801. // TODO °Å¸®Ã¼Å© ÇÊ¿ä
  2802. // °°Àº À§Ä¡¸é À̵¿ÇÒ ÇÊ¿ä ¾øÀ½ (ÀÚµ¿ ¼º°ø)
  2803. if (GetX() == x && GetY() == y)
  2804. return false;
  2805.  
  2806. if (m_posDest.x == x && m_posDest.y == y)
  2807. {
  2808. if (!IsState(m_stateMove))
  2809. {
  2810. m_dwStateDuration = 4;
  2811. GotoState(m_stateMove);
  2812. }
  2813. return false;
  2814. }
  2815.  
  2816. m_posDest.x = x;
  2817. m_posDest.y = y;
  2818.  
  2819. CalculateMoveDuration();
  2820.  
  2821. m_dwStateDuration = 4;
  2822.  
  2823.  
  2824. if (!IsState(m_stateMove))
  2825. {
  2826. MonsterLog("[MOVE] %s", GetVictim() ? "´ë»óÃßÀû" : "±×³ÉÀ̵¿");
  2827.  
  2828. if (GetVictim())
  2829. {
  2830. //MonsterChat(MONSTER_CHAT_CHASE);
  2831. MonsterChat(MONSTER_CHAT_ATTACK);
  2832. }
  2833. }
  2834.  
  2835. GotoState(m_stateMove);
  2836.  
  2837. return true;
  2838. }
  2839.  
  2840.  
  2841. DWORD CHARACTER::GetMotionMode() const
  2842. {
  2843. DWORD dwMode = MOTION_MODE_GENERAL;
  2844.  
  2845. if (IsPolymorphed())
  2846. return dwMode;
  2847.  
  2848. LPITEM pkItem;
  2849. if ((pkItem = GetWear(WEAR_WEAPON)))
  2850. {
  2851. switch (pkItem->GetProto()->bSubType)
  2852. {
  2853. case WEAPON_SWORD:
  2854. dwMode = MOTION_MODE_ONEHAND_SWORD;
  2855. break;
  2856.  
  2857. case WEAPON_TWO_HANDED:
  2858. dwMode = MOTION_MODE_TWOHAND_SWORD;
  2859. break;
  2860.  
  2861. case WEAPON_DAGGER:
  2862. dwMode = MOTION_MODE_DUALHAND_SWORD;
  2863. break;
  2864.  
  2865. case WEAPON_BOW:
  2866. dwMode = MOTION_MODE_BOW;
  2867. break;
  2868.  
  2869. case WEAPON_BELL:
  2870. dwMode = MOTION_MODE_BELL;
  2871. break;
  2872.  
  2873. case WEAPON_FAN:
  2874. dwMode = MOTION_MODE_FAN;
  2875. break;
  2876.  
  2877. case WEAPON_CLAW:
  2878. dwMode = MOTION_MODE_CLAW;
  2879. break;
  2880. }
  2881. }
  2882.  
  2883. return dwMode;
  2884. }
  2885.  
  2886. float CHARACTER::GetMoveMotionSpeed() const
  2887. {
  2888. DWORD dwMode = GetMotionMode();
  2889.  
  2890. const CMotion * pkMotion = NULL;
  2891.  
  2892. if (!GetMountVnum())
  2893. pkMotion = CMotionManager::instance().GetMotion(GetRaceNum(), MAKE_MOTION_KEY(dwMode, (IsWalking() && IsPC()) ? MOTION_WALK : MOTION_RUN));
  2894. else
  2895. {
  2896. pkMotion = CMotionManager::instance().GetMotion(GetMountVnum(), MAKE_MOTION_KEY(MOTION_MODE_GENERAL, (IsWalking() && IsPC()) ? MOTION_WALK : MOTION_RUN));
  2897.  
  2898. if (!pkMotion)
  2899. pkMotion = CMotionManager::instance().GetMotion(GetRaceNum(), MAKE_MOTION_KEY(MOTION_MODE_HORSE, (IsWalking() && IsPC()) ? MOTION_WALK : MOTION_RUN));
  2900. }
  2901.  
  2902. if (pkMotion)
  2903. return -pkMotion->GetAccumVector().y / pkMotion->GetDuration();
  2904. else
  2905. {
  2906. //sys_err("cannot find motion (name %s race %d mode %d)", GetName(), GetRaceNum(), dwMode);
  2907. return 300.0f;
  2908. }
  2909. }
  2910.  
  2911. float CHARACTER::GetMoveSpeed() const
  2912. {
  2913. return GetMoveMotionSpeed() * 10000 / CalculateDuration(GetLimitPoint(POINT_MOV_SPEED), 10000);
  2914. }
  2915.  
  2916. void CHARACTER::CalculateMoveDuration()
  2917. {
  2918. m_posStart.x = GetX();
  2919. m_posStart.y = GetY();
  2920.  
  2921. float fDist = DISTANCE_SQRT(m_posStart.x - m_posDest.x, m_posStart.y - m_posDest.y);
  2922.  
  2923. float motionSpeed = GetMoveMotionSpeed();
  2924.  
  2925. m_dwMoveDuration = CalculateDuration(GetLimitPoint(POINT_MOV_SPEED),
  2926. (int) ((fDist / motionSpeed) * 1000.0f));
  2927.  
  2928. if (IsNPC())
  2929. sys_log(1, "Maxmi - Char.cpp",
  2930. GetName(), fDist, GetLimitPoint(POINT_MOV_SPEED), m_dwMoveDuration, motionSpeed,
  2931. m_posStart.x, m_posStart.y, m_posDest.x, m_posDest.y);
  2932.  
  2933. m_dwMoveStartTime = get_dword_time();
  2934. }
  2935.  
  2936. // x y À§Ä¡·Î À̵¿ ÇÑ´Ù. (À̵¿ÇÒ ¼ö ÀÖ´Â °¡ ¾ø´Â °¡¸¦ È®ÀÎ ÇÏ°í Sync ¸Þ¼Òµå·Î ½ÇÁ¦ À̵¿ ÇÑ´Ù)
  2937. // ¼­¹ö´Â charÀÇ x, y °ªÀ» ¹Ù·Î ¹Ù²ÙÁö¸¸,
  2938. // Ŭ¶ó¿¡¼­´Â ÀÌÀü À§Ä¡¿¡¼­ ¹Ù²Û x, y±îÁö interpolationÇÑ´Ù.
  2939. // °È°Å³ª ¶Ù´Â °ÍÀº charÀÇ m_bNowWalking¿¡ ´Þ·ÁÀÖ´Ù.
  2940. // Warp¸¦ ÀǵµÇÑ °ÍÀ̶ó¸é Show¸¦ »ç¿ëÇÒ °Í.
  2941. bool CHARACTER::Move(long x, long y)
  2942. {
  2943. // °°Àº À§Ä¡¸é À̵¿ÇÒ ÇÊ¿ä ¾øÀ½ (ÀÚµ¿ ¼º°ø)
  2944. if (GetX() == x && GetY() == y)
  2945. return true;
  2946.  
  2947. if (test_server)
  2948. if (m_bDetailLog)
  2949. sys_log(0, "%s position %u %u", GetName(), x, y);
  2950.  
  2951. OnMove();
  2952. return Sync(x, y);
  2953. }
  2954.  
  2955. void CHARACTER::SendMovePacket(BYTE bFunc, BYTE bArg, DWORD x, DWORD y, DWORD dwDuration, DWORD dwTime, int iRot)
  2956. {
  2957. TPacketGCMove pack;
  2958.  
  2959. if (bFunc == FUNC_WAIT)
  2960. {
  2961. x = m_posDest.x;
  2962. y = m_posDest.y;
  2963. dwDuration = m_dwMoveDuration;
  2964. }
  2965.  
  2966. EncodeMovePacket(pack, GetVID(), bFunc, bArg, x, y, dwDuration, dwTime, iRot == -1 ? (int) GetRotation() / 5 : iRot);
  2967. PacketView(&pack, sizeof(TPacketGCMove), this);
  2968. }
  2969.  
  2970. int CHARACTER::GetRealPoint(BYTE type) const
  2971. {
  2972. return m_points.points[type];
  2973. }
  2974.  
  2975. void CHARACTER::SetRealPoint(BYTE type, int val)
  2976. {
  2977. m_points.points[type] = val;
  2978. }
  2979.  
  2980. int CHARACTER::GetPolymorphPoint(BYTE type) const
  2981. {
  2982. if (IsPolymorphed() && !IsPolyMaintainStat())
  2983. {
  2984. DWORD dwMobVnum = GetPolymorphVnum();
  2985. const CMob * pMob = CMobManager::instance().Get(dwMobVnum);
  2986. int iPower = GetPolymorphPower();
  2987.  
  2988. if (pMob)
  2989. {
  2990. switch (type)
  2991. {
  2992. case POINT_ST:
  2993. if (GetJob() == JOB_SHAMAN || GetJob() == JOB_SURA && GetSkillGroup() == 2)
  2994. return pMob->m_table.bStr * iPower / 100 + GetPoint(POINT_IQ);
  2995. return pMob->m_table.bStr * iPower / 100 + GetPoint(POINT_ST);
  2996.  
  2997. case POINT_HT:
  2998. return pMob->m_table.bCon * iPower / 100 + GetPoint(POINT_HT);
  2999.  
  3000. case POINT_IQ:
  3001. return pMob->m_table.bInt * iPower / 100 + GetPoint(POINT_IQ);
  3002.  
  3003. case POINT_DX:
  3004. return pMob->m_table.bDex * iPower / 100 + GetPoint(POINT_DX);
  3005. }
  3006. }
  3007. }
  3008.  
  3009. return GetPoint(type);
  3010. }
  3011.  
  3012. long long CHARACTER::GetPoint(BYTE type) const
  3013. {
  3014. if (type >= POINT_MAX_NUM)
  3015. {
  3016. sys_err("Point type overflow (type %u)", type);
  3017. return 0;
  3018. }
  3019.  
  3020. long long val = m_pointsInstant.points[type];
  3021. long long max_val = LLONG_MAX;
  3022.  
  3023. switch (type)
  3024. {
  3025. case POINT_STEAL_HP:
  3026. case POINT_STEAL_SP:
  3027. max_val = 50;
  3028. break;
  3029. case POINT_GOLD:
  3030. max_val = GOLD_MAX;
  3031. break;
  3032. }
  3033.  
  3034. if (val > max_val)
  3035. sys_err("POINT_ERROR: %s type %d val %lld (max: %lld)", GetName(), val, max_val);
  3036.  
  3037. return (val);
  3038. }
  3039.  
  3040. int CHARACTER::GetLimitPoint(BYTE type) const
  3041. {
  3042. if (type >= POINT_MAX_NUM)
  3043. {
  3044. sys_err("Point type overflow (type %u)", type);
  3045. return 0;
  3046. }
  3047.  
  3048. int val = m_pointsInstant.points[type];
  3049. int max_val = INT_MAX;
  3050. int limit = INT_MAX;
  3051. int min_limit = -INT_MAX;
  3052.  
  3053. switch (type)
  3054. {
  3055. case POINT_ATT_SPEED:
  3056. min_limit = 0;
  3057.  
  3058. if (IsPC())
  3059. limit = 170;
  3060. else
  3061. limit = 250;
  3062. break;
  3063.  
  3064. case POINT_MOV_SPEED:
  3065. min_limit = 0;
  3066.  
  3067. if (IsPC())
  3068. limit = 200;
  3069. else
  3070. limit = 250;
  3071. break;
  3072.  
  3073. case POINT_STEAL_HP:
  3074. case POINT_STEAL_SP:
  3075. limit = 50;
  3076. max_val = 50;
  3077. break;
  3078.  
  3079. case POINT_MALL_ATTBONUS:
  3080. case POINT_MALL_DEFBONUS:
  3081. limit = 20;
  3082. max_val = 50;
  3083. break;
  3084. }
  3085.  
  3086. if (val > max_val)
  3087. sys_err("POINT_ERROR: %s type %d val %d (max: %d)", GetName(), val, max_val);
  3088.  
  3089. if (val > limit)
  3090. val = limit;
  3091.  
  3092. if (val < min_limit)
  3093. val = min_limit;
  3094.  
  3095. return (val);
  3096. }
  3097.  
  3098. void CHARACTER::SetPoint(BYTE type, long long val)
  3099. {
  3100. if (type >= POINT_MAX_NUM)
  3101. {
  3102. sys_err("Point type overflow (type %u)", type);
  3103. return;
  3104. }
  3105.  
  3106. m_pointsInstant.points[type] = val;
  3107.  
  3108. // ¾ÆÁ÷ À̵¿ÀÌ ´Ù ¾È³¡³µ´Ù¸é À̵¿ ½Ã°£ °è»êÀ» ´Ù½Ã ÇØ¾ß ÇÑ´Ù.
  3109. if (type == POINT_MOV_SPEED && get_dword_time() < m_dwMoveStartTime + m_dwMoveDuration)
  3110. {
  3111. CalculateMoveDuration();
  3112. }
  3113. }
  3114.  
  3115. long long CHARACTER::GetAllowedGold() const
  3116. {
  3117. if (GetLevel() <= 10)
  3118. return 100000;
  3119. else if (GetLevel() <= 20)
  3120. return 500000;
  3121. else
  3122. return 50000000;
  3123. }
  3124.  
  3125. void CHARACTER::CheckMaximumPoints()
  3126. {
  3127. if (GetMaxHP() < GetHP())
  3128. PointChange(POINT_HP, GetMaxHP() - GetHP());
  3129.  
  3130. if (GetMaxSP() < GetSP())
  3131. PointChange(POINT_SP, GetMaxSP() - GetSP());
  3132. }
  3133.  
  3134. void CHARACTER::PointChange(BYTE type, long long amount, bool bAmount, bool bBroadcast)
  3135. {
  3136. long long val = 0;
  3137.  
  3138. //sys_log(0, "PointChange %d %d | %d -> %d cHP %d mHP %d", type, amount, GetPoint(type), GetPoint(type)+amount, GetHP(), GetMaxHP());
  3139.  
  3140. switch (type)
  3141. {
  3142. case POINT_NONE:
  3143. return;
  3144.  
  3145. case POINT_LEVEL:
  3146. if ((GetLevel() + amount) > gPlayerMaxLevel)
  3147. return;
  3148.  
  3149. SetLevel(GetLevel() + amount);
  3150. val = GetLevel();
  3151.  
  3152. sys_log(0, "LEVELUP: %s %d NEXT EXP %d", GetName(), GetLevel(), GetNextExp());
  3153.  
  3154. PointChange(POINT_NEXT_EXP, GetNextExp(), false);
  3155.  
  3156. if (amount)
  3157. {
  3158. quest::CQuestManager::instance().LevelUp(GetPlayerID());
  3159.  
  3160. LogManager::instance().LevelLog(this, val, GetRealPoint(POINT_PLAYTIME) + (get_dword_time() - m_dwPlayStartTime) / 60000);
  3161.  
  3162. if (GetGuild())
  3163. {
  3164. GetGuild()->LevelChange(GetPlayerID(), GetLevel());
  3165. }
  3166.  
  3167. if (GetParty())
  3168. {
  3169. GetParty()->RequestSetMemberLevel(GetPlayerID(), GetLevel());
  3170. }
  3171. }
  3172. break;
  3173.  
  3174. case POINT_NEXT_EXP:
  3175. val = GetNextExp();
  3176. bAmount = false;
  3177. break;
  3178.  
  3179. case POINT_EXP:
  3180. {
  3181. DWORD exp = GetExp();
  3182. DWORD next_exp = GetNextExp();
  3183.  
  3184. if (LC_IsNewCIBN())
  3185. {
  3186. if (IsOverTime(OT_NONE))
  3187. {
  3188. dev_log(LOG_DEB0, "<EXP_LOG> %s = NONE", GetName());
  3189. }
  3190. else if (IsOverTime(OT_3HOUR))
  3191. {
  3192. amount = (amount / 2);
  3193. dev_log(LOG_DEB0, "<EXP_LOG> %s = 3HOUR", GetName());
  3194. }
  3195. else if (IsOverTime(OT_5HOUR))
  3196. {
  3197. amount = 0;
  3198. dev_log(LOG_DEB0, "<EXP_LOG> %s = 5HOUR", GetName());
  3199. }
  3200. }
  3201.  
  3202. if (amount < 0 && (int)exp < -amount)
  3203. {
  3204. sys_log(1, "%s AMOUNT < 0 %d, CUR EXP: %d", GetName(), -amount, exp);
  3205. amount = -static_cast<int>(exp);
  3206.  
  3207. SetExp(exp + amount);
  3208. val = GetExp();
  3209. }
  3210. else
  3211. {
  3212. if (gPlayerMaxLevel <= GetLevel())
  3213. return;
  3214. if (block_exp)
  3215. {
  3216. return;
  3217. }
  3218.  
  3219. if (test_server)
  3220. ChatPacket(CHAT_TYPE_INFO, "You have gained %d exp.", amount);
  3221.  
  3222. DWORD iExpBalance = 0;
  3223. if (exp + amount >= next_exp)
  3224. {
  3225. iExpBalance = (exp + amount) - next_exp;
  3226. amount = next_exp - exp;
  3227.  
  3228. SetExp(0);
  3229. exp = next_exp;
  3230. }
  3231. else
  3232. {
  3233. SetExp(exp + amount);
  3234. exp = GetExp();
  3235. }
  3236.  
  3237. DWORD q = DWORD(next_exp / 4.0f);
  3238. int iLevStep = GetRealPoint(POINT_LEVEL_STEP);
  3239. if (iLevStep >= 4)
  3240. {
  3241. sys_err("%s LEVEL_STEP bigger than 4! (%d)", GetName(), iLevStep);
  3242. iLevStep = 4;
  3243. }
  3244.  
  3245. if (exp >= next_exp && iLevStep < 4)
  3246. {
  3247. for (int i = 0; i < 4 - iLevStep; ++i)
  3248. PointChange(POINT_LEVEL_STEP, 1, false, true);
  3249. }
  3250. else if (exp >= q * 3 && iLevStep < 3)
  3251. {
  3252. for (int i = 0; i < 3 - iLevStep; ++i)
  3253. PointChange(POINT_LEVEL_STEP, 1, false, true);
  3254. }
  3255. else if (exp >= q * 2 && iLevStep < 2)
  3256. {
  3257. for (int i = 0; i < 2 - iLevStep; ++i)
  3258. PointChange(POINT_LEVEL_STEP, 1, false, true);
  3259. }
  3260. else if (exp >= q && iLevStep < 1)
  3261. PointChange(POINT_LEVEL_STEP, 1);
  3262.  
  3263. if (iExpBalance)
  3264. {
  3265. PointChange(POINT_EXP, iExpBalance);
  3266. }
  3267.  
  3268. val = GetExp();
  3269. }
  3270. }
  3271. break;
  3272.  
  3273. case POINT_LEVEL_STEP:
  3274. if (amount > 0)
  3275. {
  3276. val = GetPoint(POINT_LEVEL_STEP) + amount;
  3277.  
  3278. switch (val)
  3279. {
  3280. case 1:
  3281. case 2:
  3282. case 3:
  3283. //if (GetLevel() < 100) PointChange(POINT_STAT, 1);
  3284. if (GetLevel() < (gPlayerMaxLevelStats+1)) PointChange(POINT_STAT, 1);
  3285. break;
  3286.  
  3287. case 4:
  3288. {
  3289. int iHP = number(JobInitialPoints[GetJob()].hp_per_lv_begin, JobInitialPoints[GetJob()].hp_per_lv_end);
  3290. int iSP = number(JobInitialPoints[GetJob()].sp_per_lv_begin, JobInitialPoints[GetJob()].sp_per_lv_end);
  3291.  
  3292. m_points.iRandomHP += iHP;
  3293. m_points.iRandomSP += iSP;
  3294. if (GetSkillGroup())
  3295. {
  3296. if (GetLevel() >= 5)
  3297. PointChange(POINT_SKILL, 1);
  3298.  
  3299. if (GetLevel() >= 9)
  3300. PointChange(POINT_SUB_SKILL, 1);
  3301. }
  3302.  
  3303. PointChange(POINT_MAX_HP, iHP);
  3304. PointChange(POINT_MAX_SP, iSP);
  3305. PointChange(POINT_LEVEL, 1, false, true);
  3306.  
  3307. val = 0;
  3308. }
  3309. break;
  3310. }
  3311.  
  3312. /*if (GetLevel() <= 10)
  3313. AutoGiveItem(27001, 2);
  3314. else if (GetLevel() <= 30)
  3315. AutoGiveItem(27002, 2);
  3316. else
  3317. {
  3318. AutoGiveItem(27002, 2);
  3319. }*/
  3320.  
  3321. PointChange(POINT_HP, GetMaxHP() - GetHP());
  3322. PointChange(POINT_SP, GetMaxSP() - GetSP());
  3323. PointChange(POINT_STAMINA, GetMaxStamina() - GetStamina());
  3324.  
  3325. SetPoint(POINT_LEVEL_STEP, val);
  3326. SetRealPoint(POINT_LEVEL_STEP, val);
  3327.  
  3328. Save();
  3329. }
  3330. else
  3331. val = GetPoint(POINT_LEVEL_STEP);
  3332.  
  3333. break;
  3334.  
  3335. case POINT_HP:
  3336. {
  3337. if (IsDead() || IsStun())
  3338. return;
  3339.  
  3340. int prev_hp = GetHP();
  3341.  
  3342. amount = MIN(GetMaxHP() - GetHP(), amount);
  3343. SetHP(GetHP() + amount);
  3344. val = GetHP();
  3345.  
  3346. BroadcastTargetPacket();
  3347.  
  3348. if (GetParty() && IsPC() && val != prev_hp)
  3349. GetParty()->SendPartyInfoOneToAll(this);
  3350. }
  3351. break;
  3352.  
  3353. case POINT_SP:
  3354. {
  3355. if (IsDead() || IsStun())
  3356. return;
  3357.  
  3358. amount = MIN(GetMaxSP() - GetSP(), amount);
  3359. SetSP(GetSP() + amount);
  3360. val = GetSP();
  3361. }
  3362. break;
  3363.  
  3364. case POINT_STAMINA:
  3365. {
  3366. if (IsDead() || IsStun())
  3367. return;
  3368.  
  3369. int prev_val = GetStamina();
  3370. amount = MIN(GetMaxStamina() - GetStamina(), amount);
  3371. SetStamina(GetStamina() + amount);
  3372. val = GetStamina();
  3373.  
  3374. if (val == 0)
  3375. {
  3376. SetNowWalking(true);
  3377. }
  3378. else if (prev_val == 0)
  3379. {
  3380. ResetWalking();
  3381. }
  3382.  
  3383. if (amount < 0 && val != 0)
  3384. return;
  3385. }
  3386. break;
  3387.  
  3388. case POINT_MAX_HP:
  3389. {
  3390. SetPoint(type, GetPoint(type) + amount);
  3391. int hp = GetRealPoint(POINT_MAX_HP);
  3392. int add_hp = MIN(3500, hp * GetPoint(POINT_MAX_HP_PCT) / 100);
  3393. add_hp += GetPoint(POINT_MAX_HP);
  3394. add_hp += GetPoint(POINT_PARTY_TANKER_BONUS);
  3395.  
  3396. SetMaxHP(hp + add_hp);
  3397. val = GetMaxHP();
  3398. }
  3399. break;
  3400.  
  3401. case POINT_MAX_SP:
  3402. {
  3403. SetPoint(type, GetPoint(type) + amount);
  3404. int sp = GetRealPoint(POINT_MAX_SP);
  3405. int add_sp = MIN(800, sp * GetPoint(POINT_MAX_SP_PCT) / 100);
  3406. add_sp += GetPoint(POINT_MAX_SP);
  3407. add_sp += GetPoint(POINT_PARTY_SKILL_MASTER_BONUS);
  3408.  
  3409. SetMaxSP(sp + add_sp);
  3410. val = GetMaxSP();
  3411. }
  3412. break;
  3413.  
  3414. case POINT_MAX_HP_PCT:
  3415. SetPoint(type, GetPoint(type) + amount);
  3416. val = GetPoint(type);
  3417.  
  3418. PointChange(POINT_MAX_HP, 0);
  3419. break;
  3420.  
  3421. case POINT_MAX_SP_PCT:
  3422. SetPoint(type, GetPoint(type) + amount);
  3423. val = GetPoint(type);
  3424.  
  3425. PointChange(POINT_MAX_SP, 0);
  3426. break;
  3427.  
  3428. case POINT_MAX_STAMINA:
  3429. SetMaxStamina(GetMaxStamina() + amount);
  3430. val = GetMaxStamina();
  3431. break;
  3432.  
  3433. case POINT_GOLD:
  3434. {
  3435. const long long nTotalMoney = static_cast<long long>(GetGold()) + static_cast<long long>(amount);
  3436.  
  3437. if (GOLD_MAX <= nTotalMoney)
  3438. {
  3439. sys_err("[OVERFLOW_GOLD] OriGold %lld AddedGold %lld id %u Name %s ", GetGold(), amount, GetPlayerID(), GetName());
  3440. LogManager::instance().CharLog(this, GetGold() + amount, "OVERFLOW_GOLD", "");
  3441. return;
  3442. }
  3443.  
  3444. if (LC_IsNewCIBN() && amount > 0)
  3445. {
  3446. if (IsOverTime(OT_NONE))
  3447. {
  3448. dev_log(LOG_DEB0, "<GOLD_LOG> %s = NONE", GetName());
  3449. }
  3450. else if (IsOverTime(OT_3HOUR))
  3451. {
  3452. amount = (amount / 2);
  3453. dev_log(LOG_DEB0, "<GOLD_LOG> %s = 3HOUR", GetName());
  3454. }
  3455. else if (IsOverTime(OT_5HOUR))
  3456. {
  3457. amount = 0;
  3458. dev_log(LOG_DEB0, "<GOLD_LOG> %s = 5HOUR", GetName());
  3459. }
  3460. }
  3461.  
  3462. SetGold(GetGold() + amount);
  3463. val = GetGold();
  3464. }
  3465. break;
  3466.  
  3467. case POINT_SKILL:
  3468. case POINT_STAT:
  3469. case POINT_SUB_SKILL:
  3470. case POINT_STAT_RESET_COUNT:
  3471. case POINT_HORSE_SKILL:
  3472. SetPoint(type, GetPoint(type) + amount);
  3473. val = GetPoint(type);
  3474.  
  3475. SetRealPoint(type, val);
  3476. break;
  3477.  
  3478. case POINT_DEF_GRADE:
  3479. SetPoint(type, GetPoint(type) + amount);
  3480. val = GetPoint(type);
  3481.  
  3482. PointChange(POINT_CLIENT_DEF_GRADE, amount);
  3483. break;
  3484.  
  3485. case POINT_CLIENT_DEF_GRADE:
  3486. SetPoint(type, GetPoint(type) + amount);
  3487. val = GetPoint(type);
  3488. break;
  3489.  
  3490. case POINT_ST:
  3491. case POINT_HT:
  3492. case POINT_DX:
  3493. case POINT_IQ:
  3494. case POINT_HP_REGEN:
  3495. case POINT_SP_REGEN:
  3496. case POINT_ATT_SPEED:
  3497. case POINT_ATT_GRADE:
  3498. case POINT_MOV_SPEED:
  3499. case POINT_CASTING_SPEED:
  3500. case POINT_MAGIC_ATT_GRADE:
  3501. case POINT_MAGIC_DEF_GRADE:
  3502. case POINT_BOW_DISTANCE:
  3503. case POINT_HP_RECOVERY:
  3504. case POINT_SP_RECOVERY:
  3505. case POINT_ATTBONUS_HUMAN:
  3506. case POINT_ATTBONUS_ANIMAL:
  3507. case POINT_ATTBONUS_ORC:
  3508. case POINT_ATTBONUS_MILGYO:
  3509. case POINT_ATTBONUS_UNDEAD:
  3510. case POINT_ATTBONUS_DEVIL:
  3511. case POINT_ATTBONUS_MONSTER:
  3512. case POINT_ATTBONUS_SURA:
  3513. case POINT_ATTBONUS_ASSASSIN:
  3514. case POINT_ATTBONUS_WARRIOR:
  3515. case POINT_ATTBONUS_SHAMAN:
  3516. case POINT_ATTBONUS_WOLFMAN:
  3517. case POINT_POISON_PCT:
  3518. case POINT_BLEEDING_PCT:
  3519. case POINT_STUN_PCT:
  3520. case POINT_SLOW_PCT:
  3521. case POINT_BLOCK:
  3522. case POINT_DODGE:
  3523. case POINT_CRITICAL_PCT:
  3524. case POINT_RESIST_CRITICAL:
  3525. case POINT_PENETRATE_PCT:
  3526. case POINT_RESIST_PENETRATE:
  3527. case POINT_CURSE_PCT:
  3528. case POINT_STEAL_HP:
  3529. case POINT_STEAL_SP:
  3530. case POINT_MANA_BURN_PCT:
  3531. case POINT_DAMAGE_SP_RECOVER:
  3532. case POINT_RESIST_NORMAL_DAMAGE:
  3533. case POINT_RESIST_SWORD:
  3534. case POINT_RESIST_TWOHAND:
  3535. case POINT_RESIST_DAGGER:
  3536. case POINT_RESIST_BELL:
  3537. case POINT_RESIST_FAN:
  3538. case POINT_RESIST_BOW:
  3539. case POINT_RESIST_CLAW:
  3540. case POINT_RESIST_FIRE:
  3541. case POINT_RESIST_ELEC:
  3542. case POINT_RESIST_MAGIC:
  3543. case POINT_RESIST_WIND:
  3544. case POINT_RESIST_ICE:
  3545. case POINT_RESIST_EARTH:
  3546. case POINT_RESIST_DARK:
  3547. case POINT_REFLECT_MELEE:
  3548. case POINT_REFLECT_CURSE:
  3549. case POINT_POISON_REDUCE:
  3550. case POINT_BLEEDING_REDUCE:
  3551. case POINT_KILL_SP_RECOVER:
  3552. case POINT_KILL_HP_RECOVERY:
  3553. case POINT_HIT_HP_RECOVERY:
  3554. case POINT_HIT_SP_RECOVERY:
  3555. case POINT_MANASHIELD:
  3556. case POINT_ATT_BONUS:
  3557. case POINT_DEF_BONUS:
  3558. case POINT_SKILL_DAMAGE_BONUS:
  3559. case POINT_NORMAL_HIT_DAMAGE_BONUS:
  3560. case POINT_SKILL_DEFEND_BONUS:
  3561. case POINT_NORMAL_HIT_DEFEND_BONUS:
  3562. SetPoint(type, GetPoint(type) + amount);
  3563. val = GetPoint(type);
  3564. break;
  3565.  
  3566. case POINT_PARTY_ATTACKER_BONUS:
  3567. case POINT_PARTY_TANKER_BONUS:
  3568. case POINT_PARTY_BUFFER_BONUS:
  3569. case POINT_PARTY_SKILL_MASTER_BONUS:
  3570. case POINT_PARTY_HASTE_BONUS:
  3571. case POINT_PARTY_DEFENDER_BONUS:
  3572. case POINT_RESIST_WARRIOR:
  3573. case POINT_RESIST_ASSASSIN:
  3574. case POINT_RESIST_SURA:
  3575. case POINT_RESIST_SHAMAN:
  3576. case POINT_RESIST_WOLFMAN:
  3577. SetPoint(type, GetPoint(type) + amount);
  3578. val = GetPoint(type);
  3579. break;
  3580.  
  3581. case POINT_MALL_ATTBONUS:
  3582. case POINT_MALL_DEFBONUS:
  3583. case POINT_MALL_EXPBONUS:
  3584. case POINT_MALL_ITEMBONUS:
  3585. case POINT_MALL_GOLDBONUS:
  3586. case POINT_MELEE_MAGIC_ATT_BONUS_PER:
  3587. if (GetPoint(type) + amount > 100)
  3588. {
  3589. sys_err("MALL_BONUS exceeded over 100!! point type: %d name: %s amount %d", type, GetName(), amount);
  3590. amount = 100 - GetPoint(type);
  3591. }
  3592.  
  3593. SetPoint(type, GetPoint(type) + amount);
  3594. val = GetPoint(type);
  3595. break;
  3596.  
  3597. case POINT_PC_BANG_EXP_BONUS :
  3598. case POINT_PC_BANG_DROP_BONUS :
  3599. case POINT_RAMADAN_CANDY_BONUS_EXP:
  3600. SetPoint(type, amount);
  3601. val = GetPoint(type);
  3602. break;
  3603.  
  3604. case POINT_EXP_DOUBLE_BONUS:
  3605. case POINT_GOLD_DOUBLE_BONUS:
  3606. case POINT_ITEM_DROP_BONUS:
  3607. case POINT_POTION_BONUS:
  3608. if (GetPoint(type) + amount > 100)
  3609. {
  3610. sys_err("BONUS exceeded over 100!! point type: %d name: %s amount %d", type, GetName(), amount);
  3611. amount = 100 - GetPoint(type);
  3612. }
  3613.  
  3614. SetPoint(type, GetPoint(type) + amount);
  3615. val = GetPoint(type);
  3616. break;
  3617.  
  3618. case POINT_IMMUNE_STUN:
  3619. SetPoint(type, GetPoint(type) + amount);
  3620. val = GetPoint(type);
  3621. if (val)
  3622. {
  3623. SET_BIT(m_pointsInstant.dwImmuneFlag, IMMUNE_STUN);
  3624. }
  3625. else
  3626. {
  3627. REMOVE_BIT(m_pointsInstant.dwImmuneFlag, IMMUNE_STUN);
  3628. }
  3629. break;
  3630.  
  3631. case POINT_IMMUNE_SLOW:
  3632. SetPoint(type, GetPoint(type) + amount);
  3633. val = GetPoint(type);
  3634. if (val)
  3635. {
  3636. SET_BIT(m_pointsInstant.dwImmuneFlag, IMMUNE_SLOW);
  3637. }
  3638. else
  3639. {
  3640. REMOVE_BIT(m_pointsInstant.dwImmuneFlag, IMMUNE_SLOW);
  3641. }
  3642. break;
  3643.  
  3644. case POINT_IMMUNE_FALL:
  3645. SetPoint(type, GetPoint(type) + amount);
  3646. val = GetPoint(type);
  3647. if (val)
  3648. {
  3649. SET_BIT(m_pointsInstant.dwImmuneFlag, IMMUNE_FALL);
  3650. }
  3651. else
  3652. {
  3653. REMOVE_BIT(m_pointsInstant.dwImmuneFlag, IMMUNE_FALL);
  3654. }
  3655. break;
  3656.  
  3657. case POINT_ATT_GRADE_BONUS:
  3658. SetPoint(type, GetPoint(type) + amount);
  3659. PointChange(POINT_ATT_GRADE, amount);
  3660. val = GetPoint(type);
  3661. break;
  3662.  
  3663. case POINT_DEF_GRADE_BONUS:
  3664. SetPoint(type, GetPoint(type) + amount);
  3665. PointChange(POINT_DEF_GRADE, amount);
  3666. val = GetPoint(type);
  3667. break;
  3668.  
  3669. case POINT_MAGIC_ATT_GRADE_BONUS:
  3670. SetPoint(type, GetPoint(type) + amount);
  3671. PointChange(POINT_MAGIC_ATT_GRADE, amount);
  3672. val = GetPoint(type);
  3673. break;
  3674.  
  3675. case POINT_MAGIC_DEF_GRADE_BONUS:
  3676. SetPoint(type, GetPoint(type) + amount);
  3677. PointChange(POINT_MAGIC_DEF_GRADE, amount);
  3678. val = GetPoint(type);
  3679. break;
  3680.  
  3681. case POINT_VOICE:
  3682. case POINT_EMPIRE_POINT:
  3683. val = GetRealPoint(type);
  3684. break;
  3685.  
  3686. case POINT_POLYMORPH:
  3687. SetPoint(type, GetPoint(type) + amount);
  3688. val = GetPoint(type);
  3689. SetPolymorph(val);
  3690. break;
  3691.  
  3692. case POINT_MOUNT:
  3693. SetPoint(type, GetPoint(type) + amount);
  3694. val = GetPoint(type);
  3695. MountVnum(val);
  3696. break;
  3697.  
  3698. case POINT_ENERGY:
  3699. case POINT_COSTUME_ATTR_BONUS:
  3700. {
  3701. int old_val = GetPoint(type);
  3702. SetPoint(type, old_val + amount);
  3703. val = GetPoint(type);
  3704. BuffOnAttr_ValueChange(type, old_val, val);
  3705. }
  3706. break;
  3707.  
  3708. default:
  3709. sys_err("CHARACTER::PointChange: %s: unknown point change type %d", GetName(), type);
  3710. return;
  3711. }
  3712.  
  3713. switch (type)
  3714. {
  3715. case POINT_LEVEL:
  3716. case POINT_ST:
  3717. case POINT_DX:
  3718. case POINT_IQ:
  3719. case POINT_HT:
  3720. ComputeBattlePoints();
  3721. break;
  3722.  
  3723. case POINT_MAX_HP:
  3724. case POINT_MAX_SP:
  3725. case POINT_MAX_STAMINA:
  3726. break;
  3727. }
  3728.  
  3729. if (type == POINT_HP && amount == 0)
  3730. return;
  3731.  
  3732. if (GetDesc())
  3733. {
  3734. struct packet_point_change pack;
  3735. pack.header = HEADER_GC_CHARACTER_POINT_CHANGE;
  3736. pack.dwVID = m_vid;
  3737. pack.type = type;
  3738. pack.value = val;
  3739.  
  3740. if (bAmount)
  3741. pack.amount = amount;
  3742. else
  3743. pack.amount = 0;
  3744.  
  3745. if (!bBroadcast)
  3746. GetDesc()->Packet(&pack, sizeof(struct packet_point_change));
  3747. else
  3748. PacketAround(&pack, sizeof(pack));
  3749. }
  3750. }
  3751.  
  3752. void CHARACTER::ApplyPoint(BYTE bApplyType, int iVal)
  3753. {
  3754. switch (bApplyType)
  3755. {
  3756. case APPLY_NONE:
  3757. break;
  3758.  
  3759. case APPLY_CON:
  3760. PointChange(POINT_HT, iVal);
  3761. PointChange(POINT_MAX_HP, (iVal * JobInitialPoints[GetJob()].hp_per_ht));
  3762. PointChange(POINT_MAX_STAMINA, (iVal * JobInitialPoints[GetJob()].stamina_per_con));
  3763. break;
  3764.  
  3765. case APPLY_INT:
  3766. PointChange(POINT_IQ, iVal);
  3767. PointChange(POINT_MAX_SP, (iVal * JobInitialPoints[GetJob()].sp_per_iq));
  3768. break;
  3769.  
  3770. case APPLY_SKILL:
  3771. {
  3772. BYTE bSkillVnum = (BYTE) (((DWORD)iVal) >> 24);
  3773. int iAdd = iVal & 0x00800000;
  3774. int iChange = iVal & 0x007fffff;
  3775.  
  3776. sys_log(1, "APPLY_SKILL skill %d add? %d change %d", bSkillVnum, iAdd ? 1 : 0, iChange);
  3777. if (0 == iAdd)
  3778. iChange = -iChange;
  3779.  
  3780. boost::unordered_map<BYTE, int>::iterator iter = m_SkillDamageBonus.find(bSkillVnum);
  3781. if (iter == m_SkillDamageBonus.end())
  3782. m_SkillDamageBonus.insert(std::make_pair(bSkillVnum, iChange));
  3783. else
  3784. iter->second += iChange;
  3785. }
  3786. break;
  3787.  
  3788. case APPLY_STR:
  3789. case APPLY_DEX:
  3790. case APPLY_MAX_HP:
  3791. case APPLY_MAX_SP:
  3792. case APPLY_MAX_HP_PCT:
  3793. case APPLY_MAX_SP_PCT:
  3794. case APPLY_ATT_SPEED:
  3795. case APPLY_MOV_SPEED:
  3796. case APPLY_CAST_SPEED:
  3797. case APPLY_HP_REGEN:
  3798. case APPLY_SP_REGEN:
  3799. case APPLY_POISON_PCT:
  3800. case APPLY_BLEEDING_PCT:
  3801. case APPLY_STUN_PCT:
  3802. case APPLY_SLOW_PCT:
  3803. case APPLY_CRITICAL_PCT:
  3804. case APPLY_PENETRATE_PCT:
  3805. case APPLY_ATTBONUS_HUMAN:
  3806. case APPLY_ATTBONUS_ANIMAL:
  3807. case APPLY_ATTBONUS_ORC:
  3808. case APPLY_ATTBONUS_MILGYO:
  3809. case APPLY_ATTBONUS_UNDEAD:
  3810. case APPLY_ATTBONUS_DEVIL:
  3811. case APPLY_ATTBONUS_WARRIOR:
  3812. case APPLY_ATTBONUS_ASSASSIN:
  3813. case APPLY_ATTBONUS_SURA:
  3814. case APPLY_ATTBONUS_SHAMAN:
  3815. case APPLY_ATTBONUS_MONSTER:
  3816. case APPLY_STEAL_HP:
  3817. case APPLY_STEAL_SP:
  3818. case APPLY_MANA_BURN_PCT:
  3819. case APPLY_DAMAGE_SP_RECOVER:
  3820. case APPLY_BLOCK:
  3821. case APPLY_DODGE:
  3822. case APPLY_RESIST_SWORD:
  3823. case APPLY_RESIST_TWOHAND:
  3824. case APPLY_RESIST_DAGGER:
  3825. case APPLY_RESIST_BELL:
  3826. case APPLY_RESIST_FAN:
  3827. case APPLY_RESIST_BOW:
  3828. case APPLY_RESIST_FIRE:
  3829. case APPLY_RESIST_ELEC:
  3830. case APPLY_RESIST_MAGIC:
  3831. case APPLY_RESIST_WIND:
  3832. case APPLY_RESIST_ICE:
  3833. case APPLY_RESIST_EARTH:
  3834. case APPLY_RESIST_DARK:
  3835. case APPLY_REFLECT_MELEE:
  3836. case APPLY_REFLECT_CURSE:
  3837. case APPLY_ANTI_CRITICAL_PCT:
  3838. case APPLY_ANTI_PENETRATE_PCT:
  3839. case APPLY_POISON_REDUCE:
  3840. case APPLY_BLEEDING_REDUCE:
  3841. case APPLY_KILL_SP_RECOVER:
  3842. case APPLY_EXP_DOUBLE_BONUS:
  3843. case APPLY_GOLD_DOUBLE_BONUS:
  3844. case APPLY_ITEM_DROP_BONUS:
  3845. case APPLY_POTION_BONUS:
  3846. case APPLY_KILL_HP_RECOVER:
  3847. case APPLY_IMMUNE_STUN:
  3848. case APPLY_IMMUNE_SLOW:
  3849. case APPLY_IMMUNE_FALL:
  3850. case APPLY_BOW_DISTANCE:
  3851. case APPLY_ATT_GRADE_BONUS:
  3852. case APPLY_DEF_GRADE_BONUS:
  3853. case APPLY_MAGIC_ATT_GRADE:
  3854. case APPLY_MAGIC_DEF_GRADE:
  3855. case APPLY_CURSE_PCT:
  3856. case APPLY_MAX_STAMINA:
  3857. case APPLY_MALL_ATTBONUS:
  3858. case APPLY_MALL_DEFBONUS:
  3859. case APPLY_MALL_EXPBONUS:
  3860. case APPLY_MALL_ITEMBONUS:
  3861. case APPLY_MALL_GOLDBONUS:
  3862. case APPLY_SKILL_DAMAGE_BONUS:
  3863. case APPLY_NORMAL_HIT_DAMAGE_BONUS:
  3864. case APPLY_SKILL_DEFEND_BONUS:
  3865. case APPLY_NORMAL_HIT_DEFEND_BONUS:
  3866. case APPLY_PC_BANG_EXP_BONUS:
  3867. case APPLY_PC_BANG_DROP_BONUS:
  3868. case APPLY_RESIST_WARRIOR:
  3869. case APPLY_RESIST_ASSASSIN:
  3870. case APPLY_RESIST_SURA:
  3871. case APPLY_RESIST_SHAMAN:
  3872. case APPLY_ENERGY:
  3873. case APPLY_DEF_GRADE:
  3874. case APPLY_COSTUME_ATTR_BONUS:
  3875. case APPLY_MAGIC_ATTBONUS_PER:
  3876. case APPLY_MELEE_MAGIC_ATTBONUS_PER:
  3877. case APPLY_ATTBONUS_WOLFMAN:
  3878. case APPLY_RESIST_WOLFMAN:
  3879. case APPLY_RESIST_CLAW:
  3880. PointChange(aApplyInfo[bApplyType].bPointType, iVal);
  3881. break;
  3882.  
  3883. default:
  3884. sys_err("Unknown apply type %d name %s", bApplyType, GetName());
  3885. break;
  3886. }
  3887. }
  3888.  
  3889. void CHARACTER::MotionPacketEncode(BYTE motion, LPCHARACTER victim, struct packet_motion * packet)
  3890. {
  3891. packet->header = HEADER_GC_MOTION;
  3892. packet->vid = m_vid;
  3893. packet->motion = motion;
  3894.  
  3895. if (victim)
  3896. packet->victim_vid = victim->GetVID();
  3897. else
  3898. packet->victim_vid = 0;
  3899. }
  3900.  
  3901. void CHARACTER::Motion(BYTE motion, LPCHARACTER victim)
  3902. {
  3903. struct packet_motion pack_motion;
  3904. MotionPacketEncode(motion, victim, &pack_motion);
  3905. PacketAround(&pack_motion, sizeof(struct packet_motion));
  3906. }
  3907.  
  3908. EVENTFUNC(save_event)
  3909. {
  3910. char_event_info* info = dynamic_cast<char_event_info*>( event->info );
  3911. if ( info == NULL )
  3912. {
  3913. sys_err( "save_event> <Factor> Null pointer" );
  3914. return 0;
  3915. }
  3916.  
  3917. LPCHARACTER ch = info->ch;
  3918.  
  3919. if (ch == NULL) { // <Factor>
  3920. return 0;
  3921. }
  3922. sys_log(1, "SAVE_EVENT: %s", ch->GetName());
  3923. ch->Save();
  3924. ch->FlushDelayedSaveItem();
  3925. return (save_event_second_cycle);
  3926. }
  3927.  
  3928. void CHARACTER::StartSaveEvent()
  3929. {
  3930. if (m_pkSaveEvent)
  3931. return;
  3932.  
  3933. char_event_info* info = AllocEventInfo<char_event_info>();
  3934.  
  3935. info->ch = this;
  3936. m_pkSaveEvent = event_create(save_event, info, save_event_second_cycle);
  3937. }
  3938.  
  3939. void CHARACTER::MonsterLog(const char* format, ...)
  3940. {
  3941. if (!test_server)
  3942. return;
  3943.  
  3944. if (IsPC())
  3945. return;
  3946.  
  3947. char chatbuf[CHAT_MAX_LEN + 1];
  3948. int len = snprintf(chatbuf, sizeof(chatbuf), "%u)", (DWORD)GetVID());
  3949.  
  3950. if (len < 0 || len >= (int) sizeof(chatbuf))
  3951. len = sizeof(chatbuf) - 1;
  3952.  
  3953. va_list args;
  3954.  
  3955. va_start(args, format);
  3956.  
  3957. int len2 = vsnprintf(chatbuf + len, sizeof(chatbuf) - len, format, args);
  3958.  
  3959. if (len2 < 0 || len2 >= (int) sizeof(chatbuf) - len)
  3960. len += (sizeof(chatbuf) - len) - 1;
  3961. else
  3962. len += len2;
  3963.  
  3964. // \0 ¹®ÀÚ Æ÷ÇÔ
  3965. ++len;
  3966.  
  3967. va_end(args);
  3968.  
  3969. TPacketGCChat pack_chat;
  3970.  
  3971. pack_chat.header = HEADER_GC_CHAT;
  3972. pack_chat.size = sizeof(TPacketGCChat) + len;
  3973. pack_chat.type = CHAT_TYPE_TALKING;
  3974. pack_chat.id = (DWORD)GetVID();
  3975. pack_chat.bEmpire = 0;
  3976.  
  3977. TEMP_BUFFER buf;
  3978. buf.write(&pack_chat, sizeof(TPacketGCChat));
  3979. buf.write(chatbuf, len);
  3980.  
  3981. CHARACTER_MANAGER::instance().PacketMonsterLog(this, buf.read_peek(), buf.size());
  3982. }
  3983.  
  3984. void CHARACTER::ChatPacket(BYTE type, const char * format, ...)
  3985. {
  3986. LPDESC d = GetDesc();
  3987.  
  3988. if (!d || !format)
  3989. return;
  3990.  
  3991. char chatbuf[CHAT_MAX_LEN + 1];
  3992. va_list args;
  3993.  
  3994. va_start(args, format);
  3995. int len = vsnprintf(chatbuf, sizeof(chatbuf), format, args);
  3996. va_end(args);
  3997.  
  3998. struct packet_chat pack_chat;
  3999.  
  4000. pack_chat.header = HEADER_GC_CHAT;
  4001. pack_chat.size = sizeof(struct packet_chat) + len;
  4002. pack_chat.type = type;
  4003. pack_chat.id = 0;
  4004. pack_chat.bEmpire = d->GetEmpire();
  4005.  
  4006. TEMP_BUFFER buf;
  4007. buf.write(&pack_chat, sizeof(struct packet_chat));
  4008. buf.write(chatbuf, len);
  4009.  
  4010. d->Packet(buf.read_peek(), buf.size());
  4011.  
  4012. if (type == CHAT_TYPE_COMMAND && test_server)
  4013. sys_log(0, "SEND_COMMAND %s %s", GetName(), chatbuf);
  4014. }
  4015.  
  4016. // MINING
  4017. void CHARACTER::mining_take()
  4018. {
  4019. m_pkMiningEvent = NULL;
  4020. }
  4021.  
  4022. void CHARACTER::mining_cancel()
  4023. {
  4024. if (m_pkMiningEvent)
  4025. {
  4026. sys_log(0, "XXX MINING CANCEL");
  4027. event_cancel(&m_pkMiningEvent);
  4028. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("䱤À» Áß´ÜÇÏ¿´½À´Ï´Ù."));
  4029. }
  4030. }
  4031.  
  4032. void CHARACTER::mining(LPCHARACTER chLoad)
  4033. {
  4034. if (m_pkMiningEvent)
  4035. {
  4036. mining_cancel();
  4037. return;
  4038. }
  4039.  
  4040. if (!chLoad)
  4041. return;
  4042.  
  4043. if (mining::GetRawOreFromLoad(chLoad->GetRaceNum()) == 0)
  4044. return;
  4045.  
  4046. LPITEM pick = GetWear(WEAR_WEAPON);
  4047.  
  4048. if (!pick || pick->GetType() != ITEM_PICK)
  4049. {
  4050. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("°î±ªÀ̸¦ ÀåÂøÇϼ¼¿ä."));
  4051. return;
  4052. }
  4053.  
  4054. int count = number(5, 15); // µ¿ÀÛ È½¼ö, ÇÑ µ¿ÀÛ´ç 2ÃÊ
  4055.  
  4056. // 䱤 µ¿ÀÛÀ» º¸¿©ÁÜ
  4057. TPacketGCDigMotion p;
  4058. p.header = HEADER_GC_DIG_MOTION;
  4059. p.vid = GetVID();
  4060. p.target_vid = chLoad->GetVID();
  4061. p.count = count;
  4062.  
  4063. PacketAround(&p, sizeof(p));
  4064.  
  4065. m_pkMiningEvent = mining::CreateMiningEvent(this, chLoad, count);
  4066. }
  4067. // END_OF_MINING
  4068.  
  4069. void CHARACTER::fishing()
  4070. {
  4071. if (m_pkFishingEvent)
  4072. {
  4073. fishing_take();
  4074. return;
  4075. }
  4076.  
  4077. // ¸ø°¨ ¼Ó¼º¿¡¼­ ³¬½Ã¸¦ ½ÃµµÇÑ´Ù?
  4078. {
  4079. LPSECTREE_MAP pkSectreeMap = SECTREE_MANAGER::instance().GetMap(GetMapIndex());
  4080.  
  4081. int x = GetX();
  4082. int y = GetY();
  4083.  
  4084. LPSECTREE tree = pkSectreeMap->Find(x, y);
  4085. DWORD dwAttr = tree->GetAttribute(x, y);
  4086.  
  4087. if (IS_SET(dwAttr, ATTR_BLOCK))
  4088. {
  4089. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("³¬½Ã¸¦ ÇÒ ¼ö ÀÖ´Â °÷ÀÌ ¾Æ´Õ´Ï´Ù"));
  4090. return;
  4091. }
  4092. }
  4093.  
  4094. LPITEM rod = GetWear(WEAR_WEAPON);
  4095.  
  4096. // ³¬½Ã´ë ÀåÂø
  4097. if (!rod || rod->GetType() != ITEM_ROD)
  4098. {
  4099. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("³¬½Ã´ë¸¦ ÀåÂø Çϼ¼¿ä."));
  4100. return;
  4101. }
  4102.  
  4103. if (0 == rod->GetSocket(2))
  4104. {
  4105. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("¹Ì³¢¸¦ ³¢°í ´øÁ® ÁÖ¼¼¿ä."));
  4106. return;
  4107. }
  4108.  
  4109. float fx, fy;
  4110. GetDeltaByDegree(GetRotation(), 400.0f, &fx, &fy);
  4111.  
  4112. m_pkFishingEvent = fishing::CreateFishingEvent(this);
  4113. }
  4114.  
  4115. void CHARACTER::fishing_take()
  4116. {
  4117. LPITEM rod = GetWear(WEAR_WEAPON);
  4118. if (rod && rod->GetType() == ITEM_ROD)
  4119. {
  4120. using fishing::fishing_event_info;
  4121. if (m_pkFishingEvent)
  4122. {
  4123. struct fishing_event_info* info = dynamic_cast<struct fishing_event_info*>(m_pkFishingEvent->info);
  4124.  
  4125. if (info)
  4126. fishing::Take(info, this);
  4127. }
  4128. }
  4129. else
  4130. {
  4131. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("³¬½Ã´ë°¡ ¾Æ´Ñ ¹°°ÇÀ¸·Î ³¬½Ã¸¦ ÇÒ ¼ö ¾ø½À´Ï´Ù!"));
  4132. }
  4133.  
  4134. event_cancel(&m_pkFishingEvent);
  4135. }
  4136.  
  4137. bool CHARACTER::StartStateMachine(int iNextPulse)
  4138. {
  4139. if (CHARACTER_MANAGER::instance().AddToStateList(this))
  4140. {
  4141. m_dwNextStatePulse = thecore_heart->pulse + iNextPulse;
  4142. return true;
  4143. }
  4144.  
  4145. return false;
  4146. }
  4147.  
  4148. void CHARACTER::StopStateMachine()
  4149. {
  4150. CHARACTER_MANAGER::instance().RemoveFromStateList(this);
  4151. }
  4152.  
  4153. void CHARACTER::UpdateStateMachine(DWORD dwPulse)
  4154. {
  4155. if (dwPulse < m_dwNextStatePulse)
  4156. return;
  4157.  
  4158. if (IsDead())
  4159. return;
  4160.  
  4161. Update();
  4162. m_dwNextStatePulse = dwPulse + m_dwStateDuration;
  4163. }
  4164.  
  4165. void CHARACTER::SetNextStatePulse(int iNextPulse)
  4166. {
  4167. CHARACTER_MANAGER::instance().AddToStateList(this);
  4168. m_dwNextStatePulse = iNextPulse;
  4169.  
  4170. if (iNextPulse < 10)
  4171. MonsterLog("´ÙÀ½»óÅ·ξ°¡ÀÚ");
  4172. }
  4173.  
  4174.  
  4175. // ij¸¯ÅÍ ÀνºÅϽº ¾÷µ¥ÀÌÆ® ÇÔ¼ö.
  4176. void CHARACTER::UpdateCharacter(DWORD dwPulse)
  4177. {
  4178. CFSM::Update();
  4179. }
  4180.  
  4181. void CHARACTER::SetShop(LPSHOP pkShop)
  4182. {
  4183. if ((m_pkShop = pkShop))
  4184. SET_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_SHOP);
  4185. else
  4186. {
  4187. REMOVE_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_SHOP);
  4188. SetShopOwner(NULL);
  4189. }
  4190. }
  4191.  
  4192. void CHARACTER::SetOfflineShop(LPOFFLINESHOP pkOfflineShop)
  4193. {
  4194. if ((m_pkOfflineShop = pkOfflineShop))
  4195. SET_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_OFFLINE_SHOP);
  4196. else
  4197. {
  4198. REMOVE_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_OFFLINE_SHOP);
  4199. SetOfflineShopOwner(NULL);
  4200. }
  4201. }
  4202.  
  4203.  
  4204. void CHARACTER::OpenMyOfflineShop(const char * c_pszSign, TShopItemTable * pTable, BYTE bItemCount, BYTE bTime)
  4205. {
  4206. quest::PC * pPC = quest::CQuestManager::Instance().GetPC(GetPlayerID());
  4207.  
  4208. if (pPC->IsRunning())
  4209. return;
  4210.  
  4211. if (bItemCount == 0)
  4212. return;
  4213.  
  4214. if (GetShop() || GetOfflineShop())
  4215. return;
  4216.  
  4217. // Brazil is not use for this option.
  4218. #ifdef __OFFLINE_SHOP_FIX_OPEN
  4219. int64_t sTotalMoneyVegas = 0;
  4220.  
  4221. for (int n = 0; n < bItemCount; ++n)
  4222. {
  4223. sTotalMoneyVegas += static_cast<int64_t>((pTable+n)->price);
  4224. }
  4225.  
  4226. std::auto_ptr<SQLMsg> pMsg(DBManager::instance().DirectQuery("SELECT money FROM player.player WHERE id = %u", GetPlayerID()));
  4227. if (pMsg->Get()->uiNumRows == 0)
  4228. return;
  4229.  
  4230. DWORD dwCurrentMoney = 0;
  4231. MYSQL_ROW row = mysql_fetch_row(pMsg->Get()->pSQLResult);
  4232. str_to_number(dwCurrentMoney, row[0]);
  4233.  
  4234. sTotalMoneyVegas += static_cast<int64_t>(dwCurrentMoney);
  4235.  
  4236. if (__OFFLINE_SHOP_VALUE_MAX <= sTotalMoneyVegas)
  4237. {
  4238. ChatPacket(CHAT_TYPE_INFO, __OFFLINE_SHOP_WARNING);
  4239. return;
  4240. }
  4241. #else
  4242. if (!LC_IsBrazil())
  4243. {
  4244. DWORD nTotalMoney = 0;
  4245. for (BYTE n = 0; n < bItemCount; ++n)
  4246. nTotalMoney += (pTable + n)->price;
  4247.  
  4248. if (GOLD_MAX - 1 <= nTotalMoney)
  4249. {
  4250. sys_err("[OVERFLOW_GOLD] Overflow (GOLD_MAX) id %u name %s", GetPlayerID(), GetName());
  4251. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("20¾ï ³ÉÀ» ÃÊ°úÇÏ¿© »óÁ¡À» ¿­¼ö°¡ ¾ø½À´Ï´Ù"));
  4252. return;
  4253. }
  4254. }
  4255. #endif
  4256.  
  4257. // Check Game admin can not open offline shop
  4258. {
  4259. if (!test_server)
  4260. {
  4261. if (IsGM())
  4262. {
  4263. ChatPacket(CHAT_TYPE_INFO, "Nu poti deschide un magazin offline deoarece,faci parte din echipa!");
  4264. return;
  4265. }
  4266. }
  4267. }
  4268. // End Of Check Game admin can not open offline shop
  4269.  
  4270. // Check if player has current items in database.
  4271. {
  4272. std::auto_ptr<SQLMsg> pMsg(DBManager::instance().DirectQuery("SELECT COUNT(*) FROM %soffline_shop_item WHERE owner_id = %u and status = 1", get_table_postfix(), GetPlayerID()));
  4273. MYSQL_ROW row = mysql_fetch_row(pMsg->Get()->pSQLResult);
  4274.  
  4275. BYTE bResult = 0;
  4276. str_to_number(bResult, row[0]);
  4277.  
  4278. if (bResult)
  4279. {
  4280. ChatPacket(CHAT_TYPE_INFO, "Mai intai trebuie sa va retrageti itemele,dupa veti putea deschide un magazin offline.");
  4281. COfflineShopManager::instance().Giveback2(this);
  4282. return;
  4283. }
  4284. }
  4285. // End of check if player has current items in database
  4286.  
  4287. // Check player is open offline shop or not
  4288. {
  4289. std::auto_ptr<SQLMsg> pMsg(DBManager::instance().DirectQuery("SELECT COUNT(*) FROM %soffline_shop_npc WHERE owner_id = %u", get_table_postfix(), GetPlayerID()));
  4290. MYSQL_ROW row = mysql_fetch_row(pMsg->Get()->pSQLResult);
  4291.  
  4292. BYTE bResult = 0;
  4293. str_to_number(bResult, row[0]);
  4294.  
  4295. if (bResult)
  4296. {
  4297. ChatPacket(CHAT_TYPE_INFO, "Aveti deja un magazin offline. Nu poti deschide altul!");
  4298. return;
  4299. }
  4300. }
  4301. // End Of check player is open offline shop or not
  4302.  
  4303. // Check map allows for Offline Shop
  4304. if (g_bOfflineShopMapAllowLimit)
  4305. {
  4306. if (!offlineshop_map_allow_find(GetMapIndex()))
  4307. {
  4308. ChatPacket(CHAT_TYPE_INFO, "Nu poti deschide un magazin offline in aceasta harta!");
  4309. return;
  4310. }
  4311. }
  4312. // End Of Check map allows for offline shop
  4313.  
  4314. // Need Item For Offline Shop
  4315. if (g_bNeedItem)
  4316. {
  4317. BYTE bCount = quest::CQuestManager::instance().GetCurrentCharacterPtr()->CountSpecifyItem(g_iItemVnum);
  4318. if (bCount < g_bItemCount)
  4319. {
  4320. LPITEM item = ITEM_MANAGER::instance().CreateItem(g_iItemVnum);
  4321. ChatPacket(CHAT_TYPE_INFO, "Nu poti deschide un magazin offline in acest moment. Ai nevoie de x%d %s", g_bItemCount, item->GetName());
  4322. return;
  4323. }
  4324. }
  4325. // End Of Need Item For Offline Shop
  4326.  
  4327. // Need Money For Offline Shop
  4328. if (g_bNeedMoney)
  4329. {
  4330. if (GetGold() < static_cast<int>(g_dwNeedMoney))
  4331. {
  4332. ChatPacket(CHAT_TYPE_INFO, "Nu ai destui bani pentru a deschide un magazin offline. Necesarul de bani : %u", g_dwNeedMoney);
  4333. return;
  4334. }
  4335. }
  4336. // End Of Need Money For Offline Shop
  4337.  
  4338. char szSign[SHOP_SIGN_MAX_LEN+1];
  4339. strlcpy(szSign, c_pszSign, sizeof(szSign));
  4340.  
  4341. m_stOfflineShopSign = szSign;
  4342.  
  4343. if (m_stOfflineShopSign.length() == 0)
  4344. return;
  4345.  
  4346. if (CBanwordManager::instance().CheckString(m_stOfflineShopSign.c_str(), m_stOfflineShopSign.length()))
  4347. {
  4348. ChatPacket(CHAT_TYPE_INFO, ("[Magazin Offline] Numele magazinului contine cuvinte interzise."));
  4349. return;
  4350. }
  4351.  
  4352. LPCHARACTER npc = CHARACTER_MANAGER::instance().SpawnMob(30000, GetMapIndex(), GetX(), GetY(), GetZ(), false, -1, false, true, GetPlayerID());
  4353.  
  4354. if (!npc)
  4355. {
  4356. ChatPacket(CHAT_TYPE_INFO, "Magazinul offline nu poate fi creat! Incearca mai tarziu.");
  4357. return;
  4358. }
  4359.  
  4360. std::map<DWORD, DWORD> itemkind;
  4361. std::set<TItemPos> cont;
  4362.  
  4363. for (BYTE i = 0; i < bItemCount; ++i)
  4364. {
  4365. if (cont.find((pTable + i)->pos) != cont.end())
  4366. {
  4367. sys_err("MY_OFFLINE_SHOP: duplicate shop item detected! (name: %s)", GetName());
  4368. return;
  4369. }
  4370.  
  4371. // ANTI_GIVE, ANTI_MYSHOP check
  4372. LPITEM pkItem = GetItem((pTable + i)->pos);
  4373.  
  4374. if (pkItem)
  4375. {
  4376. const TItemTable * item_table = pkItem->GetProto();
  4377.  
  4378. if (item_table && (IS_SET(item_table->dwAntiFlags, ITEM_ANTIFLAG_GIVE | ITEM_ANTIFLAG_MY_OFFLINE_SHOP)))
  4379. {
  4380. ChatPacket(CHAT_TYPE_INFO, "This item can not sell!");
  4381. return;
  4382. }
  4383.  
  4384. if (pkItem->IsEquipped() == true)
  4385. {
  4386. return;
  4387. }
  4388.  
  4389. if (true == pkItem->isLocked())
  4390. {
  4391. ChatPacket(CHAT_TYPE_INFO, "You can not sell locked items!");
  4392. return;
  4393. }
  4394.  
  4395. itemkind[pkItem->GetVnum()] = (pTable + i)->price / pkItem->GetCount();
  4396.  
  4397. char szColumns[QUERY_MAX_LEN], szValues[QUERY_MAX_LEN];
  4398.  
  4399. int iLen = snprintf(szColumns, sizeof(szColumns), "id,owner_id,pos,count,price,vnum");
  4400. int iUpdateLen = snprintf(szValues, sizeof(szValues), "%u,%u,%d,%u,%u,%u", pkItem->GetID(), GetPlayerID(), (pTable + i)->display_pos, pkItem->GetCount(), (pTable + i)->price, pkItem->GetVnum());
  4401.  
  4402. iLen += snprintf(szColumns + iLen, sizeof(szColumns) - iLen, ",socket0,socket1,socket2");
  4403. iUpdateLen += snprintf(szValues + iUpdateLen, sizeof(szValues) - iUpdateLen, ",%ld,%ld,%ld", pkItem->GetSocket(0), pkItem->GetSocket(1), pkItem->GetSocket(2));
  4404.  
  4405. iLen += snprintf(szColumns + iLen, sizeof(szColumns) - iLen, ",attrtype0,attrvalue0,attrtype1,attrvalue1,attrtype2,attrvalue2,attrtype3,attrvalue3,attrtype4,attrvalue4");
  4406. iUpdateLen += snprintf(szValues + iUpdateLen, sizeof(szValues) - iUpdateLen, ",%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
  4407. pkItem->GetAttributeType(0), pkItem->GetAttributeValue(0),
  4408. pkItem->GetAttributeType(1), pkItem->GetAttributeValue(1),
  4409. pkItem->GetAttributeType(2), pkItem->GetAttributeValue(2),
  4410. pkItem->GetAttributeType(3), pkItem->GetAttributeValue(3),
  4411. pkItem->GetAttributeType(4), pkItem->GetAttributeValue(4));
  4412.  
  4413. char szInsertQuery[QUERY_MAX_LEN];
  4414. snprintf(szInsertQuery, sizeof(szInsertQuery), "INSERT INTO %soffline_shop_item (%s) VALUES (%s)", get_table_postfix(), szColumns, szValues);
  4415. std::auto_ptr<SQLMsg> pMsg(DBManager::instance().DirectQuery(szInsertQuery));
  4416. pkItem->RemoveFromCharacter();
  4417. }
  4418.  
  4419. cont.insert((pTable + i)->pos);
  4420. }
  4421.  
  4422. // Time Mechanism
  4423. int iTime = 0;
  4424. switch (bTime)
  4425. {
  4426. case 1:
  4427. iTime = 1 * 60 * 60;
  4428. break;
  4429. case 2:
  4430. iTime = 2 * 60 * 60;
  4431. break;
  4432. case 3:
  4433. iTime = 4 * 60 * 60;
  4434. break;
  4435. }
  4436.  
  4437. // If bTime is not equal to unlimited time, start the time!
  4438. if (bTime != 4)
  4439. {
  4440. npc->SetOfflineShopTimer(iTime);
  4441. npc->StartOfflineShopUpdateEvent();
  4442. }
  4443.  
  4444. // Insert
  4445. char szQuery2[512];
  4446. snprintf(szQuery2, sizeof(szQuery2), "INSERT INTO %soffline_shop_npc(owner_id, sign, name, time, x, y, z, mapIndex, channel) VALUES(%u, '%s', '%s', %d, %ld, %ld, %ld, %ld, %d)", get_table_postfix(), GetPlayerID(), c_pszSign, GetName(), iTime, GetX(), GetY(), GetZ(), GetMapIndex(), g_bChannel);
  4447. DBManager::Instance().DirectQuery(szQuery2);
  4448.  
  4449. // Create Offline Shop
  4450. LPOFFLINESHOP pkOfflineShop = COfflineShopManager::instance().CreateOfflineShop(npc, GetPlayerID());
  4451.  
  4452. if (!pkOfflineShop)
  4453. {
  4454. ChatPacket(CHAT_TYPE_INFO, "Magazinul offline nu poate fi creat! Incearca mai tarziu.");
  4455. return;
  4456. }
  4457.  
  4458. npc->SetOfflineShop(pkOfflineShop);
  4459. npc->SetOfflineShopChannel(g_bChannel);
  4460. // End Of Create Offline Shop
  4461.  
  4462. // Set Name
  4463. char szName[CHARACTER_NAME_MAX_LEN + 1];
  4464. snprintf(szName, sizeof(szName), "%s's magazin offline", GetName());
  4465. npc->SetName(szName);
  4466. // End Of Set Name
  4467.  
  4468. SetOfflineShopVID(npc->GetVID());
  4469. npc->Show(GetMapIndex(), GetX(), GetY(), GetZ(), true);
  4470.  
  4471. // Send Offline Shop Sign to Everyone
  4472. TPacketGCShopSign p;
  4473. p.bHeader = HEADER_GC_OFFLINE_SHOP_SIGN;
  4474. p.dwVID = npc->GetVID();
  4475. strlcpy(p.szSign, c_pszSign, sizeof(p.szSign));
  4476.  
  4477. PacketAround(&p, sizeof(TPacketGCShopSign));
  4478. // End Of Send Offline Shop Sign to Everyone
  4479.  
  4480. if (bTime == 1)
  4481. ChatPacket(CHAT_TYPE_INFO, "[Magazin Offline] Timpul magazinului tau offline expira dupa o ora.");
  4482. else if (bTime == 2)
  4483. ChatPacket(CHAT_TYPE_INFO, "[Magazin Offline] Timpul magazinului tau offline expira dupa doua ore.");
  4484. else if (bTime == 3)//fixed
  4485. ChatPacket(CHAT_TYPE_INFO, "[Magazin Offline] Timpul magazinului tau offline expira dupa patru ore.");
  4486. else//qasta lasa.. oki
  4487. ChatPacket(CHAT_TYPE_INFO, "[Magazin Offline] Timpul magazinului tau offline este setat pe nelimitat!");
  4488.  
  4489.  
  4490. if (g_bNeedItem)
  4491. {
  4492. LPITEM item = FindSpecifyItem(g_iItemVnum);
  4493. if (!item)
  4494. {
  4495. ChatPacket(CHAT_TYPE_INFO, "Ups! Ceva a mers rau!");
  4496. return;
  4497. }
  4498.  
  4499. if (item->IsStackable())
  4500. if (item->GetCount() == g_bItemCount)
  4501. ITEM_MANAGER::instance().RemoveItem(item);
  4502. else
  4503. item->SetCount(item->GetCount() - g_bItemCount);
  4504. else
  4505. ITEM_MANAGER::instance().RemoveItem(item);
  4506. }
  4507.  
  4508. if (g_bNeedMoney)
  4509. PointChange(POINT_GOLD, -g_dwNeedMoney, false);
  4510. }
  4511.  
  4512.  
  4513. EVENTFUNC(offline_shop_update_event)
  4514. {
  4515. char_event_info* pInfo = dynamic_cast<char_event_info*>(event->info);
  4516.  
  4517. if (pInfo == NULL)
  4518. {
  4519. sys_err("offline_shop_update_event> <Factor> Null pointer");
  4520. return 0;
  4521. }
  4522.  
  4523. LPCHARACTER npc = pInfo->ch;
  4524.  
  4525. if (npc == NULL)
  4526. return 0;
  4527.  
  4528. int remain_time = npc->GetOfflineShopTimer() - processing_time / passes_per_sec;
  4529. if (remain_time <= 0)
  4530. {
  4531. sys_log(0, "OFFLINE SHOP EXPIRED : expired %s", npc->GetName());
  4532. LPCHARACTER pChar = CHARACTER_MANAGER::instance().Find(npc->GetOfflineShopRealOwner());
  4533. if (pChar)
  4534. {
  4535. pChar->ChatPacket(CHAT_TYPE_INFO, "Timpul magazinului tau offline a expirat. Obiectele din shop le vei primi in inventar.");
  4536. COfflineShopManager::instance().Giveback(pChar);
  4537. }
  4538. COfflineShopManager::instance().DestroyOfflineShop(NULL, npc->GetVID());
  4539. DBManager::instance().DirectQuery("DELETE FROM %soffline_shop_npc WHERE owner_id = %u", get_table_postfix(), npc->GetOfflineShopRealOwner());
  4540. M2_DESTROY_CHARACTER(npc);
  4541. return 0;
  4542. }
  4543.  
  4544. // If the variable is reach to maximum, start to save it
  4545. if (npc->GetOfflineShopSaveTime() >= g_bOfflineShopSaveTime)
  4546. {
  4547. DBManager::instance().DirectQuery("UPDATE %soffline_shop_npc SET time = %d WHERE owner_id = %u", get_table_postfix(), npc->GetOfflineShopTimer(), npc->GetOfflineShopRealOwner());
  4548. npc->SetOfflineShopTimer(1);
  4549. }
  4550.  
  4551. npc->SetOfflineShopTimer(remain_time);
  4552. npc->SetOfflineShopSaveTime(npc->GetOfflineShopSaveTime() + 1);
  4553. return PASSES_PER_SEC(MIN(60, remain_time));
  4554. }
  4555.  
  4556. void CHARACTER::StartOfflineShopUpdateEvent()
  4557. {
  4558. if (m_pkOfflineShopUpdateEvent)
  4559. return;
  4560.  
  4561. if (IsPC() || IsMonster())
  4562. return;
  4563.  
  4564. char_event_info * pInfo = AllocEventInfo<char_event_info>();
  4565. pInfo->ch = this;
  4566. m_pkOfflineShopUpdateEvent = event_create(offline_shop_update_event, pInfo, PASSES_PER_SEC(60));
  4567. }
  4568.  
  4569.  
  4570. void CHARACTER::StopOfflineShopUpdateEvent()
  4571. {
  4572. m_pointsInstant.bSaveTime = 0;
  4573. m_pointsInstant.leftTime = 0;
  4574. event_cancel(&m_pkOfflineShopUpdateEvent);
  4575. }
  4576.  
  4577. void CHARACTER::SetExchange(CExchange * pkExchange)
  4578. {
  4579. m_pkExchange = pkExchange;
  4580. }
  4581.  
  4582. void CHARACTER::SetPart(BYTE bPartPos, WORD wVal)
  4583. {
  4584. assert(bPartPos < PART_MAX_NUM);
  4585. m_pointsInstant.parts[bPartPos] = wVal;
  4586. }
  4587.  
  4588. WORD CHARACTER::GetPart(BYTE bPartPos) const
  4589. {
  4590. assert(bPartPos < PART_MAX_NUM);
  4591. return m_pointsInstant.parts[bPartPos];
  4592. }
  4593.  
  4594. WORD CHARACTER::GetOriginalPart(BYTE bPartPos) const
  4595. {
  4596. switch (bPartPos)
  4597. {
  4598. case PART_MAIN:
  4599. if (!IsPC())
  4600. return GetPart(PART_MAIN);
  4601. else
  4602. return m_pointsInstant.bBasePart;
  4603. case PART_HAIR:
  4604. return GetPart(PART_HAIR);
  4605. case PART_ACCE:
  4606. return GetPart(PART_ACCE);
  4607. #ifdef __WEAPON_COSTUME_SYSTEM__
  4608. case PART_WEAPON:
  4609. return GetPart(PART_WEAPON);
  4610. #endif
  4611. default:
  4612. return 0;
  4613. }
  4614. }
  4615.  
  4616. BYTE CHARACTER::GetCharType() const
  4617. {
  4618. return m_bCharType;
  4619. }
  4620.  
  4621. bool CHARACTER::SetSyncOwner(LPCHARACTER ch, bool bRemoveFromList)
  4622. {
  4623. // TRENT_MONSTER
  4624. if (IS_SET(m_pointsInstant.dwAIFlag, AIFLAG_NOMOVE))
  4625. return false;
  4626. // END_OF_TRENT_MONSTER
  4627.  
  4628. if (ch == this)
  4629. {
  4630. sys_err("SetSyncOwner owner == this (%p)", this);
  4631. return false;
  4632. }
  4633.  
  4634. if (!ch)
  4635. {
  4636. if (bRemoveFromList && m_pkChrSyncOwner)
  4637. {
  4638. m_pkChrSyncOwner->m_kLst_pkChrSyncOwned.remove(this);
  4639. }
  4640.  
  4641. if (m_pkChrSyncOwner)
  4642. sys_log(1, "SyncRelease %s %p from %s", GetName(), this, m_pkChrSyncOwner->GetName());
  4643.  
  4644. // ¸®½ºÆ®¿¡¼­ Á¦°ÅÇÏÁö ¾Ê´õ¶óµµ Æ÷ÀÎÅÍ´Â NULL·Î ¼ÂÆõǾî¾ß ÇÑ´Ù.
  4645. m_pkChrSyncOwner = NULL;
  4646. }
  4647. else
  4648. {
  4649. if (!IsSyncOwner(ch))
  4650. return false;
  4651.  
  4652. // °Å¸®°¡ 200 ÀÌ»óÀ̸é SyncOwner°¡ µÉ ¼ö ¾ø´Ù.
  4653. if (DISTANCE_APPROX(GetX() - ch->GetX(), GetY() - ch->GetY()) > 250)
  4654. {
  4655. sys_log(1, "SetSyncOwner distance over than 250 %s %s", GetName(), ch->GetName());
  4656.  
  4657. // SyncOwnerÀÏ °æ¿ì Owner·Î Ç¥½ÃÇÑ´Ù.
  4658. if (m_pkChrSyncOwner == ch)
  4659. return true;
  4660.  
  4661. return false;
  4662. }
  4663.  
  4664. if (m_pkChrSyncOwner != ch)
  4665. {
  4666. if (m_pkChrSyncOwner)
  4667. {
  4668. sys_log(1, "SyncRelease %s %p from %s", GetName(), this, m_pkChrSyncOwner->GetName());
  4669. m_pkChrSyncOwner->m_kLst_pkChrSyncOwned.remove(this);
  4670. }
  4671.  
  4672. m_pkChrSyncOwner = ch;
  4673. m_pkChrSyncOwner->m_kLst_pkChrSyncOwned.push_back(this);
  4674.  
  4675. // SyncOwner°¡ ¹Ù²î¸é LastSyncTimeÀ» ÃʱâÈ­ÇÑ´Ù.
  4676. static const timeval zero_tv = {0, 0};
  4677. SetLastSyncTime(zero_tv);
  4678.  
  4679. sys_log(1, "SetSyncOwner set %s %p to %s", GetName(), this, ch->GetName());
  4680. }
  4681.  
  4682. m_fSyncTime = get_float_time();
  4683. }
  4684.  
  4685. // TODO: Sync Owner°¡ °°´õ¶óµµ °è¼Ó ÆÐŶÀ» º¸³»°í ÀÖÀ¸¹Ç·Î,
  4686. // µ¿±âÈ­ µÈ ½Ã°£ÀÌ 3ÃÊ ÀÌ»ó Áö³µÀ» ¶§ Ç®¾îÁÖ´Â ÆÐŶÀ»
  4687. // º¸³»´Â ¹æ½ÄÀ¸·Î Çϸé ÆÐŶÀ» ÁÙÀÏ ¼ö ÀÖ´Ù.
  4688. TPacketGCOwnership pack;
  4689.  
  4690. pack.bHeader = HEADER_GC_OWNERSHIP;
  4691. pack.dwOwnerVID = ch ? ch->GetVID() : 0;
  4692. pack.dwVictimVID = GetVID();
  4693.  
  4694. PacketAround(&pack, sizeof(TPacketGCOwnership));
  4695. return true;
  4696. }
  4697.  
  4698. struct FuncClearSync
  4699. {
  4700. void operator () (LPCHARACTER ch)
  4701. {
  4702. assert(ch != NULL);
  4703. ch->SetSyncOwner(NULL, false); // false Ç÷¡±×·Î ÇØ¾ß for_each °¡ Á¦´ë·Î µ·´Ù.
  4704. }
  4705. };
  4706.  
  4707. void CHARACTER::ClearSync()
  4708. {
  4709. SetSyncOwner(NULL);
  4710.  
  4711. // ¾Æ·¡ for_each¿¡¼­ ³ª¸¦ m_pkChrSyncOwner·Î °¡Áø ÀÚµéÀÇ Æ÷ÀÎÅ͸¦ NULL·Î ÇÑ´Ù.
  4712. std::for_each(m_kLst_pkChrSyncOwned.begin(), m_kLst_pkChrSyncOwned.end(), FuncClearSync());
  4713. m_kLst_pkChrSyncOwned.clear();
  4714. }
  4715.  
  4716. bool CHARACTER::IsSyncOwner(LPCHARACTER ch) const
  4717. {
  4718. if (m_pkChrSyncOwner == ch)
  4719. return true;
  4720.  
  4721. // ¸¶Áö¸·À¸·Î µ¿±âÈ­ µÈ ½Ã°£ÀÌ 3ÃÊ ÀÌ»ó Áö³µ´Ù¸é ¼ÒÀ¯±ÇÀÌ ¾Æ¹«¿¡°Ôµµ
  4722. // ¾ø´Ù. µû¶ó¼­ ¾Æ¹«³ª SyncOwnerÀ̹ǷΠtrue ¸®ÅÏ
  4723. if (get_float_time() - m_fSyncTime >= 3.0f)
  4724. return true;
  4725.  
  4726. return false;
  4727. }
  4728.  
  4729. void CHARACTER::SetParty(LPPARTY pkParty)
  4730. {
  4731. if (pkParty == m_pkParty)
  4732. return;
  4733.  
  4734. if (pkParty && m_pkParty)
  4735. sys_err("%s is trying to reassigning party (current %p, new party %p)", GetName(), get_pointer(m_pkParty), get_pointer(pkParty));
  4736.  
  4737. sys_log(1, "PARTY set to %p", get_pointer(pkParty));
  4738.  
  4739. if (m_pkDungeon && IsPC() && !pkParty)
  4740. SetDungeon(NULL);
  4741. m_pkParty = pkParty;
  4742.  
  4743. if (IsPC())
  4744. {
  4745. if (m_pkParty)
  4746. SET_BIT(m_bAddChrState, ADD_CHARACTER_STATE_PARTY);
  4747. else
  4748. REMOVE_BIT(m_bAddChrState, ADD_CHARACTER_STATE_PARTY);
  4749.  
  4750. UpdatePacket();
  4751. }
  4752. }
  4753.  
  4754. // PARTY_JOIN_BUG_FIX
  4755. /// ÆÄƼ °¡ÀÔ event Á¤º¸
  4756. EVENTINFO(TPartyJoinEventInfo)
  4757. {
  4758. DWORD dwGuestPID; ///< ÆÄƼ¿¡ Âü¿©ÇÒ Ä³¸¯ÅÍÀÇ PID
  4759. DWORD dwLeaderPID; ///< ÆÄƼ ¸®´õÀÇ PID
  4760.  
  4761. TPartyJoinEventInfo()
  4762. : dwGuestPID( 0 )
  4763. , dwLeaderPID( 0 )
  4764. {
  4765. }
  4766. } ;
  4767.  
  4768. EVENTFUNC(party_request_event)
  4769. {
  4770. TPartyJoinEventInfo * info = dynamic_cast<TPartyJoinEventInfo *>( event->info );
  4771.  
  4772. if ( info == NULL )
  4773. {
  4774. sys_err( "party_request_event> <Factor> Null pointer" );
  4775. return 0;
  4776. }
  4777.  
  4778. LPCHARACTER ch = CHARACTER_MANAGER::instance().FindByPID(info->dwGuestPID);
  4779.  
  4780. if (ch)
  4781. {
  4782. sys_log(0, "PartyRequestEvent %s", ch->GetName());
  4783. ch->ChatPacket(CHAT_TYPE_COMMAND, "PartyRequestDenied");
  4784. ch->SetPartyRequestEvent(NULL);
  4785. }
  4786.  
  4787. return 0;
  4788. }
  4789.  
  4790. bool CHARACTER::RequestToParty(LPCHARACTER leader)
  4791. {
  4792. if (leader->GetParty())
  4793. leader = leader->GetParty()->GetLeaderCharacter();
  4794.  
  4795. if (!leader)
  4796. {
  4797. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("ÆÄƼÀåÀÌ Á¢¼Ó »óÅ°¡ ¾Æ´Ï¶ó¼­ ¿äûÀ» ÇÒ ¼ö ¾ø½À´Ï´Ù."));
  4798. return false;
  4799. }
  4800.  
  4801. if (m_pkPartyRequestEvent)
  4802. return false;
  4803.  
  4804. if (!IsPC() || !leader->IsPC())
  4805. return false;
  4806.  
  4807. if (leader->IsBlockMode(BLOCK_PARTY_REQUEST))
  4808. return false;
  4809.  
  4810. PartyJoinErrCode errcode = IsPartyJoinableCondition(leader, this);
  4811.  
  4812. switch (errcode)
  4813. {
  4814. case PERR_NONE:
  4815. break;
  4816.  
  4817. case PERR_SERVER:
  4818. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ¼­¹ö ¹®Á¦·Î ÆÄƼ °ü·Ã 󸮸¦ ÇÒ ¼ö ¾ø½À´Ï´Ù."));
  4819. return false;
  4820.  
  4821. case PERR_DIFFEMPIRE:
  4822. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ´Ù¸¥ Á¦±¹°ú ÆÄƼ¸¦ ÀÌ·ê ¼ö ¾ø½À´Ï´Ù."));
  4823. return false;
  4824.  
  4825. case PERR_DUNGEON:
  4826. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ´øÀü ¾È¿¡¼­´Â ÆÄƼ Ãʴ븦 ÇÒ ¼ö ¾ø½À´Ï´Ù."));
  4827. return false;
  4828.  
  4829. case PERR_OBSERVER:
  4830. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> °üÀü ¸ðµå¿¡¼± ÆÄƼ Ãʴ븦 ÇÒ ¼ö ¾ø½À´Ï´Ù."));
  4831. return false;
  4832.  
  4833. case PERR_LVBOUNDARY:
  4834. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> -30 ~ +30 ·¹º§ À̳»ÀÇ »ó´ë¹æ¸¸ ÃÊ´ëÇÒ ¼ö ÀÖ½À´Ï´Ù."));
  4835. return false;
  4836.  
  4837. case PERR_LOWLEVEL:
  4838. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ÆÄƼ³» ÃÖ°í ·¹º§ º¸´Ù 30·¹º§ÀÌ ³·¾Æ ÃÊ´ëÇÒ ¼ö ¾ø½À´Ï´Ù."));
  4839. return false;
  4840.  
  4841. case PERR_HILEVEL:
  4842. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ÆÄƼ³» ÃÖÀú ·¹º§ º¸´Ù 30·¹º§ÀÌ ³ô¾Æ ÃÊ´ëÇÒ ¼ö ¾ø½À´Ï´Ù."));
  4843. return false;
  4844.  
  4845. case PERR_ALREADYJOIN:
  4846. return false;
  4847.  
  4848. case PERR_PARTYISFULL:
  4849. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ´õ ÀÌ»ó ÆÄƼ¿øÀ» ÃÊ´ëÇÒ ¼ö ¾ø½À´Ï´Ù."));
  4850. return false;
  4851.  
  4852. default:
  4853. sys_err("Do not process party join error(%d)", errcode);
  4854. return false;
  4855. }
  4856.  
  4857. TPartyJoinEventInfo* info = AllocEventInfo<TPartyJoinEventInfo>();
  4858.  
  4859. info->dwGuestPID = GetPlayerID();
  4860. info->dwLeaderPID = leader->GetPlayerID();
  4861.  
  4862. SetPartyRequestEvent(event_create(party_request_event, info, PASSES_PER_SEC(10)));
  4863.  
  4864. leader->ChatPacket(CHAT_TYPE_COMMAND, "PartyRequest %u", (DWORD) GetVID());
  4865. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s ´Ô¿¡°Ô ÆÄƼ°¡ÀÔ ½ÅûÀ» Çß½À´Ï´Ù."), leader->GetName());
  4866. return true;
  4867. }
  4868.  
  4869. void CHARACTER::DenyToParty(LPCHARACTER member)
  4870. {
  4871. sys_log(1, "DenyToParty %s member %s %p", GetName(), member->GetName(), get_pointer(member->m_pkPartyRequestEvent));
  4872.  
  4873. if (!member->m_pkPartyRequestEvent)
  4874. return;
  4875.  
  4876. TPartyJoinEventInfo * info = dynamic_cast<TPartyJoinEventInfo *>(member->m_pkPartyRequestEvent->info);
  4877.  
  4878. if (!info)
  4879. {
  4880. sys_err( "CHARACTER::DenyToParty> <Factor> Null pointer" );
  4881. return;
  4882. }
  4883.  
  4884. if (info->dwGuestPID != member->GetPlayerID())
  4885. return;
  4886.  
  4887. if (info->dwLeaderPID != GetPlayerID())
  4888. return;
  4889.  
  4890. event_cancel(&member->m_pkPartyRequestEvent);
  4891.  
  4892. member->ChatPacket(CHAT_TYPE_COMMAND, "PartyRequestDenied");
  4893. }
  4894.  
  4895. void CHARACTER::AcceptToParty(LPCHARACTER member)
  4896. {
  4897. sys_log(1, "AcceptToParty %s member %s %p", GetName(), member->GetName(), get_pointer(member->m_pkPartyRequestEvent));
  4898.  
  4899. if (!member->m_pkPartyRequestEvent)
  4900. return;
  4901.  
  4902. TPartyJoinEventInfo * info = dynamic_cast<TPartyJoinEventInfo *>(member->m_pkPartyRequestEvent->info);
  4903.  
  4904. if (!info)
  4905. {
  4906. sys_err( "CHARACTER::AcceptToParty> <Factor> Null pointer" );
  4907. return;
  4908. }
  4909.  
  4910. if (info->dwGuestPID != member->GetPlayerID())
  4911. return;
  4912.  
  4913. if (info->dwLeaderPID != GetPlayerID())
  4914. return;
  4915.  
  4916. event_cancel(&member->m_pkPartyRequestEvent);
  4917.  
  4918. if (!GetParty())
  4919. member->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("»ó´ë¹æÀÌ ÆÄƼ¿¡ ¼ÓÇØÀÖÁö ¾Ê½À´Ï´Ù."));
  4920. else
  4921. {
  4922. if (GetPlayerID() != GetParty()->GetLeaderPID())
  4923. return;
  4924.  
  4925. PartyJoinErrCode errcode = IsPartyJoinableCondition(this, member);
  4926. switch (errcode)
  4927. {
  4928. case PERR_NONE: member->PartyJoin(this); return;
  4929. case PERR_SERVER: member->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ¼­¹ö ¹®Á¦·Î ÆÄƼ °ü·Ã 󸮸¦ ÇÒ ¼ö ¾ø½À´Ï´Ù.")); break;
  4930. case PERR_DUNGEON: member->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ´øÀü ¾È¿¡¼­´Â ÆÄƼ Ãʴ븦 ÇÒ ¼ö ¾ø½À´Ï´Ù.")); break;
  4931. case PERR_OBSERVER: member->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> °üÀü ¸ðµå¿¡¼± ÆÄƼ Ãʴ븦 ÇÒ ¼ö ¾ø½À´Ï´Ù.")); break;
  4932. case PERR_LVBOUNDARY: member->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> -30 ~ +30 ·¹º§ À̳»ÀÇ »ó´ë¹æ¸¸ ÃÊ´ëÇÒ ¼ö ÀÖ½À´Ï´Ù.")); break;
  4933. case PERR_LOWLEVEL: member->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ÆÄƼ³» ÃÖ°í ·¹º§ º¸´Ù 30·¹º§ÀÌ ³·¾Æ ÃÊ´ëÇÒ ¼ö ¾ø½À´Ï´Ù.")); break;
  4934. case PERR_HILEVEL: member->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ÆÄƼ³» ÃÖÀú ·¹º§ º¸´Ù 30·¹º§ÀÌ ³ô¾Æ ÃÊ´ëÇÒ ¼ö ¾ø½À´Ï´Ù.")); break;
  4935. case PERR_ALREADYJOIN: break;
  4936. case PERR_PARTYISFULL: {
  4937. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ´õ ÀÌ»ó ÆÄƼ¿øÀ» ÃÊ´ëÇÒ ¼ö ¾ø½À´Ï´Ù."));
  4938. member->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ÆÄƼÀÇ ÀοøÁ¦ÇÑÀÌ ÃÊ°úÇÏ¿© ÆÄƼ¿¡ Âü°¡ÇÒ ¼ö ¾ø½À´Ï´Ù."));
  4939. break;
  4940. }
  4941. default: sys_err("Do not process party join error(%d)", errcode);
  4942. }
  4943. }
  4944.  
  4945. member->ChatPacket(CHAT_TYPE_COMMAND, "PartyRequestDenied");
  4946. }
  4947.  
  4948. /**
  4949. * ÆÄƼ ÃÊ´ë event callback ÇÔ¼ö.
  4950. * event °¡ ¹ßµ¿Çϸé ÃÊ´ë °ÅÀý·Î ó¸®ÇÑ´Ù.
  4951. */
  4952. EVENTFUNC(party_invite_event)
  4953. {
  4954. TPartyJoinEventInfo * pInfo = dynamic_cast<TPartyJoinEventInfo *>( event->info );
  4955.  
  4956. if ( pInfo == NULL )
  4957. {
  4958. sys_err( "party_invite_event> <Factor> Null pointer" );
  4959. return 0;
  4960. }
  4961.  
  4962. LPCHARACTER pchInviter = CHARACTER_MANAGER::instance().FindByPID(pInfo->dwLeaderPID);
  4963.  
  4964. if (pchInviter)
  4965. {
  4966. sys_log(1, "PartyInviteEvent %s", pchInviter->GetName());
  4967. pchInviter->PartyInviteDeny(pInfo->dwGuestPID);
  4968. }
  4969.  
  4970. return 0;
  4971. }
  4972.  
  4973. void CHARACTER::PartyInvite(LPCHARACTER pchInvitee)
  4974. {
  4975. if (GetParty() && GetParty()->GetLeaderPID() != GetPlayerID())
  4976. {
  4977. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ÆÄƼ¿øÀ» ÃÊ´ëÇÒ ¼ö ÀÖ´Â ±ÇÇÑÀÌ ¾ø½À´Ï´Ù."));
  4978. return;
  4979. }
  4980. else if (pchInvitee->IsBlockMode(BLOCK_PARTY_INVITE))
  4981. {
  4982. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> %s ´ÔÀÌ ÆÄƼ °ÅºÎ »óÅÂÀÔ´Ï´Ù."), pchInvitee->GetName());
  4983. return;
  4984. }
  4985.  
  4986. PartyJoinErrCode errcode = IsPartyJoinableCondition(this, pchInvitee);
  4987.  
  4988. switch (errcode)
  4989. {
  4990. case PERR_NONE:
  4991. break;
  4992.  
  4993. case PERR_SERVER:
  4994. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ¼­¹ö ¹®Á¦·Î ÆÄƼ °ü·Ã 󸮸¦ ÇÒ ¼ö ¾ø½À´Ï´Ù."));
  4995. return;
  4996.  
  4997. case PERR_DIFFEMPIRE:
  4998. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ´Ù¸¥ Á¦±¹°ú ÆÄƼ¸¦ ÀÌ·ê ¼ö ¾ø½À´Ï´Ù."));
  4999. return;
  5000.  
  5001. case PERR_DUNGEON:
  5002. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ´øÀü ¾È¿¡¼­´Â ÆÄƼ Ãʴ븦 ÇÒ ¼ö ¾ø½À´Ï´Ù."));
  5003. return;
  5004.  
  5005. case PERR_OBSERVER:
  5006. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> °üÀü ¸ðµå¿¡¼± ÆÄƼ Ãʴ븦 ÇÒ ¼ö ¾ø½À´Ï´Ù."));
  5007. return;
  5008.  
  5009. case PERR_LVBOUNDARY:
  5010. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> -30 ~ +30 ·¹º§ À̳»ÀÇ »ó´ë¹æ¸¸ ÃÊ´ëÇÒ ¼ö ÀÖ½À´Ï´Ù."));
  5011. return;
  5012.  
  5013. case PERR_LOWLEVEL:
  5014. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ÆÄƼ³» ÃÖ°í ·¹º§ º¸´Ù 30·¹º§ÀÌ ³·¾Æ ÃÊ´ëÇÒ ¼ö ¾ø½À´Ï´Ù."));
  5015. return;
  5016.  
  5017. case PERR_HILEVEL:
  5018. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ÆÄƼ³» ÃÖÀú ·¹º§ º¸´Ù 30·¹º§ÀÌ ³ô¾Æ ÃÊ´ëÇÒ ¼ö ¾ø½À´Ï´Ù."));
  5019. return;
  5020.  
  5021. case PERR_ALREADYJOIN:
  5022. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ÀÌ¹Ì %s´ÔÀº ÆÄƼ¿¡ ¼ÓÇØ ÀÖ½À´Ï´Ù."), pchInvitee->GetName());
  5023. return;
  5024.  
  5025. case PERR_PARTYISFULL:
  5026. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ´õ ÀÌ»ó ÆÄƼ¿øÀ» ÃÊ´ëÇÒ ¼ö ¾ø½À´Ï´Ù."));
  5027. return;
  5028.  
  5029. default:
  5030. sys_err("Do not process party join error(%d)", errcode);
  5031. return;
  5032. }
  5033.  
  5034. if (m_PartyInviteEventMap.end() != m_PartyInviteEventMap.find(pchInvitee->GetPlayerID()))
  5035. return;
  5036.  
  5037. //
  5038. // EventMap ¿¡ À̺¥Æ® Ãß°¡
  5039. //
  5040. TPartyJoinEventInfo* info = AllocEventInfo<TPartyJoinEventInfo>();
  5041.  
  5042. info->dwGuestPID = pchInvitee->GetPlayerID();
  5043. info->dwLeaderPID = GetPlayerID();
  5044.  
  5045. m_PartyInviteEventMap.insert(EventMap::value_type(pchInvitee->GetPlayerID(), event_create(party_invite_event, info, PASSES_PER_SEC(10))));
  5046.  
  5047. //
  5048. // ÃÊ´ë ¹Þ´Â character ¿¡°Ô ÃÊ´ë ÆÐŶ Àü¼Û
  5049. //
  5050.  
  5051. TPacketGCPartyInvite p;
  5052. p.header = HEADER_GC_PARTY_INVITE;
  5053. p.leader_vid = GetVID();
  5054. pchInvitee->GetDesc()->Packet(&p, sizeof(p));
  5055. }
  5056.  
  5057. void CHARACTER::PartyInviteAccept(LPCHARACTER pchInvitee)
  5058. {
  5059. EventMap::iterator itFind = m_PartyInviteEventMap.find(pchInvitee->GetPlayerID());
  5060.  
  5061. if (itFind == m_PartyInviteEventMap.end())
  5062. {
  5063. sys_log(1, "PartyInviteAccept from not invited character(%s)", pchInvitee->GetName());
  5064. return;
  5065. }
  5066.  
  5067. event_cancel(&itFind->second);
  5068. m_PartyInviteEventMap.erase(itFind);
  5069.  
  5070. if (GetParty() && GetParty()->GetLeaderPID() != GetPlayerID())
  5071. {
  5072. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ÆÄƼ¿øÀ» ÃÊ´ëÇÒ ¼ö ÀÖ´Â ±ÇÇÑÀÌ ¾ø½À´Ï´Ù."));
  5073. return;
  5074. }
  5075.  
  5076. PartyJoinErrCode errcode = IsPartyJoinableMutableCondition(this, pchInvitee);
  5077.  
  5078. switch (errcode)
  5079. {
  5080. case PERR_NONE:
  5081. break;
  5082.  
  5083. case PERR_SERVER:
  5084. pchInvitee->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ¼­¹ö ¹®Á¦·Î ÆÄƼ °ü·Ã 󸮸¦ ÇÒ ¼ö ¾ø½À´Ï´Ù."));
  5085. return;
  5086.  
  5087. case PERR_DUNGEON:
  5088. pchInvitee->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ´øÀü ¾È¿¡¼­´Â ÆÄƼ ÃÊ´ë¿¡ ÀÀÇÒ ¼ö ¾ø½À´Ï´Ù."));
  5089. return;
  5090.  
  5091. case PERR_OBSERVER:
  5092. pchInvitee->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> °üÀü ¸ðµå¿¡¼± ÆÄƼ Ãʴ븦 ÇÒ ¼ö ¾ø½À´Ï´Ù."));
  5093. return;
  5094.  
  5095. case PERR_LVBOUNDARY:
  5096. pchInvitee->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> -30 ~ +30 ·¹º§ À̳»ÀÇ »ó´ë¹æ¸¸ ÃÊ´ëÇÒ ¼ö ÀÖ½À´Ï´Ù."));
  5097. return;
  5098.  
  5099. case PERR_LOWLEVEL:
  5100. pchInvitee->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ÆÄƼ³» ÃÖ°í ·¹º§ º¸´Ù 30·¹º§ÀÌ ³·¾Æ ÃÊ´ëÇÒ ¼ö ¾ø½À´Ï´Ù."));
  5101. return;
  5102.  
  5103. case PERR_HILEVEL:
  5104. pchInvitee->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ÆÄƼ³» ÃÖÀú ·¹º§ º¸´Ù 30·¹º§ÀÌ ³ô¾Æ ÃÊ´ëÇÒ ¼ö ¾ø½À´Ï´Ù."));
  5105. return;
  5106.  
  5107. case PERR_ALREADYJOIN:
  5108. pchInvitee->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ÆÄƼ ÃÊ´ë¿¡ ÀÀÇÒ ¼ö ¾ø½À´Ï´Ù."));
  5109. return;
  5110.  
  5111. case PERR_PARTYISFULL:
  5112. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ´õ ÀÌ»ó ÆÄƼ¿øÀ» ÃÊ´ëÇÒ ¼ö ¾ø½À´Ï´Ù."));
  5113. pchInvitee->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ÆÄƼÀÇ ÀοøÁ¦ÇÑÀÌ ÃÊ°úÇÏ¿© ÆÄƼ¿¡ Âü°¡ÇÒ ¼ö ¾ø½À´Ï´Ù."));
  5114. return;
  5115.  
  5116. default:
  5117. sys_err("ignore party join error(%d)", errcode);
  5118. return;
  5119. }
  5120.  
  5121. //
  5122. // ÆÄƼ °¡ÀÔ Ã³¸®
  5123. //
  5124.  
  5125. if (GetParty())
  5126. pchInvitee->PartyJoin(this);
  5127. else
  5128. {
  5129. LPPARTY pParty = CPartyManager::instance().CreateParty(this);
  5130.  
  5131. pParty->Join(pchInvitee->GetPlayerID());
  5132. pParty->Link(pchInvitee);
  5133. pParty->SendPartyInfoAllToOne(this);
  5134. }
  5135. }
  5136.  
  5137. void CHARACTER::PartyInviteDeny(DWORD dwPID)
  5138. {
  5139. EventMap::iterator itFind = m_PartyInviteEventMap.find(dwPID);
  5140.  
  5141. if (itFind == m_PartyInviteEventMap.end())
  5142. {
  5143. sys_log(1, "PartyInviteDeny to not exist event(inviter PID: %d, invitee PID: %d)", GetPlayerID(), dwPID);
  5144. return;
  5145. }
  5146.  
  5147. event_cancel(&itFind->second);
  5148. m_PartyInviteEventMap.erase(itFind);
  5149.  
  5150. LPCHARACTER pchInvitee = CHARACTER_MANAGER::instance().FindByPID(dwPID);
  5151. if (pchInvitee)
  5152. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> %s´ÔÀÌ ÆÄƼ Ãʴ븦 °ÅÀýÇϼ̽À´Ï´Ù."), pchInvitee->GetName());
  5153. }
  5154.  
  5155. void CHARACTER::PartyJoin(LPCHARACTER pLeader)
  5156. {
  5157. pLeader->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> %s´ÔÀÌ ÆÄƼ¿¡ Âü°¡Çϼ̽À´Ï´Ù."), GetName());
  5158. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> %s´ÔÀÇ ÆÄƼ¿¡ Âü°¡Çϼ̽À´Ï´Ù."), pLeader->GetName());
  5159.  
  5160. pLeader->GetParty()->Join(GetPlayerID());
  5161. pLeader->GetParty()->Link(this);
  5162. }
  5163.  
  5164. CHARACTER::PartyJoinErrCode CHARACTER::IsPartyJoinableCondition(const LPCHARACTER pchLeader, const LPCHARACTER pchGuest)
  5165. {
  5166. if (pchLeader->GetEmpire() != pchGuest->GetEmpire())
  5167. return PERR_DIFFEMPIRE;
  5168.  
  5169. return IsPartyJoinableMutableCondition(pchLeader, pchGuest);
  5170. }
  5171.  
  5172. static bool __party_can_join_by_level(LPCHARACTER leader, LPCHARACTER quest)
  5173. {
  5174. int level_limit = 30;
  5175.  
  5176. if (LC_IsCanada())
  5177. level_limit = 15;
  5178. else if (LC_IsBrazil() == true)
  5179. {
  5180. level_limit = 10;
  5181. }
  5182. else
  5183. level_limit = 30;
  5184.  
  5185. return (abs(leader->GetLevel() - quest->GetLevel()) <= level_limit);
  5186. }
  5187.  
  5188. CHARACTER::PartyJoinErrCode CHARACTER::IsPartyJoinableMutableCondition(const LPCHARACTER pchLeader, const LPCHARACTER pchGuest)
  5189. {
  5190. if (!CPartyManager::instance().IsEnablePCParty())
  5191. return PERR_SERVER;
  5192. else if (pchLeader->GetDungeon())
  5193. return PERR_DUNGEON;
  5194. else if (pchGuest->IsObserverMode())
  5195. return PERR_OBSERVER;
  5196. else if (false == __party_can_join_by_level(pchLeader, pchGuest))
  5197. return PERR_LVBOUNDARY;
  5198. else if (pchGuest->GetParty())
  5199. return PERR_ALREADYJOIN;
  5200. else if (pchLeader->GetParty())
  5201. {
  5202. if (pchLeader->GetParty()->GetMemberCount() == PARTY_MAX_MEMBER)
  5203. return PERR_PARTYISFULL;
  5204. }
  5205.  
  5206. return PERR_NONE;
  5207. }
  5208. // END_OF_PARTY_JOIN_BUG_FIX
  5209.  
  5210. void CHARACTER::SetDungeon(LPDUNGEON pkDungeon)
  5211. {
  5212. if (pkDungeon && m_pkDungeon)
  5213. sys_err("%s is trying to reassigning dungeon (current %p, new party %p)", GetName(), get_pointer(m_pkDungeon), get_pointer(pkDungeon));
  5214.  
  5215. if (m_pkDungeon == pkDungeon) {
  5216. return;
  5217. }
  5218.  
  5219. if (m_pkDungeon)
  5220. {
  5221. if (IsPC())
  5222. {
  5223. if (GetParty())
  5224. m_pkDungeon->DecPartyMember(GetParty(), this);
  5225. else
  5226. m_pkDungeon->DecMember(this);
  5227. }
  5228. else if (IsMonster() || IsStone())
  5229. {
  5230. m_pkDungeon->DecMonster();
  5231. }
  5232. }
  5233.  
  5234. m_pkDungeon = pkDungeon;
  5235.  
  5236. if (pkDungeon)
  5237. {
  5238. sys_log(0, "%s DUNGEON set to %p, PARTY is %p", GetName(), get_pointer(pkDungeon), get_pointer(m_pkParty));
  5239.  
  5240. if (IsPC())
  5241. {
  5242. if (GetParty())
  5243. m_pkDungeon->IncPartyMember(GetParty(), this);
  5244. else
  5245. m_pkDungeon->IncMember(this);
  5246. }
  5247. else if (IsMonster() || IsStone())
  5248. {
  5249. m_pkDungeon->IncMonster();
  5250. }
  5251. }
  5252. }
  5253.  
  5254. void CHARACTER::SetWarMap(CWarMap * pWarMap)
  5255. {
  5256. if (m_pWarMap)
  5257. m_pWarMap->DecMember(this);
  5258.  
  5259. m_pWarMap = pWarMap;
  5260.  
  5261. if (m_pWarMap)
  5262. m_pWarMap->IncMember(this);
  5263. }
  5264.  
  5265. void CHARACTER::SetWeddingMap(marriage::WeddingMap* pMap)
  5266. {
  5267. if (m_pWeddingMap)
  5268. m_pWeddingMap->DecMember(this);
  5269.  
  5270. m_pWeddingMap = pMap;
  5271.  
  5272. if (m_pWeddingMap)
  5273. m_pWeddingMap->IncMember(this);
  5274. }
  5275.  
  5276. void CHARACTER::SetRegen(LPREGEN pkRegen)
  5277. {
  5278. m_pkRegen = pkRegen;
  5279. if (pkRegen != NULL) {
  5280. regen_id_ = pkRegen->id;
  5281. }
  5282. m_fRegenAngle = GetRotation();
  5283. m_posRegen = GetXYZ();
  5284. }
  5285.  
  5286. bool CHARACTER::OnIdle()
  5287. {
  5288. return false;
  5289. }
  5290.  
  5291. void CHARACTER::OnMove(bool bIsAttack)
  5292. {
  5293. m_dwLastMoveTime = get_dword_time();
  5294.  
  5295. if (bIsAttack)
  5296. {
  5297. m_dwLastAttackTime = m_dwLastMoveTime;
  5298.  
  5299. if (IsAffectFlag(AFF_REVIVE_INVISIBLE))
  5300. RemoveAffect(AFFECT_REVIVE_INVISIBLE);
  5301.  
  5302. if (IsAffectFlag(AFF_EUNHYUNG))
  5303. {
  5304. RemoveAffect(SKILL_EUNHYUNG);
  5305. SetAffectedEunhyung();
  5306. }
  5307. else
  5308. {
  5309. ClearAffectedEunhyung();
  5310. }
  5311.  
  5312. /*if (IsAffectFlag(AFF_JEONSIN))
  5313. RemoveAffect(SKILL_JEONSINBANGEO);*/
  5314. }
  5315.  
  5316. /*if (IsAffectFlag(AFF_GUNGON))
  5317. RemoveAffect(SKILL_GUNGON);*/
  5318.  
  5319. // MINING
  5320. mining_cancel();
  5321. // END_OF_MINING
  5322. }
  5323.  
  5324. void CHARACTER::OnClick(LPCHARACTER pkChrCauser)
  5325. {
  5326. if (!pkChrCauser)
  5327. {
  5328. sys_err("OnClick %s by NULL", GetName());
  5329. return;
  5330. }
  5331.  
  5332. DWORD vid = GetVID();
  5333. //if (test_server)
  5334. sys_log(0, "OnClick %s[vnum %d ServerUniqueID %d, pid %d] by %s", GetName(), GetRaceNum(), vid, GetPlayerID(), pkChrCauser->GetName());
  5335.  
  5336. // ??? ???? ???? ??? ? ??.
  5337. {
  5338. // ?, ??? ??? ??? ??? ? ??.
  5339. if (pkChrCauser->GetMyShop() && pkChrCauser != this)
  5340. {
  5341. if (test_server)
  5342. sys_err("OnClick Fail (%s->%s) - pc has shop", pkChrCauser->GetName(), GetName());
  5343. return;
  5344. }
  5345. }
  5346.  
  5347. // ????? ???? ??? ? ??.
  5348. {
  5349. if (pkChrCauser->GetExchange())
  5350. {
  5351. if (test_server)
  5352. sys_err("OnClick Fail (%s->%s) - pc is exchanging", pkChrCauser->GetName(), GetName());
  5353. return;
  5354. }
  5355. }
  5356.  
  5357. if (IsPC() || IsNPC() && GetRaceNum() == 30000)
  5358. {
  5359. // L¸°UR¸·?LlÁ¤? ?ze´Â PCz? RÇÇN L¬¸Zµµ ??sC®·Î Al¸®?µµ? ???.
  5360. if (!CTargetManager::instance().GetTargetInfo(pkChrCauser->GetPlayerID(), TARGET_TYPE_VID, GetVID()) || GetRaceNum() == 30000)
  5361. {
  5362. // 2005.03.17.myevan.L¸°URE lC? ?ze´Â ?R?»ó? Al¸® ±â´ÉR?RU??AL??.
  5363. if (GetMyShop())
  5364. {
  5365. if (pkChrCauser->IsDead() == true) return;
  5366.  
  5367. //PREVENT_TRADE_WINDOW
  5368. if (pkChrCauser == this) // RÚ±â´??´É
  5369. {
  5370. if ((GetExchange() || IsOpenSafebox() || GetShopOwner()) || IsCubeOpen())
  5371. {
  5372. pkChrCauser->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("?? ??Áß(A?°í,?CZ,»ó?)z?´Â ?RλóÁ?R?»çzëÇN L?lr?R??."));
  5373. return;
  5374. }
  5375. }
  5376. else // ?? »ç¶÷RE L¬¸ZÇßR»¶? {
  5377. // L¬¸Z? »ç¶÷RE ?CZ/A?°í/?RλóÁ?/»ó?REzëÁ?E¶ó¸é sN?
  5378. if ((pkChrCauser->GetExchange() || pkChrCauser->IsOpenSafebox() || pkChrCauser->GetMyShop() || pkChrCauser->GetShopOwner()) || pkChrCauser->IsCubeOpen())
  5379. {
  5380. pkChrCauser->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("?? ??Áß(A?°í,?CZ,»ó?)z?´Â ?RλóÁ?R?»çzëÇN L?lr?R??."));
  5381. return;
  5382. }
  5383.  
  5384. // L¬¸Z? ´ë»óRE ?CZ/A?°í/»ó?REzëÁ?E¶ó¸é sN?
  5385. //if ((GetExchange() || IsOpenSafebox() || GetShopOwner()))
  5386. if ((GetExchange() || IsOpenSafebox() || IsCubeOpen()))
  5387. {
  5388. pkChrCauser->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("»ó´ëacRE ?? ??¸¦ ?°í RÖ´?ÁßRÔ´D?."));
  5389. return;
  5390. }
  5391. }
  5392. //END_PREVENT_TRADE_WINDOW
  5393. #ifdef OFFLINE_SHOP
  5394. if (GetMyShop()->IsLocked())
  5395. return;
  5396. GetMyShop()->AddGuest(pkChrCauser, IsPrivShop() && GetRaceNum() == 30000 && GetPrivShopOwner() == GetPlayerID() ? GetPrivShop() : GetVID(), false);
  5397. #else
  5398. GetMyShop()->AddGuest(pkChrCauser, GetVID(), false);
  5399. #endif
  5400.  
  5401. pkChrCauser->SetShopOwner(this);
  5402. return;
  5403. }
  5404.  
  5405. if (test_server)
  5406. sys_err("%s.OnClickFailure(%s) - target is PC", pkChrCauser->GetName(), GetName());
  5407.  
  5408. return;
  5409. }
  5410. }
  5411. pkChrCauser->SetQuestNPCID(GetVID());
  5412.  
  5413. if (quest::CQuestManager::instance().Click(pkChrCauser->GetPlayerID(), this))
  5414. {
  5415. return;
  5416. }
  5417.  
  5418.  
  5419. // NPC ?? ?? ?? : ?? ?? ?
  5420. if (!IsPC())
  5421. {
  5422. if (!m_triggerOnClick.pFunc)
  5423. {
  5424. return;
  5425. }
  5426.  
  5427. m_triggerOnClick.pFunc(this, pkChrCauser);
  5428. }
  5429.  
  5430. }
  5431.  
  5432. BYTE CHARACTER::GetGMLevel() const
  5433. {
  5434. if (test_server)
  5435. return GM_IMPLEMENTOR;
  5436. return m_pointsInstant.gm_level;
  5437. }
  5438.  
  5439. void CHARACTER::SetGMLevel()
  5440. {
  5441. if (GetDesc())
  5442. {
  5443. m_pointsInstant.gm_level = gm_get_level(GetName(), GetDesc()->GetHostName(), GetDesc()->GetAccountTable().login);
  5444. }
  5445. else
  5446. {
  5447. m_pointsInstant.gm_level = GM_PLAYER;
  5448. }
  5449. }
  5450.  
  5451. BOOL CHARACTER::IsGM() const
  5452. {
  5453. if (m_pointsInstant.gm_level > GM_VIP)
  5454. return true;
  5455. if (test_server)
  5456. return true;
  5457. return false;
  5458. }
  5459.  
  5460. void CHARACTER::SetStone(LPCHARACTER pkChrStone)
  5461. {
  5462. m_pkChrStone = pkChrStone;
  5463.  
  5464. if (m_pkChrStone)
  5465. {
  5466. if (pkChrStone->m_set_pkChrSpawnedBy.find(this) == pkChrStone->m_set_pkChrSpawnedBy.end())
  5467. pkChrStone->m_set_pkChrSpawnedBy.insert(this);
  5468. }
  5469. }
  5470.  
  5471. struct FuncDeadSpawnedByStone
  5472. {
  5473. void operator () (LPCHARACTER ch)
  5474. {
  5475. ch->Dead(NULL);
  5476. ch->SetStone(NULL);
  5477. }
  5478. };
  5479.  
  5480. void CHARACTER::ClearStone()
  5481. {
  5482. if (!m_set_pkChrSpawnedBy.empty())
  5483. {
  5484. // ³»°¡ ½ºÆù½ÃŲ ¸ó½ºÅ͵éÀ» ¸ðµÎ Á×ÀδÙ.
  5485. FuncDeadSpawnedByStone f;
  5486. std::for_each(m_set_pkChrSpawnedBy.begin(), m_set_pkChrSpawnedBy.end(), f);
  5487. m_set_pkChrSpawnedBy.clear();
  5488. }
  5489.  
  5490. if (!m_pkChrStone)
  5491. return;
  5492.  
  5493. m_pkChrStone->m_set_pkChrSpawnedBy.erase(this);
  5494. m_pkChrStone = NULL;
  5495. }
  5496.  
  5497. void CHARACTER::ClearTarget()
  5498. {
  5499. if (m_pkChrTarget)
  5500. {
  5501. m_pkChrTarget->m_set_pkChrTargetedBy.erase(this);
  5502. m_pkChrTarget = NULL;
  5503. }
  5504.  
  5505. TPacketGCTarget p;
  5506.  
  5507. p.header = HEADER_GC_TARGET;
  5508. p.dwVID = 0;
  5509. p.bHPPercent = 0;
  5510.  
  5511. CHARACTER_SET::iterator it = m_set_pkChrTargetedBy.begin();
  5512.  
  5513. while (it != m_set_pkChrTargetedBy.end())
  5514. {
  5515. LPCHARACTER pkChr = *(it++);
  5516. pkChr->m_pkChrTarget = NULL;
  5517.  
  5518. if (!pkChr->GetDesc())
  5519. {
  5520. sys_err("%s %p does not have desc", pkChr->GetName(), get_pointer(pkChr));
  5521. abort();
  5522. }
  5523.  
  5524. pkChr->GetDesc()->Packet(&p, sizeof(TPacketGCTarget));
  5525. }
  5526.  
  5527. m_set_pkChrTargetedBy.clear();
  5528. }
  5529.  
  5530. void CHARACTER::SetTarget(LPCHARACTER pkChrTarget)
  5531. {
  5532. if (m_pkChrTarget == pkChrTarget)
  5533. return;
  5534.  
  5535. // CASTLE
  5536. if (IS_CASTLE_MAP(GetMapIndex()) && !IsGM())
  5537. return;
  5538. // CASTLE
  5539.  
  5540. if (m_pkChrTarget)
  5541. m_pkChrTarget->m_set_pkChrTargetedBy.erase(this);
  5542.  
  5543. m_pkChrTarget = pkChrTarget;
  5544.  
  5545. TPacketGCTarget p;
  5546.  
  5547. p.header = HEADER_GC_TARGET;
  5548.  
  5549. if (m_pkChrTarget)
  5550. {
  5551. m_pkChrTarget->m_set_pkChrTargetedBy.insert(this);
  5552.  
  5553. p.dwVID = m_pkChrTarget->GetVID();
  5554.  
  5555. if (m_pkChrTarget->IsPC() && !m_pkChrTarget->IsPolymorphed() || m_pkChrTarget->GetMaxHP() <= 0)
  5556. p.bHPPercent = 0;
  5557. else
  5558. {
  5559. if (m_pkChrTarget->GetRaceNum() == 20101 ||
  5560. m_pkChrTarget->GetRaceNum() == 20102 ||
  5561. m_pkChrTarget->GetRaceNum() == 20103 ||
  5562. m_pkChrTarget->GetRaceNum() == 20104 ||
  5563. m_pkChrTarget->GetRaceNum() == 20105 ||
  5564. m_pkChrTarget->GetRaceNum() == 20106 ||
  5565. m_pkChrTarget->GetRaceNum() == 20107 ||
  5566. m_pkChrTarget->GetRaceNum() == 20108 ||
  5567. m_pkChrTarget->GetRaceNum() == 20109)
  5568. {
  5569. LPCHARACTER owner = m_pkChrTarget->GetVictim();
  5570.  
  5571. if (owner)
  5572. {
  5573. int iHorseHealth = owner->GetHorseHealth();
  5574. int iHorseMaxHealth = owner->GetHorseMaxHealth();
  5575.  
  5576. if (iHorseMaxHealth)
  5577. p.bHPPercent = MINMAX(0, iHorseHealth * 100 / iHorseMaxHealth, 100);
  5578. else
  5579. p.bHPPercent = 100;
  5580. }
  5581. else
  5582. p.bHPPercent = 100;
  5583. }
  5584. else
  5585. p.bHPPercent = MINMAX(0, (m_pkChrTarget->GetHP() * 100) / m_pkChrTarget->GetMaxHP(), 100);
  5586. }
  5587. }
  5588. else
  5589. {
  5590. p.dwVID = 0;
  5591. p.bHPPercent = 0;
  5592. }
  5593.  
  5594. GetDesc()->Packet(&p, sizeof(TPacketGCTarget));
  5595. }
  5596.  
  5597. void CHARACTER::BroadcastTargetPacket()
  5598. {
  5599. if (m_set_pkChrTargetedBy.empty())
  5600. return;
  5601.  
  5602. TPacketGCTarget p;
  5603.  
  5604. p.header = HEADER_GC_TARGET;
  5605. p.dwVID = GetVID();
  5606.  
  5607. if (IsPC())
  5608. p.bHPPercent = 0;
  5609. else
  5610. p.bHPPercent = MINMAX(0, (GetHP() * 100) / GetMaxHP(), 100);
  5611.  
  5612. CHARACTER_SET::iterator it = m_set_pkChrTargetedBy.begin();
  5613.  
  5614. while (it != m_set_pkChrTargetedBy.end())
  5615. {
  5616. LPCHARACTER pkChr = *it++;
  5617.  
  5618. if (!pkChr->GetDesc())
  5619. {
  5620. sys_err("%s %p does not have desc", pkChr->GetName(), get_pointer(pkChr));
  5621. abort();
  5622. }
  5623.  
  5624. pkChr->GetDesc()->Packet(&p, sizeof(TPacketGCTarget));
  5625. }
  5626. }
  5627.  
  5628. void CHARACTER::CheckTarget()
  5629. {
  5630. if (!m_pkChrTarget)
  5631. return;
  5632.  
  5633. if (DISTANCE_APPROX(GetX() - m_pkChrTarget->GetX(), GetY() - m_pkChrTarget->GetY()) >= 4800)
  5634. SetTarget(NULL);
  5635. }
  5636.  
  5637. void CHARACTER::SetWarpLocation(long lMapIndex, long x, long y)
  5638. {
  5639. m_posWarp.x = x * 100;
  5640. m_posWarp.y = y * 100;
  5641. m_lWarpMapIndex = lMapIndex;
  5642. }
  5643.  
  5644. void CHARACTER::SaveExitLocation()
  5645. {
  5646. m_posExit = GetXYZ();
  5647. m_lExitMapIndex = GetMapIndex();
  5648. }
  5649.  
  5650. void CHARACTER::ExitToSavedLocation()
  5651. {
  5652. sys_log (0, "ExitToSavedLocation");
  5653. WarpSet(m_posWarp.x, m_posWarp.y, m_lWarpMapIndex);
  5654.  
  5655. m_posExit.x = m_posExit.y = m_posExit.z = 0;
  5656. m_lExitMapIndex = 0;
  5657. }
  5658.  
  5659. // fixme
  5660. // Áö±Ý±îÁø privateMapIndex °¡ ÇöÀç ¸Ê À妽º¿Í °°ÀºÁö üũ ÇÏ´Â °ÍÀ» ¿ÜºÎ¿¡¼­ ÇÏ°í,
  5661. // ´Ù¸£¸é warpsetÀ» ºÒ·¶´Âµ¥
  5662. // À̸¦ warpset ¾ÈÀ¸·Î ³ÖÀÚ.
  5663. bool CHARACTER::WarpSet(long x, long y, long lPrivateMapIndex)
  5664. {
  5665. if (!IsPC())
  5666. return false;
  5667.  
  5668. long lAddr;
  5669. long lMapIndex;
  5670. WORD wPort;
  5671.  
  5672. if (!CMapLocation::instance().Get(x, y, lMapIndex, lAddr, wPort))
  5673. {
  5674. sys_err("cannot find map location index %d x %d y %d name %s", lMapIndex, x, y, GetName());
  5675. return false;
  5676. }
  5677.  
  5678. //Send Supplementary Data Block if new map requires security packages in loading this map
  5679. {
  5680. long lCurAddr;
  5681. long lCurMapIndex = 0;
  5682. WORD wCurPort;
  5683.  
  5684. CMapLocation::instance().Get(GetX(), GetY(), lCurMapIndex, lCurAddr, wCurPort);
  5685.  
  5686. //do not send SDB files if char is in the same map
  5687. if( lCurMapIndex != lMapIndex )
  5688. {
  5689. const TMapRegion * rMapRgn = SECTREE_MANAGER::instance().GetMapRegion(lMapIndex);
  5690. {
  5691. DESC_MANAGER::instance().SendClientPackageSDBToLoadMap( GetDesc(), rMapRgn->strMapName.c_str() );
  5692. }
  5693. }
  5694. }
  5695.  
  5696. if (lPrivateMapIndex >= 10000)
  5697. {
  5698. if (lPrivateMapIndex / 10000 != lMapIndex)
  5699. {
  5700. sys_err("Invalid map inedx %d, must be child of %d", lPrivateMapIndex, lMapIndex);
  5701. return false;
  5702. }
  5703.  
  5704. lMapIndex = lPrivateMapIndex;
  5705. }
  5706.  
  5707. Stop();
  5708. Save();
  5709.  
  5710. if (GetSectree())
  5711. {
  5712. GetSectree()->RemoveEntity(this);
  5713. ViewCleanup();
  5714.  
  5715. EncodeRemovePacket(this);
  5716. }
  5717.  
  5718. m_lWarpMapIndex = lMapIndex;
  5719. m_posWarp.x = x;
  5720. m_posWarp.y = y;
  5721.  
  5722. sys_log(0, "WarpSet %s %d %d current map %d target map %d", GetName(), x, y, GetMapIndex(), lMapIndex);
  5723.  
  5724. TPacketGCWarp p;
  5725.  
  5726. p.bHeader = HEADER_GC_WARP;
  5727. p.lX = x;
  5728. p.lY = y;
  5729. p.lAddr = lAddr;
  5730. p.wPort = wPort;
  5731.  
  5732. GetDesc()->Packet(&p, sizeof(TPacketGCWarp));
  5733.  
  5734. //if (!LC_IsNewCIBN())
  5735. {
  5736. char buf[256];
  5737. snprintf(buf, sizeof(buf), "%s MapIdx %ld DestMapIdx%ld DestX%ld DestY%ld Empire%d", GetName(), GetMapIndex(), lPrivateMapIndex, x, y, GetEmpire());
  5738. LogManager::instance().CharLog(this, 0, "WARP", buf);
  5739. }
  5740.  
  5741. return true;
  5742. }
  5743.  
  5744. void CHARACTER::WarpEnd()
  5745. {
  5746. if (test_server)
  5747. sys_log(0, "WarpEnd %s", GetName());
  5748.  
  5749. if (m_posWarp.x == 0 && m_posWarp.y == 0)
  5750. return;
  5751.  
  5752. int index = m_lWarpMapIndex;
  5753.  
  5754. if (index > 10000)
  5755. index /= 10000;
  5756.  
  5757. if (!map_allow_find(index))
  5758. GoHome();
  5759.  
  5760. sys_log(0, "WarpEnd %s %d %u %u", GetName(), m_lWarpMapIndex, m_posWarp.x, m_posWarp.y);
  5761.  
  5762. Show(m_lWarpMapIndex, m_posWarp.x, m_posWarp.y, 0);
  5763. Stop();
  5764.  
  5765. m_lWarpMapIndex = 0;
  5766. m_posWarp.x = m_posWarp.y = m_posWarp.z = 0;
  5767.  
  5768. {
  5769. // P2P Login
  5770. TPacketGGLogin p;
  5771.  
  5772. p.bHeader = HEADER_GG_LOGIN;
  5773. strlcpy(p.szName, GetName(), sizeof(p.szName));
  5774. p.dwPID = GetPlayerID();
  5775. p.bEmpire = GetEmpire();
  5776. p.lMapIndex = SECTREE_MANAGER::instance().GetMapIndex(GetX(), GetY());
  5777. p.bChannel = g_bChannel;
  5778.  
  5779. P2P_MANAGER::instance().Send(&p, sizeof(TPacketGGLogin));
  5780. }
  5781. }
  5782.  
  5783. bool CHARACTER::Return()
  5784. {
  5785. if (!IsNPC())
  5786. return false;
  5787.  
  5788. int x, y;
  5789. /*
  5790. float fDist = DISTANCE_SQRT(m_pkMobData->m_posLastAttacked.x - GetX(), m_pkMobData->m_posLastAttacked.y - GetY());
  5791. float fx, fy;
  5792. GetDeltaByDegree(GetRotation(), fDist, &fx, &fy);
  5793. x = GetX() + (int) fx;
  5794. y = GetY() + (int) fy;
  5795. */
  5796. SetVictim(NULL);
  5797.  
  5798. x = m_pkMobInst->m_posLastAttacked.x;
  5799. y = m_pkMobInst->m_posLastAttacked.y;
  5800.  
  5801. SetRotationToXY(x, y);
  5802.  
  5803. if (!Goto(x, y))
  5804. return false;
  5805.  
  5806. SendMovePacket(FUNC_WAIT, 0, 0, 0, 0);
  5807.  
  5808. if (test_server)
  5809. sys_log(0, "%s %p Æ÷±âÇÏ°í µ¹¾Æ°¡ÀÚ! %d %d", GetName(), this, x, y);
  5810.  
  5811. if (GetParty())
  5812. GetParty()->SendMessage(this, PM_RETURN, x, y);
  5813.  
  5814. return true;
  5815. }
  5816.  
  5817. bool CHARACTER::Follow(LPCHARACTER pkChr, float fMinDistance)
  5818. {
  5819. if (IsPC())
  5820. {
  5821. sys_err("CHARACTER::Follow : PC cannot use this method", GetName());
  5822. return false;
  5823. }
  5824.  
  5825. // TRENT_MONSTER
  5826. if (IS_SET(m_pointsInstant.dwAIFlag, AIFLAG_NOMOVE))
  5827. {
  5828. if (pkChr->IsPC()) // ÂѾư¡´Â »ó´ë°¡ PCÀÏ ¶§
  5829. {
  5830. // If i'm in a party. I must obey party leader's AI.
  5831. if (!GetParty() || !GetParty()->GetLeader() || GetParty()->GetLeader() == this)
  5832. {
  5833. if (get_dword_time() - m_pkMobInst->m_dwLastAttackedTime >= 15000) // ¸¶Áö¸·À¸·Î °ø°Ý¹ÞÀºÁö 15ÃÊ°¡ Áö³µ°í
  5834. {
  5835. // ¸¶Áö¸· ¸ÂÀº °÷À¸·Î ºÎÅÍ 50¹ÌÅÍ ÀÌ»ó Â÷À̳ª¸é Æ÷±âÇÏ°í µ¹¾Æ°£´Ù.
  5836. if (m_pkMobData->m_table.wAttackRange < DISTANCE_APPROX(pkChr->GetX() - GetX(), pkChr->GetY() - GetY()))
  5837. if (Return())
  5838. return true;
  5839. }
  5840. }
  5841. }
  5842. return false;
  5843. }
  5844. // END_OF_TRENT_MONSTER
  5845.  
  5846. long x = pkChr->GetX();
  5847. long y = pkChr->GetY();
  5848.  
  5849. if (pkChr->IsPC()) // ÂѾư¡´Â »ó´ë°¡ PCÀÏ ¶§
  5850. {
  5851. // If i'm in a party. I must obey party leader's AI.
  5852. if (!GetParty() || !GetParty()->GetLeader() || GetParty()->GetLeader() == this)
  5853. {
  5854. if (get_dword_time() - m_pkMobInst->m_dwLastAttackedTime >= 15000) // ¸¶Áö¸·À¸·Î °ø°Ý¹ÞÀºÁö 15ÃÊ°¡ Áö³µ°í
  5855. {
  5856. // ¸¶Áö¸· ¸ÂÀº °÷À¸·Î ºÎÅÍ 50¹ÌÅÍ ÀÌ»ó Â÷À̳ª¸é Æ÷±âÇÏ°í µ¹¾Æ°£´Ù.
  5857. if (5000 < DISTANCE_APPROX(m_pkMobInst->m_posLastAttacked.x - GetX(), m_pkMobInst->m_posLastAttacked.y - GetY()))
  5858. if (Return())
  5859. return true;
  5860. }
  5861. }
  5862. }
  5863.  
  5864. if (IsGuardNPC())
  5865. {
  5866. if (5000 < DISTANCE_APPROX(m_pkMobInst->m_posLastAttacked.x - GetX(), m_pkMobInst->m_posLastAttacked.y - GetY()))
  5867. if (Return())
  5868. return true;
  5869. }
  5870.  
  5871. if (pkChr->IsState(pkChr->m_stateMove) &&
  5872. GetMobBattleType() != BATTLE_TYPE_RANGE &&
  5873. GetMobBattleType() != BATTLE_TYPE_MAGIC &&
  5874. false == IsPet())
  5875. {
  5876. // ´ë»óÀÌ À̵¿ÁßÀÌ¸é ¿¹Ãø À̵¿À» ÇÑ´Ù
  5877. // ³ª¿Í »ó´ë¹æÀÇ ¼ÓµµÂ÷¿Í °Å¸®·ÎºÎÅÍ ¸¸³¯ ½Ã°£À» ¿¹»óÇÑ ÈÄ
  5878. // »ó´ë¹æÀÌ ±× ½Ã°£±îÁö Á÷¼±À¸·Î À̵¿ÇÑ´Ù°í °¡Á¤ÇÏ¿© °Å±â·Î À̵¿ÇÑ´Ù.
  5879. float rot = pkChr->GetRotation();
  5880. float rot_delta = GetDegreeDelta(rot, GetDegreeFromPositionXY(GetX(), GetY(), pkChr->GetX(), pkChr->GetY()));
  5881.  
  5882. float yourSpeed = pkChr->GetMoveSpeed();
  5883. float mySpeed = GetMoveSpeed();
  5884.  
  5885. float fDist = DISTANCE_SQRT(x - GetX(), y - GetY());
  5886. float fFollowSpeed = mySpeed - yourSpeed * cos(rot_delta * M_PI / 180);
  5887.  
  5888. if (fFollowSpeed >= 0.1f)
  5889. {
  5890. float fMeetTime = fDist / fFollowSpeed;
  5891. float fYourMoveEstimateX, fYourMoveEstimateY;
  5892.  
  5893. if( fMeetTime * yourSpeed <= 100000.0f )
  5894. {
  5895. GetDeltaByDegree(pkChr->GetRotation(), fMeetTime * yourSpeed, &fYourMoveEstimateX, &fYourMoveEstimateY);
  5896.  
  5897. x += (long) fYourMoveEstimateX;
  5898. y += (long) fYourMoveEstimateY;
  5899.  
  5900. float fDistNew = sqrt(((double)x - GetX())*(x-GetX())+((double)y - GetY())*(y-GetY()));
  5901. if (fDist < fDistNew)
  5902. {
  5903. x = (long)(GetX() + (x - GetX()) * fDist / fDistNew);
  5904. y = (long)(GetY() + (y - GetY()) * fDist / fDistNew);
  5905. }
  5906. }
  5907. }
  5908. }
  5909.  
  5910. // °¡·Á´Â À§Ä¡¸¦ ¹Ù¶óºÁ¾ß ÇÑ´Ù.
  5911. SetRotationToXY(x, y);
  5912.  
  5913. float fDist = DISTANCE_SQRT(x - GetX(), y - GetY());
  5914.  
  5915. if (fDist <= fMinDistance)
  5916. return false;
  5917.  
  5918. float fx, fy;
  5919.  
  5920. if (IsChangeAttackPosition(pkChr) && GetMobRank() < MOB_RANK_BOSS)
  5921. {
  5922. // »ó´ë¹æ ÁÖº¯ ·£´ýÇÑ °÷À¸·Î À̵¿
  5923. SetChangeAttackPositionTime();
  5924.  
  5925. int retry = 16;
  5926. int dx, dy;
  5927. int rot = (int) GetDegreeFromPositionXY(x, y, GetX(), GetY());
  5928.  
  5929. while (--retry)
  5930. {
  5931. if (fDist < 500.0f)
  5932. GetDeltaByDegree((rot + number(-90, 90) + number(-90, 90)) % 360, fMinDistance, &fx, &fy);
  5933. else
  5934. GetDeltaByDegree(number(0, 359), fMinDistance, &fx, &fy);
  5935.  
  5936. dx = x + (int) fx;
  5937. dy = y + (int) fy;
  5938.  
  5939. LPSECTREE tree = SECTREE_MANAGER::instance().Get(GetMapIndex(), dx, dy);
  5940.  
  5941. if (NULL == tree)
  5942. break;
  5943.  
  5944. if (0 == (tree->GetAttribute(dx, dy) & (ATTR_BLOCK | ATTR_OBJECT)))
  5945. break;
  5946. }
  5947.  
  5948. //sys_log(0, "±Ùó ¾îµò°¡·Î À̵¿ %s retry %d", GetName(), retry);
  5949. if (!Goto(dx, dy))
  5950. return false;
  5951. }
  5952. else
  5953. {
  5954. // Á÷¼± µû¶ó°¡±â
  5955. float fDistToGo = fDist - fMinDistance;
  5956. GetDeltaByDegree(GetRotation(), fDistToGo, &fx, &fy);
  5957.  
  5958. //sys_log(0, "Á÷¼±À¸·Î À̵¿ %s", GetName());
  5959. if (!Goto(GetX() + (int) fx, GetY() + (int) fy))
  5960. return false;
  5961. }
  5962.  
  5963. SendMovePacket(FUNC_WAIT, 0, 0, 0, 0);
  5964. //MonsterLog("ÂѾư¡±â; %s", pkChr->GetName());
  5965. return true;
  5966. }
  5967.  
  5968. float CHARACTER::GetDistanceFromSafeboxOpen() const
  5969. {
  5970. return DISTANCE_APPROX(GetX() - m_posSafeboxOpen.x, GetY() - m_posSafeboxOpen.y);
  5971. }
  5972.  
  5973. void CHARACTER::SetSafeboxOpenPosition()
  5974. {
  5975. m_posSafeboxOpen = GetXYZ();
  5976. }
  5977.  
  5978. CSafebox * CHARACTER::GetSafebox() const
  5979. {
  5980. return m_pkSafebox;
  5981. }
  5982.  
  5983. void CHARACTER::ReqSafeboxLoad(const char* pszPassword)
  5984. {
  5985. if (!*pszPassword || strlen(pszPassword) > SAFEBOX_PASSWORD_MAX_LEN)
  5986. {
  5987. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<â°í> À߸øµÈ ¾ÏÈ£¸¦ ÀÔ·ÂÇϼ̽À´Ï´Ù."));
  5988. return;
  5989. }
  5990. else if (m_pkSafebox)
  5991. {
  5992. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<â°í> â°í°¡ ÀÌ¹Ì ¿­·ÁÀÖ½À´Ï´Ù."));
  5993. return;
  5994. }
  5995.  
  5996. if (IsRestricted())
  5997. {
  5998. ChatPacket(CHAT_TYPE_INFO, "Nu ai permisiunea sa deschizi depozitul.");
  5999. return;
  6000. }
  6001.  
  6002. int iPulse = thecore_pulse();
  6003.  
  6004. if (iPulse - GetSafeboxLoadTime() < PASSES_PER_SEC(10))
  6005. {
  6006. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<â°í> â°í¸¦ ´ÝÀºÁö 10ÃÊ ¾È¿¡´Â ¿­ ¼ö ¾ø½À´Ï´Ù."));
  6007. return;
  6008. }
  6009. /* else if (GetDistanceFromSafeboxOpen() > 1000)
  6010. {
  6011. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<â°í> °Å¸®°¡ ¸Ö¾î¼­ â°í¸¦ ¿­ ¼ö ¾ø½À´Ï´Ù."));
  6012. return;
  6013. }
  6014. */
  6015. else if (m_bOpeningSafebox)
  6016. {
  6017. sys_log(0, "Overlapped safebox load request from %s", GetName());
  6018. return;
  6019. }
  6020.  
  6021. SetSafeboxLoadTime();
  6022. m_bOpeningSafebox = true;
  6023.  
  6024. TSafeboxLoadPacket p;
  6025. p.dwID = GetDesc()->GetAccountTable().id;
  6026. strlcpy(p.szLogin, GetDesc()->GetAccountTable().login, sizeof(p.szLogin));
  6027. strlcpy(p.szPassword, pszPassword, sizeof(p.szPassword));
  6028.  
  6029. db_clientdesc->DBPacket(HEADER_GD_SAFEBOX_LOAD, GetDesc()->GetHandle(), &p, sizeof(p));
  6030. }
  6031.  
  6032. void CHARACTER::LoadSafebox(int iSize, DWORD dwGold, int iItemCount, TPlayerItem * pItems)
  6033. {
  6034. bool bLoaded = false;
  6035.  
  6036. //PREVENT_TRADE_WINDOW
  6037. SetOpenSafebox(true);
  6038. //END_PREVENT_TRADE_WINDOW
  6039.  
  6040. if (m_pkSafebox)
  6041. bLoaded = true;
  6042.  
  6043. if (!m_pkSafebox)
  6044. m_pkSafebox = M2_NEW CSafebox(this, iSize, dwGold);
  6045. else
  6046. m_pkSafebox->ChangeSize(iSize);
  6047.  
  6048. m_iSafeboxSize = iSize;
  6049.  
  6050. TPacketCGSafeboxSize p;
  6051.  
  6052. p.bHeader = HEADER_GC_SAFEBOX_SIZE;
  6053. p.bSize = iSize;
  6054.  
  6055. GetDesc()->Packet(&p, sizeof(TPacketCGSafeboxSize));
  6056.  
  6057. if (!bLoaded)
  6058. {
  6059. for (int i = 0; i < iItemCount; ++i, ++pItems)
  6060. {
  6061. if (!m_pkSafebox->IsValidPosition(pItems->pos))
  6062. continue;
  6063.  
  6064. LPITEM item = ITEM_MANAGER::instance().CreateItem(pItems->vnum, pItems->count, pItems->id);
  6065.  
  6066. if (!item)
  6067. {
  6068. sys_err("cannot create item vnum %d id %u (name: %s)", pItems->vnum, pItems->id, GetName());
  6069. continue;
  6070. }
  6071.  
  6072. item->SetSkipSave(true);
  6073. item->SetSockets(pItems->alSockets);
  6074. item->SetAttributes(pItems->aAttr);
  6075.  
  6076. if (!m_pkSafebox->Add(pItems->pos, item))
  6077. {
  6078. M2_DESTROY_ITEM(item);
  6079. }
  6080. else
  6081. item->SetSkipSave(false);
  6082. }
  6083. }
  6084. }
  6085.  
  6086. void CHARACTER::ChangeSafeboxSize(BYTE bSize)
  6087. {
  6088. //if (!m_pkSafebox)
  6089. //return;
  6090.  
  6091. TPacketCGSafeboxSize p;
  6092.  
  6093. p.bHeader = HEADER_GC_SAFEBOX_SIZE;
  6094. p.bSize = bSize;
  6095.  
  6096. GetDesc()->Packet(&p, sizeof(TPacketCGSafeboxSize));
  6097.  
  6098. if (m_pkSafebox)
  6099. m_pkSafebox->ChangeSize(bSize);
  6100.  
  6101. m_iSafeboxSize = bSize;
  6102. }
  6103.  
  6104. void CHARACTER::CloseSafebox()
  6105. {
  6106. if (!m_pkSafebox)
  6107. return;
  6108.  
  6109. //PREVENT_TRADE_WINDOW
  6110. SetOpenSafebox(false);
  6111. //END_PREVENT_TRADE_WINDOW
  6112.  
  6113. m_pkSafebox->Save();
  6114.  
  6115. M2_DELETE(m_pkSafebox);
  6116. m_pkSafebox = NULL;
  6117.  
  6118. ChatPacket(CHAT_TYPE_COMMAND, "CloseSafebox");
  6119.  
  6120. SetSafeboxLoadTime();
  6121. m_bOpeningSafebox = false;
  6122.  
  6123. Save();
  6124. }
  6125.  
  6126. CSafebox * CHARACTER::GetMall() const
  6127. {
  6128. return m_pkMall;
  6129. }
  6130.  
  6131. void CHARACTER::LoadMall(int iItemCount, TPlayerItem * pItems)
  6132. {
  6133. bool bLoaded = false;
  6134.  
  6135. if (m_pkMall)
  6136. bLoaded = true;
  6137.  
  6138. if (!m_pkMall)
  6139. m_pkMall = M2_NEW CSafebox(this, 3 * SAFEBOX_PAGE_SIZE, 0);
  6140. else
  6141. m_pkMall->ChangeSize(3 * SAFEBOX_PAGE_SIZE);
  6142.  
  6143. m_pkMall->SetWindowMode(MALL);
  6144.  
  6145. TPacketCGSafeboxSize p;
  6146.  
  6147. p.bHeader = HEADER_GC_MALL_OPEN;
  6148. p.bSize = 3 * SAFEBOX_PAGE_SIZE;
  6149.  
  6150. GetDesc()->Packet(&p, sizeof(TPacketCGSafeboxSize));
  6151.  
  6152. if (!bLoaded)
  6153. {
  6154. for (int i = 0; i < iItemCount; ++i, ++pItems)
  6155. {
  6156. if (!m_pkMall->IsValidPosition(pItems->pos))
  6157. continue;
  6158.  
  6159. LPITEM item = ITEM_MANAGER::instance().CreateItem(pItems->vnum, pItems->count, pItems->id);
  6160.  
  6161. if (!item)
  6162. {
  6163. sys_err("cannot create item vnum %d id %u (name: %s)", pItems->vnum, pItems->id, GetName());
  6164. continue;
  6165. }
  6166.  
  6167. item->SetSkipSave(true);
  6168. item->SetSockets(pItems->alSockets);
  6169. item->SetAttributes(pItems->aAttr);
  6170.  
  6171. if (!m_pkMall->Add(pItems->pos, item))
  6172. M2_DESTROY_ITEM(item);
  6173. else
  6174. item->SetSkipSave(false);
  6175. }
  6176. }
  6177. }
  6178.  
  6179. void CHARACTER::CloseMall()
  6180. {
  6181. if (!m_pkMall)
  6182. return;
  6183.  
  6184. m_pkMall->Save();
  6185.  
  6186. M2_DELETE(m_pkMall);
  6187. m_pkMall = NULL;
  6188.  
  6189. ChatPacket(CHAT_TYPE_COMMAND, "CloseMall");
  6190. }
  6191.  
  6192. bool CHARACTER::BuildUpdatePartyPacket(TPacketGCPartyUpdate & out)
  6193. {
  6194. if (!GetParty())
  6195. return false;
  6196.  
  6197. memset(&out, 0, sizeof(out));
  6198.  
  6199. out.header = HEADER_GC_PARTY_UPDATE;
  6200. out.pid = GetPlayerID();
  6201. out.percent_hp = MINMAX(0, GetHP() * 100 / GetMaxHP(), 100);
  6202. out.role = GetParty()->GetRole(GetPlayerID());
  6203.  
  6204. sys_log(1, "PARTY %s role is %d", GetName(), out.role);
  6205.  
  6206. LPCHARACTER l = GetParty()->GetLeaderCharacter();
  6207.  
  6208. if (l && DISTANCE_APPROX(GetX() - l->GetX(), GetY() - l->GetY()) < PARTY_DEFAULT_RANGE)
  6209. {
  6210. if (g_iUseLocale)
  6211. out.affects[0] = GetParty()->GetPartyBonusExpPercent();
  6212. else
  6213. out.affects[0] = GetParty()->GetExpBonusPercent();
  6214. out.affects[1] = GetPoint(POINT_PARTY_ATTACKER_BONUS);
  6215. out.affects[2] = GetPoint(POINT_PARTY_TANKER_BONUS);
  6216. out.affects[3] = GetPoint(POINT_PARTY_BUFFER_BONUS);
  6217. out.affects[4] = GetPoint(POINT_PARTY_SKILL_MASTER_BONUS);
  6218. out.affects[5] = GetPoint(POINT_PARTY_HASTE_BONUS);
  6219. out.affects[6] = GetPoint(POINT_PARTY_DEFENDER_BONUS);
  6220. }
  6221.  
  6222. return true;
  6223. }
  6224.  
  6225. int CHARACTER::GetLeadershipSkillLevel() const
  6226. {
  6227. return GetSkillLevel(SKILL_LEADERSHIP);
  6228. }
  6229.  
  6230. void CHARACTER::QuerySafeboxSize()
  6231. {
  6232. if (m_iSafeboxSize == -1)
  6233. {
  6234. DBManager::instance().ReturnQuery(QID_SAFEBOX_SIZE,
  6235. GetPlayerID(),
  6236. NULL,
  6237. "SELECT size FROM safebox%s WHERE account_id = %u",
  6238. get_table_postfix(),
  6239. GetDesc()->GetAccountTable().id);
  6240. }
  6241. }
  6242.  
  6243. void CHARACTER::SetSafeboxSize(int iSize)
  6244. {
  6245. sys_log(1, "SetSafeboxSize: %s %d", GetName(), iSize);
  6246. m_iSafeboxSize = iSize;
  6247. DBManager::instance().Query("UPDATE safebox%s SET size = %d WHERE account_id = %u", get_table_postfix(), iSize / SAFEBOX_PAGE_SIZE, GetDesc()->GetAccountTable().id);
  6248. }
  6249.  
  6250. int CHARACTER::GetSafeboxSize() const
  6251. {
  6252. return m_iSafeboxSize;
  6253. }
  6254.  
  6255. void CHARACTER::SetNowWalking(bool bWalkFlag)
  6256. {
  6257. //if (m_bNowWalking != bWalkFlag || IsNPC())
  6258. if (m_bNowWalking != bWalkFlag)
  6259. {
  6260. if (bWalkFlag)
  6261. {
  6262. m_bNowWalking = true;
  6263. m_dwWalkStartTime = get_dword_time();
  6264. }
  6265. else
  6266. {
  6267. m_bNowWalking = false;
  6268. }
  6269.  
  6270. //if (m_bNowWalking)
  6271. {
  6272. TPacketGCWalkMode p;
  6273. p.vid = GetVID();
  6274. p.header = HEADER_GC_WALK_MODE;
  6275. p.mode = m_bNowWalking ? WALKMODE_WALK : WALKMODE_RUN;
  6276.  
  6277. PacketView(&p, sizeof(p));
  6278. }
  6279.  
  6280. if (IsNPC())
  6281. {
  6282. if (m_bNowWalking)
  6283. MonsterLog("°È´Â´Ù");
  6284. else
  6285. MonsterLog("¶Ú´Ù");
  6286. }
  6287.  
  6288. //sys_log(0, "%s is now %s", GetName(), m_bNowWalking?"walking.":"running.");
  6289. }
  6290. }
  6291.  
  6292. void CHARACTER::StartStaminaConsume()
  6293. {
  6294. if (m_bStaminaConsume)
  6295. return;
  6296. PointChange(POINT_STAMINA, 0);
  6297. m_bStaminaConsume = true;
  6298. //ChatPacket(CHAT_TYPE_COMMAND, "StartStaminaConsume %d %d", STAMINA_PER_STEP * passes_per_sec, GetStamina());
  6299. if (IsStaminaHalfConsume())
  6300. ChatPacket(CHAT_TYPE_COMMAND, "StartStaminaConsume %d %d", STAMINA_PER_STEP * passes_per_sec / 2, GetStamina());
  6301. else
  6302. ChatPacket(CHAT_TYPE_COMMAND, "StartStaminaConsume %d %d", STAMINA_PER_STEP * passes_per_sec, GetStamina());
  6303. }
  6304.  
  6305. void CHARACTER::StopStaminaConsume()
  6306. {
  6307. if (!m_bStaminaConsume)
  6308. return;
  6309. PointChange(POINT_STAMINA, 0);
  6310. m_bStaminaConsume = false;
  6311. ChatPacket(CHAT_TYPE_COMMAND, "StopStaminaConsume %d", GetStamina());
  6312. }
  6313.  
  6314. bool CHARACTER::IsStaminaConsume() const
  6315. {
  6316. return m_bStaminaConsume;
  6317. }
  6318.  
  6319. bool CHARACTER::IsStaminaHalfConsume() const
  6320. {
  6321. return IsEquipUniqueItem(UNIQUE_ITEM_HALF_STAMINA);
  6322. }
  6323.  
  6324. void CHARACTER::ResetStopTime()
  6325. {
  6326. m_dwStopTime = get_dword_time();
  6327. }
  6328.  
  6329. DWORD CHARACTER::GetStopTime() const
  6330. {
  6331. return m_dwStopTime;
  6332. }
  6333.  
  6334. void CHARACTER::ResetPoint(int iLv)
  6335. {
  6336. BYTE bJob = GetJob();
  6337.  
  6338. PointChange(POINT_LEVEL, iLv - GetLevel());
  6339.  
  6340. SetRealPoint(POINT_ST, JobInitialPoints[bJob].st);
  6341. SetPoint(POINT_ST, GetRealPoint(POINT_ST));
  6342.  
  6343. SetRealPoint(POINT_HT, JobInitialPoints[bJob].ht);
  6344. SetPoint(POINT_HT, GetRealPoint(POINT_HT));
  6345.  
  6346. SetRealPoint(POINT_DX, JobInitialPoints[bJob].dx);
  6347. SetPoint(POINT_DX, GetRealPoint(POINT_DX));
  6348.  
  6349. SetRealPoint(POINT_IQ, JobInitialPoints[bJob].iq);
  6350. SetPoint(POINT_IQ, GetRealPoint(POINT_IQ));
  6351.  
  6352. SetRandomHP((iLv - 1) * number(JobInitialPoints[GetJob()].hp_per_lv_begin, JobInitialPoints[GetJob()].hp_per_lv_end));
  6353. SetRandomSP((iLv - 1) * number(JobInitialPoints[GetJob()].sp_per_lv_begin, JobInitialPoints[GetJob()].sp_per_lv_end));
  6354.  
  6355. //PointChange(POINT_STAT, ((MINMAX(1, iLv, 99) - 1) * 3) + GetPoint(POINT_LEVEL_STEP) - GetPoint(POINT_STAT));
  6356. PointChange(POINT_STAT, ((MINMAX(1, iLv, gPlayerMaxLevelStats) - 1) * 3) + GetPoint(POINT_LEVEL_STEP) - GetPoint(POINT_STAT));
  6357.  
  6358. ComputePoints();
  6359.  
  6360. // ȸº¹
  6361. PointChange(POINT_HP, GetMaxHP() - GetHP());
  6362. PointChange(POINT_SP, GetMaxSP() - GetSP());
  6363.  
  6364. PointsPacket();
  6365.  
  6366. LogManager::instance().CharLog(this, 0, "RESET_POINT", "");
  6367. }
  6368.  
  6369. bool CHARACTER::IsChangeAttackPosition(LPCHARACTER target) const
  6370. {
  6371. if (!IsNPC())
  6372. return true;
  6373.  
  6374. DWORD dwChangeTime = AI_CHANGE_ATTACK_POISITION_TIME_NEAR;
  6375.  
  6376. if (DISTANCE_APPROX(GetX() - target->GetX(), GetY() - target->GetY()) >
  6377. AI_CHANGE_ATTACK_POISITION_DISTANCE + GetMobAttackRange())
  6378. dwChangeTime = AI_CHANGE_ATTACK_POISITION_TIME_FAR;
  6379.  
  6380. return get_dword_time() - m_dwLastChangeAttackPositionTime > dwChangeTime;
  6381. }
  6382.  
  6383. void CHARACTER::GiveRandomSkillBook()
  6384. {
  6385. LPITEM item = AutoGiveItem(50300);
  6386. if (NULL != item)
  6387. {
  6388. BYTE bJob = 0;
  6389. if (!number(0, 1))
  6390. bJob = GetJob() + 1;
  6391.  
  6392. DWORD dwSkillVnum = 0;
  6393. do
  6394. {
  6395. if (number(1, 20) == 2)
  6396. {
  6397. dwSkillVnum = number(170, 175);
  6398. }
  6399. else
  6400. {
  6401. dwSkillVnum = number(1, 111);
  6402. }
  6403. const CSkillProto* pkSk = CSkillManager::instance().Get(dwSkillVnum);
  6404.  
  6405. if (NULL == pkSk)
  6406. continue;
  6407.  
  6408. if (bJob && bJob != pkSk->dwType)
  6409. continue;
  6410.  
  6411. break;
  6412. } while (true);
  6413.  
  6414. item->SetSocket(0, dwSkillVnum);
  6415. }
  6416. }
  6417.  
  6418. void CHARACTER::ReviveInvisible(int iDur)
  6419. {
  6420. AddAffect(AFFECT_REVIVE_INVISIBLE, POINT_NONE, 0, AFF_REVIVE_INVISIBLE, iDur, 0, true);
  6421. }
  6422.  
  6423. void CHARACTER::ToggleMonsterLog()
  6424. {
  6425. m_bMonsterLog = !m_bMonsterLog;
  6426.  
  6427. if (m_bMonsterLog)
  6428. {
  6429. CHARACTER_MANAGER::instance().RegisterForMonsterLog(this);
  6430. }
  6431. else
  6432. {
  6433. CHARACTER_MANAGER::instance().UnregisterForMonsterLog(this);
  6434. }
  6435. }
  6436.  
  6437. void CHARACTER::SetGuild(CGuild* pGuild)
  6438. {
  6439. if (m_pGuild != pGuild)
  6440. {
  6441. m_pGuild = pGuild;
  6442. UpdatePacket();
  6443. }
  6444. }
  6445.  
  6446. void CHARACTER::SendGreetMessage()
  6447. {
  6448. typeof(DBManager::instance().GetGreetMessage()) v = DBManager::instance().GetGreetMessage();
  6449.  
  6450. for (itertype(v) it = v.begin(); it != v.end(); ++it)
  6451. {
  6452. ChatPacket(CHAT_TYPE_NOTICE, it->c_str());
  6453. }
  6454. }
  6455.  
  6456. void CHARACTER::BeginStateEmpty()
  6457. {
  6458. MonsterLog("!");
  6459. }
  6460.  
  6461. void CHARACTER::EffectPacket(int enumEffectType)
  6462. {
  6463. TPacketGCSpecialEffect p;
  6464.  
  6465. p.header = HEADER_GC_SEPCIAL_EFFECT;
  6466. p.type = enumEffectType;
  6467. p.vid = GetVID();
  6468.  
  6469. PacketAround(&p, sizeof(TPacketGCSpecialEffect));
  6470. }
  6471.  
  6472. void CHARACTER::SpecificEffectPacket(const char filename[MAX_EFFECT_FILE_NAME])
  6473. {
  6474. TPacketGCSpecificEffect p;
  6475.  
  6476. p.header = HEADER_GC_SPECIFIC_EFFECT;
  6477. p.vid = GetVID();
  6478. memcpy (p.effect_file, filename, MAX_EFFECT_FILE_NAME);
  6479.  
  6480. PacketAround(&p, sizeof(TPacketGCSpecificEffect));
  6481. }
  6482.  
  6483. void CHARACTER::MonsterChat(BYTE bMonsterChatType)
  6484. {
  6485. if (IsPC())
  6486. return;
  6487.  
  6488. char sbuf[256+1];
  6489.  
  6490. if (IsMonster())
  6491. {
  6492. if (number(0, 60))
  6493. return;
  6494.  
  6495. snprintf(sbuf, sizeof(sbuf),
  6496. "(locale.monster_chat[%i] and locale.monster_chat[%i][%d] or '')",
  6497. GetRaceNum(), GetRaceNum(), bMonsterChatType*3 + number(1, 3));
  6498. }
  6499. else
  6500. {
  6501. if (bMonsterChatType != MONSTER_CHAT_WAIT)
  6502. return;
  6503.  
  6504. if (IsGuardNPC())
  6505. {
  6506. if (number(0, 6))
  6507. return;
  6508. }
  6509. else
  6510. {
  6511. if (number(0, 30))
  6512. return;
  6513. }
  6514.  
  6515. snprintf(sbuf, sizeof(sbuf), "(locale.monster_chat[%i] and locale.monster_chat[%i][number(1, table.getn(locale.monster_chat[%i]))] or '')", GetRaceNum(), GetRaceNum(), GetRaceNum());
  6516. }
  6517.  
  6518. std::string text = quest::ScriptToString(sbuf);
  6519.  
  6520. if (text.empty())
  6521. return;
  6522.  
  6523. struct packet_chat pack_chat;
  6524.  
  6525. pack_chat.header = HEADER_GC_CHAT;
  6526. pack_chat.size = sizeof(struct packet_chat) + text.size() + 1;
  6527. pack_chat.type = CHAT_TYPE_TALKING;
  6528. pack_chat.id = GetVID();
  6529. pack_chat.bEmpire = 0;
  6530.  
  6531. TEMP_BUFFER buf;
  6532. buf.write(&pack_chat, sizeof(struct packet_chat));
  6533. buf.write(text.c_str(), text.size() + 1);
  6534.  
  6535. PacketAround(buf.read_peek(), buf.size());
  6536. }
  6537.  
  6538. void CHARACTER::SetQuestNPCID(DWORD vid)
  6539. {
  6540. m_dwQuestNPCVID = vid;
  6541. }
  6542.  
  6543. LPCHARACTER CHARACTER::GetQuestNPC() const
  6544. {
  6545. return CHARACTER_MANAGER::instance().Find(m_dwQuestNPCVID);
  6546. }
  6547.  
  6548. void CHARACTER::SetQuestItemPtr(LPITEM item)
  6549. {
  6550. m_pQuestItem = item;
  6551. }
  6552.  
  6553. void CHARACTER::ClearQuestItemPtr()
  6554. {
  6555. m_pQuestItem = NULL;
  6556. }
  6557.  
  6558. LPITEM CHARACTER::GetQuestItemPtr() const
  6559. {
  6560. return m_pQuestItem;
  6561. }
  6562.  
  6563. LPDUNGEON CHARACTER::GetDungeonForce() const
  6564. {
  6565. if (m_lWarpMapIndex > 10000)
  6566. return CDungeonManager::instance().FindByMapIndex(m_lWarpMapIndex);
  6567.  
  6568. return m_pkDungeon;
  6569. }
  6570.  
  6571. void CHARACTER::SetBlockMode(BYTE bFlag)
  6572. {
  6573. m_pointsInstant.bBlockMode = bFlag;
  6574.  
  6575. ChatPacket(CHAT_TYPE_COMMAND, "setblockmode %d", m_pointsInstant.bBlockMode);
  6576.  
  6577. SetQuestFlag("game_option.block_exchange", bFlag & BLOCK_EXCHANGE ? 1 : 0);
  6578. SetQuestFlag("game_option.block_party_invite", bFlag & BLOCK_PARTY_INVITE ? 1 : 0);
  6579. SetQuestFlag("game_option.block_guild_invite", bFlag & BLOCK_GUILD_INVITE ? 1 : 0);
  6580. SetQuestFlag("game_option.block_whisper", bFlag & BLOCK_WHISPER ? 1 : 0);
  6581. SetQuestFlag("game_option.block_messenger_invite", bFlag & BLOCK_MESSENGER_INVITE ? 1 : 0);
  6582. SetQuestFlag("game_option.block_party_request", bFlag & BLOCK_PARTY_REQUEST ? 1 : 0);
  6583. }
  6584.  
  6585. void CHARACTER::SetBlockModeForce(BYTE bFlag)
  6586. {
  6587. m_pointsInstant.bBlockMode = bFlag;
  6588. ChatPacket(CHAT_TYPE_COMMAND, "setblockmode %d", m_pointsInstant.bBlockMode);
  6589. }
  6590.  
  6591. bool CHARACTER::IsGuardNPC() const
  6592. {
  6593. return IsNPC() && (GetRaceNum() == 11000 || GetRaceNum() == 11002 || GetRaceNum() == 11004);
  6594. }
  6595.  
  6596. int CHARACTER::GetPolymorphPower() const
  6597. {
  6598. if (test_server)
  6599. {
  6600. int value = quest::CQuestManager::instance().GetEventFlag("poly");
  6601. if (value)
  6602. return value;
  6603. }
  6604. return aiPolymorphPowerByLevel[MINMAX(0, GetSkillLevel(SKILL_POLYMORPH), 40)];
  6605. }
  6606.  
  6607. void CHARACTER::SetPolymorph(DWORD dwRaceNum, bool bMaintainStat)
  6608. {
  6609. if (dwRaceNum < JOB_MAX_NUM)
  6610. {
  6611. dwRaceNum = 0;
  6612. bMaintainStat = false;
  6613. }
  6614.  
  6615. if (m_dwPolymorphRace == dwRaceNum)
  6616. return;
  6617.  
  6618. m_bPolyMaintainStat = bMaintainStat;
  6619. m_dwPolymorphRace = dwRaceNum;
  6620.  
  6621. sys_log(0, "POLYMORPH: %s race %u ", GetName(), dwRaceNum);
  6622.  
  6623. if (dwRaceNum != 0)
  6624. StopRiding();
  6625.  
  6626. SET_BIT(m_bAddChrState, ADD_CHARACTER_STATE_SPAWN);
  6627. m_afAffectFlag.Set(AFF_SPAWN);
  6628.  
  6629. ViewReencode();
  6630.  
  6631. REMOVE_BIT(m_bAddChrState, ADD_CHARACTER_STATE_SPAWN);
  6632.  
  6633. if (!bMaintainStat)
  6634. {
  6635. PointChange(POINT_ST, 0);
  6636. PointChange(POINT_DX, 0);
  6637. PointChange(POINT_IQ, 0);
  6638. PointChange(POINT_HT, 0);
  6639. }
  6640.  
  6641. // Æú¸®¸ðÇÁ »óÅ¿¡¼­ Á×´Â °æ¿ì, Æú¸®¸ðÇÁ°¡ Ç®¸®°Ô µÇ´Âµ¥
  6642. // Æú¸® ¸ðÇÁ ÀüÈÄ·Î valid combo intervalÀÌ ´Ù¸£±â ¶§¹®¿¡
  6643. // Combo ÇÙ ¶Ç´Â Hacker·Î ÀνÄÇÏ´Â °æ¿ì°¡ ÀÖ´Ù.
  6644. // µû¶ó¼­ Æú¸®¸ðÇÁ¸¦ Ç®°Å³ª Æú¸®¸ðÇÁ ÇÏ°Ô µÇ¸é,
  6645. // valid combo intervalÀ» resetÇÑ´Ù.
  6646. SetValidComboInterval(0);
  6647. SetComboSequence(0);
  6648.  
  6649. ComputeBattlePoints();
  6650. }
  6651.  
  6652. int CHARACTER::GetQuestFlag(const std::string& flag) const
  6653. {
  6654. quest::CQuestManager& q = quest::CQuestManager::instance();
  6655. quest::PC* pPC = q.GetPC(GetPlayerID());
  6656. if(!pPC)
  6657. {
  6658. sys_err("Nullpointer in CHARACTER::GetQuestFlag %lu", GetPlayerID());
  6659. return 0;
  6660. }
  6661. return pPC->GetFlag(flag);
  6662. }
  6663.  
  6664. void CHARACTER::SetQuestFlag(const std::string& flag, int value)
  6665. {
  6666. quest::CQuestManager& q = quest::CQuestManager::instance();
  6667. quest::PC* pPC = q.GetPC(GetPlayerID());
  6668. if(!pPC)
  6669. {
  6670. sys_err("Nullpointer in CHARACTER::GetQuestFlag %lu", GetPlayerID());
  6671. return;
  6672. }
  6673. pPC->SetFlag(flag, value);
  6674. }
  6675.  
  6676. void CHARACTER::DetermineDropMetinStone()
  6677. {
  6678. const int METIN_STONE_NUM = 14;
  6679. static DWORD c_adwMetin[METIN_STONE_NUM] =
  6680. {
  6681. 28030,
  6682. 28031,
  6683. 28032,
  6684. 28033,
  6685. 28034,
  6686. 28035,
  6687. 28036,
  6688. 28037,
  6689. 28038,
  6690. 28039,
  6691. 28040,
  6692. 28041,
  6693. 28042,
  6694. 28043,
  6695. };
  6696. DWORD stone_num = GetRaceNum();
  6697. int idx = std::lower_bound(aStoneDrop, aStoneDrop+STONE_INFO_MAX_NUM, stone_num) - aStoneDrop;
  6698. if (idx >= STONE_INFO_MAX_NUM || aStoneDrop[idx].dwMobVnum != stone_num)
  6699. {
  6700. m_dwDropMetinStone = 0;
  6701. }
  6702. else
  6703. {
  6704. const SStoneDropInfo & info = aStoneDrop[idx];
  6705. m_bDropMetinStonePct = info.iDropPct;
  6706. {
  6707. m_dwDropMetinStone = c_adwMetin[number(0, METIN_STONE_NUM - 1)];
  6708. int iGradePct = number(1, 100);
  6709. for (int iStoneLevel = 0; iStoneLevel < STONE_LEVEL_MAX_NUM; iStoneLevel ++)
  6710. {
  6711. int iLevelGradePortion = info.iLevelPct[iStoneLevel];
  6712. if (iGradePct <= iLevelGradePortion)
  6713. {
  6714. break;
  6715. }
  6716. else
  6717. {
  6718. iGradePct -= iLevelGradePortion;
  6719. m_dwDropMetinStone += 100; // µ¹ +a -> +(a+1)ÀÌ µÉ¶§¸¶´Ù 100¾¿ Áõ°¡
  6720. }
  6721. }
  6722. }
  6723. }
  6724. }
  6725.  
  6726. void CHARACTER::SendEquipment(LPCHARACTER ch)
  6727. {
  6728. TPacketViewEquip p;
  6729. p.header = HEADER_GC_VIEW_EQUIP;
  6730. p.vid = GetVID();
  6731. for (int i = 0; i<WEAR_MAX_NUM; i++)
  6732. {
  6733. LPITEM item = GetWear(i);
  6734. if (item)
  6735. {
  6736. p.equips[i].vnum = item->GetVnum();
  6737. p.equips[i].count = item->GetCount();
  6738.  
  6739. thecore_memcpy(p.equips[i].alSockets, item->GetSockets(), sizeof(p.equips[i].alSockets));
  6740. thecore_memcpy(p.equips[i].aAttr, item->GetAttributes(), sizeof(p.equips[i].aAttr));
  6741. }
  6742. else
  6743. {
  6744. p.equips[i].vnum = 0;
  6745. }
  6746. }
  6747. ch->GetDesc()->Packet(&p, sizeof(p));
  6748. }
  6749.  
  6750. bool CHARACTER::CanSummon(int iLeaderShip)
  6751. {
  6752. return (iLeaderShip >= 20 || iLeaderShip >= 12 && m_dwLastDeadTime + 180 > get_dword_time());
  6753. }
  6754.  
  6755.  
  6756. void CHARACTER::MountVnum(DWORD vnum)
  6757. {
  6758. if (m_dwMountVnum == vnum)
  6759. return;
  6760.  
  6761. m_dwMountVnum = vnum;
  6762. m_dwMountTime = get_dword_time();
  6763.  
  6764. if (m_bIsObserver)
  6765. return;
  6766.  
  6767. //NOTE : MountÇÑ´Ù°í Çؼ­ Client SideÀÇ °´Ã¼¸¦ »èÁ¦ÇÏÁø ¾Ê´Â´Ù.
  6768. //±×¸®°í ¼­¹öSide¿¡¼­ ÅÀÀ»¶§ À§Ä¡ À̵¿Àº ÇÏÁö ¾Ê´Â´Ù. ¿Ö³ÄÇϸé Client Side¿¡¼­ Coliision Adjust¸¦ ÇÒ¼ö Àִµ¥
  6769. //°´Ã¼¸¦ ¼Ò¸ê½ÃÄ×´Ù°¡ ¼­¹öÀ§Ä¡·Î À̵¿½ÃÅ°¸é À̶§ collision check¸¦ ÇÏÁö´Â ¾ÊÀ¸¹Ç·Î ¹è°æ¿¡ ³¢°Å³ª ¶Õ°í ³ª°¡´Â ¹®Á¦°¡ Á¸ÀçÇÑ´Ù.
  6770. m_posDest.x = m_posStart.x = GetX();
  6771. m_posDest.y = m_posStart.y = GetY();
  6772. //EncodeRemovePacket(this);
  6773. EncodeInsertPacket(this);
  6774.  
  6775. ENTITY_MAP::iterator it = m_map_view.begin();
  6776.  
  6777. while (it != m_map_view.end())
  6778. {
  6779. LPENTITY entity = (it++)->first;
  6780.  
  6781. //MountÇÑ´Ù°í Çؼ­ Client SideÀÇ °´Ã¼¸¦ »èÁ¦ÇÏÁø ¾Ê´Â´Ù.
  6782. //EncodeRemovePacket(entity);
  6783. //if (!m_bIsObserver)
  6784. EncodeInsertPacket(entity);
  6785.  
  6786. //if (!entity->IsObserverMode())
  6787. // entity->EncodeInsertPacket(this);
  6788. }
  6789.  
  6790. SetValidComboInterval(0);
  6791. SetComboSequence(0);
  6792.  
  6793. ComputePoints();
  6794. }
  6795.  
  6796. namespace {
  6797. class FuncCheckWarp
  6798. {
  6799. public:
  6800. FuncCheckWarp(LPCHARACTER pkWarp)
  6801. {
  6802. m_lTargetY = 0;
  6803. m_lTargetX = 0;
  6804.  
  6805. m_lX = pkWarp->GetX();
  6806. m_lY = pkWarp->GetY();
  6807.  
  6808. m_bInvalid = false;
  6809. m_bEmpire = pkWarp->GetEmpire();
  6810.  
  6811. char szTmp[64];
  6812.  
  6813. if (3 != sscanf(pkWarp->GetName(), " %s %ld %ld ", szTmp, &m_lTargetX, &m_lTargetY))
  6814. {
  6815. if (number(1, 100) < 5)
  6816. //sys_err("Warp NPC name wrong : vnum(%d) name(%s)", pkWarp->GetRaceNum(), pkWarp->GetName());
  6817.  
  6818. m_bInvalid = true;
  6819.  
  6820. return;
  6821. }
  6822.  
  6823. m_lTargetX *= 100;
  6824. m_lTargetY *= 100;
  6825.  
  6826. m_bUseWarp = true;
  6827.  
  6828. if (pkWarp->IsGoto())
  6829. {
  6830. LPSECTREE_MAP pkSectreeMap = SECTREE_MANAGER::instance().GetMap(pkWarp->GetMapIndex());
  6831. m_lTargetX += pkSectreeMap->m_setting.iBaseX;
  6832. m_lTargetY += pkSectreeMap->m_setting.iBaseY;
  6833. m_bUseWarp = false;
  6834. }
  6835. }
  6836.  
  6837. bool Valid()
  6838. {
  6839. return !m_bInvalid;
  6840. }
  6841.  
  6842. void operator () (LPENTITY ent)
  6843. {
  6844. if (!Valid())
  6845. return;
  6846.  
  6847. if (!ent->IsType(ENTITY_CHARACTER))
  6848. return;
  6849.  
  6850. LPCHARACTER pkChr = (LPCHARACTER) ent;
  6851.  
  6852. if (!pkChr->IsPC())
  6853. return;
  6854.  
  6855. int iDist = DISTANCE_APPROX(pkChr->GetX() - m_lX, pkChr->GetY() - m_lY);
  6856.  
  6857. if (iDist > 300)
  6858. return;
  6859.  
  6860. if (m_bEmpire && pkChr->GetEmpire() && m_bEmpire != pkChr->GetEmpire())
  6861. return;
  6862.  
  6863. if (pkChr->IsHack())
  6864. return;
  6865.  
  6866. if (!pkChr->CanHandleItem(false, true))
  6867. return;
  6868.  
  6869. if (m_bUseWarp)
  6870. pkChr->WarpSet(m_lTargetX, m_lTargetY);
  6871. else
  6872. {
  6873. pkChr->Show(pkChr->GetMapIndex(), m_lTargetX, m_lTargetY);
  6874. pkChr->Stop();
  6875. }
  6876. }
  6877.  
  6878. bool m_bInvalid;
  6879. bool m_bUseWarp;
  6880.  
  6881. long m_lX;
  6882. long m_lY;
  6883. long m_lTargetX;
  6884. long m_lTargetY;
  6885.  
  6886. BYTE m_bEmpire;
  6887. };
  6888. }
  6889.  
  6890. EVENTFUNC(warp_npc_event)
  6891. {
  6892. char_event_info* info = dynamic_cast<char_event_info*>( event->info );
  6893. if ( info == NULL )
  6894. {
  6895. sys_err( "warp_npc_event> <Factor> Null pointer" );
  6896. return 0;
  6897. }
  6898.  
  6899. LPCHARACTER ch = info->ch;
  6900.  
  6901. if (ch == NULL) { // <Factor>
  6902. return 0;
  6903. }
  6904.  
  6905. if (!ch->GetSectree())
  6906. {
  6907. ch->m_pkWarpNPCEvent = NULL;
  6908. return 0;
  6909. }
  6910.  
  6911. FuncCheckWarp f(ch);
  6912. if (f.Valid())
  6913. ch->GetSectree()->ForEachAround(f);
  6914.  
  6915. return passes_per_sec / 2;
  6916. }
  6917.  
  6918.  
  6919. void CHARACTER::StartWarpNPCEvent()
  6920. {
  6921. if (m_pkWarpNPCEvent)
  6922. return;
  6923.  
  6924. if (!IsWarp() && !IsGoto())
  6925. return;
  6926.  
  6927. char_event_info* info = AllocEventInfo<char_event_info>();
  6928.  
  6929. info->ch = this;
  6930.  
  6931. m_pkWarpNPCEvent = event_create(warp_npc_event, info, passes_per_sec / 2);
  6932. }
  6933.  
  6934. void CHARACTER::SyncPacket()
  6935. {
  6936. TEMP_BUFFER buf;
  6937.  
  6938. TPacketCGSyncPositionElement elem;
  6939.  
  6940. elem.dwVID = GetVID();
  6941. elem.lX = GetX();
  6942. elem.lY = GetY();
  6943.  
  6944. TPacketGCSyncPosition pack;
  6945.  
  6946. pack.bHeader = HEADER_GC_SYNC_POSITION;
  6947. pack.wSize = sizeof(TPacketGCSyncPosition) + sizeof(elem);
  6948.  
  6949. buf.write(&pack, sizeof(pack));
  6950. buf.write(&elem, sizeof(elem));
  6951.  
  6952. PacketAround(buf.read_peek(), buf.size());
  6953. }
  6954.  
  6955. LPCHARACTER CHARACTER::GetMarryPartner() const
  6956. {
  6957. return m_pkChrMarried;
  6958. }
  6959.  
  6960. void CHARACTER::SetMarryPartner(LPCHARACTER ch)
  6961. {
  6962. m_pkChrMarried = ch;
  6963. }
  6964.  
  6965. int CHARACTER::GetMarriageBonus(DWORD dwItemVnum, bool bSum)
  6966. {
  6967. if (IsNPC())
  6968. return 0;
  6969.  
  6970. marriage::TMarriage* pMarriage = marriage::CManager::instance().Get(GetPlayerID());
  6971.  
  6972. if (!pMarriage)
  6973. return 0;
  6974.  
  6975. return pMarriage->GetBonus(dwItemVnum, bSum, this);
  6976. }
  6977.  
  6978. void CHARACTER::ConfirmWithMsg(const char* szMsg, int iTimeout, DWORD dwRequestPID)
  6979. {
  6980. if (!IsPC())
  6981. return;
  6982.  
  6983. TPacketGCQuestConfirm p;
  6984.  
  6985. p.header = HEADER_GC_QUEST_CONFIRM;
  6986. p.requestPID = dwRequestPID;
  6987. p.timeout = iTimeout;
  6988. strlcpy(p.msg, szMsg, sizeof(p.msg));
  6989.  
  6990. GetDesc()->Packet(&p, sizeof(p));
  6991. }
  6992.  
  6993. int CHARACTER::GetPremiumRemainSeconds(BYTE bType) const
  6994. {
  6995. if (bType >= PREMIUM_MAX_NUM)
  6996. return 0;
  6997.  
  6998. return m_aiPremiumTimes[bType] - get_global_time();
  6999. }
  7000.  
  7001. bool CHARACTER::WarpToPID(DWORD dwPID)
  7002. {
  7003. LPCHARACTER victim;
  7004. if ((victim = (CHARACTER_MANAGER::instance().FindByPID(dwPID))))
  7005. {
  7006. int mapIdx = victim->GetMapIndex();
  7007. if (IS_SUMMONABLE_ZONE(mapIdx))
  7008. {
  7009. if (CAN_ENTER_ZONE(this, mapIdx))
  7010. {
  7011. WarpSet(victim->GetX(), victim->GetY());
  7012. }
  7013. else
  7014. {
  7015. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("»ó´ë¹æÀÌ ÀÖ´Â °÷À¸·Î ¿öÇÁÇÒ ¼ö ¾ø½À´Ï´Ù."));
  7016. return false;
  7017. }
  7018. }
  7019. else
  7020. {
  7021. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("»ó´ë¹æÀÌ ÀÖ´Â °÷À¸·Î ¿öÇÁÇÒ ¼ö ¾ø½À´Ï´Ù."));
  7022. return false;
  7023. }
  7024. }
  7025. else
  7026. {
  7027. // ´Ù¸¥ ¼­¹ö¿¡ ·Î±×ÀÎµÈ »ç¶÷ÀÌ ÀÖÀ½ -> ¸Þ½ÃÁö º¸³» ÁÂÇ¥¸¦ ¹Þ¾Æ¿ÀÀÚ
  7028. // 1. A.pid, B.pid ¸¦ »Ñ¸²
  7029. // 2. B.pid¸¦ °¡Áø ¼­¹ö°¡ »Ñ¸°¼­¹ö¿¡°Ô A.pid, ÁÂÇ¥ ¸¦ º¸³¿
  7030. // 3. ¿öÇÁ
  7031. CCI * pcci = P2P_MANAGER::instance().FindByPID(dwPID);
  7032.  
  7033. if (!pcci)
  7034. {
  7035. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("»ó´ë¹æÀÌ ¿Â¶óÀÎ »óÅ°¡ ¾Æ´Õ´Ï´Ù."));
  7036. return false;
  7037. }
  7038.  
  7039. if (pcci->bChannel != g_bChannel)
  7040. {
  7041. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("»ó´ë¹æÀÌ %d ä³Î¿¡ ÀÖ½À´Ï´Ù. (ÇöÀç ä³Î %d)"), pcci->bChannel, g_bChannel);
  7042. return false;
  7043. }
  7044. else if (false == IS_SUMMONABLE_ZONE(pcci->lMapIndex))
  7045. {
  7046. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("»ó´ë¹æÀÌ ÀÖ´Â °÷À¸·Î ¿öÇÁÇÒ ¼ö ¾ø½À´Ï´Ù."));
  7047. return false;
  7048. }
  7049. else
  7050. {
  7051. if (!CAN_ENTER_ZONE(this, pcci->lMapIndex))
  7052. {
  7053. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("»ó´ë¹æÀÌ ÀÖ´Â °÷À¸·Î ¿öÇÁÇÒ ¼ö ¾ø½À´Ï´Ù."));
  7054. return false;
  7055. }
  7056.  
  7057. TPacketGGFindPosition p;
  7058. p.header = HEADER_GG_FIND_POSITION;
  7059. p.dwFromPID = GetPlayerID();
  7060. p.dwTargetPID = dwPID;
  7061. pcci->pkDesc->Packet(&p, sizeof(TPacketGGFindPosition));
  7062.  
  7063. if (test_server)
  7064. ChatPacket(CHAT_TYPE_PARTY, "sent find position packet for teleport");
  7065. }
  7066. }
  7067. return true;
  7068. }
  7069.  
  7070. // ADD_REFINE_BUILDING
  7071. CGuild* CHARACTER::GetRefineGuild() const
  7072. {
  7073. LPCHARACTER chRefineNPC = CHARACTER_MANAGER::instance().Find(m_dwRefineNPCVID);
  7074.  
  7075. return (chRefineNPC ? chRefineNPC->GetGuild() : NULL);
  7076. }
  7077.  
  7078. bool CHARACTER::IsRefineThroughGuild() const
  7079. {
  7080. return GetRefineGuild() != NULL;
  7081. }
  7082.  
  7083. int CHARACTER::ComputeRefineFee(int iCost, int iMultiply) const
  7084. {
  7085. CGuild* pGuild = GetRefineGuild();
  7086. if (pGuild)
  7087. {
  7088. if (pGuild == GetGuild())
  7089. return iCost * iMultiply * 9 / 10;
  7090.  
  7091. // ´Ù¸¥ Á¦±¹ »ç¶÷ÀÌ ½ÃµµÇÏ´Â °æ¿ì Ãß°¡·Î 3¹è ´õ
  7092. LPCHARACTER chRefineNPC = CHARACTER_MANAGER::instance().Find(m_dwRefineNPCVID);
  7093. if (chRefineNPC && chRefineNPC->GetEmpire() != GetEmpire())
  7094. return iCost * iMultiply * 3;
  7095.  
  7096. return iCost * iMultiply;
  7097. }
  7098. else
  7099. return iCost;
  7100. }
  7101.  
  7102. void CHARACTER::PayRefineFee(int iTotalMoney)
  7103. {
  7104. int iFee = iTotalMoney / 10;
  7105. CGuild* pGuild = GetRefineGuild();
  7106.  
  7107. int iRemain = iTotalMoney;
  7108.  
  7109. if (pGuild)
  7110. {
  7111. // Àڱ⠱æµåÀ̸é iTotalMoney¿¡ ÀÌ¹Ì 10%°¡ Á¦¿ÜµÇ¾îÀÖ´Ù
  7112. if (pGuild != GetGuild())
  7113. {
  7114. pGuild->RequestDepositMoney(this, iFee);
  7115. iRemain -= iFee;
  7116. }
  7117. }
  7118.  
  7119. PointChange(POINT_GOLD, -iRemain);
  7120. }
  7121. // END_OF_ADD_REFINE_BUILDING
  7122.  
  7123. //Hack ¹æÁö¸¦ À§ÇÑ Ã¼Å©.
  7124. bool CHARACTER::IsHack(bool bSendMsg, bool bCheckShopOwner, int limittime)
  7125. {
  7126. const int iPulse = thecore_pulse();
  7127.  
  7128. if (test_server)
  7129. bSendMsg = true;
  7130.  
  7131. //â°í ¿¬ÈÄ Ã¼Å©
  7132. if (iPulse - GetSafeboxLoadTime() < PASSES_PER_SEC(limittime))
  7133. {
  7134. if (bSendMsg)
  7135. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("â°í¸¦ ¿¬ÈÄ %dÃÊ À̳»¿¡´Â ´Ù¸¥°÷À¸·Î À̵¿ÇÒ¼ö ¾ø½À´Ï´Ù."), limittime);
  7136.  
  7137. if (test_server)
  7138. ChatPacket(CHAT_TYPE_INFO, "[TestOnly]Pulse %d LoadTime %d PASS %d", iPulse, GetSafeboxLoadTime(), PASSES_PER_SEC(limittime));
  7139. return true;
  7140. }
  7141.  
  7142. //°Å·¡°ü·Ã â üũ
  7143. if (bCheckShopOwner)
  7144. {
  7145. if (GetExchange() || GetMyShop() || GetShopOwner() || IsOpenSafebox() || IsCubeOpen() || IsAcceOpen() || GetOfflineShopOwner())
  7146. {
  7147. if (bSendMsg)
  7148. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("°Å·¡Ã¢,â°í µîÀ» ¿¬ »óÅ¿¡¼­´Â ´Ù¸¥°÷À¸·Î À̵¿,Á¾·á ÇÒ¼ö ¾ø½À´Ï´Ù"));
  7149.  
  7150. return true;
  7151. }
  7152. }
  7153. else
  7154. {
  7155. if (GetExchange() || GetMyShop() || IsOpenSafebox() || IsCubeOpen() || IsAcceOpen())
  7156. {
  7157. if (bSendMsg)
  7158. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("°Å·¡Ã¢,â°í µîÀ» ¿¬ »óÅ¿¡¼­´Â ´Ù¸¥°÷À¸·Î À̵¿,Á¾·á ÇÒ¼ö ¾ø½À´Ï´Ù"));
  7159.  
  7160. return true;
  7161. }
  7162. }
  7163.  
  7164. //PREVENT_PORTAL_AFTER_EXCHANGE
  7165. //±³È¯ ÈÄ ½Ã°£Ã¼Å©
  7166. if (iPulse - GetExchangeTime() < PASSES_PER_SEC(limittime))
  7167. {
  7168. if (bSendMsg)
  7169. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("°Å·¡ ÈÄ %dÃÊ À̳»¿¡´Â ´Ù¸¥Áö¿ªÀ¸·Î À̵¿ ÇÒ ¼ö ¾ø½À´Ï´Ù."), limittime );
  7170. return true;
  7171. }
  7172. //END_PREVENT_PORTAL_AFTER_EXCHANGE
  7173.  
  7174. //PREVENT_ITEM_COPY
  7175. if (iPulse - GetMyShopTime() < PASSES_PER_SEC(limittime))
  7176. {
  7177. if (bSendMsg)
  7178. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("°Å·¡ ÈÄ %dÃÊ À̳»¿¡´Â ´Ù¸¥Áö¿ªÀ¸·Î À̵¿ ÇÒ ¼ö ¾ø½À´Ï´Ù."), limittime);
  7179. return true;
  7180. }
  7181.  
  7182. if (iPulse - GetRefineTime() < PASSES_PER_SEC(limittime))
  7183. {
  7184. if (bSendMsg)
  7185. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("¾ÆÀÌÅÛ °³·®ÈÄ %dÃÊ À̳»¿¡´Â ±ÍȯºÎ,±Íȯ±â¾ïºÎ¸¦ »ç¿ëÇÒ ¼ö ¾ø½À´Ï´Ù."), limittime);
  7186. return true;
  7187. }
  7188. //END_PREVENT_ITEM_COPY
  7189.  
  7190. return false;
  7191. }
  7192.  
  7193. BOOL CHARACTER::IsMonarch() const
  7194. {
  7195. //MONARCH_LIMIT
  7196. if (CMonarch::instance().IsMonarch(GetPlayerID(), GetEmpire()))
  7197. return true;
  7198.  
  7199. return false;
  7200.  
  7201. //END_MONARCH_LIMIT
  7202. }
  7203. void CHARACTER::Say(const std::string & s)
  7204. {
  7205. struct ::packet_script packet_script;
  7206.  
  7207. packet_script.header = HEADER_GC_SCRIPT;
  7208. packet_script.skin = 1;
  7209. packet_script.src_size = s.size();
  7210. packet_script.size = packet_script.src_size + sizeof(struct packet_script);
  7211.  
  7212. TEMP_BUFFER buf;
  7213.  
  7214. buf.write(&packet_script, sizeof(struct packet_script));
  7215. buf.write(&s[0], s.size());
  7216.  
  7217. if (IsPC())
  7218. {
  7219. GetDesc()->Packet(buf.read_peek(), buf.size());
  7220. }
  7221. }
  7222.  
  7223. //
  7224. // Monarch
  7225. //
  7226. void CHARACTER::InitMC()
  7227. {
  7228. for (int n = 0; n < MI_MAX; ++n)
  7229. {
  7230. m_dwMonarchCooltime[n] = thecore_pulse();
  7231. }
  7232.  
  7233. m_dwMonarchCooltimelimit[MI_HEAL] = PASSES_PER_SEC(MC_HEAL);
  7234. m_dwMonarchCooltimelimit[MI_WARP] = PASSES_PER_SEC(MC_WARP);
  7235. m_dwMonarchCooltimelimit[MI_TRANSFER] = PASSES_PER_SEC(MC_TRANSFER);
  7236. m_dwMonarchCooltimelimit[MI_TAX] = PASSES_PER_SEC(MC_TAX);
  7237. m_dwMonarchCooltimelimit[MI_SUMMON] = PASSES_PER_SEC(MC_SUMMON);
  7238.  
  7239. m_dwMonarchCooltime[MI_HEAL] -= PASSES_PER_SEC(GetMCL(MI_HEAL));
  7240. m_dwMonarchCooltime[MI_WARP] -= PASSES_PER_SEC(GetMCL(MI_WARP));
  7241. m_dwMonarchCooltime[MI_TRANSFER] -= PASSES_PER_SEC(GetMCL(MI_TRANSFER));
  7242. m_dwMonarchCooltime[MI_TAX] -= PASSES_PER_SEC(GetMCL(MI_TAX));
  7243. m_dwMonarchCooltime[MI_SUMMON] -= PASSES_PER_SEC(GetMCL(MI_SUMMON));
  7244. }
  7245.  
  7246. DWORD CHARACTER::GetMC(enum MONARCH_INDEX e) const
  7247. {
  7248. return m_dwMonarchCooltime[e];
  7249. }
  7250.  
  7251. void CHARACTER::SetMC(enum MONARCH_INDEX e)
  7252. {
  7253. m_dwMonarchCooltime[e] = thecore_pulse();
  7254. }
  7255.  
  7256. bool CHARACTER::IsMCOK(enum MONARCH_INDEX e) const
  7257. {
  7258. int iPulse = thecore_pulse();
  7259.  
  7260. if ((iPulse - GetMC(e)) < GetMCL(e))
  7261. {
  7262. if (test_server)
  7263. sys_log(0, " Pulse %d cooltime %d, limit %d", iPulse, GetMC(e), GetMCL(e));
  7264.  
  7265. return false;
  7266. }
  7267.  
  7268. if (test_server)
  7269. sys_log(0, " Pulse %d cooltime %d, limit %d", iPulse, GetMC(e), GetMCL(e));
  7270.  
  7271. return true;
  7272. }
  7273.  
  7274. DWORD CHARACTER::GetMCL(enum MONARCH_INDEX e) const
  7275. {
  7276. return m_dwMonarchCooltimelimit[e];
  7277. }
  7278.  
  7279. DWORD CHARACTER::GetMCLTime(enum MONARCH_INDEX e) const
  7280. {
  7281. int iPulse = thecore_pulse();
  7282.  
  7283. if (test_server)
  7284. sys_log(0, " Pulse %d cooltime %d, limit %d", iPulse, GetMC(e), GetMCL(e));
  7285.  
  7286. return (GetMCL(e)) / passes_per_sec - (iPulse - GetMC(e)) / passes_per_sec;
  7287. }
  7288.  
  7289. bool CHARACTER::IsSiegeNPC() const
  7290. {
  7291. return IsNPC() && (GetRaceNum() == 11000 || GetRaceNum() == 11002 || GetRaceNum() == 11004);
  7292. }
  7293.  
  7294. //------------------------------------------------
  7295. void CHARACTER::UpdateDepositPulse()
  7296. {
  7297. m_deposit_pulse = thecore_pulse() + PASSES_PER_SEC(60*5); // 5ºÐ
  7298. }
  7299.  
  7300. bool CHARACTER::CanDeposit() const
  7301. {
  7302. return (m_deposit_pulse == 0 || (m_deposit_pulse < thecore_pulse()));
  7303. }
  7304. //------------------------------------------------
  7305.  
  7306. ESex GET_SEX(LPCHARACTER ch)
  7307. {
  7308. switch (ch->GetRaceNum())
  7309. {
  7310. case MAIN_RACE_WARRIOR_M:
  7311. case MAIN_RACE_SURA_M:
  7312. case MAIN_RACE_ASSASSIN_M:
  7313. case MAIN_RACE_SHAMAN_M:
  7314. case MAIN_RACE_WOLFMAN_M:
  7315. return SEX_MALE;
  7316.  
  7317. case MAIN_RACE_ASSASSIN_W:
  7318. case MAIN_RACE_SHAMAN_W:
  7319. case MAIN_RACE_WARRIOR_W:
  7320. case MAIN_RACE_SURA_W:
  7321. return SEX_FEMALE;
  7322. }
  7323.  
  7324. /* default sex = male */
  7325. return SEX_MALE;
  7326. }
  7327.  
  7328. int CHARACTER::GetHPPct() const
  7329. {
  7330. return (GetHP() * 100) / GetMaxHP();
  7331. }
  7332.  
  7333. bool CHARACTER::IsBerserk() const
  7334. {
  7335. if (m_pkMobInst != NULL)
  7336. return m_pkMobInst->m_IsBerserk;
  7337. else
  7338. return false;
  7339. }
  7340.  
  7341. void CHARACTER::SetBerserk(bool mode)
  7342. {
  7343. if (m_pkMobInst != NULL)
  7344. m_pkMobInst->m_IsBerserk = mode;
  7345. }
  7346.  
  7347. bool CHARACTER::IsGodSpeed() const
  7348. {
  7349. if (m_pkMobInst != NULL)
  7350. {
  7351. return m_pkMobInst->m_IsGodSpeed;
  7352. }
  7353. else
  7354. {
  7355. return false;
  7356. }
  7357. }
  7358.  
  7359. void CHARACTER::SetGodSpeed(bool mode)
  7360. {
  7361. if (m_pkMobInst != NULL)
  7362. {
  7363. m_pkMobInst->m_IsGodSpeed = mode;
  7364.  
  7365. if (mode == true)
  7366. {
  7367. SetPoint(POINT_ATT_SPEED, 250);
  7368. }
  7369. else
  7370. {
  7371. SetPoint(POINT_ATT_SPEED, m_pkMobData->m_table.sAttackSpeed);
  7372. }
  7373. }
  7374. }
  7375.  
  7376. bool CHARACTER::IsDeathBlow() const
  7377. {
  7378. if (number(1, 100) <= m_pkMobData->m_table.bDeathBlowPoint)
  7379. {
  7380. return true;
  7381. }
  7382. else
  7383. {
  7384. return false;
  7385. }
  7386. }
  7387.  
  7388. struct FFindReviver
  7389. {
  7390. FFindReviver()
  7391. {
  7392. pChar = NULL;
  7393. HasReviver = false;
  7394. }
  7395.  
  7396. void operator() (LPCHARACTER ch)
  7397. {
  7398. if (ch->IsMonster() != true)
  7399. {
  7400. return;
  7401. }
  7402.  
  7403. if (ch->IsReviver() == true && pChar != ch && ch->IsDead() != true)
  7404. {
  7405. if (number(1, 100) <= ch->GetMobTable().bRevivePoint)
  7406. {
  7407. HasReviver = true;
  7408. pChar = ch;
  7409. }
  7410. }
  7411. }
  7412.  
  7413. LPCHARACTER pChar;
  7414. bool HasReviver;
  7415. };
  7416.  
  7417. bool CHARACTER::HasReviverInParty() const
  7418. {
  7419. LPPARTY party = GetParty();
  7420.  
  7421. if (party != NULL)
  7422. {
  7423. if (party->GetMemberCount() == 1) return false;
  7424.  
  7425. FFindReviver f;
  7426. party->ForEachMemberPtr(f);
  7427. return f.HasReviver;
  7428. }
  7429.  
  7430. return false;
  7431. }
  7432.  
  7433. bool CHARACTER::IsRevive() const
  7434. {
  7435. if (m_pkMobInst != NULL)
  7436. {
  7437. return m_pkMobInst->m_IsRevive;
  7438. }
  7439.  
  7440. return false;
  7441. }
  7442.  
  7443. void CHARACTER::SetRevive(bool mode)
  7444. {
  7445. if (m_pkMobInst != NULL)
  7446. {
  7447. m_pkMobInst->m_IsRevive = mode;
  7448. }
  7449. }
  7450.  
  7451. #define IS_SPEED_HACK_PLAYER(ch) (ch->m_speed_hack_count > SPEEDHACK_LIMIT_COUNT)
  7452.  
  7453. EVENTFUNC(check_speedhack_event)
  7454. {
  7455. char_event_info* info = dynamic_cast<char_event_info*>( event->info );
  7456. if ( info == NULL )
  7457. {
  7458. sys_err( "check_speedhack_event> <Factor> Null pointer" );
  7459. return 0;
  7460. }
  7461.  
  7462. LPCHARACTER ch = info->ch;
  7463.  
  7464. if (NULL == ch || ch->IsNPC())
  7465. return 0;
  7466.  
  7467. if (IS_SPEED_HACK_PLAYER(ch))
  7468. {
  7469. // write hack log
  7470. LogManager::instance().SpeedHackLog(ch->GetPlayerID(), ch->GetX(), ch->GetY(), ch->m_speed_hack_count);
  7471.  
  7472. if (false == LC_IsEurope())
  7473. {
  7474. // close connection
  7475. LPDESC desc = ch->GetDesc();
  7476.  
  7477. if (desc)
  7478. {
  7479. DESC_MANAGER::instance().DestroyDesc(desc);
  7480. return 0;
  7481. }
  7482. }
  7483. }
  7484.  
  7485. ch->m_speed_hack_count = 0;
  7486.  
  7487. ch->ResetComboHackCount();
  7488. return PASSES_PER_SEC(60);
  7489. }
  7490.  
  7491. void CHARACTER::StartCheckSpeedHackEvent()
  7492. {
  7493. if (m_pkCheckSpeedHackEvent)
  7494. return;
  7495.  
  7496. char_event_info* info = AllocEventInfo<char_event_info>();
  7497.  
  7498. info->ch = this;
  7499.  
  7500. m_pkCheckSpeedHackEvent = event_create(check_speedhack_event, info, PASSES_PER_SEC(60)); // 1ºÐ
  7501. }
  7502.  
  7503. void CHARACTER::GoHome()
  7504. {
  7505. WarpSet(EMPIRE_START_X(GetEmpire()), EMPIRE_START_Y(GetEmpire()));
  7506. }
  7507.  
  7508. void CHARACTER::SendGuildName(CGuild* pGuild)
  7509. {
  7510. if (NULL == pGuild) return;
  7511.  
  7512. DESC *desc = GetDesc();
  7513.  
  7514. if (NULL == desc) return;
  7515. if (m_known_guild.find(pGuild->GetID()) != m_known_guild.end()) return;
  7516.  
  7517. m_known_guild.insert(pGuild->GetID());
  7518.  
  7519. TPacketGCGuildName pack;
  7520. memset(&pack, 0x00, sizeof(pack));
  7521.  
  7522. pack.header = HEADER_GC_GUILD;
  7523. pack.subheader = GUILD_SUBHEADER_GC_GUILD_NAME;
  7524. pack.size = sizeof(TPacketGCGuildName);
  7525. pack.guildID = pGuild->GetID();
  7526. memcpy(pack.guildName, pGuild->GetName(), GUILD_NAME_MAX_LEN);
  7527.  
  7528. desc->Packet(&pack, sizeof(pack));
  7529. }
  7530.  
  7531. void CHARACTER::SendGuildName(DWORD dwGuildID)
  7532. {
  7533. SendGuildName(CGuildManager::instance().FindGuild(dwGuildID));
  7534. }
  7535.  
  7536. EVENTFUNC(destroy_when_idle_event)
  7537. {
  7538. char_event_info* info = dynamic_cast<char_event_info*>( event->info );
  7539. if ( info == NULL )
  7540. {
  7541. sys_err( "destroy_when_idle_event> <Factor> Null pointer" );
  7542. return 0;
  7543. }
  7544.  
  7545. LPCHARACTER ch = info->ch;
  7546. if (ch == NULL) { // <Factor>
  7547. return 0;
  7548. }
  7549.  
  7550. if (ch->GetVictim())
  7551. {
  7552. return PASSES_PER_SEC(300);
  7553. }
  7554.  
  7555. sys_log(1, "DESTROY_WHEN_IDLE: %s", ch->GetName());
  7556.  
  7557. ch->m_pkDestroyWhenIdleEvent = NULL;
  7558. M2_DESTROY_CHARACTER(ch);
  7559. return 0;
  7560. }
  7561.  
  7562. void CHARACTER::StartDestroyWhenIdleEvent()
  7563. {
  7564. if (m_pkDestroyWhenIdleEvent)
  7565. return;
  7566.  
  7567. char_event_info* info = AllocEventInfo<char_event_info>();
  7568.  
  7569. info->ch = this;
  7570.  
  7571. m_pkDestroyWhenIdleEvent = event_create(destroy_when_idle_event, info, PASSES_PER_SEC(300));
  7572. }
  7573.  
  7574. void CHARACTER::SetComboSequence(BYTE seq)
  7575. {
  7576. m_bComboSequence = seq;
  7577. }
  7578.  
  7579. BYTE CHARACTER::GetComboSequence() const
  7580. {
  7581. return m_bComboSequence;
  7582. }
  7583.  
  7584. void CHARACTER::SetLastComboTime(DWORD time)
  7585. {
  7586. m_dwLastComboTime = time;
  7587. }
  7588.  
  7589. DWORD CHARACTER::GetLastComboTime() const
  7590. {
  7591. return m_dwLastComboTime;
  7592. }
  7593.  
  7594. void CHARACTER::SetValidComboInterval(int interval)
  7595. {
  7596. m_iValidComboInterval = interval;
  7597. }
  7598.  
  7599. int CHARACTER::GetValidComboInterval() const
  7600. {
  7601. return m_iValidComboInterval;
  7602. }
  7603.  
  7604. BYTE CHARACTER::GetComboIndex() const
  7605. {
  7606. return m_bComboIndex;
  7607. }
  7608.  
  7609. void CHARACTER::IncreaseComboHackCount(int k)
  7610. {
  7611. m_iComboHackCount += k;
  7612. if (m_iComboHackCount >= 10)
  7613. {
  7614. if (GetJob() == JOB_WOLFMAN && m_iComboHackCount <= 20)
  7615. {
  7616. return;
  7617. }
  7618.  
  7619. if (GetDesc())
  7620. {
  7621. if (GetDesc()->DelayedDisconnect(number(2, 7)))
  7622. {
  7623. sys_log(0, "COMBO_HACK_DISCONNECT: %s count: %d", GetName(), m_iComboHackCount);
  7624. LogManager::instance().HackLog("Combo", this);
  7625. }
  7626. }
  7627. }
  7628. }
  7629.  
  7630. void CHARACTER::ResetComboHackCount()
  7631. {
  7632. m_iComboHackCount = 0;
  7633. }
  7634.  
  7635. void CHARACTER::SkipComboAttackByTime(int interval)
  7636. {
  7637. m_dwSkipComboAttackByTime = get_dword_time() + interval;
  7638. }
  7639.  
  7640. DWORD CHARACTER::GetSkipComboAttackByTime() const
  7641. {
  7642. return m_dwSkipComboAttackByTime;
  7643. }
  7644.  
  7645. void CHARACTER::ResetChatCounter()
  7646. {
  7647. m_bChatCounter = 0;
  7648. }
  7649.  
  7650. BYTE CHARACTER::IncreaseChatCounter()
  7651. {
  7652. return ++m_bChatCounter;
  7653. }
  7654.  
  7655. BYTE CHARACTER::GetChatCounter() const
  7656. {
  7657. return m_bChatCounter;
  7658. }
  7659.  
  7660. // ¸»À̳ª ´Ù¸¥°ÍÀ» Ÿ°í ÀÖ³ª?
  7661. bool CHARACTER::IsRiding() const
  7662. {
  7663. return IsHorseRiding() || GetMountVnum();
  7664. }
  7665.  
  7666. bool CHARACTER::CanWarp() const
  7667. {
  7668. const int iPulse = thecore_pulse();
  7669. const int limit_time = PASSES_PER_SEC(g_nPortalLimitTime);
  7670.  
  7671. if ((iPulse - GetSafeboxLoadTime()) < limit_time)
  7672. return false;
  7673.  
  7674. if ((iPulse - GetExchangeTime()) < limit_time)
  7675. return false;
  7676.  
  7677. if ((iPulse - GetMyShopTime()) < limit_time)
  7678. return false;
  7679.  
  7680. if ((iPulse - GetRefineTime()) < limit_time)
  7681. return false;
  7682.  
  7683. if (GetExchange() || GetMyShop() || GetShopOwner() || IsOpenSafebox() || IsCubeOpen() || IsAcceOpen() || GetOfflineShopOwner())
  7684. return false;
  7685.  
  7686. return true;
  7687. }
  7688.  
  7689. DWORD CHARACTER::GetNextExp() const
  7690. {
  7691. if (PLAYER_EXP_TABLE_MAX < GetLevel())
  7692. return 2500000000;
  7693. else
  7694. return exp_table[GetLevel()];
  7695. }
  7696.  
  7697. int CHARACTER::GetSkillPowerByLevel(int level, bool bMob) const
  7698. {
  7699. return CTableBySkill::instance().GetSkillPowerByLevelFromType(GetJob(), GetSkillGroup(), MINMAX(0, level, SKILL_MAX_LEVEL), bMob);
  7700. }
  7701.  
  7702. void CHARACTER::SetOfflineShopSign(const char * c_szSign)
  7703. {
  7704. char szSign[SHOP_SIGN_MAX_LEN + 1];
  7705. strlcpy(szSign, c_szSign, sizeof(szSign));
  7706. m_stOfflineShopSign = szSign;
  7707. }
  7708.  
  7709. void CHARACTER::DestroyOfflineShop()
  7710. {
  7711. DBManager::instance().DirectQuery("DELETE FROM %soffline_shop_npc WHERE owner_id = %u", get_table_postfix(), GetOfflineShopRealOwner());
  7712. LPOFFLINESHOP pkOfflineShop = GetOfflineShop();
  7713. if (pkOfflineShop)
  7714. pkOfflineShop->RemoveAllGuest();
  7715. M2_DESTROY_CHARACTER(this);
  7716. }
  7717.  
  7718. #ifdef GIFT_SYSTEM
  7719. #include <boost/algorithm/string.hpp>
  7720. EVENTFUNC(gift_refresh_event)
  7721. {
  7722. char_event_info* info = dynamic_cast<char_event_info*>(event->info);
  7723. if (info == NULL)
  7724. {
  7725. sys_err("gift_refresh_event> <Factor> Null pointer");
  7726. return 0;
  7727. }
  7728.  
  7729. LPCHARACTER ch = info->ch;
  7730.  
  7731. if (NULL == ch || ch->IsNPC())
  7732. return 0;
  7733. ch->RefreshGift();
  7734. return PASSES_PER_SEC(5 * 60);
  7735. }
  7736. void CHARACTER::StartRefreshGift()
  7737. {
  7738. if (m_pkGiftRefresh)
  7739. return;
  7740. char_event_info* info = AllocEventInfo<char_event_info>();
  7741.  
  7742. info->ch = this;
  7743. m_pkGiftRefresh = event_create(gift_refresh_event, info, PASSES_PER_SEC(1)); // 1o?
  7744. }
  7745. void SendGift(LPCHARACTER ch, TGiftItem item)
  7746. {
  7747. char szSockets[1024] = { '\0' };
  7748. char *tempSockets = szSockets;
  7749. for (int soc = 0; soc < ITEM_SOCKET_MAX_NUM; soc++)
  7750. tempSockets += sprintf(tempSockets, "%ld%s", item.alSockets[soc], (soc<ITEM_SOCKET_MAX_NUM - 1 ? "|" : ""));
  7751. char szAttrs[1024] = { '\0' };
  7752. char *tempAttrs = szAttrs;
  7753. for (int attr = 0; attr < ITEM_ATTRIBUTE_MAX_NUM; attr++)
  7754. tempAttrs += sprintf(tempAttrs, "%u,%d%s", item.aAttr[attr].bType, item.aAttr[attr].sValue, (attr<ITEM_ATTRIBUTE_MAX_NUM - 1 ? "|" : ""));
  7755. #ifdef FULL_YANG
  7756. ch->ChatPacket(CHAT_TYPE_COMMAND, "gift_item %d %d %lld %d %d %s %s %s %s", item.id, item.vnum, item.count, item.pos, item.dwDateAdd, item.szFrom, item.szReason, szSockets, szAttrs);
  7757. #else
  7758. ch->ChatPacket(CHAT_TYPE_COMMAND, "gift_item %d %d %d %d %d %s %s %s %s", item.id, item.vnum, item.count, item.pos, item.dwDateAdd, item.szFrom, item.szReason, szSockets, szAttrs);
  7759. #endif
  7760. }
  7761. void CHARACTER::LoadGiftPage(int page)
  7762. {
  7763. page = MINMAX(1, page, m_mapGiftGrid.size());
  7764. ChatPacket(CHAT_TYPE_COMMAND, "gift_clear");
  7765. GIFT_MAP::iterator it = m_mapGiftGrid.find(page);
  7766. if (it == m_mapGiftGrid.end())
  7767. return;
  7768. m_dwLastGiftPage = page;
  7769. for (int i = 0; i < it->second.size(); i++)
  7770. SendGift(this, it->second[i]);
  7771. ChatPacket(CHAT_TYPE_COMMAND, "gift_load");
  7772.  
  7773. }
  7774. static CGrid* grid;
  7775. void CHARACTER::AddGiftGrid(int page)
  7776. {
  7777. if (m_mapGiftGrid.find(page) == m_mapGiftGrid.end())
  7778. {
  7779. std::vector<TGiftItem> vec;
  7780. m_mapGiftGrid.insert(std::make_pair(page, vec));
  7781. }
  7782.  
  7783. }
  7784. int CHARACTER::AddGiftGridItem( int page, int size)
  7785. {
  7786. AddGiftGrid(page);
  7787. int iPos = grid->FindBlank(1, size);
  7788.  
  7789. if (iPos < 0)
  7790. return -1;
  7791.  
  7792. if (!grid->IsEmpty(iPos, 1, size))
  7793. return -1;
  7794.  
  7795.  
  7796. grid->Put(iPos, 1, size);
  7797. return iPos;
  7798.  
  7799. }
  7800. void CHARACTER::RefreshGift()
  7801. {
  7802. char szSockets[1024] = { '\0' };
  7803. char *tempSockets = szSockets;
  7804. for (int i = 0; i < ITEM_SOCKET_MAX_NUM; i++)
  7805. {
  7806. tempSockets += sprintf(tempSockets, "socket%d", i);
  7807.  
  7808. if (i<ITEM_SOCKET_MAX_NUM - 1)
  7809. tempSockets += sprintf(tempSockets, ",");
  7810. }
  7811. char szAttrs[1024] = { '\0' };
  7812. char *tempAttrs = szAttrs;
  7813. for (int i = 0; i < ITEM_ATTRIBUTE_MAX_NUM; i++)
  7814. {
  7815. if (i < 7)
  7816. tempAttrs += sprintf(tempAttrs, "attrtype%d,attrvalue%d", i, i);
  7817. else
  7818. tempAttrs += sprintf(tempAttrs, "applytype%d,applyvalue%d", i - 7, i - 7);
  7819. if (i<ITEM_ATTRIBUTE_MAX_NUM - 1)
  7820. tempAttrs += sprintf(tempAttrs, ",");
  7821. }
  7822. SQLMsg * pkMsg(DBManager::instance().DirectQuery("SELECT id,vnum,count,unix_timestamp(date_add),replace(reason,' ','_'),replace(`from`,' ','_'),%s,%s from player_gift where owner_id = %d and status = 'WAIT' ORDER BY date_add ", szSockets, szAttrs, GetPlayerID()));
  7823. SQLResult * pRes = pkMsg->Get();
  7824. m_mapGiftGrid.clear();
  7825. grid = M2_NEW CGrid(15, 8);
  7826. grid->Clear();
  7827. int page = 1;
  7828. if (pRes->uiNumRows>0)
  7829. {
  7830. AddGiftGrid(page);
  7831. MYSQL_ROW row;
  7832. while ((row = mysql_fetch_row(pRes->pSQLResult)) != NULL)
  7833. {
  7834. int col = 0;
  7835. TGiftItem item;
  7836. memset(&item, 0, sizeof(item));
  7837. str_to_number(item.id, row[col++]);
  7838. str_to_number(item.vnum, row[col++]);
  7839. str_to_number(item.count, row[col++]);
  7840. str_to_number(item.dwDateAdd, row[col++]);
  7841. strlcpy(item.szReason, row[col++], sizeof(item.szReason) - 1);
  7842. strlcpy(item.szFrom, row[col++], sizeof(item.szFrom) - 1);
  7843. for (int i = 0; i < ITEM_SOCKET_MAX_NUM; i++)
  7844. str_to_number(item.alSockets[i], row[col++]);
  7845. for (int i = 0; i < ITEM_ATTRIBUTE_MAX_NUM; i++)
  7846. {
  7847. str_to_number(item.aAttr[i].bType, row[col++]);
  7848. str_to_number(item.aAttr[i].sValue, row[col++]);
  7849. }
  7850.  
  7851. const TItemTable * item_table = ITEM_MANAGER::instance().GetTable(item.vnum);
  7852. if (!item_table)
  7853. continue;
  7854. int iPos = AddGiftGridItem( page, item_table->bSize);
  7855. if (iPos < 0)
  7856. {
  7857. page++;
  7858. grid->Clear();
  7859. iPos = AddGiftGridItem(page, item_table->bSize);
  7860. if (iPos < 0)
  7861. {
  7862. sys_err("iPos <0");
  7863. break;
  7864. }
  7865. }
  7866. item.pos = iPos;
  7867. m_mapGiftGrid[page].push_back(item);
  7868.  
  7869. }
  7870. M2_DELETE(grid);
  7871. }
  7872. if(GetGiftPages()>0)
  7873. ChatPacket(CHAT_TYPE_COMMAND, "gift_info %d", GetGiftPages());
  7874. }
  7875. #endif
  7876.  
  7877. #ifdef OFFLINE_SHOP
  7878.  
  7879. extern std::map<DWORD, DWORD> g_ShopIndexCount;
  7880. extern std::map<int, TShopCost> g_ShopCosts;
  7881. void CHARACTER::OpenMyShop(const char * c_pszSign, TShopItemTable * pTable, BYTE bItemCount, DWORD id)
  7882. {
  7883.  
  7884. if (g_ShopCosts.find(id) == g_ShopCosts.end())
  7885. {
  7886. sys_log(0, "Shop days error %s %d", c_pszSign, id);
  7887. return;
  7888. }
  7889. int days = g_ShopCosts[id].days;
  7890. long long price = g_ShopCosts[id].price;
  7891. if (price > 0 && GetGold() < price)
  7892. {
  7893. ChatPacket(CHAT_TYPE_INFO, LC_TEXT( "SHOP_NEED_MONEY"), price);
  7894. return;
  7895. }
  7896. if (days == 0 && GetPart(PART_MAIN) > 2)
  7897. {
  7898. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("°©zER?atl???R?»ó?R?z­ L?R?R??."));
  7899. return;
  7900. }
  7901.  
  7902. if (GetMyShop())
  7903. {
  7904. CloseMyShop();
  7905. return;
  7906. }
  7907.  
  7908.  
  7909. int gShopMax = quest::CQuestManager::Instance().GetEventFlag("shop_max");
  7910. if (m_mapshops.size() >= (gShopMax ? gShopMax : 2))
  7911. {
  7912. ChatPacket(CHAT_TYPE_INFO, LC_TEXT( "SHOP_MAX_ERR"));
  7913. return;
  7914. }
  7915.  
  7916.  
  7917. if (g_ShopIndexCount.count(GetMapIndex())>0)
  7918. {
  7919. int shop_max = g_ShopIndexCount[GetMapIndex()];
  7920. bool block = false;
  7921.  
  7922. #ifdef SHOP_ONLY_ALLOWED_INDEX
  7923. if (shop_max > 0)
  7924. {
  7925. #else
  7926. if (shop_max == 0)
  7927. block = true;
  7928. else{
  7929. #endif
  7930. std::auto_ptr<SQLMsg> pkMsg(DBManager::instance().DirectQuery("SELECT map_index from player_shop WHERE channel=%d and status='OK' and map_index=%d", g_bChannel, GetMapIndex()));
  7931. SQLResult * pRes = pkMsg->Get();
  7932. if (pRes->uiNumRows >= shop_max)
  7933. block = true;
  7934. }
  7935. if (block)
  7936. {
  7937. ChatPacket(CHAT_TYPE_INFO, LC_TEXT( "SHOP_MAP_MAX"));
  7938. return;
  7939. }
  7940. }
  7941. #ifdef SHOP_ONLY_ALLOWED_INDEX
  7942. else
  7943. {
  7944. ChatPacket(CHAT_TYPE_INFO, LC_TEXT( "SHOP_CANNOT_OPEN_HERE"));
  7945. return;
  7946. }
  7947. #endif
  7948. if (GetMyShop()) // AI1I 1YAI ?­·Á A?¸¸?´Ý´Â?.
  7949. {
  7950. CloseMyShop();
  7951. return;
  7952. }
  7953. #ifndef FULL_YANG
  7954. int64_t nTotalMoney = 0;
  7955.  
  7956. for (int n = 0; n < bItemCount; ++n)
  7957. {
  7958. nTotalMoney += static_cast<int64_t> ((pTable + n)->price);
  7959. }
  7960.  
  7961. nTotalMoney += static_cast<int64_t> (GetGold());
  7962.  
  7963. if (GOLD_MAX <= nTotalMoney)
  7964. {
  7965. sys_err("[OVERFLOW_GOLD] Overflow (GOLD_MAX) id %u name %s", GetPlayerID(), GetName());
  7966. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("20ld l
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement