protozaki

Untitled

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