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