Guest User

Untitled

a guest
Dec 6th, 2017
1,401
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 68.14 KB | None | 0 0
  1. #include "stdafx.h"
  2. #ifdef __FreeBSD__
  3. #include <md5.h>
  4. #else
  5. #include "../../libthecore/include/xmd5.h"
  6. #endif
  7.  
  8. #include "utils.h"
  9. #include "config.h"
  10. #include "desc_client.h"
  11. #include "desc_manager.h"
  12. #include "char.h"
  13. #include "char_manager.h"
  14. #include "motion.h"
  15. #include "packet.h"
  16. #include "affect.h"
  17. #include "pvp.h"
  18. #include "start_position.h"
  19. #include "party.h"
  20. #include "guild_manager.h"
  21. #include "p2p.h"
  22. #include "dungeon.h"
  23. #include "messenger_manager.h"
  24. #include "war_map.h"
  25. #include "questmanager.h"
  26. #include "item_manager.h"
  27. #include "monarch.h"
  28. #include "mob_manager.h"
  29. #include "dev_log.h"
  30. #include "item.h"
  31. #include "arena.h"
  32. #include "buffer_manager.h"
  33. #include "unique_item.h"
  34. #include "threeway_war.h"
  35. #include "log.h"
  36. #include "../../common/VnumHelper.h"
  37. #ifdef __AUCTION__
  38. #include "auction_manager.h"
  39. #endif
  40.  
  41. extern int g_server_id;
  42.  
  43. extern int g_nPortalLimitTime;
  44.  
  45. ACMD(do_user_horse_ride)
  46. {
  47. if (ch->IsObserverMode())
  48. return;
  49.  
  50. if (ch->IsDead() || ch->IsStun())
  51. return;
  52.  
  53. if (ch->IsHorseRiding() == false)
  54. {
  55. // 말이 아닌 다른탈것을 타고있다.
  56. if (ch->GetMountVnum())
  57. {
  58. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("이미 탈것을 이용중입니다."));
  59. return;
  60. }
  61.  
  62. if (ch->GetHorse() == NULL)
  63. {
  64. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("말을 먼저 소환해주세요."));
  65. return;
  66. }
  67.  
  68. ch->StartRiding();
  69. }
  70. else
  71. {
  72. ch->StopRiding();
  73. }
  74. }
  75.  
  76. ACMD(do_user_horse_back)
  77. {
  78. if (ch->GetHorse() != NULL)
  79. {
  80. ch->HorseSummon(false);
  81. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("말을 돌려보냈습니다."));
  82. }
  83. else if (ch->IsHorseRiding() == true)
  84. {
  85. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("말에서 먼저 내려야 합니다."));
  86. }
  87. else
  88. {
  89. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("말을 먼저 소환해주세요."));
  90. }
  91. }
  92.  
  93. ACMD(do_user_horse_feed)
  94. {
  95. // 개인상점을 연 상태에서는 말 먹이를 줄 수 없다.
  96. if (ch->GetMyShop())
  97. return;
  98.  
  99. if (ch->GetHorse() == NULL)
  100. {
  101. if (ch->IsHorseRiding() == false)
  102. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("말을 먼저 소환해주세요."));
  103. else
  104. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("말을 탄 상태에서는 먹이를 줄 수 없습니다."));
  105. return;
  106. }
  107.  
  108. DWORD dwFood = ch->GetHorseGrade() + 50054 - 1;
  109.  
  110. if (ch->CountSpecifyItem(dwFood) > 0)
  111. {
  112. ch->RemoveSpecifyItem(dwFood, 1);
  113. ch->FeedHorse();
  114. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("말에게 %s%s 주었습니다."),
  115. ITEM_MANAGER::instance().GetTable(dwFood)->szLocaleName,
  116. g_iUseLocale ? "" : under_han(ITEM_MANAGER::instance().GetTable(dwFood)->szLocaleName) ? LC_TEXT("을") : LC_TEXT("를"));
  117. }
  118. else
  119. {
  120. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s 아이템이 필요합니다"), ITEM_MANAGER::instance().GetTable(dwFood)->szLocaleName);
  121. }
  122. }
  123.  
  124. #define MAX_REASON_LEN 128
  125.  
  126. EVENTINFO(TimedEventInfo)
  127. {
  128. DynamicCharacterPtr ch;
  129. int subcmd;
  130. int left_second;
  131. char szReason[MAX_REASON_LEN];
  132.  
  133. TimedEventInfo()
  134. : ch()
  135. , subcmd( 0 )
  136. , left_second( 0 )
  137. {
  138. ::memset( szReason, 0, MAX_REASON_LEN );
  139. }
  140. };
  141.  
  142. struct SendDisconnectFunc
  143. {
  144. void operator () (LPDESC d)
  145. {
  146. if (d->GetCharacter())
  147. {
  148. if (d->GetCharacter()->GetGMLevel() == GM_PLAYER)
  149. d->GetCharacter()->ChatPacket(CHAT_TYPE_COMMAND, "quit Shutdown(SendDisconnectFunc)");
  150. }
  151. }
  152. };
  153.  
  154. struct DisconnectFunc
  155. {
  156. void operator () (LPDESC d)
  157. {
  158. if (d->GetType() == DESC_TYPE_CONNECTOR)
  159. return;
  160.  
  161. if (d->IsPhase(PHASE_P2P))
  162. return;
  163.  
  164. if (d->GetCharacter())
  165. d->GetCharacter()->Disconnect("Shutdown(DisconnectFunc)");
  166.  
  167. d->SetPhase(PHASE_CLOSE);
  168. }
  169. };
  170.  
  171. EVENTINFO(shutdown_event_data)
  172. {
  173. int seconds;
  174.  
  175. shutdown_event_data()
  176. : seconds( 0 )
  177. {
  178. }
  179. };
  180.  
  181. EVENTFUNC(shutdown_event)
  182. {
  183. shutdown_event_data* info = dynamic_cast<shutdown_event_data*>( event->info );
  184.  
  185. if ( info == NULL )
  186. {
  187. sys_err( "shutdown_event> <Factor> Null pointer" );
  188. return 0;
  189. }
  190.  
  191. int * pSec = & (info->seconds);
  192.  
  193. if (*pSec < 0)
  194. {
  195. sys_log(0, "shutdown_event sec %d", *pSec);
  196.  
  197. if (--*pSec == -10)
  198. {
  199. const DESC_MANAGER::DESC_SET & c_set_desc = DESC_MANAGER::instance().GetClientSet();
  200. std::for_each(c_set_desc.begin(), c_set_desc.end(), DisconnectFunc());
  201. return passes_per_sec;
  202. }
  203. else if (*pSec < -10)
  204. return 0;
  205.  
  206. return passes_per_sec;
  207. }
  208. else if (*pSec == 0)
  209. {
  210. const DESC_MANAGER::DESC_SET & c_set_desc = DESC_MANAGER::instance().GetClientSet();
  211. std::for_each(c_set_desc.begin(), c_set_desc.end(), SendDisconnectFunc());
  212. g_bNoMoreClient = true;
  213. --*pSec;
  214. return passes_per_sec;
  215. }
  216. else
  217. {
  218. char buf[64];
  219. snprintf(buf, sizeof(buf), LC_TEXT("셧다운이 %d초 남았습니다."), *pSec);
  220. SendNotice(buf);
  221.  
  222. --*pSec;
  223. return passes_per_sec;
  224. }
  225. }
  226.  
  227. void Shutdown(int iSec)
  228. {
  229. if (g_bNoMoreClient)
  230. {
  231. thecore_shutdown();
  232. return;
  233. }
  234.  
  235. CWarMapManager::instance().OnShutdown();
  236.  
  237. char buf[64];
  238. snprintf(buf, sizeof(buf), LC_TEXT("%d초 후 게임이 셧다운 됩니다."), iSec);
  239.  
  240. SendNotice(buf);
  241.  
  242. shutdown_event_data* info = AllocEventInfo<shutdown_event_data>();
  243. info->seconds = iSec;
  244.  
  245. event_create(shutdown_event, info, 1);
  246. }
  247.  
  248. ACMD(do_shutdown)
  249. {
  250. if (NULL == ch)
  251. {
  252. sys_err("Accept shutdown command from %s.", ch->GetName());
  253. }
  254. TPacketGGShutdown p;
  255. p.bHeader = HEADER_GG_SHUTDOWN;
  256. P2P_MANAGER::instance().Send(&p, sizeof(TPacketGGShutdown));
  257.  
  258. Shutdown(10);
  259. }
  260.  
  261. EVENTFUNC(timed_event)
  262. {
  263. TimedEventInfo * info = dynamic_cast<TimedEventInfo *>( event->info );
  264.  
  265. if ( info == NULL )
  266. {
  267. sys_err( "timed_event> <Factor> Null pointer" );
  268. return 0;
  269. }
  270.  
  271. LPCHARACTER ch = info->ch;
  272. if (ch == NULL) { // <Factor>
  273. return 0;
  274. }
  275. LPDESC d = ch->GetDesc();
  276.  
  277. if (info->left_second <= 0)
  278. {
  279. ch->m_pkTimedEvent = NULL;
  280.  
  281. if (true == LC_IsEurope() || true == LC_IsYMIR() || true == LC_IsKorea())
  282. {
  283. switch (info->subcmd)
  284. {
  285. case SCMD_LOGOUT:
  286. case SCMD_QUIT:
  287. case SCMD_PHASE_SELECT:
  288. {
  289. TPacketNeedLoginLogInfo acc_info;
  290. acc_info.dwPlayerID = ch->GetDesc()->GetAccountTable().id;
  291.  
  292. db_clientdesc->DBPacket( HEADER_GD_VALID_LOGOUT, 0, &acc_info, sizeof(acc_info) );
  293.  
  294. LogManager::instance().DetailLoginLog( false, ch );
  295. }
  296. break;
  297. }
  298. }
  299.  
  300. switch (info->subcmd)
  301. {
  302. case SCMD_LOGOUT:
  303. if (d)
  304. d->SetPhase(PHASE_CLOSE);
  305. break;
  306.  
  307. case SCMD_QUIT:
  308. ch->ChatPacket(CHAT_TYPE_COMMAND, "quit");
  309. break;
  310.  
  311. case SCMD_PHASE_SELECT:
  312. {
  313. ch->Disconnect("timed_event - SCMD_PHASE_SELECT");
  314.  
  315. if (d)
  316. {
  317. d->SetPhase(PHASE_SELECT);
  318. }
  319. }
  320. break;
  321. }
  322.  
  323. return 0;
  324. }
  325. else
  326. {
  327. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%d초 남았습니다."), info->left_second);
  328. --info->left_second;
  329. }
  330.  
  331. return PASSES_PER_SEC(1);
  332. }
  333.  
  334. ACMD(do_cmd)
  335. {
  336. /* RECALL_DELAY
  337. if (ch->m_pkRecallEvent != NULL)
  338. {
  339. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("취소 되었습니다."));
  340. event_cancel(&ch->m_pkRecallEvent);
  341. return;
  342. }
  343. // END_OF_RECALL_DELAY */
  344.  
  345. if (ch->m_pkTimedEvent)
  346. {
  347. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("취소 되었습니다."));
  348. event_cancel(&ch->m_pkTimedEvent);
  349. return;
  350. }
  351.  
  352. switch (subcmd)
  353. {
  354. case SCMD_LOGOUT:
  355. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("로그인 화면으로 돌아 갑니다. 잠시만 기다리세요."));
  356. break;
  357.  
  358. case SCMD_QUIT:
  359. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("게임을 종료 합니다. 잠시만 기다리세요."));
  360. break;
  361.  
  362. case SCMD_PHASE_SELECT:
  363. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("캐릭터를 전환 합니다. 잠시만 기다리세요."));
  364. break;
  365. }
  366.  
  367. int nExitLimitTime = 10;
  368.  
  369. if (ch->IsHack(false, true, nExitLimitTime) &&
  370. false == CThreeWayWar::instance().IsSungZiMapIndex(ch->GetMapIndex()) &&
  371. (!ch->GetWarMap() || ch->GetWarMap()->GetType() == GUILD_WAR_TYPE_FLAG))
  372. {
  373. return;
  374. }
  375.  
  376. switch (subcmd)
  377. {
  378. case SCMD_LOGOUT:
  379. case SCMD_QUIT:
  380. case SCMD_PHASE_SELECT:
  381. {
  382. TimedEventInfo* info = AllocEventInfo<TimedEventInfo>();
  383.  
  384. {
  385. if (ch->IsPosition(POS_FIGHTING))
  386. info->left_second = 10;
  387. else
  388. info->left_second = 3;
  389. }
  390.  
  391. info->ch = ch;
  392. info->subcmd = subcmd;
  393. strlcpy(info->szReason, argument, sizeof(info->szReason));
  394.  
  395. ch->m_pkTimedEvent = event_create(timed_event, info, 1);
  396. }
  397. break;
  398. }
  399. }
  400.  
  401. ACMD(do_mount)
  402. {
  403. /*
  404. char arg1[256];
  405. struct action_mount_param param;
  406.  
  407. // 이미 타고 있으면
  408. if (ch->GetMountingChr())
  409. {
  410. char arg2[256];
  411. two_arguments(argument, arg1, sizeof(arg1), arg2, sizeof(arg2));
  412.  
  413. if (!*arg1 || !*arg2)
  414. return;
  415.  
  416. param.x = atoi(arg1);
  417. param.y = atoi(arg2);
  418. param.vid = ch->GetMountingChr()->GetVID();
  419. param.is_unmount = true;
  420.  
  421. float distance = DISTANCE_SQRT(param.x - (DWORD) ch->GetX(), param.y - (DWORD) ch->GetY());
  422.  
  423. if (distance > 600.0f)
  424. {
  425. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("좀 더 가까이 가서 내리세요."));
  426. return;
  427. }
  428.  
  429. action_enqueue(ch, ACTION_TYPE_MOUNT, &param, 0.0f, true);
  430. return;
  431. }
  432.  
  433. one_argument(argument, arg1, sizeof(arg1));
  434.  
  435. if (!*arg1)
  436. return;
  437.  
  438. LPCHARACTER tch = CHARACTER_MANAGER::instance().Find(atoi(arg1));
  439.  
  440. if (!tch->IsNPC() || !tch->IsMountable())
  441. {
  442. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("거기에는 탈 수 없어요."));
  443. return;
  444. }
  445.  
  446. float distance = DISTANCE_SQRT(tch->GetX() - ch->GetX(), tch->GetY() - ch->GetY());
  447.  
  448. if (distance > 600.0f)
  449. {
  450. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("좀 더 가까이 가서 타세요."));
  451. return;
  452. }
  453.  
  454. param.vid = tch->GetVID();
  455. param.is_unmount = false;
  456.  
  457. action_enqueue(ch, ACTION_TYPE_MOUNT, &param, 0.0f, true);
  458. */
  459. }
  460.  
  461. ACMD(do_fishing)
  462. {
  463. char arg1[256];
  464. one_argument(argument, arg1, sizeof(arg1));
  465.  
  466. if (!*arg1)
  467. return;
  468.  
  469. ch->SetRotation(atof(arg1));
  470. ch->fishing();
  471. }
  472.  
  473. ACMD(do_console)
  474. {
  475. ch->ChatPacket(CHAT_TYPE_COMMAND, "ConsoleEnable");
  476. }
  477.  
  478. ACMD(do_restart)
  479. {
  480. if (false == ch->IsDead())
  481. {
  482. ch->ChatPacket(CHAT_TYPE_COMMAND, "CloseRestartWindow");
  483. ch->StartRecoveryEvent();
  484. return;
  485. }
  486.  
  487. if (NULL == ch->m_pkDeadEvent)
  488. return;
  489.  
  490. int iTimeToDead = (event_time(ch->m_pkDeadEvent) / passes_per_sec);
  491.  
  492. if (subcmd != SCMD_RESTART_TOWN && (!ch->GetWarMap() || ch->GetWarMap()->GetType() == GUILD_WAR_TYPE_FLAG))
  493. {
  494. if (!test_server)
  495. {
  496. if (ch->IsHack())
  497. {
  498. //성지 맵일경우에는 체크 하지 않는다.
  499. if (false == CThreeWayWar::instance().IsSungZiMapIndex(ch->GetMapIndex()))
  500. {
  501. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("아직 재시작 할 수 없습니다. (%d초 남음)"), iTimeToDead - (180 - g_nPortalLimitTime));
  502. return;
  503. }
  504. }
  505.  
  506. if (iTimeToDead > 170)
  507. {
  508. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("아직 재시작 할 수 없습니다. (%d초 남음)"), iTimeToDead - 170);
  509. return;
  510. }
  511. }
  512. }
  513.  
  514. //PREVENT_HACK
  515. //DESC : 창고, 교환 창 후 포탈을 사용하는 버그에 이용될수 있어서
  516. // 쿨타임을 추가
  517. if (subcmd == SCMD_RESTART_TOWN)
  518. {
  519. if (ch->IsHack())
  520. {
  521. //길드맵, 성지맵에서는 체크 하지 않는다.
  522. if ((!ch->GetWarMap() || ch->GetWarMap()->GetType() == GUILD_WAR_TYPE_FLAG) ||
  523. false == CThreeWayWar::instance().IsSungZiMapIndex(ch->GetMapIndex()))
  524. {
  525. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("아직 재시작 할 수 없습니다. (%d초 남음)"), iTimeToDead - (180 - g_nPortalLimitTime));
  526. return;
  527. }
  528. }
  529.  
  530. if (iTimeToDead > 173)
  531. {
  532. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("아직 마을에서 재시작 할 수 없습니다. (%d 초 남음)"), iTimeToDead - 173);
  533. return;
  534. }
  535. }
  536. //END_PREVENT_HACK
  537.  
  538. ch->ChatPacket(CHAT_TYPE_COMMAND, "CloseRestartWindow");
  539.  
  540. ch->GetDesc()->SetPhase(PHASE_GAME);
  541. ch->SetPosition(POS_STANDING);
  542. ch->StartRecoveryEvent();
  543.  
  544. //FORKED_LOAD
  545. //DESC: 삼거리 전투시 부활을 할경우 맵의 입구가 아닌 삼거리 전투의 시작지점으로 이동하게 된다.
  546. if (1 == quest::CQuestManager::instance().GetEventFlag("threeway_war"))
  547. {
  548. if (subcmd == SCMD_RESTART_TOWN || subcmd == SCMD_RESTART_HERE)
  549. {
  550. if (true == CThreeWayWar::instance().IsThreeWayWarMapIndex(ch->GetMapIndex()) &&
  551. false == CThreeWayWar::instance().IsSungZiMapIndex(ch->GetMapIndex()))
  552. {
  553. ch->WarpSet(EMPIRE_START_X(ch->GetEmpire()), EMPIRE_START_Y(ch->GetEmpire()));
  554.  
  555. ch->ReviveInvisible(5);
  556. ch->PointChange(POINT_HP, ch->GetMaxHP() - ch->GetHP());
  557. ch->PointChange(POINT_SP, ch->GetMaxSP() - ch->GetSP());
  558.  
  559. return;
  560. }
  561.  
  562. //성지
  563. if (true == CThreeWayWar::instance().IsSungZiMapIndex(ch->GetMapIndex()))
  564. {
  565. if (CThreeWayWar::instance().GetReviveTokenForPlayer(ch->GetPlayerID()) <= 0)
  566. {
  567. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("성지에서 부활 기회를 모두 잃었습니다! 마을로 이동합니다!"));
  568. ch->WarpSet(EMPIRE_START_X(ch->GetEmpire()), EMPIRE_START_Y(ch->GetEmpire()));
  569. }
  570. else
  571. {
  572. ch->Show(ch->GetMapIndex(), GetSungziStartX(ch->GetEmpire()), GetSungziStartY(ch->GetEmpire()));
  573. }
  574.  
  575. ch->PointChange(POINT_HP, ch->GetMaxHP() - ch->GetHP());
  576. ch->PointChange(POINT_SP, ch->GetMaxSP() - ch->GetSP());
  577. ch->ReviveInvisible(5);
  578.  
  579. return;
  580. }
  581. }
  582. }
  583. //END_FORKED_LOAD
  584.  
  585. if (ch->GetDungeon())
  586. ch->GetDungeon()->UseRevive(ch);
  587.  
  588. if (ch->GetWarMap() && !ch->IsObserverMode())
  589. {
  590. CWarMap * pMap = ch->GetWarMap();
  591. DWORD dwGuildOpponent = pMap ? pMap->GetGuildOpponent(ch) : 0;
  592.  
  593. if (dwGuildOpponent)
  594. {
  595. switch (subcmd)
  596. {
  597. case SCMD_RESTART_TOWN:
  598. sys_log(0, "do_restart: restart town");
  599. PIXEL_POSITION pos;
  600.  
  601. if (CWarMapManager::instance().GetStartPosition(ch->GetMapIndex(), ch->GetGuild()->GetID() < dwGuildOpponent ? 0 : 1, pos))
  602. ch->Show(ch->GetMapIndex(), pos.x, pos.y);
  603. else
  604. ch->ExitToSavedLocation();
  605.  
  606. ch->PointChange(POINT_HP, ch->GetMaxHP() - ch->GetHP());
  607. ch->PointChange(POINT_SP, ch->GetMaxSP() - ch->GetSP());
  608. ch->ReviveInvisible(5);
  609. break;
  610.  
  611. case SCMD_RESTART_HERE:
  612. sys_log(0, "do_restart: restart here");
  613. ch->RestartAtSamePos();
  614. //ch->Show(ch->GetMapIndex(), ch->GetX(), ch->GetY());
  615. ch->PointChange(POINT_HP, ch->GetMaxHP() - ch->GetHP());
  616. ch->PointChange(POINT_SP, ch->GetMaxSP() - ch->GetSP());
  617. ch->ReviveInvisible(5);
  618. break;
  619. }
  620.  
  621. return;
  622. }
  623. }
  624.  
  625. switch (subcmd)
  626. {
  627. case SCMD_RESTART_TOWN:
  628. sys_log(0, "do_restart: restart town");
  629. PIXEL_POSITION pos;
  630.  
  631. if (SECTREE_MANAGER::instance().GetRecallPositionByEmpire(ch->GetMapIndex(), ch->GetEmpire(), pos))
  632. ch->WarpSet(pos.x, pos.y);
  633. else
  634. ch->WarpSet(EMPIRE_START_X(ch->GetEmpire()), EMPIRE_START_Y(ch->GetEmpire()));
  635.  
  636. ch->PointChange(POINT_HP, 50 - ch->GetHP());
  637. ch->DeathPenalty(1);
  638. break;
  639.  
  640. case SCMD_RESTART_HERE:
  641. sys_log(0, "do_restart: restart here");
  642. ch->RestartAtSamePos();
  643. //ch->Show(ch->GetMapIndex(), ch->GetX(), ch->GetY());
  644. ch->PointChange(POINT_HP, 50 - ch->GetHP());
  645. ch->DeathPenalty(0);
  646. ch->ReviveInvisible(5);
  647. break;
  648. }
  649. }
  650.  
  651. #define MAX_STAT 140
  652.  
  653. ACMD(do_stat_reset)
  654. {
  655. ch->PointChange(POINT_STAT_RESET_COUNT, 12 - ch->GetPoint(POINT_STAT_RESET_COUNT));
  656. }
  657.  
  658. ACMD(do_stat_minus)
  659. {
  660. char arg1[256];
  661. one_argument(argument, arg1, sizeof(arg1));
  662.  
  663. if (!*arg1)
  664. return;
  665.  
  666. if (ch->IsPolymorphed())
  667. {
  668. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("둔갑 중에는 능력을 올릴 수 없습니다."));
  669. return;
  670. }
  671.  
  672. if (ch->GetPoint(POINT_STAT_RESET_COUNT) <= 0)
  673. return;
  674.  
  675. if (!strcmp(arg1, "st"))
  676. {
  677. if (ch->GetRealPoint(POINT_ST) <= JobInitialPoints[ch->GetJob()].st)
  678. return;
  679.  
  680. ch->SetRealPoint(POINT_ST, ch->GetRealPoint(POINT_ST) - 1);
  681. ch->SetPoint(POINT_ST, ch->GetPoint(POINT_ST) - 1);
  682. ch->ComputePoints();
  683. ch->PointChange(POINT_ST, 0);
  684. }
  685. else if (!strcmp(arg1, "dx"))
  686. {
  687. if (ch->GetRealPoint(POINT_DX) <= JobInitialPoints[ch->GetJob()].dx)
  688. return;
  689.  
  690. ch->SetRealPoint(POINT_DX, ch->GetRealPoint(POINT_DX) - 1);
  691. ch->SetPoint(POINT_DX, ch->GetPoint(POINT_DX) - 1);
  692. ch->ComputePoints();
  693. ch->PointChange(POINT_DX, 0);
  694. }
  695. else if (!strcmp(arg1, "ht"))
  696. {
  697. if (ch->GetRealPoint(POINT_HT) <= JobInitialPoints[ch->GetJob()].ht)
  698. return;
  699.  
  700. ch->SetRealPoint(POINT_HT, ch->GetRealPoint(POINT_HT) - 1);
  701. ch->SetPoint(POINT_HT, ch->GetPoint(POINT_HT) - 1);
  702. ch->ComputePoints();
  703. ch->PointChange(POINT_HT, 0);
  704. ch->PointChange(POINT_MAX_HP, 0);
  705. }
  706. else if (!strcmp(arg1, "iq"))
  707. {
  708. if (ch->GetRealPoint(POINT_IQ) <= JobInitialPoints[ch->GetJob()].iq)
  709. return;
  710.  
  711. ch->SetRealPoint(POINT_IQ, ch->GetRealPoint(POINT_IQ) - 1);
  712. ch->SetPoint(POINT_IQ, ch->GetPoint(POINT_IQ) - 1);
  713. ch->ComputePoints();
  714. ch->PointChange(POINT_IQ, 0);
  715. ch->PointChange(POINT_MAX_SP, 0);
  716. }
  717. else
  718. return;
  719.  
  720. ch->PointChange(POINT_STAT, +1);
  721. ch->PointChange(POINT_STAT_RESET_COUNT, -1);
  722. ch->ComputePoints();
  723. }
  724.  
  725. ACMD(do_stat)
  726. {
  727. char arg1[256];
  728. one_argument(argument, arg1, sizeof(arg1));
  729.  
  730. if (!*arg1)
  731. return;
  732.  
  733. if (ch->IsPolymorphed())
  734. {
  735. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("둔갑 중에는 능력을 올릴 수 없습니다."));
  736. return;
  737. }
  738.  
  739. if (ch->GetPoint(POINT_STAT) <= 0)
  740. return;
  741.  
  742. BYTE idx = 0;
  743.  
  744. if (!strcmp(arg1, "st"))
  745. idx = POINT_ST;
  746. else if (!strcmp(arg1, "dx"))
  747. idx = POINT_DX;
  748. else if (!strcmp(arg1, "ht"))
  749. idx = POINT_HT;
  750. else if (!strcmp(arg1, "iq"))
  751. idx = POINT_IQ;
  752. else
  753. return;
  754.  
  755. if (ch->GetRealPoint(idx) >= MAX_STAT)
  756. return;
  757.  
  758. ch->SetRealPoint(idx, ch->GetRealPoint(idx) + 1);
  759. ch->SetPoint(idx, ch->GetPoint(idx) + 1);
  760. ch->ComputePoints();
  761. ch->PointChange(idx, 0);
  762.  
  763. if (idx == POINT_IQ)
  764. {
  765. ch->PointChange(POINT_MAX_HP, 0);
  766. }
  767. else if (idx == POINT_HT)
  768. {
  769. ch->PointChange(POINT_MAX_SP, 0);
  770. }
  771.  
  772. ch->PointChange(POINT_STAT, -1);
  773. ch->ComputePoints();
  774. }
  775.  
  776. ACMD(do_pvp)
  777. {
  778. if (ch->GetArena() != NULL || CArenaManager::instance().IsArenaMap(ch->GetMapIndex()) == true)
  779. {
  780. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("대련장에서 사용하실 수 없습니다."));
  781. return;
  782. }
  783.  
  784. char arg1[256];
  785. one_argument(argument, arg1, sizeof(arg1));
  786.  
  787. DWORD vid = 0;
  788. str_to_number(vid, arg1);
  789. LPCHARACTER pkVictim = CHARACTER_MANAGER::instance().Find(vid);
  790.  
  791. if (!pkVictim)
  792. return;
  793.  
  794. if (pkVictim->IsNPC())
  795. return;
  796.  
  797. if (pkVictim->GetArena() != NULL)
  798. {
  799. pkVictim->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("상대방이 대련중입니다."));
  800. return;
  801. }
  802.  
  803. CPVPManager::instance().Insert(ch, pkVictim);
  804. }
  805.  
  806. ACMD(do_guildskillup)
  807. {
  808. char arg1[256];
  809. one_argument(argument, arg1, sizeof(arg1));
  810.  
  811. if (!*arg1)
  812. return;
  813.  
  814. if (!ch->GetGuild())
  815. {
  816. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드에 속해있지 않습니다."));
  817. return;
  818. }
  819.  
  820. CGuild* g = ch->GetGuild();
  821. TGuildMember* gm = g->GetMember(ch->GetPlayerID());
  822. if (gm->grade == GUILD_LEADER_GRADE)
  823. {
  824. DWORD vnum = 0;
  825. str_to_number(vnum, arg1);
  826. g->SkillLevelUp(vnum);
  827. }
  828. else
  829. {
  830. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드 스킬 레벨을 변경할 권한이 없습니다."));
  831. }
  832. }
  833.  
  834. ACMD(do_skillup)
  835. {
  836. char arg1[256];
  837. one_argument(argument, arg1, sizeof(arg1));
  838.  
  839. if (!*arg1)
  840. return;
  841.  
  842. DWORD vnum = 0;
  843. str_to_number(vnum, arg1);
  844.  
  845. if (true == ch->CanUseSkill(vnum))
  846. {
  847. ch->SkillLevelUp(vnum);
  848. }
  849. else
  850. {
  851. switch(vnum)
  852. {
  853. case SKILL_HORSE_WILDATTACK:
  854. case SKILL_HORSE_CHARGE:
  855. case SKILL_HORSE_ESCAPE:
  856. case SKILL_HORSE_WILDATTACK_RANGE:
  857.  
  858. case SKILL_7_A_ANTI_TANHWAN:
  859. case SKILL_7_B_ANTI_AMSEOP:
  860. case SKILL_7_C_ANTI_SWAERYUNG:
  861. case SKILL_7_D_ANTI_YONGBI:
  862.  
  863. case SKILL_8_A_ANTI_GIGONGCHAM:
  864. case SKILL_8_B_ANTI_YEONSA:
  865. case SKILL_8_C_ANTI_MAHWAN:
  866. case SKILL_8_D_ANTI_BYEURAK:
  867.  
  868. case SKILL_ADD_HP:
  869. case SKILL_RESIST_PENETRATE:
  870. ch->SkillLevelUp(vnum);
  871. break;
  872. }
  873. }
  874. }
  875.  
  876. //
  877. // @version 05/06/20 Bang2ni - 커맨드 처리 Delegate to CHARACTER class
  878. //
  879. ACMD(do_safebox_close)
  880. {
  881. ch->CloseSafebox();
  882. }
  883.  
  884. //
  885. // @version 05/06/20 Bang2ni - 커맨드 처리 Delegate to CHARACTER class
  886. //
  887. ACMD(do_safebox_password)
  888. {
  889. char arg1[256];
  890. one_argument(argument, arg1, sizeof(arg1));
  891. ch->ReqSafeboxLoad(arg1);
  892. }
  893.  
  894. ACMD(do_safebox_change_password)
  895. {
  896. char arg1[256];
  897. char arg2[256];
  898.  
  899. two_arguments(argument, arg1, sizeof(arg1), arg2, sizeof(arg2));
  900.  
  901. if (!*arg1 || strlen(arg1)>6)
  902. {
  903. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<창고> 잘못된 암호를 입력하셨습니다."));
  904. return;
  905. }
  906.  
  907. if (!*arg2 || strlen(arg2)>6)
  908. {
  909. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<창고> 잘못된 암호를 입력하셨습니다."));
  910. return;
  911. }
  912.  
  913. if (LC_IsBrazil() == true)
  914. {
  915. for (int i = 0; i < 6; ++i)
  916. {
  917. if (arg2[i] == '\0')
  918. break;
  919.  
  920. if (isalpha(arg2[i]) == false)
  921. {
  922. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<창고> 비밀번호는 영문자만 가능합니다."));
  923. return;
  924. }
  925. }
  926. }
  927.  
  928. TSafeboxChangePasswordPacket p;
  929.  
  930. p.dwID = ch->GetDesc()->GetAccountTable().id;
  931. strlcpy(p.szOldPassword, arg1, sizeof(p.szOldPassword));
  932. strlcpy(p.szNewPassword, arg2, sizeof(p.szNewPassword));
  933.  
  934. db_clientdesc->DBPacket(HEADER_GD_SAFEBOX_CHANGE_PASSWORD, ch->GetDesc()->GetHandle(), &p, sizeof(p));
  935. }
  936.  
  937. ACMD(do_mall_password)
  938. {
  939. char arg1[256];
  940. one_argument(argument, arg1, sizeof(arg1));
  941.  
  942. if (!*arg1 || strlen(arg1) > 6)
  943. {
  944. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<창고> 잘못된 암호를 입력하셨습니다."));
  945. return;
  946. }
  947.  
  948. int iPulse = thecore_pulse();
  949.  
  950. if (ch->GetMall())
  951. {
  952. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<창고> 창고가 이미 열려있습니다."));
  953. return;
  954. }
  955.  
  956. if (iPulse - ch->GetMallLoadTime() < passes_per_sec * 10) // 10초에 한번만 요청 가능
  957. {
  958. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<창고> 창고를 닫은지 10초 안에는 열 수 없습니다."));
  959. return;
  960. }
  961.  
  962. ch->SetMallLoadTime(iPulse);
  963.  
  964. TSafeboxLoadPacket p;
  965. p.dwID = ch->GetDesc()->GetAccountTable().id;
  966. strlcpy(p.szLogin, ch->GetDesc()->GetAccountTable().login, sizeof(p.szLogin));
  967. strlcpy(p.szPassword, arg1, sizeof(p.szPassword));
  968.  
  969. db_clientdesc->DBPacket(HEADER_GD_MALL_LOAD, ch->GetDesc()->GetHandle(), &p, sizeof(p));
  970. }
  971.  
  972. ACMD(do_mall_close)
  973. {
  974. if (ch->GetMall())
  975. {
  976. ch->SetMallLoadTime(thecore_pulse());
  977. ch->CloseMall();
  978. ch->Save();
  979. }
  980. }
  981.  
  982. ACMD(do_ungroup)
  983. {
  984. if (!ch->GetParty())
  985. return;
  986.  
  987. if (!CPartyManager::instance().IsEnablePCParty())
  988. {
  989. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 서버 문제로 파티 관련 처리를 할 수 없습니다."));
  990. return;
  991. }
  992.  
  993. if (ch->GetDungeon())
  994. {
  995. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 던전 안에서는 파티에서 나갈 수 없습니다."));
  996. return;
  997. }
  998.  
  999. LPPARTY pParty = ch->GetParty();
  1000.  
  1001. if (pParty->GetMemberCount() == 2)
  1002. {
  1003. // party disband
  1004. CPartyManager::instance().DeleteParty(pParty);
  1005. }
  1006. else
  1007. {
  1008. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 파티에서 나가셨습니다."));
  1009. //pParty->SendPartyRemoveOneToAll(ch);
  1010. pParty->Quit(ch->GetPlayerID());
  1011. //pParty->SendPartyRemoveAllToOne(ch);
  1012. }
  1013. }
  1014.  
  1015. ACMD(do_close_shop)
  1016. {
  1017. if (ch->GetMyShop())
  1018. {
  1019. ch->CloseMyShop();
  1020. return;
  1021. }
  1022. }
  1023.  
  1024. ACMD(do_set_walk_mode)
  1025. {
  1026. ch->SetNowWalking(true);
  1027. ch->SetWalking(true);
  1028. }
  1029.  
  1030. ACMD(do_set_run_mode)
  1031. {
  1032. ch->SetNowWalking(false);
  1033. ch->SetWalking(false);
  1034. }
  1035.  
  1036. ACMD(do_war)
  1037. {
  1038. //내 길드 정보를 얻어오고
  1039. CGuild * g = ch->GetGuild();
  1040.  
  1041. if (!g)
  1042. return;
  1043.  
  1044. //전쟁중인지 체크한번!
  1045. if (g->UnderAnyWar())
  1046. {
  1047. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 이미 다른 전쟁에 참전 중 입니다."));
  1048. return;
  1049. }
  1050.  
  1051. //파라메터를 두배로 나누고
  1052. char arg1[256], arg2[256];
  1053. unsigned int type = GUILD_WAR_TYPE_FIELD;
  1054. two_arguments(argument, arg1, sizeof(arg1), arg2, sizeof(arg2));
  1055.  
  1056. if (!*arg1)
  1057. return;
  1058.  
  1059. if (*arg2)
  1060. {
  1061. str_to_number(type, arg2);
  1062.  
  1063. if (type >= GUILD_WAR_TYPE_MAX_NUM || type < 0)
  1064. type = GUILD_WAR_TYPE_FIELD;
  1065. }
  1066.  
  1067. //길드의 마스터 아이디를 얻어온뒤
  1068. DWORD gm_pid = g->GetMasterPID();
  1069.  
  1070. //마스터인지 체크(길전은 길드장만이 가능)
  1071. if (gm_pid != ch->GetPlayerID())
  1072. {
  1073. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드전에 대한 권한이 없습니다."));
  1074. return;
  1075. }
  1076.  
  1077. //상대 길드를 얻어오고
  1078. CGuild * opp_g = CGuildManager::instance().FindGuildByName(arg1);
  1079.  
  1080. if (!opp_g)
  1081. {
  1082. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 그런 길드가 없습니다."));
  1083. return;
  1084. }
  1085.  
  1086. //상대길드와의 상태 체크
  1087. switch (g->GetGuildWarState(opp_g->GetID()))
  1088. {
  1089. case GUILD_WAR_NONE:
  1090. {
  1091. if (opp_g->UnderAnyWar())
  1092. {
  1093. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 상대방 길드가 이미 전쟁 중 입니다."));
  1094. return;
  1095. }
  1096.  
  1097. int iWarPrice = KOR_aGuildWarInfo[type].iWarPrice;
  1098.  
  1099. if (g->GetGuildMoney() < iWarPrice)
  1100. {
  1101. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 전비가 부족하여 길드전을 할 수 없습니다."));
  1102. return;
  1103. }
  1104.  
  1105. if (opp_g->GetGuildMoney() < iWarPrice)
  1106. {
  1107. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 상대방 길드의 전비가 부족하여 길드전을 할 수 없습니다."));
  1108. return;
  1109. }
  1110. }
  1111. break;
  1112.  
  1113. case GUILD_WAR_SEND_DECLARE:
  1114. {
  1115. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("이미 선전포고 중인 길드입니다."));
  1116. return;
  1117. }
  1118. break;
  1119.  
  1120. case GUILD_WAR_RECV_DECLARE:
  1121. {
  1122. if (opp_g->UnderAnyWar())
  1123. {
  1124. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 상대방 길드가 이미 전쟁 중 입니다."));
  1125. g->RequestRefuseWar(opp_g->GetID());
  1126. return;
  1127. }
  1128. }
  1129. break;
  1130.  
  1131. case GUILD_WAR_RESERVE:
  1132. {
  1133. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 이미 전쟁이 예약된 길드 입니다."));
  1134. return;
  1135. }
  1136. break;
  1137.  
  1138. case GUILD_WAR_END:
  1139. return;
  1140.  
  1141. default:
  1142. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 이미 전쟁 중인 길드입니다."));
  1143. g->RequestRefuseWar(opp_g->GetID());
  1144. return;
  1145. }
  1146.  
  1147. if (!g->CanStartWar(type))
  1148. {
  1149. // 길드전을 할 수 있는 조건을 만족하지않는다.
  1150. if (g->GetLadderPoint() == 0)
  1151. {
  1152. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 레더 점수가 모자라서 길드전을 할 수 없습니다."));
  1153. sys_log(0, "GuildWar.StartError.NEED_LADDER_POINT");
  1154. }
  1155. else if (g->GetMemberCount() < GUILD_WAR_MIN_MEMBER_COUNT)
  1156. {
  1157. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드전을 하기 위해선 최소한 %d명이 있어야 합니다."), GUILD_WAR_MIN_MEMBER_COUNT);
  1158. sys_log(0, "GuildWar.StartError.NEED_MINIMUM_MEMBER[%d]", GUILD_WAR_MIN_MEMBER_COUNT);
  1159. }
  1160. else
  1161. {
  1162. sys_log(0, "GuildWar.StartError.UNKNOWN_ERROR");
  1163. }
  1164. return;
  1165. }
  1166.  
  1167. // 필드전 체크만 하고 세세한 체크는 상대방이 승낙할때 한다.
  1168. if (!opp_g->CanStartWar(GUILD_WAR_TYPE_FIELD))
  1169. {
  1170. if (opp_g->GetLadderPoint() == 0)
  1171. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 상대방 길드의 레더 점수가 모자라서 길드전을 할 수 없습니다."));
  1172. else if (opp_g->GetMemberCount() < GUILD_WAR_MIN_MEMBER_COUNT)
  1173. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 상대방 길드의 길드원 수가 부족하여 길드전을 할 수 없습니다."));
  1174. return;
  1175. }
  1176.  
  1177. do
  1178. {
  1179. if (g->GetMasterCharacter() != NULL)
  1180. break;
  1181.  
  1182. CCI *pCCI = P2P_MANAGER::instance().FindByPID(g->GetMasterPID());
  1183.  
  1184. if (pCCI != NULL)
  1185. break;
  1186.  
  1187. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 상대방 길드의 길드장이 접속중이 아닙니다."));
  1188. g->RequestRefuseWar(opp_g->GetID());
  1189. return;
  1190.  
  1191. } while (false);
  1192.  
  1193. do
  1194. {
  1195. if (opp_g->GetMasterCharacter() != NULL)
  1196. break;
  1197.  
  1198. CCI *pCCI = P2P_MANAGER::instance().FindByPID(opp_g->GetMasterPID());
  1199.  
  1200. if (pCCI != NULL)
  1201. break;
  1202.  
  1203. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 상대방 길드의 길드장이 접속중이 아닙니다."));
  1204. g->RequestRefuseWar(opp_g->GetID());
  1205. return;
  1206.  
  1207. } while (false);
  1208.  
  1209. g->RequestDeclareWar(opp_g->GetID(), type);
  1210. }
  1211.  
  1212. ACMD(do_nowar)
  1213. {
  1214. CGuild* g = ch->GetGuild();
  1215. if (!g)
  1216. return;
  1217.  
  1218. char arg1[256];
  1219. one_argument(argument, arg1, sizeof(arg1));
  1220.  
  1221. if (!*arg1)
  1222. return;
  1223.  
  1224. DWORD gm_pid = g->GetMasterPID();
  1225.  
  1226. if (gm_pid != ch->GetPlayerID())
  1227. {
  1228. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드전에 대한 권한이 없습니다."));
  1229. return;
  1230. }
  1231.  
  1232. CGuild* opp_g = CGuildManager::instance().FindGuildByName(arg1);
  1233.  
  1234. if (!opp_g)
  1235. {
  1236. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 그런 길드가 없습니다."));
  1237. return;
  1238. }
  1239.  
  1240. g->RequestRefuseWar(opp_g->GetID());
  1241. }
  1242.  
  1243. ACMD(do_detaillog)
  1244. {
  1245. ch->DetailLog();
  1246. }
  1247.  
  1248. ACMD(do_monsterlog)
  1249. {
  1250. ch->ToggleMonsterLog();
  1251. }
  1252.  
  1253. ACMD(do_pkmode)
  1254. {
  1255. char arg1[256];
  1256. one_argument(argument, arg1, sizeof(arg1));
  1257.  
  1258. if (!*arg1)
  1259. return;
  1260.  
  1261. BYTE mode = 0;
  1262. str_to_number(mode, arg1);
  1263.  
  1264. if (mode == PK_MODE_PROTECT)
  1265. return;
  1266.  
  1267. if (ch->GetLevel() < PK_PROTECT_LEVEL && mode != 0)
  1268. return;
  1269.  
  1270. ch->SetPKMode(mode);
  1271. }
  1272.  
  1273. ACMD(do_messenger_auth)
  1274. {
  1275. if (ch->GetArena())
  1276. {
  1277. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("대련장에서 사용하실 수 없습니다."));
  1278. return;
  1279. }
  1280.  
  1281. char arg1[256], arg2[256];
  1282. two_arguments(argument, arg1, sizeof(arg1), arg2, sizeof(arg2));
  1283.  
  1284. if (!*arg1 || !*arg2)
  1285. return;
  1286.  
  1287. char answer = LOWER(*arg1);
  1288.  
  1289. if (!MessengerManager::instance().AuthToAdd(ch->GetName(), arg2, answer == 'y' ? false : true))
  1290. return;
  1291.  
  1292. if (answer != 'y')
  1293. {
  1294. LPCHARACTER tch = CHARACTER_MANAGER::instance().FindPC(arg2);
  1295.  
  1296. if (tch)
  1297. tch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s 님으로 부터 친구 등록을 거부 당했습니다."), ch->GetName());
  1298. }
  1299.  
  1300. MessengerManager::instance().AuthToAdd(ch->GetName(), arg2, answer == 'y' ? false : true); // DENY
  1301. }
  1302.  
  1303. ACMD(do_setblockmode)
  1304. {
  1305. char arg1[256];
  1306. one_argument(argument, arg1, sizeof(arg1));
  1307.  
  1308. if (*arg1)
  1309. {
  1310. BYTE flag = 0;
  1311. str_to_number(flag, arg1);
  1312. ch->SetBlockMode(flag);
  1313. }
  1314. }
  1315.  
  1316. ACMD(do_unmount)
  1317. {
  1318. if (true == ch->UnEquipSpecialRideUniqueItem())
  1319. {
  1320. ch->RemoveAffect(AFFECT_MOUNT);
  1321. ch->RemoveAffect(AFFECT_MOUNT_BONUS);
  1322.  
  1323. if (ch->IsHorseRiding())
  1324. {
  1325. ch->StopRiding();
  1326. }
  1327. }
  1328. else
  1329. {
  1330. ch->ChatPacket( CHAT_TYPE_INFO, LC_TEXT("인벤토리가 꽉 차서 내릴 수 없습니다."));
  1331. }
  1332.  
  1333. }
  1334.  
  1335. ACMD(do_observer_exit)
  1336. {
  1337. if (ch->IsObserverMode())
  1338. {
  1339. if (ch->GetWarMap())
  1340. ch->SetWarMap(NULL);
  1341.  
  1342. if (ch->GetArena() != NULL || ch->GetArenaObserverMode() == true)
  1343. {
  1344. ch->SetArenaObserverMode(false);
  1345.  
  1346. if (ch->GetArena() != NULL)
  1347. ch->GetArena()->RemoveObserver(ch->GetPlayerID());
  1348.  
  1349. ch->SetArena(NULL);
  1350. ch->WarpSet(ARENA_RETURN_POINT_X(ch->GetEmpire()), ARENA_RETURN_POINT_Y(ch->GetEmpire()));
  1351. }
  1352. else
  1353. {
  1354. ch->ExitToSavedLocation();
  1355. }
  1356. ch->SetObserverMode(false);
  1357. }
  1358. }
  1359.  
  1360. ACMD(do_view_equip)
  1361. {
  1362. if (ch->GetGMLevel() <= GM_PLAYER)
  1363. return;
  1364.  
  1365. char arg1[256];
  1366. one_argument(argument, arg1, sizeof(arg1));
  1367.  
  1368. if (*arg1)
  1369. {
  1370. DWORD vid = 0;
  1371. str_to_number(vid, arg1);
  1372. LPCHARACTER tch = CHARACTER_MANAGER::instance().Find(vid);
  1373.  
  1374. if (!tch)
  1375. return;
  1376.  
  1377. if (!tch->IsPC())
  1378. return;
  1379. /*
  1380. int iSPCost = ch->GetMaxSP() / 3;
  1381.  
  1382. if (ch->GetSP() < iSPCost)
  1383. {
  1384. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("정신력이 부족하여 다른 사람의 장비를 볼 수 없습니다."));
  1385. return;
  1386. }
  1387. ch->PointChange(POINT_SP, -iSPCost);
  1388. */
  1389. tch->SendEquipment(ch);
  1390. }
  1391. }
  1392.  
  1393. ACMD(do_party_request)
  1394. {
  1395. if (ch->GetArena())
  1396. {
  1397. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("대련장에서 사용하실 수 없습니다."));
  1398. return;
  1399. }
  1400.  
  1401. if (ch->GetParty())
  1402. {
  1403. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("이미 파티에 속해 있으므로 가입신청을 할 수 없습니다."));
  1404. return;
  1405. }
  1406.  
  1407. char arg1[256];
  1408. one_argument(argument, arg1, sizeof(arg1));
  1409.  
  1410. if (!*arg1)
  1411. return;
  1412.  
  1413. DWORD vid = 0;
  1414. str_to_number(vid, arg1);
  1415. LPCHARACTER tch = CHARACTER_MANAGER::instance().Find(vid);
  1416.  
  1417. if (tch)
  1418. if (!ch->RequestToParty(tch))
  1419. ch->ChatPacket(CHAT_TYPE_COMMAND, "PartyRequestDenied");
  1420. }
  1421.  
  1422. ACMD(do_party_request_accept)
  1423. {
  1424. char arg1[256];
  1425. one_argument(argument, arg1, sizeof(arg1));
  1426.  
  1427. if (!*arg1)
  1428. return;
  1429.  
  1430. DWORD vid = 0;
  1431. str_to_number(vid, arg1);
  1432. LPCHARACTER tch = CHARACTER_MANAGER::instance().Find(vid);
  1433.  
  1434. if (tch)
  1435. ch->AcceptToParty(tch);
  1436. }
  1437.  
  1438. ACMD(do_party_request_deny)
  1439. {
  1440. char arg1[256];
  1441. one_argument(argument, arg1, sizeof(arg1));
  1442.  
  1443. if (!*arg1)
  1444. return;
  1445.  
  1446. DWORD vid = 0;
  1447. str_to_number(vid, arg1);
  1448. LPCHARACTER tch = CHARACTER_MANAGER::instance().Find(vid);
  1449.  
  1450. if (tch)
  1451. ch->DenyToParty(tch);
  1452. }
  1453.  
  1454. ACMD(do_monarch_warpto)
  1455. {
  1456. if (true == LC_IsYMIR() || true == LC_IsKorea())
  1457. return;
  1458.  
  1459. if (!CMonarch::instance().IsMonarch(ch->GetPlayerID(), ch->GetEmpire()))
  1460. {
  1461. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("군주만이 사용 가능한 기능입니다"));
  1462. return;
  1463. }
  1464.  
  1465. //군주 쿨타임 검사
  1466. if (!ch->IsMCOK(CHARACTER::MI_WARP))
  1467. {
  1468. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%d 초간 쿨타임이 적용중입니다."), ch->GetMCLTime(CHARACTER::MI_WARP));
  1469. return;
  1470. }
  1471.  
  1472. //군주 몹 소환 비용
  1473. const int WarpPrice = 10000;
  1474.  
  1475. //군주 국고 검사
  1476. if (!CMonarch::instance().IsMoneyOk(WarpPrice, ch->GetEmpire()))
  1477. {
  1478. int NationMoney = CMonarch::instance().GetMoney(ch->GetEmpire());
  1479. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("국고에 돈이 부족합니다. 현재 : %u 필요금액 : %u"), NationMoney, WarpPrice);
  1480. return;
  1481. }
  1482.  
  1483. int x = 0, y = 0;
  1484. char arg1[256];
  1485.  
  1486. one_argument(argument, arg1, sizeof(arg1));
  1487.  
  1488. if (!*arg1)
  1489. {
  1490. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("사용법: warpto <character name>"));
  1491. return;
  1492. }
  1493.  
  1494. LPCHARACTER tch = CHARACTER_MANAGER::instance().FindPC(arg1);
  1495.  
  1496. if (!tch)
  1497. {
  1498. CCI * pkCCI = P2P_MANAGER::instance().Find(arg1);
  1499.  
  1500. if (pkCCI)
  1501. {
  1502. if (pkCCI->bEmpire != ch->GetEmpire())
  1503. {
  1504. ch->ChatPacket (CHAT_TYPE_INFO, LC_TEXT("타제국 유저에게는 이동할수 없습니다"));
  1505. return;
  1506. }
  1507.  
  1508. if (pkCCI->bChannel != g_bChannel)
  1509. {
  1510. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("해당 유저는 %d 채널에 있습니다. (현재 채널 %d)"), pkCCI->bChannel, g_bChannel);
  1511. return;
  1512. }
  1513. if (!IsMonarchWarpZone(pkCCI->lMapIndex))
  1514. {
  1515. ch->ChatPacket (CHAT_TYPE_INFO, LC_TEXT("해당 지역으로 이동할 수 없습니다."));
  1516. return;
  1517. }
  1518.  
  1519. PIXEL_POSITION pos;
  1520.  
  1521. if (!SECTREE_MANAGER::instance().GetCenterPositionOfMap(pkCCI->lMapIndex, pos))
  1522. ch->ChatPacket(CHAT_TYPE_INFO, "Cannot find map (index %d)", pkCCI->lMapIndex);
  1523. else
  1524. {
  1525. //ch->ChatPacket(CHAT_TYPE_INFO, "You warp to (%d, %d)", pos.x, pos.y);
  1526. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s 에게로 이동합니다"), arg1);
  1527. ch->WarpSet(pos.x, pos.y);
  1528.  
  1529. //군주 돈 삭감
  1530. CMonarch::instance().SendtoDBDecMoney(WarpPrice, ch->GetEmpire(), ch);
  1531.  
  1532. //쿨타임 초기화
  1533. ch->SetMC(CHARACTER::MI_WARP);
  1534. }
  1535. }
  1536. else if (NULL == CHARACTER_MANAGER::instance().FindPC(arg1))
  1537. {
  1538. ch->ChatPacket(CHAT_TYPE_INFO, "There is no one by that name");
  1539. }
  1540.  
  1541. return;
  1542. }
  1543. else
  1544. {
  1545. if (tch->GetEmpire() != ch->GetEmpire())
  1546. {
  1547. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("타제국 유저에게는 이동할수 없습니다"));
  1548. return;
  1549. }
  1550. if (!IsMonarchWarpZone(tch->GetMapIndex()))
  1551. {
  1552. ch->ChatPacket (CHAT_TYPE_INFO, LC_TEXT("해당 지역으로 이동할 수 없습니다."));
  1553. return;
  1554. }
  1555. x = tch->GetX();
  1556. y = tch->GetY();
  1557. }
  1558.  
  1559. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s 에게로 이동합니다"), arg1);
  1560. ch->WarpSet(x, y);
  1561. ch->Stop();
  1562.  
  1563. //군주 돈 삭감
  1564. CMonarch::instance().SendtoDBDecMoney(WarpPrice, ch->GetEmpire(), ch);
  1565.  
  1566. //쿨타임 초기화
  1567. ch->SetMC(CHARACTER::MI_WARP);
  1568. }
  1569.  
  1570. ACMD(do_monarch_transfer)
  1571. {
  1572. if (true == LC_IsYMIR() || true == LC_IsKorea())
  1573. return;
  1574.  
  1575. char arg1[256];
  1576. one_argument(argument, arg1, sizeof(arg1));
  1577.  
  1578. if (!*arg1)
  1579. {
  1580. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("사용법: transfer <name>"));
  1581. return;
  1582. }
  1583.  
  1584. if (!CMonarch::instance().IsMonarch(ch->GetPlayerID(), ch->GetEmpire()))
  1585. {
  1586. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("군주만이 사용 가능한 기능입니다"));
  1587. return;
  1588. }
  1589.  
  1590. //군주 쿨타임 검사
  1591. if (!ch->IsMCOK(CHARACTER::MI_TRANSFER))
  1592. {
  1593. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%d 초간 쿨타임이 적용중입니다."), ch->GetMCLTime(CHARACTER::MI_TRANSFER));
  1594. return;
  1595. }
  1596.  
  1597. //군주 워프 비용
  1598. const int WarpPrice = 10000;
  1599.  
  1600. //군주 국고 검사
  1601. if (!CMonarch::instance().IsMoneyOk(WarpPrice, ch->GetEmpire()))
  1602. {
  1603. int NationMoney = CMonarch::instance().GetMoney(ch->GetEmpire());
  1604. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("국고에 돈이 부족합니다. 현재 : %u 필요금액 : %u"), NationMoney, WarpPrice);
  1605. return;
  1606. }
  1607.  
  1608.  
  1609. LPCHARACTER tch = CHARACTER_MANAGER::instance().FindPC(arg1);
  1610.  
  1611. if (!tch)
  1612. {
  1613. CCI * pkCCI = P2P_MANAGER::instance().Find(arg1);
  1614.  
  1615. if (pkCCI)
  1616. {
  1617. if (pkCCI->bEmpire != ch->GetEmpire())
  1618. {
  1619. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("다른 제국 유저는 소환할 수 없습니다."));
  1620. return;
  1621. }
  1622. if (pkCCI->bChannel != g_bChannel)
  1623. {
  1624. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s 님은 %d 채널에 접속 중 입니다. (현재 채널: %d)"), arg1, pkCCI->bChannel, g_bChannel);
  1625. return;
  1626. }
  1627. if (!IsMonarchWarpZone(pkCCI->lMapIndex))
  1628. {
  1629. ch->ChatPacket (CHAT_TYPE_INFO, LC_TEXT("해당 지역으로 이동할 수 없습니다."));
  1630. return;
  1631. }
  1632. if (!IsMonarchWarpZone(ch->GetMapIndex()))
  1633. {
  1634. ch->ChatPacket (CHAT_TYPE_INFO, LC_TEXT("해당 지역으로 소환할 수 없습니다."));
  1635. return;
  1636. }
  1637.  
  1638. TPacketGGTransfer pgg;
  1639.  
  1640. pgg.bHeader = HEADER_GG_TRANSFER;
  1641. strlcpy(pgg.szName, arg1, sizeof(pgg.szName));
  1642. pgg.lX = ch->GetX();
  1643. pgg.lY = ch->GetY();
  1644.  
  1645. P2P_MANAGER::instance().Send(&pgg, sizeof(TPacketGGTransfer));
  1646. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s 님을 소환하였습니다."), arg1);
  1647.  
  1648. //군주 돈 삭감
  1649. CMonarch::instance().SendtoDBDecMoney(WarpPrice, ch->GetEmpire(), ch);
  1650. //쿨타임 초기화
  1651. ch->SetMC(CHARACTER::MI_TRANSFER);
  1652. }
  1653. else
  1654. {
  1655. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("입력하신 이름을 가진 사용자가 없습니다."));
  1656. }
  1657.  
  1658. return;
  1659. }
  1660.  
  1661.  
  1662. if (ch == tch)
  1663. {
  1664. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("자신을 소환할 수 없습니다."));
  1665. return;
  1666. }
  1667.  
  1668. if (tch->GetEmpire() != ch->GetEmpire())
  1669. {
  1670. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("다른 제국 유저는 소환할 수 없습니다."));
  1671. return;
  1672. }
  1673. if (!IsMonarchWarpZone(tch->GetMapIndex()))
  1674. {
  1675. ch->ChatPacket (CHAT_TYPE_INFO, LC_TEXT("해당 지역으로 이동할 수 없습니다."));
  1676. return;
  1677. }
  1678. if (!IsMonarchWarpZone(ch->GetMapIndex()))
  1679. {
  1680. ch->ChatPacket (CHAT_TYPE_INFO, LC_TEXT("해당 지역으로 소환할 수 없습니다."));
  1681. return;
  1682. }
  1683.  
  1684. //tch->Show(ch->GetMapIndex(), ch->GetX(), ch->GetY(), ch->GetZ());
  1685. tch->WarpSet(ch->GetX(), ch->GetY(), ch->GetMapIndex());
  1686.  
  1687. //군주 돈 삭감
  1688. CMonarch::instance().SendtoDBDecMoney(WarpPrice, ch->GetEmpire(), ch);
  1689. //쿨타임 초기화
  1690. ch->SetMC(CHARACTER::MI_TRANSFER);
  1691. }
  1692.  
  1693. ACMD(do_monarch_info)
  1694. {
  1695. if (CMonarch::instance().IsMonarch(ch->GetPlayerID(), ch->GetEmpire()))
  1696. {
  1697. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("나의 군주 정보"));
  1698. TMonarchInfo * p = CMonarch::instance().GetMonarch();
  1699. for (int n = 1; n < 4; ++n)
  1700. {
  1701. if (n == ch->GetEmpire())
  1702. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[%s군주] : %s 보유금액 %lld "), EMPIRE_NAME(n), p->name[n], p->money[n]);
  1703. else
  1704. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[%s군주] : %s "), EMPIRE_NAME(n), p->name[n]);
  1705.  
  1706. }
  1707. }
  1708. else
  1709. {
  1710. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("군주 정보"));
  1711. TMonarchInfo * p = CMonarch::instance().GetMonarch();
  1712. for (int n = 1; n < 4; ++n)
  1713. {
  1714. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[%s군주] : %s "), EMPIRE_NAME(n), p->name[n]);
  1715.  
  1716. }
  1717. }
  1718.  
  1719. }
  1720.  
  1721. ACMD(do_elect)
  1722. {
  1723. db_clientdesc->DBPacketHeader(HEADER_GD_COME_TO_VOTE, ch->GetDesc()->GetHandle(), 0);
  1724. }
  1725.  
  1726. // LUA_ADD_GOTO_INFO
  1727. struct GotoInfo
  1728. {
  1729. std::string st_name;
  1730.  
  1731. BYTE empire;
  1732. int mapIndex;
  1733. DWORD x, y;
  1734.  
  1735. GotoInfo()
  1736. {
  1737. st_name = "";
  1738. empire = 0;
  1739. mapIndex = 0;
  1740.  
  1741. x = 0;
  1742. y = 0;
  1743. }
  1744.  
  1745. GotoInfo(const GotoInfo& c_src)
  1746. {
  1747. __copy__(c_src);
  1748. }
  1749.  
  1750. void operator = (const GotoInfo& c_src)
  1751. {
  1752. __copy__(c_src);
  1753. }
  1754.  
  1755. void __copy__(const GotoInfo& c_src)
  1756. {
  1757. st_name = c_src.st_name;
  1758. empire = c_src.empire;
  1759. mapIndex = c_src.mapIndex;
  1760.  
  1761. x = c_src.x;
  1762. y = c_src.y;
  1763. }
  1764. };
  1765.  
  1766. extern void BroadcastNotice(const char * c_pszBuf);
  1767.  
  1768. ACMD(do_monarch_tax)
  1769. {
  1770. char arg1[256];
  1771. one_argument(argument, arg1, sizeof(arg1));
  1772.  
  1773. if (!*arg1)
  1774. {
  1775. ch->ChatPacket(CHAT_TYPE_INFO, "Usage: monarch_tax <1-50>");
  1776. return;
  1777. }
  1778.  
  1779. // 군주 검사
  1780. if (!ch->IsMonarch())
  1781. {
  1782. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("군주만이 사용할수 있는 기능입니다"));
  1783. return;
  1784. }
  1785.  
  1786. // 세금설정
  1787. int tax = 0;
  1788. str_to_number(tax, arg1);
  1789.  
  1790. if (tax < 1 || tax > 50)
  1791. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("1-50 사이의 수치를 선택해주세요"));
  1792.  
  1793. quest::CQuestManager::instance().SetEventFlag("trade_tax", tax);
  1794.  
  1795. // 군주에게 메세지 하나
  1796. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("세금이 %d %로 설정되었습니다"));
  1797.  
  1798. // 공지
  1799. char szMsg[1024];
  1800.  
  1801. snprintf(szMsg, sizeof(szMsg), "군주의 명으로 세금이 %d %% 로 변경되었습니다", tax);
  1802. BroadcastNotice(szMsg);
  1803.  
  1804. snprintf(szMsg, sizeof(szMsg), "앞으로는 거래 금액의 %d %% 가 국고로 들어가게됩니다.", tax);
  1805. BroadcastNotice(szMsg);
  1806.  
  1807. // 쿨타임 초기화
  1808. ch->SetMC(CHARACTER::MI_TAX);
  1809. }
  1810.  
  1811. static const DWORD cs_dwMonarchMobVnums[] =
  1812. {
  1813. 191, // 산견신
  1814. 192, // 저신
  1815. 193, // 웅신
  1816. 194, // 호신
  1817. 391, // 미정
  1818. 392, // 은정
  1819. 393, // 세랑
  1820. 394, // 진희
  1821. 491, // 맹환
  1822. 492, // 보우
  1823. 493, // 구패
  1824. 494, // 추흔
  1825. 591, // 비류단대장
  1826. 691, // 웅귀 족장
  1827. 791, // 밀교교주
  1828. 1304, // 누렁범귀
  1829. 1901, // 구미호
  1830. 2091, // 여왕거미
  1831. 2191, // 거대사막거북
  1832. 2206, // 화염왕i
  1833. 0,
  1834. };
  1835.  
  1836. ACMD(do_monarch_mob)
  1837. {
  1838. char arg1[256];
  1839. LPCHARACTER tch;
  1840.  
  1841. one_argument(argument, arg1, sizeof(arg1));
  1842.  
  1843. if (!ch->IsMonarch())
  1844. {
  1845. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("군주만이 사용할수 있는 기능입니다"));
  1846. return;
  1847. }
  1848.  
  1849. if (!*arg1)
  1850. {
  1851. ch->ChatPacket(CHAT_TYPE_INFO, "Usage: mmob <mob name>");
  1852. return;
  1853. }
  1854.  
  1855. BYTE pcEmpire = ch->GetEmpire();
  1856. BYTE mapEmpire = SECTREE_MANAGER::instance().GetEmpireFromMapIndex(ch->GetMapIndex());
  1857.  
  1858. if (LC_IsYMIR() == true || LC_IsKorea() == true)
  1859. {
  1860. if (mapEmpire != pcEmpire && mapEmpire != 0)
  1861. {
  1862. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("자국 영토에서만 사용할 수 있는 기능입니다"));
  1863. return;
  1864. }
  1865. }
  1866.  
  1867. // 군주 몹 소환 비용
  1868. const int SummonPrice = 5000000;
  1869.  
  1870. // 군주 쿨타임 검사
  1871. if (!ch->IsMCOK(CHARACTER::MI_SUMMON))
  1872. {
  1873. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%d 초간 쿨타임이 적용중입니다."), ch->GetMCLTime(CHARACTER::MI_SUMMON));
  1874. return;
  1875. }
  1876.  
  1877. // 군주 국고 검사
  1878. if (!CMonarch::instance().IsMoneyOk(SummonPrice, ch->GetEmpire()))
  1879. {
  1880. int NationMoney = CMonarch::instance().GetMoney(ch->GetEmpire());
  1881. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("국고에 돈이 부족합니다. 현재 : %u 필요금액 : %u"), NationMoney, SummonPrice);
  1882. return;
  1883. }
  1884.  
  1885. const CMob * pkMob;
  1886. DWORD vnum = 0;
  1887.  
  1888. if (isdigit(*arg1))
  1889. {
  1890. str_to_number(vnum, arg1);
  1891.  
  1892. if ((pkMob = CMobManager::instance().Get(vnum)) == NULL)
  1893. vnum = 0;
  1894. }
  1895. else
  1896. {
  1897. pkMob = CMobManager::Instance().Get(arg1, true);
  1898.  
  1899. if (pkMob)
  1900. vnum = pkMob->m_table.dwVnum;
  1901. }
  1902.  
  1903. DWORD count;
  1904.  
  1905. // 소환 가능 몹 검사
  1906. for (count = 0; cs_dwMonarchMobVnums[count] != 0; ++count)
  1907. if (cs_dwMonarchMobVnums[count] == vnum)
  1908. break;
  1909.  
  1910. if (0 == cs_dwMonarchMobVnums[count])
  1911. {
  1912. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("소환할수 없는 몬스터 입니다. 소환가능한 몬스터는 홈페이지를 참조하세요"));
  1913. return;
  1914. }
  1915.  
  1916. tch = CHARACTER_MANAGER::instance().SpawnMobRange(vnum,
  1917. ch->GetMapIndex(),
  1918. ch->GetX() - number(200, 750),
  1919. ch->GetY() - number(200, 750),
  1920. ch->GetX() + number(200, 750),
  1921. ch->GetY() + number(200, 750),
  1922. true,
  1923. pkMob->m_table.bType == CHAR_TYPE_STONE,
  1924. true);
  1925.  
  1926. if (tch)
  1927. {
  1928. // 군주 돈 삭감
  1929. CMonarch::instance().SendtoDBDecMoney(SummonPrice, ch->GetEmpire(), ch);
  1930.  
  1931. // 쿨타임 초기화
  1932. ch->SetMC(CHARACTER::MI_SUMMON);
  1933. }
  1934. }
  1935.  
  1936. static const char* FN_point_string(int apply_number)
  1937. {
  1938. switch (apply_number)
  1939. {
  1940. case POINT_MAX_HP: return LC_TEXT("최대 생명력 +%d");
  1941. case POINT_MAX_SP: return LC_TEXT("최대 정신력 +%d");
  1942. case POINT_HT: return LC_TEXT("체력 +%d");
  1943. case POINT_IQ: return LC_TEXT("지능 +%d");
  1944. case POINT_ST: return LC_TEXT("근력 +%d");
  1945. case POINT_DX: return LC_TEXT("민첩 +%d");
  1946. case POINT_ATT_SPEED: return LC_TEXT("공격속도 +%d");
  1947. case POINT_MOV_SPEED: return LC_TEXT("이동속도 %d");
  1948. case POINT_CASTING_SPEED: return LC_TEXT("쿨타임 -%d");
  1949. case POINT_HP_REGEN: return LC_TEXT("생명력 회복 +%d");
  1950. case POINT_SP_REGEN: return LC_TEXT("정신력 회복 +%d");
  1951. case POINT_POISON_PCT: return LC_TEXT("독공격 %d");
  1952. case POINT_STUN_PCT: return LC_TEXT("스턴 +%d");
  1953. case POINT_SLOW_PCT: return LC_TEXT("슬로우 +%d");
  1954. case POINT_CRITICAL_PCT: return LC_TEXT("%d%% 확률로 치명타 공격");
  1955. case POINT_RESIST_CRITICAL: return LC_TEXT("상대의 치명타 확률 %d%% 감소");
  1956. case POINT_PENETRATE_PCT: return LC_TEXT("%d%% 확률로 관통 공격");
  1957. case POINT_RESIST_PENETRATE: return LC_TEXT("상대의 관통 공격 확률 %d%% 감소");
  1958. case POINT_ATTBONUS_HUMAN: return LC_TEXT("인간류 몬스터 타격치 +%d%%");
  1959. case POINT_ATTBONUS_ANIMAL: return LC_TEXT("동물류 몬스터 타격치 +%d%%");
  1960. case POINT_ATTBONUS_ORC: return LC_TEXT("웅귀족 타격치 +%d%%");
  1961. case POINT_ATTBONUS_MILGYO: return LC_TEXT("밀교류 타격치 +%d%%");
  1962. case POINT_ATTBONUS_UNDEAD: return LC_TEXT("시체류 타격치 +%d%%");
  1963. case POINT_ATTBONUS_DEVIL: return LC_TEXT("악마류 타격치 +%d%%");
  1964. case POINT_STEAL_HP: return LC_TEXT("타격치 %d%% 를 생명력으로 흡수");
  1965. case POINT_STEAL_SP: return LC_TEXT("타력치 %d%% 를 정신력으로 흡수");
  1966. case POINT_MANA_BURN_PCT: return LC_TEXT("%d%% 확률로 타격시 상대 전신력 소모");
  1967. case POINT_DAMAGE_SP_RECOVER: return LC_TEXT("%d%% 확률로 피해시 정신력 회복");
  1968. case POINT_BLOCK: return LC_TEXT("물리타격시 블럭 확률 %d%%");
  1969. case POINT_DODGE: return LC_TEXT("활 공격 회피 확률 %d%%");
  1970. case POINT_RESIST_SWORD: return LC_TEXT("한손검 방어 %d%%");
  1971. case POINT_RESIST_TWOHAND: return LC_TEXT("양손검 방어 %d%%");
  1972. case POINT_RESIST_DAGGER: return LC_TEXT("두손검 방어 %d%%");
  1973. case POINT_RESIST_BELL: return LC_TEXT("방울 방어 %d%%");
  1974. case POINT_RESIST_FAN: return LC_TEXT("부채 방어 %d%%");
  1975. case POINT_RESIST_BOW: return LC_TEXT("활공격 저항 %d%%");
  1976. case POINT_RESIST_FIRE: return LC_TEXT("화염 저항 %d%%");
  1977. case POINT_RESIST_ELEC: return LC_TEXT("전기 저항 %d%%");
  1978. case POINT_RESIST_MAGIC: return LC_TEXT("마법 저항 %d%%");
  1979. case POINT_RESIST_WIND: return LC_TEXT("바람 저항 %d%%");
  1980. case POINT_RESIST_ICE: return LC_TEXT("냉기 저항 %d%%");
  1981. case POINT_RESIST_EARTH: return LC_TEXT("대지 저항 %d%%");
  1982. case POINT_RESIST_DARK: return LC_TEXT("어둠 저항 %d%%");
  1983. case POINT_REFLECT_MELEE: return LC_TEXT("직접 타격치 반사 확률 : %d%%");
  1984. case POINT_REFLECT_CURSE: return LC_TEXT("저주 되돌리기 확률 %d%%");
  1985. case POINT_POISON_REDUCE: return LC_TEXT("독 저항 %d%%");
  1986. case POINT_KILL_SP_RECOVER: return LC_TEXT("%d%% 확률로 적퇴치시 정신력 회복");
  1987. case POINT_EXP_DOUBLE_BONUS: return LC_TEXT("%d%% 확률로 적퇴치시 경험치 추가 상승");
  1988. case POINT_GOLD_DOUBLE_BONUS: return LC_TEXT("%d%% 확률로 적퇴치시 돈 2배 드롭");
  1989. case POINT_ITEM_DROP_BONUS: return LC_TEXT("%d%% 확률로 적퇴치시 아이템 2배 드롭");
  1990. case POINT_POTION_BONUS: return LC_TEXT("물약 사용시 %d%% 성능 증가");
  1991. case POINT_KILL_HP_RECOVERY: return LC_TEXT("%d%% 확률로 적퇴치시 생명력 회복");
  1992. // case POINT_IMMUNE_STUN: return LC_TEXT("기절하지 않음 %d%%");
  1993. // case POINT_IMMUNE_SLOW: return LC_TEXT("느려지지 않음 %d%%");
  1994. // case POINT_IMMUNE_FALL: return LC_TEXT("넘어지지 않음 %d%%");
  1995. // case POINT_SKILL: return LC_TEXT("");
  1996. // case POINT_BOW_DISTANCE: return LC_TEXT("");
  1997. case POINT_ATT_GRADE_BONUS: return LC_TEXT("공격력 +%d");
  1998. case POINT_DEF_GRADE_BONUS: return LC_TEXT("방어력 +%d");
  1999. case POINT_MAGIC_ATT_GRADE: return LC_TEXT("마법 공격력 +%d");
  2000. case POINT_MAGIC_DEF_GRADE: return LC_TEXT("마법 방어력 +%d");
  2001. // case POINT_CURSE_PCT: return LC_TEXT("");
  2002. case POINT_MAX_STAMINA: return LC_TEXT("최대 지구력 +%d");
  2003. case POINT_ATTBONUS_WARRIOR: return LC_TEXT("무사에게 강함 +%d%%");
  2004. case POINT_ATTBONUS_ASSASSIN: return LC_TEXT("자객에게 강함 +%d%%");
  2005. case POINT_ATTBONUS_SURA: return LC_TEXT("수라에게 강함 +%d%%");
  2006. case POINT_ATTBONUS_SHAMAN: return LC_TEXT("무당에게 강함 +%d%%");
  2007. case POINT_ATTBONUS_MONSTER: return LC_TEXT("몬스터에게 강함 +%d%%");
  2008. case POINT_MALL_ATTBONUS: return LC_TEXT("공격력 +%d%%");
  2009. case POINT_MALL_DEFBONUS: return LC_TEXT("방어력 +%d%%");
  2010. case POINT_MALL_EXPBONUS: return LC_TEXT("경험치 %d%%");
  2011. case POINT_MALL_ITEMBONUS: return LC_TEXT("아이템 드롭율 %.1f배");
  2012. case POINT_MALL_GOLDBONUS: return LC_TEXT("돈 드롭율 %.1f배");
  2013. case POINT_MAX_HP_PCT: return LC_TEXT("최대 생명력 +%d%%");
  2014. case POINT_MAX_SP_PCT: return LC_TEXT("최대 정신력 +%d%%");
  2015. case POINT_SKILL_DAMAGE_BONUS: return LC_TEXT("스킬 데미지 %d%%");
  2016. case POINT_NORMAL_HIT_DAMAGE_BONUS: return LC_TEXT("평타 데미지 %d%%");
  2017. case POINT_SKILL_DEFEND_BONUS: return LC_TEXT("스킬 데미지 저항 %d%%");
  2018. case POINT_NORMAL_HIT_DEFEND_BONUS: return LC_TEXT("평타 데미지 저항 %d%%");
  2019. // case POINT_PC_BANG_EXP_BONUS: return LC_TEXT("");
  2020. // case POINT_PC_BANG_DROP_BONUS: return LC_TEXT("");
  2021. // case POINT_EXTRACT_HP_PCT: return LC_TEXT("");
  2022. case POINT_RESIST_WARRIOR: return LC_TEXT("무사공격에 %d%% 저항");
  2023. case POINT_RESIST_ASSASSIN: return LC_TEXT("자객공격에 %d%% 저항");
  2024. case POINT_RESIST_SURA: return LC_TEXT("수라공격에 %d%% 저항");
  2025. case POINT_RESIST_SHAMAN: return LC_TEXT("무당공격에 %d%% 저항");
  2026. default: return NULL;
  2027. }
  2028. }
  2029.  
  2030. static bool FN_hair_affect_string(LPCHARACTER ch, char *buf, size_t bufsiz)
  2031. {
  2032. if (NULL == ch || NULL == buf)
  2033. return false;
  2034.  
  2035. CAffect* aff = NULL;
  2036. time_t expire = 0;
  2037. struct tm ltm;
  2038. int year, mon, day;
  2039. int offset = 0;
  2040.  
  2041. aff = ch->FindAffect(AFFECT_HAIR);
  2042.  
  2043. if (NULL == aff)
  2044. return false;
  2045.  
  2046. expire = ch->GetQuestFlag("hair.limit_time");
  2047.  
  2048. if (expire < get_global_time())
  2049. return false;
  2050.  
  2051. // set apply string
  2052. offset = snprintf(buf, bufsiz, FN_point_string(aff->bApplyOn), aff->lApplyValue);
  2053.  
  2054. if (offset < 0 || offset >= (int) bufsiz)
  2055. offset = bufsiz - 1;
  2056.  
  2057. localtime_r(&expire, &ltm);
  2058.  
  2059. year = ltm.tm_year + 1900;
  2060. mon = ltm.tm_mon + 1;
  2061. day = ltm.tm_mday;
  2062.  
  2063. snprintf(buf + offset, bufsiz - offset, LC_TEXT(" (만료일 : %d년 %d월 %d일)"), year, mon, day);
  2064.  
  2065. return true;
  2066. }
  2067.  
  2068. ACMD(do_costume)
  2069. {
  2070. char buf[512];
  2071. const size_t bufferSize = sizeof(buf);
  2072.  
  2073. char arg1[256];
  2074. one_argument(argument, arg1, sizeof(arg1));
  2075.  
  2076. CItem* pBody = ch->GetWear(WEAR_COSTUME_BODY);
  2077. CItem* pHair = ch->GetWear(WEAR_COSTUME_HAIR);
  2078.  
  2079. ch->ChatPacket(CHAT_TYPE_INFO, "COSTUME status:");
  2080.  
  2081. if (pHair)
  2082. {
  2083. const char* itemName = pHair->GetName();
  2084. ch->ChatPacket(CHAT_TYPE_INFO, " HAIR : %s", itemName);
  2085.  
  2086. for (int i = 0; i < pHair->GetAttributeCount(); ++i)
  2087. {
  2088. const TPlayerItemAttribute& attr = pHair->GetAttribute(i);
  2089. if (0 < attr.bType)
  2090. {
  2091. snprintf(buf, bufferSize, FN_point_string(attr.bType), attr.sValue);
  2092. ch->ChatPacket(CHAT_TYPE_INFO, " %s", buf);
  2093. }
  2094. }
  2095.  
  2096. if (pHair->IsEquipped() && arg1[0] == 'h')
  2097. ch->UnequipItem(pHair);
  2098. }
  2099.  
  2100. if (pBody)
  2101. {
  2102. const char* itemName = pBody->GetName();
  2103. ch->ChatPacket(CHAT_TYPE_INFO, " BODY : %s", itemName);
  2104.  
  2105. if (pBody->IsEquipped() && arg1[0] == 'b')
  2106. ch->UnequipItem(pBody);
  2107. }
  2108. }
  2109.  
  2110. ACMD(do_hair)
  2111. {
  2112. char buf[256];
  2113.  
  2114. if (false == FN_hair_affect_string(ch, buf, sizeof(buf)))
  2115. return;
  2116.  
  2117. ch->ChatPacket(CHAT_TYPE_INFO, buf);
  2118. }
  2119.  
  2120. ACMD(do_inventory)
  2121. {
  2122. int index = 0;
  2123. int count = 1;
  2124.  
  2125. char arg1[256];
  2126. char arg2[256];
  2127.  
  2128. LPITEM item;
  2129.  
  2130. two_arguments(argument, arg1, sizeof(arg1), arg2, sizeof(arg2));
  2131.  
  2132. if (!*arg1)
  2133. {
  2134. ch->ChatPacket(CHAT_TYPE_INFO, "Usage: inventory <start_index> <count>");
  2135. return;
  2136. }
  2137.  
  2138. if (!*arg2)
  2139. {
  2140. index = 0;
  2141. str_to_number(count, arg1);
  2142. }
  2143. else
  2144. {
  2145. str_to_number(index, arg1); index = MIN(index, INVENTORY_MAX_NUM);
  2146. str_to_number(count, arg2); count = MIN(count, INVENTORY_MAX_NUM);
  2147. }
  2148.  
  2149. for (int i = 0; i < count; ++i)
  2150. {
  2151. if (index >= INVENTORY_MAX_NUM)
  2152. break;
  2153.  
  2154. item = ch->GetInventoryItem(index);
  2155.  
  2156. ch->ChatPacket(CHAT_TYPE_INFO, "inventory [%d] = %s",
  2157. index, item ? item->GetName() : "<NONE>");
  2158. ++index;
  2159. }
  2160. }
  2161.  
  2162. //gift notify quest command
  2163. ACMD(do_gift)
  2164. {
  2165. ch->ChatPacket(CHAT_TYPE_COMMAND, "gift");
  2166. }
  2167.  
  2168. ACMD(do_cube)
  2169. {
  2170. if (!ch->CanDoCube())
  2171. return;
  2172.  
  2173. dev_log(LOG_DEB0, "CUBE COMMAND <%s>: %s", ch->GetName(), argument);
  2174. int cube_index = 0, inven_index = 0;
  2175. const char *line;
  2176.  
  2177. char arg1[256], arg2[256], arg3[256];
  2178.  
  2179. line = two_arguments(argument, arg1, sizeof(arg1), arg2, sizeof(arg2));
  2180. one_argument(line, arg3, sizeof(arg3));
  2181.  
  2182. if (0 == arg1[0])
  2183. {
  2184. // print usage
  2185. ch->ChatPacket(CHAT_TYPE_INFO, "Usage: cube open");
  2186. ch->ChatPacket(CHAT_TYPE_INFO, " cube close");
  2187. ch->ChatPacket(CHAT_TYPE_INFO, " cube add <inveltory_index>");
  2188. ch->ChatPacket(CHAT_TYPE_INFO, " cube delete <cube_index>");
  2189. ch->ChatPacket(CHAT_TYPE_INFO, " cube list");
  2190. ch->ChatPacket(CHAT_TYPE_INFO, " cube cancel");
  2191. ch->ChatPacket(CHAT_TYPE_INFO, " cube make [all]");
  2192. return;
  2193. }
  2194.  
  2195. const std::string& strArg1 = std::string(arg1);
  2196.  
  2197. // r_info (request information)
  2198. // /cube r_info ==> (Client -> Server) 현재 NPC가 만들 수 있는 레시피 요청
  2199. // (Server -> Client) /cube r_list npcVNUM resultCOUNT 123,1/125,1/128,1/130,5
  2200. //
  2201. // /cube r_info 3 ==> (Client -> Server) 현재 NPC가 만들수 있는 레시피 중 3번째 아이템을 만드는 데 필요한 정보를 요청
  2202. // /cube r_info 3 5 ==> (Client -> Server) 현재 NPC가 만들수 있는 레시피 중 3번째 아이템부터 이후 5개의 아이템을 만드는 데 필요한 재료 정보를 요청
  2203. // (Server -> Client) /cube m_info startIndex count 125,1|126,2|127,2|123,5&555,5&555,4/120000@125,1|126,2|127,2|123,5&555,5&555,4/120000
  2204. //
  2205. if (strArg1 == "r_info")
  2206. {
  2207. if (0 == arg2[0])
  2208. Cube_request_result_list(ch);
  2209. else
  2210. {
  2211. if (isdigit(*arg2))
  2212. {
  2213. int listIndex = 0, requestCount = 1;
  2214. str_to_number(listIndex, arg2);
  2215.  
  2216. if (0 != arg3[0] && isdigit(*arg3))
  2217. str_to_number(requestCount, arg3);
  2218.  
  2219. Cube_request_material_info(ch, listIndex, requestCount);
  2220. }
  2221. }
  2222.  
  2223. return;
  2224. }
  2225.  
  2226. switch (LOWER(arg1[0]))
  2227. {
  2228. case 'o': // open
  2229. Cube_open(ch);
  2230. break;
  2231.  
  2232. case 'c': // close
  2233. Cube_close(ch);
  2234. break;
  2235.  
  2236. case 'l': // list
  2237. Cube_show_list(ch);
  2238. break;
  2239.  
  2240. case 'a': // add cue_index inven_index
  2241. {
  2242. if (0 == arg2[0] || !isdigit(*arg2) ||
  2243. 0 == arg3[0] || !isdigit(*arg3))
  2244. return;
  2245.  
  2246. str_to_number(cube_index, arg2);
  2247. str_to_number(inven_index, arg3);
  2248. Cube_add_item (ch, cube_index, inven_index);
  2249. }
  2250. break;
  2251.  
  2252. case 'd': // delete
  2253. {
  2254. if (0 == arg2[0] || !isdigit(*arg2))
  2255. return;
  2256.  
  2257. str_to_number(cube_index, arg2);
  2258. Cube_delete_item (ch, cube_index);
  2259. }
  2260. break;
  2261.  
  2262. case 'm': // make
  2263. if (0 != arg2[0])
  2264. {
  2265. while (true == Cube_make(ch))
  2266. dev_log (LOG_DEB0, "cube make success");
  2267. }
  2268. else
  2269. Cube_make(ch);
  2270. break;
  2271.  
  2272. default:
  2273. return;
  2274. }
  2275. }
  2276.  
  2277. ACMD(do_in_game_mall)
  2278. {
  2279. if (LC_IsYMIR() == true || LC_IsKorea() == true)
  2280. {
  2281. ch->ChatPacket(CHAT_TYPE_COMMAND, "mall http://metin2.co.kr/04_mall/mall/login.htm");
  2282. return;
  2283. }
  2284.  
  2285. if (true == LC_IsTaiwan())
  2286. {
  2287. ch->ChatPacket(CHAT_TYPE_COMMAND, "mall http://203.69.141.203/mall/mall/item_main.htm");
  2288. return;
  2289. }
  2290.  
  2291. // ㅠ_ㅠ 쾌도서버 아이템몰 URL 하드코딩 추가
  2292. if (true == LC_IsWE_Korea())
  2293. {
  2294. ch->ChatPacket(CHAT_TYPE_COMMAND, "mall http://metin2.co.kr/50_we_mall/mall/login.htm");
  2295. return;
  2296. }
  2297.  
  2298. if (LC_IsJapan() == true)
  2299. {
  2300. ch->ChatPacket(CHAT_TYPE_COMMAND, "mall http://mt2.oge.jp/itemmall/itemList.php");
  2301. return;
  2302. }
  2303.  
  2304. if (LC_IsNewCIBN() == true && test_server)
  2305. {
  2306. ch->ChatPacket(CHAT_TYPE_COMMAND, "mall http://218.99.6.51/04_mall/mall/login.htm");
  2307. return;
  2308. }
  2309.  
  2310. if (LC_IsSingapore() == true)
  2311. {
  2312. ch->ChatPacket(CHAT_TYPE_COMMAND, "mall http://www.metin2.sg/ishop.php");
  2313. return;
  2314. }
  2315.  
  2316. /*
  2317. if (LC_IsCanada() == true)
  2318. {
  2319. ch->ChatPacket(CHAT_TYPE_COMMAND, "mall http://mall.z8games.com/mall_entry.aspx?tb=m2");
  2320. return;
  2321. }*/
  2322.  
  2323. if (LC_IsEurope() == true)
  2324. {
  2325. char country_code[3];
  2326.  
  2327. switch (LC_GetLocalType())
  2328. {
  2329. case LC_GERMANY: country_code[0] = 'd'; country_code[1] = 'e'; country_code[2] = '\0'; break;
  2330. case LC_FRANCE: country_code[0] = 'f'; country_code[1] = 'r'; country_code[2] = '\0'; break;
  2331. case LC_ITALY: country_code[0] = 'i'; country_code[1] = 't'; country_code[2] = '\0'; break;
  2332. case LC_SPAIN: country_code[0] = 'e'; country_code[1] = 's'; country_code[2] = '\0'; break;
  2333. case LC_UK: country_code[0] = 'e'; country_code[1] = 'n'; country_code[2] = '\0'; break;
  2334. case LC_TURKEY: country_code[0] = 't'; country_code[1] = 'r'; country_code[2] = '\0'; break;
  2335. case LC_POLAND: country_code[0] = 'p'; country_code[1] = 'l'; country_code[2] = '\0'; break;
  2336. case LC_PORTUGAL: country_code[0] = 'p'; country_code[1] = 't'; country_code[2] = '\0'; break;
  2337. case LC_GREEK: country_code[0] = 'g'; country_code[1] = 'r'; country_code[2] = '\0'; break;
  2338. case LC_RUSSIA: country_code[0] = 'r'; country_code[1] = 'u'; country_code[2] = '\0'; break;
  2339. case LC_DENMARK: country_code[0] = 'd'; country_code[1] = 'k'; country_code[2] = '\0'; break;
  2340. case LC_BULGARIA: country_code[0] = 'b'; country_code[1] = 'g'; country_code[2] = '\0'; break;
  2341. case LC_CROATIA: country_code[0] = 'h'; country_code[1] = 'r'; country_code[2] = '\0'; break;
  2342. case LC_MEXICO: country_code[0] = 'm'; country_code[1] = 'x'; country_code[2] = '\0'; break;
  2343. case LC_ARABIA: country_code[0] = 'a'; country_code[1] = 'e'; country_code[2] = '\0'; break;
  2344. case LC_CZECH: country_code[0] = 'c'; country_code[1] = 'z'; country_code[2] = '\0'; break;
  2345. case LC_ROMANIA: country_code[0] = 'r'; country_code[1] = 'o'; country_code[2] = '\0'; break;
  2346. case LC_HUNGARY: country_code[0] = 'h'; country_code[1] = 'u'; country_code[2] = '\0'; break;
  2347. case LC_NETHERLANDS: country_code[0] = 'n'; country_code[1] = 'l'; country_code[2] = '\0'; break;
  2348. case LC_USA: country_code[0] = 'u'; country_code[1] = 's'; country_code[2] = '\0'; break;
  2349. case LC_CANADA: country_code[0] = 'c'; country_code[1] = 'a'; country_code[2] = '\0'; break;
  2350. default:
  2351. if (test_server == true)
  2352. {
  2353. country_code[0] = 'd'; country_code[1] = 'e'; country_code[2] = '\0';
  2354. }
  2355. break;
  2356. }
  2357.  
  2358. char buf[512+1];
  2359. char sas[33];
  2360. MD5_CTX ctx;
  2361. const char sas_key[] = "GF9001";
  2362.  
  2363. snprintf(buf, sizeof(buf), "%u%u%s", ch->GetPlayerID(), ch->GetAID(), sas_key);
  2364.  
  2365. MD5Init(&ctx);
  2366. MD5Update(&ctx, (const unsigned char *) buf, strlen(buf));
  2367. #ifdef __FreeBSD__
  2368. MD5End(&ctx, sas);
  2369. #else
  2370. static const char hex[] = "0123456789abcdef";
  2371. unsigned char digest[16];
  2372. MD5Final(digest, &ctx);
  2373. int i;
  2374. for (i = 0; i < 16; ++i) {
  2375. sas[i+i] = hex[digest[i] >> 4];
  2376. sas[i+i+1] = hex[digest[i] & 0x0f];
  2377. }
  2378. sas[i+i] = '\0';
  2379. #endif
  2380.  
  2381. snprintf(buf, sizeof(buf), "mall http://%s/ishop?pid=%u&c=%s&sid=%d&sas=%s",
  2382. g_strWebMallURL.c_str(), ch->GetPlayerID(), country_code, g_server_id, sas);
  2383.  
  2384. ch->ChatPacket(CHAT_TYPE_COMMAND, buf);
  2385. }
  2386. }
  2387.  
  2388. // 주사위
  2389.  
  2390. ACMD(do_dice)
  2391. {
  2392. ch->ChatPacket(CHAT_TYPE_INFO, "This command has been disabled.");
  2393. }
  2394.  
  2395. ACMD(do_click_mall)
  2396. {
  2397. ch->ChatPacket(CHAT_TYPE_COMMAND, "ShowMeMallPassword");
  2398. }
  2399.  
  2400. ACMD(do_ride)
  2401. {
  2402. dev_log(LOG_DEB0, "[DO_RIDE] start");
  2403. if (ch->IsDead() || ch->IsStun())
  2404. return;
  2405.  
  2406. // 내리기
  2407. {
  2408. if (ch->IsHorseRiding())
  2409. {
  2410. dev_log(LOG_DEB0, "[DO_RIDE] stop riding");
  2411. ch->StopRiding();
  2412. return;
  2413. }
  2414.  
  2415. if (ch->GetMountVnum())
  2416. {
  2417. dev_log(LOG_DEB0, "[DO_RIDE] unmount");
  2418. do_unmount(ch, NULL, 0, 0);
  2419. return;
  2420. }
  2421. }
  2422.  
  2423. // 타기
  2424. {
  2425. if (ch->GetHorse() != NULL)
  2426. {
  2427. dev_log(LOG_DEB0, "[DO_RIDE] start riding");
  2428. ch->StartRiding();
  2429. return;
  2430. }
  2431.  
  2432. for (UINT i=0; i<INVENTORY_MAX_NUM; ++i)
  2433. {
  2434. LPITEM item = ch->GetInventoryItem(i);
  2435. if (NULL == item)
  2436. continue;
  2437.  
  2438. // 유니크 탈것 아이템
  2439. if (item->IsRideItem())
  2440. {
  2441. if (NULL==ch->GetWear(WEAR_UNIQUE1) || NULL==ch->GetWear(WEAR_UNIQUE2))
  2442. {
  2443. dev_log(LOG_DEB0, "[DO_RIDE] USE UNIQUE ITEM");
  2444. //ch->EquipItem(item);
  2445. ch->UseItem(TItemPos (INVENTORY, i));
  2446. return;
  2447. }
  2448. }
  2449.  
  2450. // 일반 탈것 아이템
  2451. // TODO : 탈것용 SubType 추가
  2452. switch (item->GetVnum())
  2453. {
  2454. case 71114: // 저신이용권
  2455. case 71116: // 산견신이용권
  2456. case 71118: // 투지범이용권
  2457. case 71120: // 사자왕이용권
  2458. dev_log(LOG_DEB0, "[DO_RIDE] USE QUEST ITEM");
  2459. ch->UseItem(TItemPos (INVENTORY, i));
  2460. return;
  2461. }
  2462.  
  2463. // GF mantis #113524, 52001~52090 번 탈것
  2464. if( (item->GetVnum() > 52000) && (item->GetVnum() < 52091) ) {
  2465. dev_log(LOG_DEB0, "[DO_RIDE] USE QUEST ITEM");
  2466. ch->UseItem(TItemPos (INVENTORY, i));
  2467. return;
  2468. }
  2469. }
  2470. }
  2471.  
  2472.  
  2473. // 타거나 내릴 수 없을때
  2474. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("말을 먼저 소환해주세요."));
  2475. }
  2476.  
  2477. #ifdef __AUCTION__
  2478. // temp_auction
  2479. ACMD(do_get_item_id_list)
  2480. {
  2481. for (int i = 0; i < INVENTORY_MAX_NUM; i++)
  2482. {
  2483. LPITEM item = ch->GetInventoryItem(i);
  2484. if (item != NULL)
  2485. ch->ChatPacket(CHAT_TYPE_INFO, "name : %s id : %d", item->GetProto()->szName, item->GetID());
  2486. }
  2487. }
  2488.  
  2489. // temp_auction
  2490.  
  2491. ACMD(do_enroll_auction)
  2492. {
  2493. char arg1[256];
  2494. char arg2[256];
  2495. char arg3[256];
  2496. char arg4[256];
  2497. two_arguments (two_arguments(argument, arg1, sizeof(arg1), arg2, sizeof(arg2)), arg3, sizeof(arg3), arg4, sizeof(arg4));
  2498.  
  2499. DWORD item_id = strtoul(arg1, NULL, 10);
  2500. BYTE empire = strtoul(arg2, NULL, 10);
  2501. int bidPrice = strtol(arg3, NULL, 10);
  2502. int immidiatePurchasePrice = strtol(arg4, NULL, 10);
  2503.  
  2504. LPITEM item = ITEM_MANAGER::instance().Find(item_id);
  2505. if (item == NULL)
  2506. return;
  2507.  
  2508. AuctionManager::instance().enroll_auction(ch, item, empire, bidPrice, immidiatePurchasePrice);
  2509. }
  2510.  
  2511. ACMD(do_enroll_wish)
  2512. {
  2513. char arg1[256];
  2514. char arg2[256];
  2515. char arg3[256];
  2516. one_argument (two_arguments(argument, arg1, sizeof(arg1), arg2, sizeof(arg2)), arg3, sizeof(arg3));
  2517.  
  2518. DWORD item_num = strtoul(arg1, NULL, 10);
  2519. BYTE empire = strtoul(arg2, NULL, 10);
  2520. int wishPrice = strtol(arg3, NULL, 10);
  2521.  
  2522. AuctionManager::instance().enroll_wish(ch, item_num, empire, wishPrice);
  2523. }
  2524.  
  2525. ACMD(do_enroll_sale)
  2526. {
  2527. char arg1[256];
  2528. char arg2[256];
  2529. char arg3[256];
  2530. one_argument (two_arguments(argument, arg1, sizeof(arg1), arg2, sizeof(arg2)), arg3, sizeof(arg3));
  2531.  
  2532. DWORD item_id = strtoul(arg1, NULL, 10);
  2533. DWORD wisher_id = strtoul(arg2, NULL, 10);
  2534. int salePrice = strtol(arg3, NULL, 10);
  2535.  
  2536. LPITEM item = ITEM_MANAGER::instance().Find(item_id);
  2537. if (item == NULL)
  2538. return;
  2539.  
  2540. AuctionManager::instance().enroll_sale(ch, item, wisher_id, salePrice);
  2541. }
  2542.  
  2543. // temp_auction
  2544. // packet으로 통신하게 하고, 이건 삭제해야한다.
  2545. ACMD(do_get_auction_list)
  2546. {
  2547. char arg1[256];
  2548. char arg2[256];
  2549. char arg3[256];
  2550. two_arguments (one_argument (argument, arg1, sizeof(arg1)), arg2, sizeof(arg2), arg3, sizeof(arg3));
  2551.  
  2552. AuctionManager::instance().get_auction_list (ch, strtoul(arg1, NULL, 10), strtoul(arg2, NULL, 10), strtoul(arg3, NULL, 10));
  2553. }
  2554. //
  2555. //ACMD(do_get_wish_list)
  2556. //{
  2557. // char arg1[256];
  2558. // char arg2[256];
  2559. // char arg3[256];
  2560. // two_arguments (one_argument (argument, arg1, sizeof(arg1)), arg2, sizeof(arg2), arg3, sizeof(arg3));
  2561. //
  2562. // AuctionManager::instance().get_wish_list (ch, strtoul(arg1, NULL, 10), strtoul(arg2, NULL, 10), strtoul(arg3, NULL, 10));
  2563. //}
  2564. ACMD (do_get_my_auction_list)
  2565. {
  2566. char arg1[256];
  2567. char arg2[256];
  2568. two_arguments (argument, arg1, sizeof(arg1), arg2, sizeof(arg2));
  2569.  
  2570. AuctionManager::instance().get_my_auction_list (ch, strtoul(arg1, NULL, 10), strtoul(arg2, NULL, 10));
  2571. }
  2572.  
  2573. ACMD (do_get_my_purchase_list)
  2574. {
  2575. char arg1[256];
  2576. char arg2[256];
  2577. two_arguments (argument, arg1, sizeof(arg1), arg2, sizeof(arg2));
  2578.  
  2579. AuctionManager::instance().get_my_purchase_list (ch, strtoul(arg1, NULL, 10), strtoul(arg2, NULL, 10));
  2580. }
  2581.  
  2582. ACMD (do_auction_bid)
  2583. {
  2584. char arg1[256];
  2585. char arg2[256];
  2586. two_arguments (argument, arg1, sizeof(arg1), arg2, sizeof(arg2));
  2587.  
  2588. AuctionManager::instance().bid (ch, strtoul(arg1, NULL, 10), strtoul(arg2, NULL, 10));
  2589. }
  2590.  
  2591. ACMD (do_auction_impur)
  2592. {
  2593. char arg1[256];
  2594. one_argument (argument, arg1, sizeof(arg1));
  2595.  
  2596. AuctionManager::instance().immediate_purchase (ch, strtoul(arg1, NULL, 10));
  2597. }
  2598.  
  2599. ACMD (do_get_auctioned_item)
  2600. {
  2601. char arg1[256];
  2602. char arg2[256];
  2603. two_arguments (argument, arg1, sizeof(arg1), arg2, sizeof(arg2));
  2604.  
  2605. AuctionManager::instance().get_auctioned_item (ch, strtoul(arg1, NULL, 10), strtoul(arg2, NULL, 10));
  2606. }
  2607.  
  2608. ACMD (do_buy_sold_item)
  2609. {
  2610. char arg1[256];
  2611. char arg2[256];
  2612. one_argument (argument, arg1, sizeof(arg1));
  2613.  
  2614. AuctionManager::instance().get_auctioned_item (ch, strtoul(arg1, NULL, 10), strtoul(arg2, NULL, 10));
  2615. }
  2616.  
  2617. ACMD (do_cancel_auction)
  2618. {
  2619. char arg1[256];
  2620. one_argument (argument, arg1, sizeof(arg1));
  2621.  
  2622. AuctionManager::instance().cancel_auction (ch, strtoul(arg1, NULL, 10));
  2623. }
  2624.  
  2625. ACMD (do_cancel_wish)
  2626. {
  2627. char arg1[256];
  2628. one_argument (argument, arg1, sizeof(arg1));
  2629.  
  2630. AuctionManager::instance().cancel_wish (ch, strtoul(arg1, NULL, 10));
  2631. }
  2632.  
  2633. ACMD (do_cancel_sale)
  2634. {
  2635. char arg1[256];
  2636. one_argument (argument, arg1, sizeof(arg1));
  2637.  
  2638. AuctionManager::instance().cancel_sale (ch, strtoul(arg1, NULL, 10));
  2639. }
  2640.  
  2641. ACMD (do_rebid)
  2642. {
  2643. char arg1[256];
  2644. char arg2[256];
  2645. two_arguments (argument, arg1, sizeof(arg1), arg2, sizeof(arg2));
  2646.  
  2647. AuctionManager::instance().rebid (ch, strtoul(arg1, NULL, 10), strtoul(arg2, NULL, 10));
  2648. }
  2649.  
  2650. ACMD (do_bid_cancel)
  2651. {
  2652. char arg1[256];
  2653. char arg2[256];
  2654. two_arguments (argument, arg1, sizeof(arg1), arg2, sizeof(arg2));
  2655.  
  2656. AuctionManager::instance().bid_cancel (ch, strtoul(arg1, NULL, 10));
  2657. }
  2658.  
  2659. ACMD(do_stat_val)
  2660. {
  2661. char arg1[256], arg2[256];
  2662. two_arguments(argument, arg1, sizeof(arg1), arg2, sizeof(arg2));
  2663.  
  2664. int val = 0;
  2665. str_to_number(val, arg2);
  2666.  
  2667. if (!*arg1 || val <= 0)
  2668. return;
  2669.  
  2670. if (ch->IsPolymorphed())
  2671. {
  2672. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("둔갑 중에는 능력을 올릴 수 없습니다."));
  2673. return;
  2674. }
  2675.  
  2676. if (ch->GetPoint(POINT_STAT) <= 0)
  2677. return;
  2678.  
  2679. BYTE idx = 0;
  2680.  
  2681. if (!strcmp(arg1, "st"))
  2682. idx = POINT_ST;
  2683. else if (!strcmp(arg1, "dx"))
  2684. idx = POINT_DX;
  2685. else if (!strcmp(arg1, "ht"))
  2686. idx = POINT_HT;
  2687. else if (!strcmp(arg1, "iq"))
  2688. idx = POINT_IQ;
  2689. else
  2690. return;
  2691.  
  2692. if (ch->GetRealPoint(idx) >= MAX_STAT)
  2693. return;
  2694.  
  2695. if (val > ch->GetPoint(POINT_STAT))
  2696. {
  2697. val = ch->GetPoint(POINT_STAT);
  2698. }
  2699.  
  2700. if (ch->GetRealPoint(idx) + val > MAX_STAT)
  2701. {
  2702. val = MAX_STAT - ch->GetRealPoint(idx);
  2703. }
  2704.  
  2705. ch->SetRealPoint(idx, ch->GetRealPoint(idx) + val);
  2706. ch->SetPoint(idx, ch->GetPoint(idx) + val);
  2707. ch->ComputePoints();
  2708. ch->PointChange(idx, 0);
  2709.  
  2710. if (idx == POINT_IQ)
  2711. {
  2712. ch->PointChange(POINT_MAX_HP, 0);
  2713. }
  2714. else if (idx == POINT_HT)
  2715. {
  2716. ch->PointChange(POINT_MAX_SP, 0);
  2717. }
  2718.  
  2719. ch->PointChange(POINT_STAT, -val);
  2720. ch->ComputePoints();
  2721. }
  2722. #endif
Advertisement
Add Comment
Please, Sign In to add comment