Guest User

item_manager.cpp

a guest
May 23rd, 2020
93
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 49.89 KB | None | 0 0
  1. #include "stdafx.h"
  2. #include "utils.h"
  3. #include "config.h"
  4. #include "char.h"
  5. #include "char_manager.h"
  6. #include "desc_client.h"
  7. #include "db.h"
  8. #include "log.h"
  9. #include "skill.h"
  10. #include "text_file_loader.h"
  11. #include "priv_manager.h"
  12. #include "questmanager.h"
  13. #include "unique_item.h"
  14. #include "safebox.h"
  15. #include "blend_item.h"
  16. #include "dev_log.h"
  17. #include "locale_service.h"
  18. #include "item.h"
  19. #include "item_manager.h"
  20.  
  21. #include "../../common/VnumHelper.h"
  22. #include "DragonSoul.h"
  23. #ifndef ENABLE_CUBE_RENEWAL_WORLDARD
  24. #include "cube.h"
  25. #else
  26. #include "cuberenewal.h"
  27. #endif
  28.  
  29. ITEM_MANAGER::ITEM_MANAGER()
  30.     : m_iTopOfTable(0), m_dwVIDCount(0), m_dwCurrentID(0)
  31. {
  32.     m_ItemIDRange.dwMin = m_ItemIDRange.dwMax = m_ItemIDRange.dwUsableItemIDMin = 0;
  33.     m_ItemIDSpareRange.dwMin = m_ItemIDSpareRange.dwMax = m_ItemIDSpareRange.dwUsableItemIDMin = 0;
  34. }
  35.  
  36. ITEM_MANAGER::~ITEM_MANAGER()
  37. {
  38.     Destroy();
  39. }
  40.  
  41. void ITEM_MANAGER::Destroy()
  42. {
  43.     itertype(m_VIDMap) it = m_VIDMap.begin();
  44.     for ( ; it != m_VIDMap.end(); ++it) {
  45. #ifdef M2_USE_POOL
  46.         pool_.Destroy(it->second);
  47. #else
  48.         M2_DELETE(it->second);
  49. #endif
  50.     }
  51.     m_VIDMap.clear();
  52. }
  53.  
  54. void ITEM_MANAGER::GracefulShutdown()
  55. {
  56.     TR1_NS::unordered_set<LPITEM>::iterator it = m_set_pkItemForDelayedSave.begin();
  57.  
  58.     while (it != m_set_pkItemForDelayedSave.end())
  59.         SaveSingleItem(*(it++));
  60.  
  61.     m_set_pkItemForDelayedSave.clear();
  62. }
  63.  
  64. bool ITEM_MANAGER::Initialize(TItemTable * table, int size)
  65. {
  66.     if (!m_vec_prototype.empty())
  67.         m_vec_prototype.clear();
  68.  
  69.     int i;
  70.  
  71.     m_vec_prototype.resize(size);
  72.     thecore_memcpy(&m_vec_prototype[0], table, sizeof(TItemTable) * size);
  73.     for (int i = 0; i < size; i++)
  74.     {
  75.         if (0 != m_vec_prototype[i].dwVnumRange)
  76.         {
  77.             m_vec_item_vnum_range_info.push_back( &m_vec_prototype[i]);
  78.         }
  79.     }
  80.  
  81.     m_map_ItemRefineFrom.clear();
  82.     for (i = 0; i < size; ++i)
  83.     {
  84.  
  85.         if (m_vec_prototype[i].dwRefinedVnum)
  86.             m_map_ItemRefineFrom.insert(std::make_pair(m_vec_prototype[i].dwRefinedVnum, m_vec_prototype[i].dwVnum));
  87.  
  88.         // NOTE : QUEST_GIVE 플래그는 npc 이벤트로 발생.
  89.         if (m_vec_prototype[i].bType == ITEM_QUEST || IS_SET(m_vec_prototype[i].dwFlags, ITEM_FLAG_QUEST_USE | ITEM_FLAG_QUEST_USE_MULTIPLE))
  90.             quest::CQuestManager::instance().RegisterNPCVnum(m_vec_prototype[i].dwVnum);
  91.  
  92.         m_map_vid.insert( std::map<DWORD,TItemTable>::value_type( m_vec_prototype[i].dwVnum, m_vec_prototype[i] ) );
  93.         if ( test_server )
  94.             sys_log( 0, "ITEM_INFO %d %s ", m_vec_prototype[i].dwVnum, m_vec_prototype[i].szName );
  95.     }
  96.  
  97.     int len = 0, len2;
  98.     char buf[512];
  99.  
  100.     for (i = 0; i < size; ++i)
  101.     {
  102.         len2 = snprintf(buf + len, sizeof(buf) - len, "%5u %-16s", m_vec_prototype[i].dwVnum, m_vec_prototype[i].szLocaleName);
  103.  
  104.         if (len2 < 0 || len2 >= (int) sizeof(buf) - len)
  105.             len += (sizeof(buf) - len) - 1;
  106.         else
  107.             len += len2;
  108.  
  109.         if (!((i + 1) % 4))
  110.         {
  111.             if ( !test_server )
  112.                 sys_log(0, "%s", buf);
  113.             len = 0;
  114.         }
  115.         else
  116.         {
  117.             buf[len++] = '\t';
  118.             buf[len] = '\0';
  119.         }
  120.     }
  121.  
  122.     if ((i + 1) % 4)
  123.     {
  124.         if ( !test_server )
  125.             sys_log(0, "%s", buf);
  126.     }
  127.  
  128.     ITEM_VID_MAP::iterator it = m_VIDMap.begin();
  129.  
  130.     sys_log (1, "ITEM_VID_MAP %d", m_VIDMap.size() );
  131.  
  132.     while (it != m_VIDMap.end())
  133.     {
  134.         LPITEM item = it->second;
  135.         ++it;
  136.  
  137.         const TItemTable* tableInfo = GetTable(item->GetOriginalVnum());
  138.  
  139.         if (NULL == tableInfo)
  140.         {
  141.             sys_err("cannot reset item table");
  142.             item->SetProto(NULL);
  143.         }
  144.  
  145.         item->SetProto(tableInfo);
  146.     }
  147.  
  148.     return true;
  149. }
  150.  
  151. LPITEM ITEM_MANAGER::CreateItem(DWORD vnum, DWORD count, DWORD id, bool bTryMagic, int iRarePct, bool bSkipSave)
  152. {
  153.     if (0 == vnum)
  154.         return NULL;
  155.  
  156.     DWORD dwMaskVnum = 0;
  157.     if (GetMaskVnum(vnum))
  158.     {
  159.         dwMaskVnum = GetMaskVnum(vnum);
  160.     }
  161.  
  162.     if (LC_IsKorea() || LC_IsYMIR())
  163.     {
  164.         if (vnum == 50300 && bTryMagic)
  165.         {
  166.             // 수련서를 아이템 번호를 다르게 만들어 준다.
  167.             DWORD dwSkillVnum;
  168.  
  169.             do
  170.             {
  171.                 dwSkillVnum = number(1, 111);
  172.  
  173.                 CSkillProto * pkSk = CSkillManager::instance().Get(dwSkillVnum);
  174.  
  175.                 if (!pkSk)
  176.                     continue;
  177.  
  178.                 break;
  179.             } while (1);
  180.  
  181.             vnum = 50400 + dwSkillVnum;
  182.         }
  183.     }
  184.  
  185.     const TItemTable* table = GetTable(vnum);
  186.  
  187.     if (NULL == table)
  188.         return NULL;
  189.  
  190.     LPITEM item = NULL;
  191.  
  192.     //id로 검사해서 존재한다면 -- 리턴!
  193.     if (m_map_pkItemByID.find(id) != m_map_pkItemByID.end())
  194.     {
  195.         item = m_map_pkItemByID[id];
  196.         LPCHARACTER owner = item->GetOwner();
  197.         sys_err("ITEM_ID_DUP: %u %s owner %p", id, item->GetName(), get_pointer(owner));
  198.         return NULL;
  199.     }
  200.  
  201.     //아이템 하나 할당하고
  202. #ifdef M2_USE_POOL
  203.     item = pool_.Construct();
  204. #else
  205.     item = M2_NEW CItem(vnum);
  206. #endif
  207.  
  208.     bool bIsNewItem = (0 == id);
  209.  
  210.     //초기화 하고. 테이블 셋하고
  211.     item->Initialize();
  212.     item->SetProto(table);
  213.     item->SetMaskVnum(dwMaskVnum);
  214.  
  215.     if (item->GetType() == ITEM_ELK) // 돈은 ID가 필요없고 저장도 필요없다.
  216.         item->SetSkipSave(true);
  217. #ifdef __ENABLE_CHEQUE_SYSTEM__
  218.     else if (item->GetType() == ITEM_CHEQUE)
  219.         item->SetSkipSave(true);
  220. #endif // __ENABLE_CHEQUE_SYSTEM__
  221.     // Unique ID를 세팅하자
  222.     else if (!bIsNewItem)
  223.     {
  224.         item->SetID(id);
  225.         item->SetSkipSave(true);
  226.     }
  227.     else
  228.     {
  229.         item->SetID(GetNewID());
  230.  
  231.         if (item->GetType() == ITEM_UNIQUE) // 유니크 아이템은 생성시에 소켓에 남은시간을 기록한다.
  232.         {
  233.             if (item->GetValue(2) == 0)
  234.                 item->SetSocket(ITEM_SOCKET_UNIQUE_REMAIN_TIME, item->GetValue(0)); // 게임 시간 유니크
  235.             else
  236.             {
  237.                 //int globalTime = get_global_time();
  238.                 //int lastTime = item->GetValue(0);
  239.                 //int endTime = get_global_time() + item->GetValue(0);
  240.                 item->SetSocket(ITEM_SOCKET_UNIQUE_REMAIN_TIME, get_global_time() + item->GetValue(0)); // 실시간 유니크
  241.             }
  242.         }
  243.     }
  244.  
  245.  
  246.     switch (item->GetVnum())
  247.     {
  248.         case ITEM_AUTO_HP_RECOVERY_S:
  249.         case ITEM_AUTO_HP_RECOVERY_M:
  250.         case ITEM_AUTO_HP_RECOVERY_L:
  251.         case ITEM_AUTO_HP_RECOVERY_X:
  252.         case ITEM_AUTO_SP_RECOVERY_S:
  253.         case ITEM_AUTO_SP_RECOVERY_M:
  254.         case ITEM_AUTO_SP_RECOVERY_L:
  255.         case ITEM_AUTO_SP_RECOVERY_X:
  256.         case REWARD_BOX_ITEM_AUTO_SP_RECOVERY_XS:
  257.         case REWARD_BOX_ITEM_AUTO_SP_RECOVERY_S:
  258.         case REWARD_BOX_ITEM_AUTO_HP_RECOVERY_XS:
  259.         case REWARD_BOX_ITEM_AUTO_HP_RECOVERY_S:
  260.         case FUCKING_BRAZIL_ITEM_AUTO_SP_RECOVERY_S:
  261.         case FUCKING_BRAZIL_ITEM_AUTO_HP_RECOVERY_S:
  262.             if (bIsNewItem)
  263.                 item->SetSocket(2, item->GetValue(0), true);
  264.             else
  265.                 item->SetSocket(2, item->GetValue(0), false);
  266.             break;
  267.     }
  268.  
  269. #ifdef __ENABLE_CHEQUE_SYSTEM__
  270.     if (item->GetType() == ITEM_ELK || item->GetType() == ITEM_CHEQUE)
  271.         ;
  272. #else
  273.     if (item->GetType() == ITEM_ELK)
  274.         ;
  275. #endif // __ENABLE_CHEQUE_SYSTEM__
  276.     else if (item->IsStackable())  // 합칠 수 있는 아이템의 경우
  277.     {
  278.         count = MINMAX(1, count, ITEM_MAX_COUNT);
  279.  
  280.         if (bTryMagic && count <= 1 && IS_SET(item->GetFlag(), ITEM_FLAG_MAKECOUNT))
  281.             count = item->GetValue(1);
  282.     }
  283.     else
  284.         count = 1;
  285.  
  286.     item->SetVID(++m_dwVIDCount);
  287.  
  288.     if (bSkipSave == false)
  289.         m_VIDMap.insert(ITEM_VID_MAP::value_type(item->GetVID(), item));
  290.  
  291.     if (item->GetID() != 0 && bSkipSave == false)
  292.         m_map_pkItemByID.insert(std::map<DWORD, LPITEM>::value_type(item->GetID(), item));
  293.  
  294.     if (!item->SetCount(count))
  295.         return NULL;
  296.  
  297.     item->SetSkipSave(false);
  298.  
  299.     if (item->GetType() == ITEM_UNIQUE && item->GetValue(2) != 0)
  300.         item->StartUniqueExpireEvent();
  301.  
  302.     for (int i=0 ; i < ITEM_LIMIT_MAX_NUM ; i++)
  303.     {
  304.         // 아이템 생성 시점부터 사용하지 않아도 시간이 차감되는 방식
  305.         if (LIMIT_REAL_TIME == item->GetLimitType(i))
  306.         {
  307.             if (item->GetLimitValue(i))
  308.             {
  309.                 item->SetSocket(0, time(0) + item->GetLimitValue(i));
  310.             }
  311.             else
  312.             {
  313.                 item->SetSocket(0, time(0) + 60*60*24*7);
  314.             }
  315.  
  316.             item->StartRealTimeExpireEvent();
  317.         }
  318.  
  319.         // 기존 유니크 아이템처럼 착용시에만 사용가능 시간이 차감되는 방식
  320.         else if (LIMIT_TIMER_BASED_ON_WEAR == item->GetLimitType(i))
  321.         {
  322.             // 이미 착용중인 아이템이면 타이머를 시작하고, 새로 만드는 아이템은 사용 가능 시간을 세팅해준다. (
  323.             // 아이템몰로 지급하는 경우에는 이 로직에 들어오기 전에 Socket0 값이 세팅이 되어 있어야 한다.
  324.             if (true == item->IsEquipped())
  325.             {
  326.                 item->StartTimerBasedOnWearExpireEvent();
  327.             }
  328.             else if(0 == id)
  329.             {
  330.                 long duration = item->GetSocket(0);
  331.                 if (0 == duration)
  332.                     duration = item->GetLimitValue(i);
  333.  
  334.                 if (0 == duration)
  335.                     duration = 60 * 60 * 10;    // 정보가 아무것도 없으면 디폴트로 10시간 세팅
  336.  
  337.                 item->SetSocket(0, duration);
  338.             }
  339.         }
  340.     }
  341. #ifdef GACHA_SYSTEM
  342.     if(item->GetType() == ITEM_GACHA)
  343.         item->SetSocket(0, item->GetLimitValue(1));
  344. #endif
  345.     if (id == 0) // 새로 만드는 아이템일 때만 처리
  346.     {
  347.         // 새로추가되는 약초들일경우 성능을 다르게처리
  348.         if (ITEM_BLEND==item->GetType())
  349.         {
  350.             if (Blend_Item_find(item->GetVnum()))
  351.             {
  352.                 Blend_Item_set_value(item);
  353.                 return item;
  354.             }
  355.         }
  356.  
  357.         if (table->sAddonType)
  358.         {
  359.             item->ApplyAddon(table->sAddonType);
  360.         }
  361.  
  362.         if (bTryMagic)
  363.         {
  364.             if (iRarePct == -1)
  365.                 iRarePct = table->bAlterToMagicItemPct;
  366.  
  367.             if (number(1, 100) <= iRarePct)
  368.                 item->AlterToMagicItem();
  369.         }
  370.  
  371.         if (table->bGainSocketPct)
  372.             item->AlterToSocketItem(table->bGainSocketPct);
  373.  
  374.         // 50300 == 기술 수련서
  375.         if (vnum == 50300 || vnum == ITEM_SKILLFORGET_VNUM)
  376.         {
  377.             DWORD dwSkillVnum;
  378.  
  379.             do
  380.             {
  381.                 dwSkillVnum = number(1, 111);
  382.  
  383.                 if (NULL != CSkillManager::instance().Get(dwSkillVnum))
  384.                     break;
  385.             } while (true);
  386.  
  387.             item->SetSocket(0, dwSkillVnum);
  388.         }
  389.         else if (ITEM_SKILLFORGET2_VNUM == vnum)
  390.         {
  391.             DWORD dwSkillVnum;
  392.  
  393.             do
  394.             {
  395.                 dwSkillVnum = number(112, 119);
  396.  
  397.                 if (NULL != CSkillManager::instance().Get(dwSkillVnum))
  398.                     break;
  399.             } while (true);
  400.  
  401.             item->SetSocket(0, dwSkillVnum);
  402.         }
  403.     }
  404.  
  405.     if (item->GetType() == ITEM_QUEST)
  406.     {
  407.         for (itertype (m_map_pkQuestItemGroup) it = m_map_pkQuestItemGroup.begin(); it != m_map_pkQuestItemGroup.end(); it++)
  408.         {
  409.             if (it->second->m_bType == CSpecialItemGroup::QUEST && it->second->Contains(vnum))
  410.             {
  411.                 item->SetSIGVnum(it->first);
  412.             }
  413.         }
  414.     }
  415. #ifdef WJ_ENABLE_COSTUME_MOUNT
  416.     else if (item->GetType() == ITEM_UNIQUE || item->GetSubType() == COSTUME_MOUNT)
  417. #else
  418.     else if (item->GetType() == ITEM_UNIQUE
  419. #endif
  420.     {
  421.         for (itertype (m_map_pkSpecialItemGroup) it = m_map_pkSpecialItemGroup.begin(); it != m_map_pkSpecialItemGroup.end(); it++)
  422.         {
  423.             if (it->second->m_bType == CSpecialItemGroup::SPECIAL && it->second->Contains(vnum))
  424.             {
  425.                 item->SetSIGVnum(it->first);
  426.             }
  427.         }
  428.     }
  429.  
  430.     // 새로 생성되는 용혼석 처리.
  431.     if (item->IsDragonSoul() && 0 == id)
  432.     {
  433.         DSManager::instance().DragonSoulItemInitialize(item);
  434.     }
  435.     return item;
  436. }
  437.  
  438. void ITEM_MANAGER::DelayedSave(LPITEM item)
  439. {
  440.     if (item->GetID() != 0)
  441.         m_set_pkItemForDelayedSave.insert(item);
  442. }
  443.  
  444. void ITEM_MANAGER::FlushDelayedSave(LPITEM item)
  445. {
  446.     TR1_NS::unordered_set<LPITEM>::iterator it = m_set_pkItemForDelayedSave.find(item);
  447.  
  448.     if (it == m_set_pkItemForDelayedSave.end())
  449.     {
  450.         return;
  451.     }
  452.  
  453.     m_set_pkItemForDelayedSave.erase(it);
  454.     SaveSingleItem(item);
  455. }
  456.  
  457. void ITEM_MANAGER::SaveSingleItem(LPITEM item)
  458. {
  459.     if (!item->GetOwner())
  460.     {
  461.         DWORD dwID = item->GetID();
  462.         DWORD dwOwnerID = item->GetLastOwnerPID();
  463.  
  464.         db_clientdesc->DBPacketHeader(HEADER_GD_ITEM_DESTROY, 0, sizeof(DWORD) + sizeof(DWORD));
  465.         db_clientdesc->Packet(&dwID, sizeof(DWORD));
  466.         db_clientdesc->Packet(&dwOwnerID, sizeof(DWORD));
  467.  
  468.         sys_log(1, "ITEM_DELETE %s:%u", item->GetName(), dwID);
  469.         return;
  470.     }
  471.  
  472.     sys_log(1, "ITEM_SAVE %s:%d in %s window %d", item->GetName(), item->GetID(), item->GetOwner()->GetName(), item->GetWindow());
  473.  
  474.     TPlayerItem t;
  475.  
  476.     t.id = item->GetID();
  477.     t.window = item->GetWindow();
  478.     t.pos = t.window == EQUIPMENT ? item->GetCell() - INVENTORY_MAX_NUM : item->GetCell();
  479.     t.count = item->GetCount();
  480.     t.vnum = item->GetOriginalVnum();
  481. #ifdef __CHANGELOOK_SYSTEM__
  482.     t.transmutation = item->GetTransmutation();
  483. #endif
  484.     t.owner = (t.window == SAFEBOX || t.window == MALL) ? item->GetOwner()->GetDesc()->GetAccountTable().id : item->GetOwner()->GetPlayerID();
  485.     thecore_memcpy(t.alSockets, item->GetSockets(), sizeof(t.alSockets));
  486.     thecore_memcpy(t.aAttr, item->GetAttributes(), sizeof(t.aAttr));
  487.  
  488.     db_clientdesc->DBPacketHeader(HEADER_GD_ITEM_SAVE, 0, sizeof(TPlayerItem));
  489.     db_clientdesc->Packet(&t, sizeof(TPlayerItem));
  490. }
  491.  
  492. void ITEM_MANAGER::Update()
  493. {
  494.     TR1_NS::unordered_set<LPITEM>::iterator it = m_set_pkItemForDelayedSave.begin();
  495.     TR1_NS::unordered_set<LPITEM>::iterator this_it;
  496.  
  497.     while (it != m_set_pkItemForDelayedSave.end())
  498.     {
  499.         this_it = it++;
  500.         LPITEM item = *this_it;
  501.  
  502.         // SLOW_QUERY 플래그가 있는 것은 종료시에만 저장한다.
  503.         if (item->GetOwner() && IS_SET(item->GetFlag(), ITEM_FLAG_SLOW_QUERY))
  504.             continue;
  505.  
  506.         SaveSingleItem(item);
  507.  
  508.         m_set_pkItemForDelayedSave.erase(this_it);
  509.     }
  510. }
  511.  
  512. void ITEM_MANAGER::RemoveItem(LPITEM item, const char * c_pszReason)
  513. {
  514.     LPCHARACTER o;
  515.  
  516.     if ((o = item->GetOwner()))
  517.     {
  518.         char szHint[64];
  519.         snprintf(szHint, sizeof(szHint), "%s %u ", item->GetName(), item->GetCount());
  520.         LogManager::instance().ItemLog(o, item, c_pszReason ? c_pszReason : "REMOVE", szHint);
  521.  
  522.         // SAFEBOX_TIME_LIMIT_ITEM_BUG_FIX
  523.         if (item->GetWindow() == MALL || item->GetWindow() == SAFEBOX)
  524.         {
  525.             // 20050613.ipkn.시간제 아이템이 상점에 있을 경우 시간만료시 서버가 다운된다.
  526.             CSafebox* pSafebox = item->GetWindow() == MALL ? o->GetMall() : o->GetSafebox();
  527.             if (pSafebox)
  528.             {
  529.                 pSafebox->Remove(item->GetCell());
  530.             }
  531.         }
  532.         // END_OF_SAFEBOX_TIME_LIMIT_ITEM_BUG_FIX
  533.         else
  534.         {
  535.             o->SyncQuickslot(QUICKSLOT_TYPE_ITEM, item->GetCell(), 255);
  536.             item->RemoveFromCharacter();
  537.         }
  538.     }
  539.  
  540.     M2_DESTROY_ITEM(item);
  541. }
  542.  
  543. #ifndef DEBUG_ALLOC
  544. void ITEM_MANAGER::DestroyItem(LPITEM item)
  545. #else
  546. void ITEM_MANAGER::DestroyItem(LPITEM item, const char* file, size_t line)
  547. #endif
  548. {
  549.     if (item->GetSectree())
  550.         item->RemoveFromGround();
  551.  
  552.     if (item->GetOwner())
  553.     {
  554.         if (CHARACTER_MANAGER::instance().Find(item->GetOwner()->GetPlayerID()) != NULL)
  555.         {
  556.             sys_err("DestroyItem: GetOwner %s %s!!", item->GetName(), item->GetOwner()->GetName());
  557.             item->RemoveFromCharacter();
  558.         }
  559.         else
  560.         {
  561.             sys_err ("WTH! Invalid item owner. owner pointer : %p", item->GetOwner());
  562.         }
  563.     }
  564.  
  565.     TR1_NS::unordered_set<LPITEM>::iterator it = m_set_pkItemForDelayedSave.find(item);
  566.  
  567.     if (it != m_set_pkItemForDelayedSave.end())
  568.         m_set_pkItemForDelayedSave.erase(it);
  569.  
  570.     DWORD dwID = item->GetID();
  571.     sys_log(2, "ITEM_DESTROY %s:%u", item->GetName(), dwID);
  572.  
  573.     if (!item->GetSkipSave() && dwID)
  574.     {
  575.         DWORD dwOwnerID = item->GetLastOwnerPID();
  576.  
  577.         db_clientdesc->DBPacketHeader(HEADER_GD_ITEM_DESTROY, 0, sizeof(DWORD) + sizeof(DWORD));
  578.         db_clientdesc->Packet(&dwID, sizeof(DWORD));
  579.         db_clientdesc->Packet(&dwOwnerID, sizeof(DWORD));
  580.     }
  581.     else
  582.     {
  583.         sys_log(2, "ITEM_DESTROY_SKIP %s:%u (skip=%d)", item->GetName(), dwID, item->GetSkipSave());
  584.     }
  585.  
  586.     if (dwID)
  587.         m_map_pkItemByID.erase(dwID);
  588.  
  589.     m_VIDMap.erase(item->GetVID());
  590.  
  591. #ifdef M2_USE_POOL
  592.     pool_.Destroy(item);
  593. #else
  594. #ifndef DEBUG_ALLOC
  595.     M2_DELETE(item);
  596. #else
  597.     M2_DELETE_EX(item, file, line);
  598. #endif
  599. #endif
  600. }
  601.  
  602. LPITEM ITEM_MANAGER::Find(DWORD id)
  603. {
  604.     itertype(m_map_pkItemByID) it = m_map_pkItemByID.find(id);
  605.     if (it == m_map_pkItemByID.end())
  606.         return NULL;
  607.     return it->second;
  608. }
  609.  
  610. LPITEM ITEM_MANAGER::FindByVID(DWORD vid)
  611. {
  612.     ITEM_VID_MAP::iterator it = m_VIDMap.find(vid);
  613.  
  614.     if (it == m_VIDMap.end())
  615.         return NULL;
  616.  
  617.     return (it->second);
  618. }
  619.  
  620. TItemTable * ITEM_MANAGER::GetTable(DWORD vnum)
  621. {
  622.     int rnum = RealNumber(vnum);
  623.  
  624.     if (rnum < 0)
  625.     {
  626.         for (size_t i = 0; i < m_vec_item_vnum_range_info.size(); i++)
  627.         {
  628.             TItemTable* p = m_vec_item_vnum_range_info[i];
  629.             if ((p->dwVnum < vnum) &&
  630.                 vnum < (p->dwVnum + p->dwVnumRange))
  631.             {
  632.                 return p;
  633.             }
  634.         }
  635.            
  636.         return NULL;
  637.     }
  638.  
  639.     return &m_vec_prototype[rnum];
  640. }
  641.  
  642. int ITEM_MANAGER::RealNumber(DWORD vnum)
  643. {
  644.     int bot, top, mid;
  645.  
  646.     bot = 0;
  647.     top = m_vec_prototype.size();
  648.  
  649.     TItemTable * pTable = &m_vec_prototype[0];
  650.  
  651.     while (1)
  652.     {
  653.         mid = (bot + top) >> 1;
  654.  
  655.         if ((pTable + mid)->dwVnum == vnum)
  656.             return (mid);
  657.  
  658.         if (bot >= top)
  659.             return (-1);
  660.  
  661.         if ((pTable + mid)->dwVnum > vnum)
  662.             top = mid - 1;
  663.         else        
  664.             bot = mid + 1;
  665.     }
  666. }
  667.  
  668. bool ITEM_MANAGER::GetVnum(const char * c_pszName, DWORD & r_dwVnum)
  669. {
  670.     int len = strlen(c_pszName);
  671.  
  672.     TItemTable * pTable = &m_vec_prototype[0];
  673.  
  674.     for (DWORD i = 0; i < m_vec_prototype.size(); ++i, ++pTable)
  675.     {
  676.         if (!strncasecmp(c_pszName, pTable->szLocaleName, len))
  677.         {
  678.             r_dwVnum = pTable->dwVnum;
  679.             return true;
  680.         }
  681.     }
  682.  
  683.     return false;
  684. }
  685.  
  686. bool ITEM_MANAGER::GetVnumByOriginalName(const char * c_pszName, DWORD & r_dwVnum)
  687. {
  688.     int len = strlen(c_pszName);
  689.  
  690.     TItemTable * pTable = &m_vec_prototype[0];
  691.  
  692.     for (DWORD i = 0; i < m_vec_prototype.size(); ++i, ++pTable)
  693.     {
  694.         if (!strncasecmp(c_pszName, pTable->szName, len))
  695.         {
  696.             r_dwVnum = pTable->dwVnum;
  697.             return true;
  698.         }
  699.     }
  700.  
  701.     return false;
  702. }
  703.  
  704. std::set<DWORD> g_set_lotto;
  705.  
  706. void load_lotto()
  707. {
  708.     static int bLoaded = false;
  709.  
  710.     if (bLoaded)
  711.         return;
  712.  
  713.     bLoaded = true;
  714.     FILE * fp = fopen("lotto.txt", "r");
  715.  
  716.     if (!fp)
  717.         return;
  718.  
  719.     char buf[256];
  720.  
  721.     while (fgets(buf, 256, fp))
  722.     {
  723.         char * psz = strchr(buf, '\n');
  724.  
  725.         if (NULL != psz)
  726.             *psz = '\0';
  727.  
  728.         DWORD dw = 0;
  729.         str_to_number(dw, buf);
  730.         g_set_lotto.insert(dw);
  731.     }
  732.  
  733.     fclose(fp);
  734. }
  735.  
  736. DWORD lotto()
  737. {
  738.     load_lotto();
  739.  
  740.     char szBuf[6 + 1];
  741.  
  742.     do
  743.     {
  744.         for (int i = 0; i < 6; ++i)
  745.             szBuf[i] = 48 + number(1, 9);
  746.  
  747.         szBuf[6] = '\0';
  748.  
  749.         DWORD dw = 0;
  750.         str_to_number(dw, szBuf);
  751.  
  752.         if (g_set_lotto.end() == g_set_lotto.find(dw))
  753.         {
  754.             FILE * fp = fopen("lotto.txt", "a+");
  755.             if (fp)
  756.             {
  757.                 fprintf(fp, "%u\n", dw);
  758.                 fclose(fp);
  759.             }
  760.             return dw;
  761.         }
  762.     }
  763.     while (1);
  764. }
  765.  
  766.  
  767. class CItemDropInfo
  768. {
  769.     public:
  770.         CItemDropInfo(int iLevelStart, int iLevelEnd, int iPercent, DWORD dwVnum) :
  771.             m_iLevelStart(iLevelStart), m_iLevelEnd(iLevelEnd), m_iPercent(iPercent), m_dwVnum(dwVnum)
  772.             {
  773.             }
  774.  
  775.         int m_iLevelStart;
  776.         int m_iLevelEnd;
  777.         int m_iPercent; // 1 ~ 1000
  778.         DWORD   m_dwVnum;
  779.  
  780.         friend bool operator < (const CItemDropInfo & l, const CItemDropInfo & r)
  781.         {
  782.             return l.m_iLevelEnd < r.m_iLevelEnd;
  783.         }
  784. };
  785.  
  786. extern std::vector<CItemDropInfo> g_vec_pkCommonDropItem[MOB_RANK_MAX_NUM];
  787.  
  788. // 20050503.ipkn.
  789. // iMinimum 보다 작으면 iDefault 세팅 (단, iMinimum은 0보다 커야함)
  790. // 1, 0 식으로 ON/OFF 되는 방식을 지원하기 위해 존재
  791. int GetDropPerKillPct(int iMinimum, int iDefault, int iDeltaPercent, const char * c_pszFlag)
  792. {
  793.     int iVal = 0;
  794.  
  795.     if ((iVal = quest::CQuestManager::instance().GetEventFlag(c_pszFlag)))
  796.     {
  797.         if (!test_server && !LC_IsJapan())
  798.         {
  799.             if (iVal < iMinimum)
  800.                 iVal = iDefault;
  801.  
  802.             if (iVal < 0)
  803.                 iVal = iDefault;
  804.         }
  805.     }
  806.  
  807.     if (iVal == 0)
  808.         return 0;
  809.  
  810.     // 기본 세팅일때 (iDeltaPercent=100)
  811.     // 40000 iVal 마리당 하나 느낌을 주기 위한 상수임
  812.     return (40000 * iDeltaPercent / iVal);
  813. }
  814.  
  815. bool ITEM_MANAGER::GetDropPct(LPCHARACTER pkChr, LPCHARACTER pkKiller, OUT int& iDeltaPercent, OUT int& iRandRange)
  816. {
  817.     if (NULL == pkChr || NULL == pkKiller)
  818.         return false;
  819.  
  820.     int iLevel = pkKiller->GetLevel();
  821.     iDeltaPercent = 100;
  822.  
  823.     if (!pkChr->IsStone() && pkChr->GetMobRank() >= MOB_RANK_BOSS)
  824.         iDeltaPercent = PERCENT_LVDELTA_BOSS(pkKiller->GetLevel(), pkChr->GetLevel());
  825.     else
  826.         iDeltaPercent = PERCENT_LVDELTA(pkKiller->GetLevel(), pkChr->GetLevel());
  827.  
  828.     BYTE bRank = pkChr->GetMobRank();
  829.  
  830.     if (1 == number(1, 50000))
  831.         iDeltaPercent += 1000;
  832.     else if (1 == number(1, 10000))
  833.         iDeltaPercent += 500;
  834.  
  835.     sys_log(3, "CreateDropItem for level: %d rank: %u pct: %d", iLevel, bRank, iDeltaPercent);
  836.     iDeltaPercent = iDeltaPercent * CHARACTER_MANAGER::instance().GetMobItemRate(pkKiller) / 100;
  837.  
  838.     //if (pkKiller->GetPoint(POINT_MALL_ITEMBONUS) > 0)
  839.     //iDeltaPercent += iDeltaPercent * pkKiller->GetPoint(POINT_MALL_ITEMBONUS) / 100;
  840.     // ADD_PREMIUM
  841.     if (pkKiller->GetPremiumRemainSeconds(PREMIUM_ITEM) > 0 ||
  842.             pkKiller->IsEquipUniqueGroup(UNIQUE_GROUP_DOUBLE_ITEM))
  843.         iDeltaPercent += iDeltaPercent;
  844.     // END_OF_ADD_PREMIUM
  845.  
  846.     // PC_BANG_ITEM_ADD
  847.     if (pkKiller->GetPoint(POINT_PC_BANG_DROP_BONUS) > 0)
  848.     {
  849.         if (pkKiller->IsPCBang() == true)
  850.             iDeltaPercent += iDeltaPercent * pkKiller->GetPoint(POINT_PC_BANG_DROP_BONUS)/100;
  851.     }
  852.     // END_PC_BANG_ITEM_ADD
  853.  
  854.     iRandRange = 4000000;
  855.     iRandRange = iRandRange * 100 /
  856.         (100 +
  857.          CPrivManager::instance().GetPriv(pkKiller, PRIV_ITEM_DROP) +
  858.          pkKiller->IsEquipUniqueItem(UNIQUE_ITEM_DOUBLE_ITEM)?100:0);
  859.  
  860.     if (distribution_test_server) iRandRange /= 3;
  861.  
  862.     return true;
  863. }
  864.  
  865. #ifdef __SEND_TARGET_INFO__
  866. bool ITEM_MANAGER::CreateDropItemVector(LPCHARACTER pkChr, LPCHARACTER pkKiller, std::vector<LPITEM> & vec_item)
  867. {
  868.     if (pkChr->IsPolymorphed() || pkChr->IsPC())
  869.     {
  870.         return false;
  871.     }
  872.  
  873.     int iLevel = pkKiller->GetLevel();
  874.  
  875.     BYTE bRank = pkChr->GetMobRank();
  876.     LPITEM item = NULL;
  877.  
  878.     std::vector<CItemDropInfo>::iterator it = g_vec_pkCommonDropItem[bRank].begin();
  879.  
  880.     while (it != g_vec_pkCommonDropItem[bRank].end())
  881.     {
  882.         const CItemDropInfo & c_rInfo = *(it++);
  883.  
  884.         if (iLevel < c_rInfo.m_iLevelStart || iLevel > c_rInfo.m_iLevelEnd)
  885.             continue;
  886.  
  887.         TItemTable * table = GetTable(c_rInfo.m_dwVnum);
  888.  
  889.         if (!table)
  890.             continue;
  891.  
  892.         item = NULL;
  893.  
  894.         if (table->bType == ITEM_POLYMORPH)
  895.         {
  896.             if (c_rInfo.m_dwVnum == pkChr->GetPolymorphItemVnum())
  897.             {
  898.                 item = CreateItem(c_rInfo.m_dwVnum, 1, 0, true);
  899.  
  900.                 if (item)
  901.                     item->SetSocket(0, pkChr->GetRaceNum());
  902.             }
  903.         }
  904.         else
  905.             item = CreateItem(c_rInfo.m_dwVnum, 1, 0, true);
  906.  
  907.         if (item) vec_item.push_back(item);
  908.     }
  909.  
  910.     // Drop Item Group
  911.     {
  912.         itertype(m_map_pkDropItemGroup) it;
  913.         it = m_map_pkDropItemGroup.find(pkChr->GetRaceNum());
  914.  
  915.         if (it != m_map_pkDropItemGroup.end())
  916.         {
  917.             __typeof(it->second->GetVector()) v = it->second->GetVector();
  918.  
  919.             for (DWORD i = 0; i < v.size(); ++i)
  920.             {
  921.                 item = CreateItem(v[i].dwVnum, v[i].iCount, 0, true);
  922.  
  923.                 if (item)
  924.                 {
  925.                     if (item->GetType() == ITEM_POLYMORPH)
  926.                     {
  927.                         if (item->GetVnum() == pkChr->GetPolymorphItemVnum())
  928.                         {
  929.                             item->SetSocket(0, pkChr->GetRaceNum());
  930.                         }
  931.                     }
  932.  
  933.                     vec_item.push_back(item);
  934.                 }
  935.             }
  936.         }
  937.     }
  938.  
  939.     // MobDropItem Group
  940.     {
  941.         itertype(m_map_pkMobItemGroup) it;
  942.         it = m_map_pkMobItemGroup.find(pkChr->GetRaceNum());
  943.  
  944.         if ( it != m_map_pkMobItemGroup.end() )
  945.         {
  946.             CMobItemGroup* pGroup = it->second;
  947.  
  948.             // MOB_DROP_ITEM_BUG_FIX
  949.             // 20050805.myevan.MobDropItem ? ???? ?? ?? CMobItemGroup::GetOne() ??? ?? ?? ??
  950.             if (pGroup && !pGroup->IsEmpty())
  951.             {
  952.                 const CMobItemGroup::SMobItemGroupInfo& info = pGroup->GetOne();
  953.                 item = CreateItem(info.dwItemVnum, info.iCount, 0, true, info.iRarePct);
  954.  
  955.                 if (item) vec_item.push_back(item);
  956.             }
  957.             // END_OF_MOB_DROP_ITEM_BUG_FIX
  958.         }
  959.     }
  960.  
  961.     // Level Item Group
  962.     {
  963.         itertype(m_map_pkLevelItemGroup) it;
  964.         it = m_map_pkLevelItemGroup.find(pkChr->GetRaceNum());
  965.  
  966.         if ( it != m_map_pkLevelItemGroup.end() )
  967.         {
  968.             if ( it->second->GetLevelLimit() <= (DWORD)iLevel )
  969.             {
  970.                 __typeof(it->second->GetVector()) v = it->second->GetVector();
  971.  
  972.                 for ( DWORD i=0; i < v.size(); i++ )
  973.                 {
  974.                     DWORD dwVnum = v[i].dwVNum;
  975.                     item = CreateItem(dwVnum, v[i].iCount, 0, true);
  976.                     if ( item ) vec_item.push_back(item);
  977.                 }
  978.             }
  979.         }
  980.     }
  981.  
  982.     // BuyerTheitGloves Item Group
  983.     {
  984.         // by mhh ?? ??? ??? ?? drop ? ???? ??
  985.         if (pkKiller->GetPremiumRemainSeconds(PREMIUM_ITEM) > 0 ||
  986.                 pkKiller->IsEquipUniqueGroup(UNIQUE_GROUP_DOUBLE_ITEM))
  987.         {
  988.             itertype(m_map_pkGloveItemGroup) it;
  989.             it = m_map_pkGloveItemGroup.find(pkChr->GetRaceNum());
  990.  
  991.             if (it != m_map_pkGloveItemGroup.end())
  992.             {
  993.                 __typeof(it->second->GetVector()) v = it->second->GetVector();
  994.  
  995.                 for (DWORD i = 0; i < v.size(); ++i)
  996.                 {
  997.                    
  998.                     DWORD dwVnum = v[i].dwVnum;
  999.                     item = CreateItem(dwVnum, v[i].iCount, 0, true);
  1000.                     if (item) vec_item.push_back(item);
  1001.                 }
  1002.             }
  1003.         }
  1004.     }
  1005.  
  1006.     // ??
  1007.     if (pkChr->GetMobDropItemVnum())
  1008.     {
  1009.         itertype(m_map_dwEtcItemDropProb) it = m_map_dwEtcItemDropProb.find(pkChr->GetMobDropItemVnum());
  1010.  
  1011.         if (it != m_map_dwEtcItemDropProb.end())
  1012.         {      
  1013.             item = CreateItem(pkChr->GetMobDropItemVnum(), 1, 0, true);
  1014.             if (item) vec_item.push_back(item);
  1015.         }
  1016.     }
  1017.  
  1018.     if (pkChr->IsStone())
  1019.     {
  1020.         if (pkChr->GetDropMetinStoneVnum())
  1021.         {
  1022.             item = CreateItem(pkChr->GetDropMetinStoneVnum(), 1, 0, true);
  1023.             if (item) vec_item.push_back(item);
  1024.         }
  1025.     }
  1026.  
  1027.     return vec_item.size();
  1028. }
  1029. #endif
  1030.  
  1031. bool ITEM_MANAGER::CreateDropItem(LPCHARACTER pkChr, LPCHARACTER pkKiller, std::vector<LPITEM> & vec_item)
  1032. {
  1033.     int iLevel = pkKiller->GetLevel();
  1034.  
  1035.     int iDeltaPercent, iRandRange;
  1036.     if (!GetDropPct(pkChr, pkKiller, iDeltaPercent, iRandRange))
  1037.         return false;
  1038.  
  1039.     BYTE bRank = pkChr->GetMobRank();
  1040.     LPITEM item = NULL;
  1041.  
  1042.     // Common Drop Items
  1043.     std::vector<CItemDropInfo>::iterator it = g_vec_pkCommonDropItem[bRank].begin();
  1044.  
  1045.     while (it != g_vec_pkCommonDropItem[bRank].end())
  1046.     {
  1047.         const CItemDropInfo & c_rInfo = *(it++);
  1048.  
  1049.         if (iLevel < c_rInfo.m_iLevelStart || iLevel > c_rInfo.m_iLevelEnd)
  1050.             continue;
  1051.  
  1052.         int iPercent = (c_rInfo.m_iPercent * iDeltaPercent) / 100;
  1053.         sys_log(3, "CreateDropItem %d ~ %d %d(%d)", c_rInfo.m_iLevelStart, c_rInfo.m_iLevelEnd, c_rInfo.m_dwVnum, iPercent, c_rInfo.m_iPercent);
  1054.  
  1055.         if (iPercent >= number(1, iRandRange))
  1056.         {
  1057.             TItemTable * table = GetTable(c_rInfo.m_dwVnum);
  1058.  
  1059.             if (!table)
  1060.                 continue;
  1061.  
  1062.             item = NULL;
  1063.  
  1064.             if (table->bType == ITEM_POLYMORPH)
  1065.             {
  1066.                 if (c_rInfo.m_dwVnum == pkChr->GetPolymorphItemVnum())
  1067.                 {
  1068.                     item = CreateItem(c_rInfo.m_dwVnum, 1, 0, true);
  1069.  
  1070.                     if (item)
  1071.                         item->SetSocket(0, pkChr->GetRaceNum());
  1072.                 }
  1073.             }
  1074.             else
  1075.                 item = CreateItem(c_rInfo.m_dwVnum, 1, 0, true);
  1076.  
  1077.             if (item) vec_item.push_back(item);
  1078.         }
  1079.     }
  1080.  
  1081.     // Drop Item Group
  1082.     {
  1083.         itertype(m_map_pkDropItemGroup) it;
  1084.         it = m_map_pkDropItemGroup.find(pkChr->GetRaceNum());
  1085.  
  1086.         if (it != m_map_pkDropItemGroup.end())
  1087.         {
  1088.             __typeof(it->second->GetVector()) v = it->second->GetVector();
  1089.  
  1090.             for (DWORD i = 0; i < v.size(); ++i)
  1091.             {
  1092.                 int iPercent = (v[i].dwPct * iDeltaPercent) / 100;
  1093.  
  1094.                 if (iPercent >= number(1, iRandRange))
  1095.                 {
  1096.                     item = CreateItem(v[i].dwVnum, v[i].iCount, 0, true);
  1097.  
  1098.                     if (item)
  1099.                     {
  1100.                         if (item->GetType() == ITEM_POLYMORPH)
  1101.                         {
  1102.                             if (item->GetVnum() == pkChr->GetPolymorphItemVnum())
  1103.                             {
  1104.                                 item->SetSocket(0, pkChr->GetRaceNum());
  1105.                             }
  1106.                         }
  1107.  
  1108.                         vec_item.push_back(item);
  1109.                     }
  1110.                 }
  1111.             }
  1112.         }
  1113.     }
  1114.  
  1115.     // MobDropItem Group
  1116.     {
  1117.         itertype(m_map_pkMobItemGroup) it;
  1118.         it = m_map_pkMobItemGroup.find(pkChr->GetRaceNum());
  1119.  
  1120.         if ( it != m_map_pkMobItemGroup.end() )
  1121.         {
  1122.             CMobItemGroup* pGroup = it->second;
  1123.  
  1124.             // MOB_DROP_ITEM_BUG_FIX
  1125.             // 20050805.myevan.MobDropItem 에 아이템이 없을 경우 CMobItemGroup::GetOne() 접근시 문제 발생 수정
  1126.             if (pGroup && !pGroup->IsEmpty())
  1127.             {
  1128.                 int iPercent = 40000 * iDeltaPercent / pGroup->GetKillPerDrop();
  1129.                 if (iPercent >= number(1, iRandRange))
  1130.                 {
  1131.                     const CMobItemGroup::SMobItemGroupInfo& info = pGroup->GetOne();
  1132.                     item = CreateItem(info.dwItemVnum, info.iCount, 0, true, info.iRarePct);
  1133.  
  1134.                     if (item) vec_item.push_back(item);
  1135.                 }
  1136.             }
  1137.             // END_OF_MOB_DROP_ITEM_BUG_FIX
  1138.         }
  1139.     }
  1140.  
  1141.     // Level Item Group
  1142.     {
  1143.         itertype(m_map_pkLevelItemGroup) it;
  1144.         it = m_map_pkLevelItemGroup.find(pkChr->GetRaceNum());
  1145.  
  1146.         if ( it != m_map_pkLevelItemGroup.end() )
  1147.         {
  1148.             if ( it->second->GetLevelLimit() <= (DWORD)iLevel )
  1149.             {
  1150.                 __typeof(it->second->GetVector()) v = it->second->GetVector();
  1151.  
  1152.                 for ( DWORD i=0; i < v.size(); i++ )
  1153.                 {
  1154.                     if ( v[i].dwPct >= (DWORD)number(1, 1000000/*iRandRange*/) )
  1155.                     {
  1156.                         DWORD dwVnum = v[i].dwVNum;
  1157.                         item = CreateItem(dwVnum, v[i].iCount, 0, true);
  1158.                         if ( item ) vec_item.push_back(item);
  1159.                     }
  1160.                 }
  1161.             }
  1162.         }
  1163.     }
  1164.    
  1165.     // BuyerTheitGloves Item Group
  1166.     {
  1167.         if (pkKiller->GetPremiumRemainSeconds(PREMIUM_ITEM) > 0 ||
  1168.                 pkKiller->IsEquipUniqueGroup(UNIQUE_GROUP_DOUBLE_ITEM))
  1169.         {
  1170.             itertype(m_map_pkGloveItemGroup) it;
  1171.             it = m_map_pkGloveItemGroup.find(pkChr->GetRaceNum());
  1172.  
  1173.             if (it != m_map_pkGloveItemGroup.end())
  1174.             {
  1175.                 __typeof(it->second->GetVector()) v = it->second->GetVector();
  1176.  
  1177.                 for (DWORD i = 0; i < v.size(); ++i)
  1178.                 {
  1179.                     int iPercent = (v[i].dwPct * iDeltaPercent) / 100;
  1180.  
  1181.                     if (iPercent >= number(1, iRandRange))
  1182.                     {
  1183.                         DWORD dwVnum = v[i].dwVnum;
  1184.                         item = CreateItem(dwVnum, v[i].iCount, 0, true);
  1185.                         if (item) vec_item.push_back(item);
  1186.                     }
  1187.                 }
  1188.             }
  1189.         }
  1190.     }
  1191.    
  1192.     // 잡템
  1193.     if (pkChr->GetMobDropItemVnum())
  1194.     {
  1195.         itertype(m_map_dwEtcItemDropProb) it = m_map_dwEtcItemDropProb.find(pkChr->GetMobDropItemVnum());
  1196.  
  1197.         if (it != m_map_dwEtcItemDropProb.end())
  1198.         {
  1199.             int iPercent = (it->second * iDeltaPercent) / 100;
  1200.  
  1201.             if (iPercent >= number(1, iRandRange))
  1202.             {
  1203.                 item = CreateItem(pkChr->GetMobDropItemVnum(), 1, 0, true);
  1204.                 if (item) vec_item.push_back(item);
  1205.             }
  1206.         }
  1207.     }
  1208.  
  1209.     if (pkChr->IsStone())
  1210.     {
  1211.         if (pkChr->GetDropMetinStoneVnum())
  1212.         {
  1213.             int iPercent = (pkChr->GetDropMetinStonePct() * iDeltaPercent) * 400;
  1214.  
  1215.             if (iPercent >= number(1, iRandRange))
  1216.             {
  1217.                 item = CreateItem(pkChr->GetDropMetinStoneVnum(), 1, 0, true);
  1218.                 if (item) vec_item.push_back(item);
  1219.             }
  1220.         }
  1221.     }
  1222.  
  1223.     if (pkKiller->IsHorseRiding() &&
  1224.             GetDropPerKillPct(1000, 1000000, iDeltaPercent, "horse_skill_book_drop") >= number(1, iRandRange))
  1225.     {
  1226.         sys_log(0, "EVENT HORSE_SKILL_BOOK_DROP");
  1227.  
  1228.         if ((item = CreateItem(ITEM_HORSE_SKILL_TRAIN_BOOK, 1, 0, true)))
  1229.             vec_item.push_back(item);
  1230.     }
  1231.  
  1232.  
  1233.     if (GetDropPerKillPct(100, 1000, iDeltaPercent, "lotto_drop") >= number(1, iRandRange))
  1234.     {
  1235.         DWORD * pdw = M2_NEW DWORD[3];
  1236.  
  1237.         pdw[0] = 50001;
  1238.         pdw[1] = 1;
  1239.         pdw[2] = quest::CQuestManager::instance().GetEventFlag("lotto_round");
  1240.  
  1241.         // 행운의 서는 소켓을 설정한다
  1242.         DBManager::instance().ReturnQuery(QID_LOTTO, pkKiller->GetPlayerID(), pdw,
  1243.                 "INSERT INTO lotto_list VALUES(0, 'server%s', %u, NOW())",
  1244.                 get_table_postfix(), pkKiller->GetPlayerID());
  1245.     }
  1246.  
  1247.     //
  1248.     // 스페셜 드롭 아이템
  1249.     //
  1250.     CreateQuestDropItem(pkChr, pkKiller, vec_item, iDeltaPercent, iRandRange);
  1251.  
  1252.     for (itertype(vec_item) it = vec_item.begin(); it != vec_item.end(); ++it)
  1253.     {
  1254.         LPITEM item = *it;
  1255.         DBManager::instance().SendMoneyLog(MONEY_LOG_DROP, item->GetVnum(), item->GetCount());
  1256.     }
  1257.  
  1258.     //
  1259.     // 승룡곡 천의동굴 2층에서만 수룡방 입장권
  1260.     //
  1261.     if (LC_IsYMIR() || LC_IsKorea())
  1262.     {
  1263.         if (73 == pkKiller->GetMapIndex())
  1264.         {
  1265.             int per = 25;   // 0.25%
  1266.             if (number(1, 10000) <= per)
  1267.             {
  1268.                 LPITEM item = 0;
  1269.                 if ((item = CreateItem(71122, 1, 0, true)))
  1270.                     vec_item.push_back(item);
  1271.             }
  1272.         }
  1273.     }
  1274.  
  1275.     //
  1276.     // 승룡곡 1층, 2층에서만 7,8 스킬입문서 드롭
  1277.     //
  1278.     if (LC_IsYMIR() || LC_IsKorea())
  1279.     {
  1280.         switch (pkKiller->GetMapIndex())
  1281.         {
  1282.             case 72:    // 천의동굴 1층
  1283.             case 73:    // 천의동굴 2층
  1284.                 {
  1285.                     int vnum = 0;
  1286.  
  1287.                     if (2403 == pkChr->GetRaceNum())    // 천의법사
  1288.                         vnum = 69200;   // 7스킬 입문서
  1289.                     else if (2411 == pkChr->GetRaceNum())   // 진천의병사
  1290.                         vnum = 69201;   // 8스킬 입문서
  1291.                     else
  1292.                         break;
  1293.  
  1294.                     int per = 5;    // 0.05%
  1295.                     if (number(1, 10000) <= per)
  1296.                     {
  1297.                         LPITEM item = 0;
  1298.                         item = CreateItem(vnum, 1, 0, true);
  1299.                         if (item)
  1300.                             vec_item.push_back(item);
  1301.                     }
  1302.                 }
  1303.                 break;
  1304.         }
  1305.     }
  1306.  
  1307.     return vec_item.size();
  1308. }
  1309.  
  1310. // ADD_GRANDMASTER_SKILL
  1311. int GetThreeSkillLevelAdjust(int level)
  1312. {
  1313.     if (level < 40)
  1314.         return 32;
  1315.     if (level < 45)
  1316.         return 16;
  1317.     if (level < 50)
  1318.         return 8;
  1319.     if (level < 55)
  1320.         return 4;
  1321.     if (level < 60)
  1322.         return 2;
  1323.     return 1;
  1324. }
  1325. // END_OF_ADD_GRANDMASTER_SKILL
  1326.  
  1327. // DROPEVENT_CHARSTONE
  1328. // drop_char_stone 1
  1329. // drop_char_stone.percent_lv01_10 5
  1330. // drop_char_stone.percent_lv11_30 10
  1331. // drop_char_stone.percent_lv31_MX 15
  1332. // drop_char_stone.level_range     10
  1333. static struct DropEvent_CharStone
  1334. {
  1335.     int percent_lv01_10;
  1336.     int percent_lv11_30;
  1337.     int percent_lv31_MX;
  1338.     int level_range;
  1339.     bool alive;
  1340.  
  1341.     DropEvent_CharStone()
  1342.     {
  1343.         percent_lv01_10 =  100;
  1344.         percent_lv11_30 =  200;
  1345.         percent_lv31_MX =  300;
  1346.         level_range = 10;
  1347.         alive = false;
  1348.     }
  1349. } gs_dropEvent_charStone;
  1350.  
  1351. static int __DropEvent_CharStone_GetDropPercent(int killer_level)
  1352. {
  1353.     int killer_levelStep = (killer_level-1)/10;
  1354.  
  1355.     switch (killer_levelStep)
  1356.     {
  1357.         case 0:
  1358.             return gs_dropEvent_charStone.percent_lv01_10;
  1359.  
  1360.         case 1:
  1361.         case 2:
  1362.             return gs_dropEvent_charStone.percent_lv11_30;
  1363.     }
  1364.  
  1365.     return gs_dropEvent_charStone.percent_lv31_MX;
  1366. }
  1367.  
  1368. static void __DropEvent_CharStone_DropItem(CHARACTER & killer, CHARACTER & victim, ITEM_MANAGER& itemMgr, std::vector<LPITEM>& vec_item)
  1369. {
  1370.     if (!gs_dropEvent_charStone.alive)
  1371.         return;
  1372.  
  1373.     int killer_level = killer.GetLevel();
  1374.     int dropPercent = __DropEvent_CharStone_GetDropPercent(killer_level);
  1375.  
  1376.     int MaxRange = 10000;
  1377.  
  1378.     if (LC_IsCanada() == true)
  1379.         MaxRange = 20000;
  1380.  
  1381.     if (number(1, MaxRange) <= dropPercent)
  1382.     {
  1383.         int log_level = (test_server || killer.GetGMLevel() >= GM_LOW_WIZARD) ? 0 : 1;
  1384.         int victim_level = victim.GetLevel();
  1385.         int level_diff = victim_level - killer_level;
  1386.  
  1387.         if (level_diff >= +gs_dropEvent_charStone.level_range || level_diff <= -gs_dropEvent_charStone.level_range)
  1388.         {
  1389.             sys_log(log_level,
  1390.                     "dropevent.drop_char_stone.level_range_over: killer(%s: lv%d), victim(%s: lv:%d), level_diff(%d)",
  1391.                     killer.GetName(), killer.GetLevel(), victim.GetName(), victim.GetLevel(), level_diff); 
  1392.             return;
  1393.         }
  1394.  
  1395.         static const int Stones[] = { 30210, 30211, 30212, 30213, 30214, 30215, 30216, 30217, 30218, 30219, 30258, 30259, 30260, 30261, 30262, 30263 };
  1396.         int item_vnum = Stones[number(0, _countof(Stones))];
  1397.  
  1398.         LPITEM p_item = NULL;
  1399.  
  1400.         if ((p_item = itemMgr.CreateItem(item_vnum, 1, 0, true)))
  1401.         {
  1402.             vec_item.push_back(p_item);
  1403.  
  1404.             sys_log(log_level,
  1405.                     "dropevent.drop_char_stone.item_drop: killer(%s: lv%d), victim(%s: lv:%d), item_name(%s)",
  1406.                     killer.GetName(), killer.GetLevel(), victim.GetName(), victim.GetLevel(), p_item->GetName());  
  1407.         }
  1408.     }
  1409. }
  1410.  
  1411. bool DropEvent_CharStone_SetValue(const std::string& name, int value)
  1412. {
  1413.     if (name == "drop_char_stone")
  1414.     {
  1415.         gs_dropEvent_charStone.alive = value;
  1416.  
  1417.         if (value)
  1418.             sys_log(0, "dropevent.drop_char_stone = on");
  1419.         else
  1420.             sys_log(0, "dropevent.drop_char_stone = off");
  1421.  
  1422.     }
  1423.     else if (name == "drop_char_stone.percent_lv01_10")
  1424.         gs_dropEvent_charStone.percent_lv01_10 = value;
  1425.     else if (name == "drop_char_stone.percent_lv11_30")
  1426.         gs_dropEvent_charStone.percent_lv11_30 = value;
  1427.     else if (name == "drop_char_stone.percent_lv31_MX")
  1428.         gs_dropEvent_charStone.percent_lv31_MX = value;
  1429.     else if (name == "drop_char_stone.level_range")
  1430.         gs_dropEvent_charStone.level_range = value;
  1431.     else
  1432.         return false;
  1433.  
  1434.     sys_log(0, "dropevent.drop_char_stone: %d", gs_dropEvent_charStone.alive ? true : false);
  1435.     sys_log(0, "dropevent.drop_char_stone.percent_lv01_10: %f", gs_dropEvent_charStone.percent_lv01_10/100.0f);
  1436.     sys_log(0, "dropevent.drop_char_stone.percent_lv11_30: %f", gs_dropEvent_charStone.percent_lv11_30/100.0f);
  1437.     sys_log(0, "dropevent.drop_char_stone.percent_lv31_MX: %f", gs_dropEvent_charStone.percent_lv31_MX/100.0f);
  1438.     sys_log(0, "dropevent.drop_char_stone.level_range: %d", gs_dropEvent_charStone.level_range);
  1439.  
  1440.     return true;
  1441. }
  1442.  
  1443. // END_OF_DROPEVENT_CHARSTONE
  1444.  
  1445. // fixme
  1446. // 위의 것과 함께 quest로 뺄것 빼보자.
  1447. // 이거 너무 더럽잖아...
  1448. // ”?. 하드코딩 싫다 ㅜㅠ
  1449. // 계량 아이템 보상 시작.
  1450. // by rtsummit 고치자 진짜
  1451. static struct DropEvent_RefineBox
  1452. {
  1453.     int percent_low;
  1454.     int low;
  1455.     int percent_mid;
  1456.     int mid;
  1457.     int percent_high;
  1458.     //int level_range;
  1459.     bool alive;
  1460.  
  1461.     DropEvent_RefineBox()
  1462.     {
  1463.         percent_low =  100;
  1464.         low = 20;
  1465.         percent_mid =  100;
  1466.         mid = 45;
  1467.         percent_high =  100;
  1468.         //level_range = 10;
  1469.         alive = false;
  1470.     }
  1471. } gs_dropEvent_refineBox;
  1472.  
  1473. static LPITEM __DropEvent_RefineBox_GetDropItem(CHARACTER & killer, CHARACTER & victim, ITEM_MANAGER& itemMgr)
  1474. {
  1475.     static const int lowerBox[] = { 50197, 50198, 50199 };
  1476.     static const int lowerBox_range = 3;
  1477.     static const int midderBox[] = { 50203, 50204, 50205, 50206 };
  1478.     static const int midderBox_range = 4;
  1479.     static const int higherBox[] = { 50207, 50208, 50209, 50210, 50211 };
  1480.     static const int higherBox_range = 5;
  1481.  
  1482.     if (victim.GetMobRank() < MOB_RANK_KNIGHT)
  1483.         return NULL;
  1484.  
  1485.     int killer_level = killer.GetLevel();
  1486.     //int level_diff = victim_level - killer_level;
  1487.  
  1488.     //if (level_diff >= +gs_dropEvent_refineBox.level_range || level_diff <= -gs_dropEvent_refineBox.level_range)
  1489.     //{
  1490.     //  sys_log(log_level,
  1491.     //      "dropevent.drop_refine_box.level_range_over: killer(%s: lv%d), victim(%s: lv:%d), level_diff(%d)",
  1492.     //      killer.GetName(), killer.GetLevel(), victim.GetName(), victim.GetLevel(), level_diff); 
  1493.     //  return NULL;
  1494.     //}
  1495.  
  1496.     if (killer_level <= gs_dropEvent_refineBox.low)
  1497.     {
  1498.         if (number (1, gs_dropEvent_refineBox.percent_low) == 1)
  1499.         {
  1500.             return itemMgr.CreateItem(lowerBox [number (1,lowerBox_range) - 1], 1, 0, true);
  1501.         }
  1502.     }
  1503.     else if (killer_level <= gs_dropEvent_refineBox.mid)
  1504.     {
  1505.         if (number (1, gs_dropEvent_refineBox.percent_mid) == 1)
  1506.         {
  1507.             return itemMgr.CreateItem(midderBox [number (1,midderBox_range) - 1], 1, 0, true);
  1508.         }
  1509.     }
  1510.     else
  1511.     {
  1512.         if (number (1, gs_dropEvent_refineBox.percent_high) == 1)
  1513.         {
  1514.             return itemMgr.CreateItem(higherBox [number (1,higherBox_range) - 1], 1, 0, true);
  1515.         }
  1516.     }
  1517.     return NULL;
  1518. }
  1519.  
  1520. static void __DropEvent_RefineBox_DropItem(CHARACTER & killer, CHARACTER & victim, ITEM_MANAGER& itemMgr, std::vector<LPITEM>& vec_item)
  1521. {
  1522.     if (!gs_dropEvent_refineBox.alive)
  1523.         return;
  1524.  
  1525.     int log_level = (test_server || killer.GetGMLevel() >= GM_LOW_WIZARD) ? 0 : 1;
  1526.  
  1527.     LPITEM p_item = __DropEvent_RefineBox_GetDropItem(killer, victim, itemMgr);
  1528.  
  1529.     if (p_item)
  1530.     {
  1531.         vec_item.push_back(p_item);
  1532.  
  1533.         sys_log(log_level,
  1534.             "dropevent.drop_refine_box.item_drop: killer(%s: lv%d), victim(%s: lv:%d), item_name(%s)",
  1535.             killer.GetName(), killer.GetLevel(), victim.GetName(), victim.GetLevel(), p_item->GetName());  
  1536.     }
  1537. }
  1538.  
  1539. bool DropEvent_RefineBox_SetValue(const std::string& name, int value)
  1540. {
  1541.     if (name == "refine_box_drop")
  1542.     {
  1543.         gs_dropEvent_refineBox.alive = value;
  1544.  
  1545.         if (value)
  1546.             sys_log(0, "refine_box_drop = on");
  1547.         else
  1548.             sys_log(0, "refine_box_drop = off");
  1549.  
  1550.     }
  1551.     else if (name == "refine_box_low")
  1552.         gs_dropEvent_refineBox.percent_low = value < 100 ? 100 : value;
  1553.     else if (name == "refine_box_mid")
  1554.         gs_dropEvent_refineBox.percent_mid = value < 100 ? 100 : value;
  1555.     else if (name == "refine_box_high")
  1556.         gs_dropEvent_refineBox.percent_high = value < 100 ? 100 : value;
  1557.     //else if (name == "refine_box_level_range")
  1558.     //  gs_dropEvent_refineBox.level_range = value;
  1559.     else
  1560.         return false;
  1561.  
  1562.     sys_log(0, "refine_box_drop: %d", gs_dropEvent_refineBox.alive ? true : false);
  1563.     sys_log(0, "refine_box_low: %d", gs_dropEvent_refineBox.percent_low);
  1564.     sys_log(0, "refine_box_mid: %d", gs_dropEvent_refineBox.percent_mid);
  1565.     sys_log(0, "refine_box_high: %d", gs_dropEvent_refineBox.percent_high);
  1566.     //sys_log(0, "refine_box_low_level_range: %d", gs_dropEvent_refineBox.level_range);
  1567.  
  1568.     return true;
  1569. }
  1570. // 개량 아이템 보상 끝.
  1571.  
  1572.  
  1573. void ITEM_MANAGER::CreateQuestDropItem(LPCHARACTER pkChr, LPCHARACTER pkKiller, std::vector<LPITEM> & vec_item, int iDeltaPercent, int iRandRange)
  1574. {
  1575.     LPITEM item = NULL;
  1576.  
  1577.     if (!pkChr)
  1578.         return;
  1579.  
  1580.     if (!pkKiller)
  1581.         return;
  1582.  
  1583.     sys_log(1, "CreateQuestDropItem victim(%s), killer(%s)", pkChr->GetName(), pkKiller->GetName() );
  1584.  
  1585.     // DROPEVENT_CHARSTONE
  1586.     __DropEvent_CharStone_DropItem(*pkKiller, *pkChr, *this, vec_item);
  1587.     // END_OF_DROPEVENT_CHARSTONE
  1588.     __DropEvent_RefineBox_DropItem(*pkKiller, *pkChr, *this, vec_item);
  1589.  
  1590.     // 크리스마스 양말
  1591.     if (quest::CQuestManager::instance().GetEventFlag("xmas_sock"))
  1592.     {
  1593.         //const DWORD SOCK_ITEM_VNUM = 50010;
  1594.         DWORD   SOCK_ITEM_VNUM  = 0;
  1595.         if (LC_IsKorea() || LC_IsYMIR())
  1596.         {
  1597.             SOCK_ITEM_VNUM = (number(1,100)<=50) ? 50010 : 71111;
  1598.         }
  1599.         else
  1600.         {
  1601.             SOCK_ITEM_VNUM = 50010;
  1602.         }
  1603.  
  1604.         int iDropPerKill[MOB_RANK_MAX_NUM] =
  1605.         {
  1606.             2000,
  1607.             1000,
  1608.             300,
  1609.             50,
  1610.             0,
  1611.             0,
  1612.         };
  1613.  
  1614.         if ( iDropPerKill[pkChr->GetMobRank()] != 0 )
  1615.         {
  1616.             int iPercent = 40000 * iDeltaPercent / iDropPerKill[pkChr->GetMobRank()];
  1617.  
  1618.             if ( LC_IsHongKong() )
  1619.             {
  1620.                 iPercent *= 10;
  1621.             }
  1622.  
  1623.             sys_log(0, "SOCK DROP %d %d", iPercent, iRandRange);
  1624.             if (iPercent >= number(1, iRandRange))
  1625.             {
  1626.                 if ((item = CreateItem(SOCK_ITEM_VNUM, 1, 0, true)))
  1627.                     vec_item.push_back(item);
  1628.             }
  1629.         }
  1630.     }
  1631.  
  1632.     // 월광 보합
  1633.     if (quest::CQuestManager::instance().GetEventFlag("drop_moon"))
  1634.     {
  1635.         const DWORD ITEM_VNUM = 50011;
  1636.  
  1637.         int iDropPerKill[MOB_RANK_MAX_NUM] =
  1638.         {
  1639.             2000,
  1640.             1000,
  1641.             300,
  1642.             50,
  1643.             0,
  1644.             0,
  1645.         };
  1646.  
  1647.         if (iDropPerKill[pkChr->GetMobRank()])
  1648.         {
  1649.             int iPercent = 40000 * iDeltaPercent / iDropPerKill[pkChr->GetMobRank()];
  1650.  
  1651.             if (iPercent >= number(1, iRandRange))
  1652.             {
  1653.                 if ((item = CreateItem(ITEM_VNUM, 1, 0, true)))
  1654.                     vec_item.push_back(item);
  1655.             }
  1656.         }
  1657.     }
  1658.  
  1659.     if (LC_IsEurope())
  1660.     {
  1661.         if (pkKiller->GetLevel() >= 15 && abs(pkKiller->GetLevel() - pkChr->GetLevel()) <= 5)
  1662.         {
  1663.             int pct = quest::CQuestManager::instance().GetEventFlag("hc_drop");
  1664.  
  1665.             if (pct > 0)
  1666.             {
  1667.                 const DWORD ITEM_VNUM = 30178;
  1668.  
  1669.                 if (number(1,100) <= pct)
  1670.                 {
  1671.                     if ((item = CreateItem(ITEM_VNUM, 1, 0, true)))
  1672.                         vec_item.push_back(item);
  1673.                 }
  1674.             }
  1675.         }
  1676.     }
  1677.  
  1678.     //육각보합
  1679.     if (GetDropPerKillPct(100, g_iUseLocale ? 2000 : 800, iDeltaPercent, "2006_drop") >= number(1, iRandRange))
  1680.     {
  1681.         sys_log(0, "육각보합 DROP EVENT ");
  1682.  
  1683.         const static DWORD dwVnum = 50037;
  1684.  
  1685.         if ((item = CreateItem(dwVnum, 1, 0, true)))
  1686.             vec_item.push_back(item);
  1687.  
  1688.     }
  1689.  
  1690.     //육각보합+
  1691.     if (GetDropPerKillPct(100, g_iUseLocale ? 2000 : 800, iDeltaPercent, "2007_drop") >= number(1, iRandRange))
  1692.     {
  1693.         sys_log(0, "육각보합 DROP EVENT ");
  1694.  
  1695.         const static DWORD dwVnum = 50043;
  1696.  
  1697.         if ((item = CreateItem(dwVnum, 1, 0, true)))
  1698.             vec_item.push_back(item);
  1699.     }
  1700.  
  1701.     // 새해 폭죽 이벤트
  1702.     if (GetDropPerKillPct(/* minimum */ 100, /* default */ 1000, iDeltaPercent, "newyear_fire") >= number(1, iRandRange))
  1703.     {
  1704.         // 중국은 폭죽, 한국 팽이
  1705.         const DWORD ITEM_VNUM_FIRE = g_iUseLocale ? 50107 : 50108;
  1706.  
  1707.         if ((item = CreateItem(ITEM_VNUM_FIRE, 1, 0, true)))
  1708.             vec_item.push_back(item);
  1709.     }
  1710.  
  1711.     // 새해 대보름 원소 이벤트
  1712.     if (GetDropPerKillPct(100, 500, iDeltaPercent, "newyear_moon") >= number(1, iRandRange))
  1713.     {
  1714.         sys_log(0, "EVENT NEWYEAR_MOON DROP");
  1715.  
  1716.         const static DWORD wonso_items[6] = { 50016, 50017, 50018, 50019, 50019, 50019, };
  1717.         DWORD dwVnum = wonso_items[number(0,5)];
  1718.  
  1719.         if ((item = CreateItem(dwVnum, 1, 0, true)))
  1720.             vec_item.push_back(item);
  1721.     }
  1722.  
  1723.     // 발렌타인 데이 이벤트. OGE의 요구에 따라 event 최소값을 1로 변경.(다른 이벤트는 일단 그대로 둠.)
  1724.     if (GetDropPerKillPct(1, g_iUseLocale ? 2000 : 800, iDeltaPercent, "valentine_drop") >= number(1, iRandRange))
  1725.     {
  1726.         sys_log(0, "EVENT VALENTINE_DROP");
  1727.  
  1728.         const static DWORD valentine_items[2] = { 50024, 50025 };
  1729.         DWORD dwVnum = valentine_items[number(0, 1)];
  1730.  
  1731.         if ((item = CreateItem(dwVnum, 1, 0, true)))
  1732.             vec_item.push_back(item);
  1733.     }
  1734.  
  1735.     // 아이스크림 이벤트
  1736.     if (GetDropPerKillPct(100, g_iUseLocale ? 2000 : 800, iDeltaPercent, "icecream_drop") >= number(1, iRandRange))
  1737.     {
  1738.         const static DWORD icecream = 50123;
  1739.  
  1740.         if ((item = CreateItem(icecream, 1, 0, true)))
  1741.             vec_item.push_back(item);
  1742.     }
  1743.  
  1744.     // new 크리스마스 이벤트
  1745.     // 53002 : 아기 순록 소환권
  1746.     if ((pkKiller->CountSpecifyItem(53002) > 0) && (GetDropPerKillPct(50, 100, iDeltaPercent, "new_xmas_event") >= number(1, iRandRange)))
  1747.     {
  1748.         const static DWORD xmas_sock = 50010;
  1749.         pkKiller->AutoGiveItem (xmas_sock, 1);
  1750.     }
  1751.  
  1752.     if ((pkKiller->CountSpecifyItem(53007) > 0) && (GetDropPerKillPct(50, 100, iDeltaPercent, "new_xmas_event") >= number(1, iRandRange)))
  1753.     {
  1754.         const static DWORD xmas_sock = 50010;
  1755.         pkKiller->AutoGiveItem (xmas_sock, 1);
  1756.     }
  1757.  
  1758.     //if (pkChr->GetLevel() >= 30 && (GetDropPerKillPct(50, 100, iDeltaPercent, "ds_drop") >= number(1, iRandRange)))
  1759.     //{
  1760.     //  const static DWORD dragon_soul_gemstone = 30270;
  1761.     //  if ((item = CreateItem(dragon_soul_gemstone, 1, 0, true)))
  1762.     //      vec_item.push_back(item);
  1763.     //}
  1764.  
  1765.     if ( GetDropPerKillPct(100, g_iUseLocale ? 2000 : 800, iDeltaPercent, "halloween_drop") >= number(1, iRandRange) )
  1766.     {
  1767.         const static DWORD halloween_item = 30321;
  1768.  
  1769.         if ( (item=CreateItem(halloween_item, 1, 0, true)) )
  1770.             vec_item.push_back(item);
  1771.     }
  1772.    
  1773.     if ( GetDropPerKillPct(100, g_iUseLocale ? 2000 : 800, iDeltaPercent, "ramadan_drop") >= number(1, iRandRange) )
  1774.     {
  1775.         const static DWORD ramadan_item = 30315;
  1776.  
  1777.         if ( (item=CreateItem(ramadan_item, 1, 0, true)) )
  1778.             vec_item.push_back(item);
  1779.     }
  1780.  
  1781.     if ( GetDropPerKillPct(100, g_iUseLocale ? 2000 : 800, iDeltaPercent, "easter_drop") >= number(1, iRandRange) )
  1782.     {
  1783.         const static DWORD easter_item_base = 50160;
  1784.  
  1785.         if ( (item=CreateItem(easter_item_base+number(0,19), 1, 0, true)) )
  1786.             vec_item.push_back(item);
  1787.     }
  1788.  
  1789.     // 월드컵 이벤트
  1790.     if ( GetDropPerKillPct(100, g_iUseLocale ? 2000 : 800, iDeltaPercent, "football_drop") >= number(1, iRandRange) )
  1791.     {
  1792.         const static DWORD football_item = 50096;
  1793.  
  1794.         if ( (item=CreateItem(football_item, 1, 0, true)) )
  1795.             vec_item.push_back(item);
  1796.     }
  1797.  
  1798.     // 화이트 데이 이벤트
  1799.     if (GetDropPerKillPct(100, g_iUseLocale ? 2000 : 800, iDeltaPercent, "whiteday_drop") >= number(1, iRandRange))
  1800.     {
  1801.         sys_log(0, "EVENT WHITEDAY_DROP");
  1802.         const static DWORD whiteday_items[2] = { ITEM_WHITEDAY_ROSE, ITEM_WHITEDAY_CANDY };
  1803.         DWORD dwVnum = whiteday_items[number(0,1)];
  1804.  
  1805.         if ((item = CreateItem(dwVnum, 1, 0, true)))
  1806.             vec_item.push_back(item);
  1807.     }
  1808.  
  1809.     // 어린이날 수수께끼 상자 이벤트
  1810.     if (pkKiller->GetLevel()>=50)
  1811.     {
  1812.         if (GetDropPerKillPct(100, 1000, iDeltaPercent, "kids_day_drop_high") >= number(1, iRandRange))
  1813.         {
  1814.             DWORD ITEM_QUIZ_BOX = 50034;
  1815.  
  1816.             if ((item = CreateItem(ITEM_QUIZ_BOX, 1, 0, true)))
  1817.                 vec_item.push_back(item);
  1818.         }
  1819.     }
  1820.     else
  1821.     {
  1822.         if (GetDropPerKillPct(100, 1000, iDeltaPercent, "kids_day_drop") >= number(1, iRandRange))
  1823.         {
  1824.             DWORD ITEM_QUIZ_BOX = 50034;
  1825.  
  1826.             if ((item = CreateItem(ITEM_QUIZ_BOX, 1, 0, true)))
  1827.                 vec_item.push_back(item);
  1828.         }
  1829.     }
  1830.  
  1831.     // 올림픽 드롭 이벤트
  1832.     if (pkChr->GetLevel() >= 30 && GetDropPerKillPct(50, 100, iDeltaPercent, "medal_part_drop") >= number(1, iRandRange))
  1833.     {
  1834.         const static DWORD drop_items[] = { 30265, 30266, 30267, 30268, 30269 };
  1835.         int i = number (0, 4);
  1836.         item = CreateItem(drop_items[i]);
  1837.         if (item != NULL)
  1838.             vec_item.push_back(item);
  1839.     }
  1840.  
  1841.     // ADD_GRANDMASTER_SKILL
  1842.     // 혼석 아이템 드롭
  1843.     if (pkChr->GetLevel() >= 40 && pkChr->GetMobRank() >= MOB_RANK_BOSS && GetDropPerKillPct(/* minimum */ 1, /* default */ 1000, iDeltaPercent, "three_skill_item") / GetThreeSkillLevelAdjust(pkChr->GetLevel()) >= number(1, iRandRange))
  1844.     {
  1845.         const DWORD ITEM_VNUM = 50513;
  1846.  
  1847.         if ((item = CreateItem(ITEM_VNUM, 1, 0, true)))
  1848.             vec_item.push_back(item);
  1849.     }
  1850.     // END_OF_ADD_GRANDMASTER_SKILL
  1851.  
  1852.     //
  1853.     // 종자 아이템 drop
  1854.     //
  1855.     if (GetDropPerKillPct(100, 1000, iDeltaPercent, "dragon_boat_festival_drop") >= number(1, iRandRange))
  1856.     {
  1857.         const DWORD ITEM_SEED = 50085;
  1858.  
  1859.         if ((item = CreateItem(ITEM_SEED, 1, 0, true)))
  1860.             vec_item.push_back(item);
  1861.     }
  1862.  
  1863.     // 무신의 축복서용 만년한철 drop
  1864.     if (pkKiller->GetLevel() >= 15 && quest::CQuestManager::instance().GetEventFlag("mars_drop"))
  1865.     {
  1866.         const DWORD ITEM_HANIRON = 70035;
  1867.         int iDropMultiply[MOB_RANK_MAX_NUM] =
  1868.         {
  1869.             50,
  1870.             30,
  1871.             5,
  1872.             1,
  1873.             0,
  1874.             0,
  1875.         };
  1876.  
  1877.         if (iDropMultiply[pkChr->GetMobRank()] &&
  1878.                 GetDropPerKillPct(1000, 1500, iDeltaPercent, "mars_drop") >= number(1, iRandRange) * iDropMultiply[pkChr->GetMobRank()])
  1879.         {
  1880.             if ((item = CreateItem(ITEM_HANIRON, 1, 0, true)))
  1881.                 vec_item.push_back(item);
  1882.         }
  1883.     }
  1884. }
  1885.  
  1886. DWORD ITEM_MANAGER::GetRefineFromVnum(DWORD dwVnum)
  1887. {
  1888.     itertype(m_map_ItemRefineFrom) it = m_map_ItemRefineFrom.find(dwVnum);
  1889.     if (it != m_map_ItemRefineFrom.end())
  1890.         return it->second;
  1891.     return 0;
  1892. }
  1893.  
  1894. const CSpecialItemGroup* ITEM_MANAGER::GetSpecialItemGroup(DWORD dwVnum)
  1895. {
  1896.     itertype(m_map_pkSpecialItemGroup) it = m_map_pkSpecialItemGroup.find(dwVnum);
  1897.     if (it != m_map_pkSpecialItemGroup.end())
  1898.     {
  1899.         return it->second;
  1900.     }
  1901.     return NULL;
  1902. }
  1903.  
  1904. const CSpecialAttrGroup* ITEM_MANAGER::GetSpecialAttrGroup(DWORD dwVnum)
  1905. {
  1906.     itertype(m_map_pkSpecialAttrGroup) it = m_map_pkSpecialAttrGroup.find(dwVnum);
  1907.     if (it != m_map_pkSpecialAttrGroup.end())
  1908.     {
  1909.         return it->second;
  1910.     }
  1911.     return NULL;
  1912. }
  1913.  
  1914. DWORD ITEM_MANAGER::GetMaskVnum(DWORD dwVnum)
  1915. {
  1916.     TMapDW2DW::iterator it = m_map_new_to_ori.find (dwVnum);
  1917.     if (it != m_map_new_to_ori.end())
  1918.     {
  1919.         return it->second;
  1920.     }
  1921.     else
  1922.         return 0;
  1923. }
  1924.  
  1925. // pkNewItem으로 모든 속성과 소켓 값들을 목사하는 함수.
  1926. // 기존에 char_item.cpp 파일에 있던 로컬함수인 TransformRefineItem 그대로 복사함
  1927. void ITEM_MANAGER::CopyAllAttrTo(LPITEM pkOldItem, LPITEM pkNewItem)
  1928. {
  1929.     // ACCESSORY_REFINE
  1930.     if (pkOldItem->IsAccessoryForSocket())
  1931.     {
  1932.         for (int i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
  1933.         {
  1934.             pkNewItem->SetSocket(i, pkOldItem->GetSocket(i));
  1935.         }
  1936.         //pkNewItem->StartAccessorySocketExpireEvent();
  1937.     }
  1938.     // END_OF_ACCESSORY_REFINE
  1939.     else
  1940.     {
  1941.         // 여기서 깨진석이 자동적으로 청소 됨
  1942.         for (int i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
  1943.         {
  1944.             if (!pkOldItem->GetSocket(i))
  1945.                 break;
  1946.             else
  1947.                 pkNewItem->SetSocket(i, 1);
  1948.         }
  1949.  
  1950.         // 소켓 설정
  1951.         int slot = 0;
  1952.  
  1953.         for (int i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
  1954.         {
  1955.             long socket = pkOldItem->GetSocket(i);
  1956.             const int ITEM_BROKEN_METIN_VNUM = 28960; // 이건 뭐 똑같은 상수가 3군데나 있냐... 하나로 해놓지ㅠㅠㅠ 나는 패스 홍이 할꺼임
  1957.             if (socket > 2 && socket != ITEM_BROKEN_METIN_VNUM)
  1958.                 pkNewItem->SetSocket(slot++, socket);
  1959.         }
  1960.  
  1961.     }
  1962.  
  1963.     // 매직 아이템 설정
  1964.     pkOldItem->CopyAttributeTo(pkNewItem);
  1965. }
Add Comment
Please, Sign In to add comment