Guest User

char.cpp

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