Advertisement
Guest User

Untitled

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