Advertisement
Guest User

item_manager.cpp

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