MrP0wers

char.cpp

Oct 1st, 2025
50
0
Never
9
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 187.61 KB | None | 0 0
  1. #include "stdafx.h"
  2. #include "char.h"
  3. #include "config.h"
  4. #include "utils.h"
  5. #include "crc32.h"
  6. #include "char_manager.h"
  7. #include "desc_client.h"
  8. #include "desc_manager.h"
  9. #include "buffer_manager.h"
  10. #include "item_manager.h"
  11. #include "motion.h"
  12. #include "vector.h"
  13. #include "packet.h"
  14. #include "cmd.h"
  15. #include "fishing.h"
  16. #include "exchange.h"
  17. #include "battle.h"
  18. #include "affect.h"
  19. #include "shop.h"
  20. #include "shop_manager.h"
  21. #include "safebox.h"
  22. #include "regen.h"
  23. #include "pvp.h"
  24. #include "party.h"
  25. #include "start_position.h"
  26. #include "questmanager.h"
  27. #include "log.h"
  28. #include "p2p.h"
  29. #include "guild.h"
  30. #include "guild_manager.h"
  31. #include "dungeon.h"
  32. #include "messenger_manager.h"
  33. #include "unique_item.h"
  34. #include "priv_manager.h"
  35. #include "war_map.h"
  36. #include "xmas_event.h"
  37. #include "banword.h"
  38. #include "target.h"
  39. #include "wedding.h"
  40. #include "mob_manager.h"
  41. #include "mining.h"
  42. #include "arena.h"
  43. #include "dev_log.h"
  44. #include "horsename_manager.h"
  45. #include "gm.h"
  46. #include "map_location.h"
  47. #include "BlueDragon_Binder.h"
  48. #include "DragonSoul.h"
  49. #include "OXEvent.h"
  50. #include "skill_power.h"
  51. #include "buff_on_attributes.h"
  52.  
  53. #include "../../common/VnumHelper.h"
  54.  
  55. #include <boost/algorithm/string/classification.hpp>
  56. #include <boost/algorithm/string/split.hpp>
  57.  
  58. #ifdef __PET_SYSTEM__
  59. #include "PetSystem.h"
  60. #endif
  61.  
  62. #ifdef __SWITCHBOT__
  63. #include "new_switchbot.h"
  64. #endif
  65.  
  66. #ifdef __SEND_TARGET_INFO__
  67. #include <algorithm>
  68. #include <iterator>
  69. using namespace std;
  70. #endif
  71.  
  72. extern const BYTE g_aBuffOnAttrPoints;
  73. extern bool RaceToJob(unsigned race, unsigned *ret_job);
  74.  
  75. extern int g_nPortalLimitTime;
  76. extern int test_server;
  77.  
  78. extern bool IS_SUMMONABLE_ZONE(int map_index);
  79. extern long long yang_max;
  80.  
  81. bool CAN_ENTER_ZONE(const LPCHARACTER& ch, int map_index);
  82.  
  83. bool CAN_ENTER_ZONE(const LPCHARACTER& ch, int map_index)
  84. {
  85. switch (map_index)
  86. {
  87. case 301:
  88. case 302:
  89. case 303:
  90. case 304:
  91. if (ch->GetLevel() < 90)
  92. return false;
  93. }
  94.  
  95. return true;
  96. }
  97.  
  98. LPCHARACTER DynamicCharacterPtr::Get() const
  99. {
  100. LPCHARACTER p = NULL;
  101.  
  102. if (is_pc)
  103. {
  104. p = CHARACTER_MANAGER::instance().FindByPID(id);
  105. }
  106.  
  107. else
  108. {
  109. p = CHARACTER_MANAGER::instance().Find(id);
  110. }
  111.  
  112. return p;
  113. }
  114.  
  115. DynamicCharacterPtr& DynamicCharacterPtr::operator=(LPCHARACTER character)
  116. {
  117. if (character == NULL)
  118. {
  119. Reset();
  120. return *this;
  121. }
  122.  
  123. if (character->IsPC())
  124. {
  125. is_pc = true;
  126. id = character->GetPlayerID();
  127. }
  128.  
  129. else
  130. {
  131. is_pc = false;
  132. id = character->GetVID();
  133. }
  134.  
  135. return *this;
  136. }
  137.  
  138. CHARACTER::CHARACTER()
  139. {
  140. m_stateIdle.Set(this, &CHARACTER::BeginStateEmpty, &CHARACTER::StateIdle, &CHARACTER::EndStateEmpty);
  141. m_stateMove.Set(this, &CHARACTER::BeginStateEmpty, &CHARACTER::StateMove, &CHARACTER::EndStateEmpty);
  142. m_stateBattle.Set(this, &CHARACTER::BeginStateEmpty, &CHARACTER::StateBattle, &CHARACTER::EndStateEmpty);
  143.  
  144. Initialize();
  145. }
  146.  
  147. CHARACTER::~CHARACTER()
  148. {
  149. Destroy();
  150. }
  151.  
  152. void CHARACTER::Initialize()
  153. {
  154. CEntity::Initialize(ENTITY_CHARACTER);
  155.  
  156. m_bNoOpenedShop = true;
  157.  
  158. m_bOpeningSafebox = false;
  159.  
  160. m_fSyncTime = get_float_time()-3;
  161. m_dwPlayerID = 0;
  162. m_dwKillerPID = 0;
  163.  
  164. #ifdef __SEND_TARGET_INFO__
  165. dwLastTargetInfoPulse = 0;
  166. #endif
  167.  
  168. m_iMoveCount = 0;
  169.  
  170. m_pkRegen = NULL;
  171. regen_id_ = 0;
  172. m_posRegen.x = m_posRegen.y = m_posRegen.z = 0;
  173. m_posStart.x = m_posStart.y = 0;
  174. m_posDest.x = m_posDest.y = 0;
  175. m_fRegenAngle = 0.0f;
  176.  
  177. m_pkMobData = NULL;
  178. m_pkMobInst = NULL;
  179.  
  180. m_pkShop = NULL;
  181. m_pkChrShopOwner = NULL;
  182. m_pkMyShop = NULL;
  183. m_pkExchange = NULL;
  184. m_pkParty = NULL;
  185. m_pkPartyRequestEvent = NULL;
  186.  
  187. m_pGuild = NULL;
  188.  
  189. m_pkChrTarget = NULL;
  190.  
  191. m_pkMuyeongEvent = NULL;
  192.  
  193. m_pkWarpNPCEvent = NULL;
  194. m_pkDeadEvent = NULL;
  195. m_pkStunEvent = NULL;
  196. m_pkSaveEvent = NULL;
  197. m_pkRecoveryEvent = NULL;
  198. m_pkTimedEvent = NULL;
  199. m_pkFishingEvent = NULL;
  200. m_pkWarpEvent = NULL;
  201.  
  202. m_pkMiningEvent = NULL;
  203.  
  204. m_pkPoisonEvent = NULL;
  205. m_pkFireEvent = NULL;
  206. m_pkCheckSpeedHackEvent = NULL;
  207. m_speed_hack_count = 0;
  208.  
  209. m_pkAffectEvent = NULL;
  210. m_afAffectFlag = TAffectFlag(0, 0);
  211.  
  212. m_pkDestroyWhenIdleEvent = NULL;
  213.  
  214. m_pkChrSyncOwner = NULL;
  215.  
  216. memset(&m_points, 0, sizeof(m_points));
  217. memset(&m_pointsInstant, 0, sizeof(m_pointsInstant));
  218. memset(&m_quickslot, 0, sizeof(m_quickslot));
  219.  
  220. m_bCharType = CHAR_TYPE_MONSTER;
  221.  
  222. SetPosition(POS_STANDING);
  223.  
  224. m_dwPlayStartTime = m_dwLastMoveTime = get_dword_time();
  225.  
  226. GotoState(m_stateIdle);
  227. m_dwStateDuration = 1;
  228.  
  229. m_dwLastAttackTime = get_dword_time() - 20000;
  230.  
  231. m_bAddChrState = 0;
  232.  
  233. m_pkChrStone = NULL;
  234.  
  235. m_pkSafebox = NULL;
  236. m_iSafeboxSize = -1;
  237. m_iSafeboxLoadTime = 0;
  238.  
  239. m_pkMall = NULL;
  240. m_iMallLoadTime = 0;
  241.  
  242. m_posWarp.x = m_posWarp.y = m_posWarp.z = 0;
  243. m_lWarpMapIndex = 0;
  244.  
  245. m_posExit.x = m_posExit.y = m_posExit.z = 0;
  246. m_lExitMapIndex = 0;
  247.  
  248. m_pSkillLevels = NULL;
  249.  
  250. m_dwMoveStartTime = 0;
  251. m_dwMoveDuration = 0;
  252.  
  253. m_dwFlyTargetID = 0;
  254.  
  255. m_dwNextStatePulse = 0;
  256.  
  257. m_dwLastDeadTime = get_dword_time()-180000;
  258.  
  259. m_bSkipSave = false;
  260.  
  261. m_bItemLoaded = false;
  262.  
  263. m_bHasPoisoned = false;
  264.  
  265. m_pkDungeon = NULL;
  266. m_iEventAttr = 0;
  267.  
  268. m_kAttackLog.dwVID = 0;
  269. m_kAttackLog.dwTime = 0;
  270.  
  271. m_bNowWalking = m_bWalking = false;
  272. ResetChangeAttackPositionTime();
  273.  
  274. m_bDetailLog = false;
  275. m_bMonsterLog = false;
  276.  
  277. m_bDisableCooltime = false;
  278.  
  279. m_iAlignment = 0;
  280. m_iRealAlignment = 0;
  281.  
  282. m_iKillerModePulse = 0;
  283. m_bPKMode = PK_MODE_PEACE;
  284.  
  285. m_dwQuestNPCVID = 0;
  286. m_dwQuestByVnum = 0;
  287. m_pQuestItem = NULL;
  288.  
  289. m_dwUnderGuildWarInfoMessageTime = get_dword_time()-60000;
  290.  
  291. m_bUnderRefine = false;
  292.  
  293. m_dwRefineNPCVID = 0;
  294.  
  295. m_dwPolymorphRace = 0;
  296.  
  297. m_bStaminaConsume = false;
  298.  
  299. ResetChainLightningIndex();
  300.  
  301. m_dwMountVnum = 0;
  302. m_chHorse = NULL;
  303. m_chRider = NULL;
  304.  
  305. m_pWarMap = NULL;
  306. m_pWeddingMap = NULL;
  307. m_bChatCounter = 0;
  308.  
  309. ResetStopTime();
  310.  
  311. m_dwLastVictimSetTime = get_dword_time() - 3000;
  312. m_iMaxAggro = -100;
  313.  
  314. m_bSendHorseLevel = 0;
  315. m_bSendHorseHealthGrade = 0;
  316. m_bSendHorseStaminaGrade = 0;
  317.  
  318. m_dwLoginPlayTime = 0;
  319.  
  320. m_pkChrMarried = NULL;
  321.  
  322. m_posSafeboxOpen.x = -1000;
  323. m_posSafeboxOpen.y = -1000;
  324.  
  325. m_dwLastSkillTime = get_dword_time();
  326.  
  327. memset(m_adwMobSkillCooltime, 0, sizeof(m_adwMobSkillCooltime));
  328.  
  329. m_pArena = NULL;
  330. m_nPotionLimit = quest::CQuestManager::instance().GetEventFlag("arena_potion_limit_count");
  331.  
  332. m_isOpenSafebox = 0;
  333.  
  334. m_iRefineTime = 0;
  335.  
  336. m_iSeedTime = 0;
  337.  
  338. m_iExchangeTime = 0;
  339.  
  340. m_iSafeboxLoadTime = 0;
  341.  
  342. m_iMyShopTime = 0;
  343.  
  344. m_deposit_pulse = 0;
  345.  
  346. SET_OVER_TIME(this, OT_NONE);
  347.  
  348. m_strNewName = "";
  349.  
  350. m_known_guild.clear();
  351.  
  352. m_dwLogOffInterval = 0;
  353.  
  354. m_bComboSequence = 0;
  355. m_dwLastComboTime = 0;
  356. m_bComboIndex = 0;
  357. m_iComboHackCount = 0;
  358. m_dwSkipComboAttackByTime = 0;
  359.  
  360. m_dwMountTime = 0;
  361.  
  362. m_dwLastGoldDropTime = 0;
  363.  
  364. m_bIsLoadedAffect = false;
  365. cannot_dead = false;
  366.  
  367. #ifdef __PET_SYSTEM__
  368. m_petSystem = 0;
  369. m_bIsPet = false;
  370. #endif
  371.  
  372. m_fAttMul = 1.0f;
  373. m_fDamMul = 1.0f;
  374.  
  375. m_pointsInstant.iDragonSoulActiveDeck = -1;
  376.  
  377. #ifdef __CUSTOM_TITLE_SYSTEM__
  378. m_stTitle = "";
  379. memset(m_bTitleColor, 0, sizeof(m_bTitleColor));
  380.  
  381. m_stTitle2 = "";
  382. memset(m_bTitle2Color, 0, sizeof(m_bTitle2Color));
  383. #endif
  384.  
  385. memset(&m_tvLastSyncTime, 0, sizeof(m_tvLastSyncTime));
  386. m_iSyncHackCount = 0;
  387. }
  388.  
  389. void CHARACTER::Create(const char * c_pszName, DWORD vid, bool isPC)
  390. {
  391. static int s_crc = 172814;
  392.  
  393. char crc_string[128+1];
  394.  
  395. snprintf(crc_string, sizeof(crc_string), "%s%p%d", c_pszName, this, ++s_crc);
  396. m_vid = VID(vid, GetCRC32(crc_string, strlen(crc_string)));
  397.  
  398. if (isPC)
  399. m_stName = c_pszName;
  400. }
  401.  
  402. void CHARACTER::Destroy()
  403. {
  404. CloseMyShop();
  405.  
  406. if (m_pkRegen)
  407. {
  408. if (m_pkDungeon)
  409. {
  410. if (m_pkDungeon->IsValidRegen(m_pkRegen, regen_id_))
  411. {
  412. --m_pkRegen->count;
  413. }
  414. }
  415.  
  416. else
  417. {
  418. --m_pkRegen->count;
  419. }
  420.  
  421. m_pkRegen = NULL;
  422. }
  423.  
  424. if (m_pkDungeon)
  425. {
  426. SetDungeon(NULL);
  427. }
  428.  
  429. #ifdef __PET_SYSTEM__
  430. if (m_petSystem)
  431. {
  432. m_petSystem->Destroy();
  433. delete m_petSystem;
  434.  
  435. m_petSystem = 0;
  436. }
  437. #endif
  438.  
  439. HorseSummon(false);
  440.  
  441. if (GetRider())
  442. GetRider()->ClearHorseInfo();
  443.  
  444. if (GetDesc())
  445. {
  446. GetDesc()->BindCharacter(NULL);
  447. }
  448.  
  449. if (m_pkExchange)
  450. m_pkExchange->Cancel();
  451.  
  452. SetVictim(NULL);
  453.  
  454. if (GetShop())
  455. {
  456. GetShop()->RemoveGuest(this);
  457. SetShop(NULL);
  458. }
  459.  
  460. ClearStone();
  461. ClearSync();
  462. ClearTarget();
  463.  
  464. if (NULL == m_pkMobData)
  465. {
  466. DragonSoul_CleanUp();
  467. ClearItem();
  468. }
  469.  
  470. LPPARTY party = m_pkParty;
  471.  
  472. if (party)
  473. {
  474. if (party->GetLeaderPID() == GetVID() && !IsPC())
  475. {
  476. M2_DELETE(party);
  477. }
  478.  
  479. else
  480. {
  481. party->Unlink(this);
  482.  
  483. if (!IsPC())
  484. party->Quit(GetVID());
  485. }
  486.  
  487. SetParty(NULL);
  488. }
  489.  
  490. if (m_pkMobInst)
  491. {
  492. M2_DELETE(m_pkMobInst);
  493. m_pkMobInst = NULL;
  494. }
  495.  
  496. m_pkMobData = NULL;
  497.  
  498. if (m_pkSafebox)
  499. {
  500. M2_DELETE(m_pkSafebox);
  501. m_pkSafebox = NULL;
  502. }
  503.  
  504. if (m_pkMall)
  505. {
  506. M2_DELETE(m_pkMall);
  507. m_pkMall = NULL;
  508. }
  509.  
  510. for (TMapBuffOnAttrs::iterator it = m_map_buff_on_attrs.begin(); it != m_map_buff_on_attrs.end(); it++)
  511. {
  512. if (NULL != it->second)
  513. {
  514. M2_DELETE(it->second);
  515. }
  516. }
  517.  
  518. m_map_buff_on_attrs.clear();
  519.  
  520. m_set_pkChrSpawnedBy.clear();
  521.  
  522. StopMuyeongEvent();
  523. event_cancel(&m_pkWarpNPCEvent);
  524. event_cancel(&m_pkRecoveryEvent);
  525. event_cancel(&m_pkDeadEvent);
  526. event_cancel(&m_pkSaveEvent);
  527. event_cancel(&m_pkTimedEvent);
  528. event_cancel(&m_pkStunEvent);
  529. event_cancel(&m_pkFishingEvent);
  530. event_cancel(&m_pkPoisonEvent);
  531. event_cancel(&m_pkFireEvent);
  532. event_cancel(&m_pkPartyRequestEvent);
  533.  
  534. event_cancel(&m_pkWarpEvent);
  535. event_cancel(&m_pkCheckSpeedHackEvent);
  536.  
  537. //event_cancel(&m_pkRecallEvent);
  538.  
  539. event_cancel(&m_pkMiningEvent);
  540.  
  541. for (itertype(m_mapMobSkillEvent) it = m_mapMobSkillEvent.begin(); it != m_mapMobSkillEvent.end(); ++it)
  542. {
  543. LPEVENT pkEvent = it->second;
  544. event_cancel(&pkEvent);
  545. }
  546.  
  547. m_mapMobSkillEvent.clear();
  548.  
  549. //event_cancel(&m_pkAffectEvent);
  550.  
  551. ClearAffect();
  552.  
  553. event_cancel(&m_pkDestroyWhenIdleEvent);
  554.  
  555. if (m_pSkillLevels)
  556. {
  557. M2_DELETE_ARRAY(m_pSkillLevels);
  558. m_pSkillLevels = NULL;
  559. }
  560.  
  561. CEntity::Destroy();
  562.  
  563. if (GetSectree())
  564. GetSectree()->RemoveEntity(this);
  565.  
  566. if (m_bMonsterLog)
  567. CHARACTER_MANAGER::instance().UnregisterForMonsterLog(this);
  568. }
  569.  
  570. const char * CHARACTER::GetName() const
  571. {
  572. return m_stName.empty() ? (m_pkMobData ? m_pkMobData->m_table.szLocaleName : "") : m_stName.c_str();
  573. }
  574.  
  575. void CHARACTER::OpenMyShop(const char * c_pszSign, TShopItemTable * pTable, BYTE bItemCount)
  576. {
  577. if (!CanHandleItem())
  578. {
  579. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("다른 거래중(창고,교환,상점)에는 개인상점을 사용할 수 없습니다."));
  580. return;
  581. }
  582. if (GetPart(PART_MAIN) > 2)
  583. {
  584. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("갑옷을 벗어야 개인 상점을 열 수 있습니다."));
  585. return;
  586. }
  587.  
  588. if (GetMyShop())
  589. {
  590. CloseMyShop();
  591. return;
  592. }
  593.  
  594. #ifdef __INVENTORY_PROTECT_SYSTEM__
  595. if (GetQuestFlag("abs.INVENTORY_LOCK") == 1)
  596. {
  597. ChatPacket(CHAT_TYPE_INFO, "|cFF00ff33[Info] > |h|r Inventarul este blocat .");
  598. return;
  599. }
  600. #endif
  601.  
  602. quest::PC * pPC = quest::CQuestManager::instance().GetPCForce(GetPlayerID());
  603.  
  604. if (pPC->IsRunning())
  605. return;
  606.  
  607. if (bItemCount == 0)
  608. return;
  609.  
  610. long long nTotalMoney = 0;
  611.  
  612. for (int n = 0; n < bItemCount; ++n)
  613. {
  614. nTotalMoney += static_cast<long long>((pTable + n)->price);
  615. }
  616.  
  617. nTotalMoney += static_cast<long long>(GetGold());
  618.  
  619. if (yang_max <= nTotalMoney)
  620. {
  621. sys_err("[OVERFLOW_GOLD] Overflow (GOLD_MAX) id %u name %s", GetPlayerID(), GetName());
  622. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("20? ?? ???? ??? ??? ????"));
  623. return;
  624. }
  625.  
  626. char szSign[SHOP_SIGN_MAX_LEN+1];
  627. strlcpy(szSign, c_pszSign, sizeof(szSign));
  628.  
  629. m_stShopSign = szSign;
  630.  
  631. if (m_stShopSign.length() == 0)
  632. return;
  633.  
  634. if (CBanwordManager::instance().CheckString(m_stShopSign.c_str(), m_stShopSign.length()))
  635. {
  636. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("비속어나 은어가 포함된 상점 이름으로 상점을 열 수 없습니다."));
  637. return;
  638. }
  639.  
  640. std::map<DWORD, DWORD> itemkind;
  641.  
  642. std::set<TItemPos> cont;
  643. for (BYTE i = 0; i < bItemCount; ++i)
  644. {
  645. if (cont.find((pTable + i)->pos) != cont.end())
  646. {
  647. sys_err("MYSHOP: duplicate shop item detected! (name: %s)", GetName());
  648. return;
  649. }
  650.  
  651. LPITEM pkItem = GetItem((pTable + i)->pos);
  652.  
  653. if (pkItem)
  654. {
  655. const TItemTable * item_table = pkItem->GetProto();
  656.  
  657. if (item_table && (IS_SET(item_table->dwAntiFlags, ITEM_ANTIFLAG_GIVE | ITEM_ANTIFLAG_MYSHOP)))
  658. {
  659. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("유료화 아이템은 개인상점에서 판매할 수 없습니다."));
  660. return;
  661. }
  662.  
  663. if (pkItem->IsEquipped() == true)
  664. {
  665. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("장비중인 아이템은 개인상점에서 판매할 수 없습니다."));
  666. return;
  667. }
  668.  
  669. if (true == pkItem->isLocked())
  670. {
  671. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("사용중인 아이템은 개인상점에서 판매할 수 없습니다."));
  672. return;
  673. }
  674.  
  675. itemkind[pkItem->GetVnum()] = (pTable + i)->price / pkItem->GetCount();
  676. }
  677.  
  678. cont.insert((pTable + i)->pos);
  679. }
  680.  
  681. if (CountSpecifyItem(71049))
  682. {
  683. TItemPriceListTable header;
  684. memset(&header, 0, sizeof(TItemPriceListTable));
  685.  
  686. header.dwOwnerID = GetPlayerID();
  687. header.byCount = itemkind.size();
  688.  
  689. size_t idx=0;
  690. for (itertype(itemkind) it = itemkind.begin(); it != itemkind.end(); ++it)
  691. {
  692. header.aPriceInfo[idx].dwVnum = it->first;
  693. header.aPriceInfo[idx].dwPrice = it->second;
  694. idx++;
  695. }
  696.  
  697. db_clientdesc->DBPacket(HEADER_GD_MYSHOP_PRICELIST_UPDATE, GetDesc()->GetHandle(), &header, sizeof(TItemPriceListTable));
  698. }
  699.  
  700.  
  701. else if (CountSpecifyItem(50200))
  702. RemoveSpecifyItem(50200, 1);
  703.  
  704. else
  705. return;
  706.  
  707. if (m_pkExchange)
  708. m_pkExchange->Cancel();
  709.  
  710. TPacketGCShopSign p;
  711.  
  712. p.bHeader = HEADER_GC_SHOP_SIGN;
  713. p.dwVID = GetVID();
  714. strlcpy(p.szSign, c_pszSign, sizeof(p.szSign));
  715.  
  716. PacketAround(&p, sizeof(TPacketGCShopSign));
  717.  
  718. m_pkMyShop = CShopManager::instance().CreatePCShop(this, pTable, bItemCount);
  719.  
  720. if (IsPolymorphed() == true)
  721. {
  722. RemoveAffect(AFFECT_POLYMORPH);
  723. }
  724.  
  725. if (GetHorse())
  726. {
  727. HorseSummon( false, true );
  728. }
  729.  
  730. else if (GetMountVnum())
  731. {
  732. RemoveAffect(AFFECT_MOUNT);
  733. RemoveAffect(AFFECT_MOUNT_BONUS);
  734. }
  735.  
  736. SetPolymorph(30000, true);
  737. }
  738.  
  739. void CHARACTER::CloseMyShop()
  740. {
  741. if (GetMyShop())
  742. {
  743. m_stShopSign.clear();
  744. CShopManager::instance().DestroyPCShop(this);
  745. m_pkMyShop = NULL;
  746.  
  747. TPacketGCShopSign p;
  748.  
  749. p.bHeader = HEADER_GC_SHOP_SIGN;
  750. p.dwVID = GetVID();
  751. p.szSign[0] = '\0';
  752.  
  753. PacketAround(&p, sizeof(p));
  754.  
  755. SetPolymorph(GetJob(), true);
  756. }
  757. }
  758.  
  759. void EncodeMovePacket(TPacketGCMove & pack, DWORD dwVID, BYTE bFunc, BYTE bArg, DWORD x, DWORD y, DWORD dwDuration, DWORD dwTime, BYTE bRot)
  760. {
  761. pack.bHeader = HEADER_GC_CHARACTER_MOVE;
  762. pack.bFunc = bFunc;
  763. pack.bArg = bArg;
  764. pack.dwVID = dwVID;
  765. pack.dwTime = dwTime ? dwTime : get_dword_time();
  766. pack.bRot = bRot;
  767. pack.lX = x;
  768. pack.lY = y;
  769. pack.dwDuration = dwDuration;
  770. }
  771.  
  772. void CHARACTER::RestartAtSamePos()
  773. {
  774. if (m_bIsObserver)
  775. return;
  776.  
  777. EncodeRemovePacket(this);
  778. EncodeInsertPacket(this);
  779.  
  780. ENTITY_MAP::iterator it = m_map_view.begin();
  781.  
  782. while (it != m_map_view.end())
  783. {
  784. LPENTITY entity = (it++)->first;
  785.  
  786. EncodeRemovePacket(entity);
  787. if (!m_bIsObserver)
  788. EncodeInsertPacket(entity);
  789.  
  790. if( entity->IsType(ENTITY_CHARACTER) )
  791. {
  792. LPCHARACTER lpChar = (LPCHARACTER)entity;
  793. if( lpChar->IsPC() || lpChar->IsNPC() || lpChar->IsMonster() )
  794. {
  795. if (!entity->IsObserverMode())
  796. entity->EncodeInsertPacket(this);
  797. }
  798. }
  799.  
  800. else
  801. {
  802. if( !entity->IsObserverMode())
  803. {
  804. entity->EncodeInsertPacket(this);
  805. }
  806. }
  807. }
  808. }
  809.  
  810. void CHARACTER::EncodeInsertPacket(LPENTITY entity)
  811. {
  812. LPDESC d;
  813.  
  814. if (!(d = entity->GetDesc()))
  815. return;
  816.  
  817. LPCHARACTER ch = (LPCHARACTER) entity;
  818. ch->SendGuildName(GetGuild());
  819.  
  820. TPacketGCCharacterAdd pack;
  821.  
  822. pack.header = HEADER_GC_CHARACTER_ADD;
  823.  
  824. pack.dwVID = m_vid;
  825. pack.bType = GetCharType();
  826. pack.angle = GetRotation();
  827.  
  828. pack.x = GetX();
  829. pack.y = GetY();
  830. pack.z = GetZ();
  831.  
  832. pack.wRaceNum = GetRaceNum();
  833.  
  834. if (IsPet())
  835. {
  836. pack.bMovingSpeed = 150;
  837. }
  838.  
  839. else
  840. {
  841. pack.bMovingSpeed = GetLimitPoint(POINT_MOV_SPEED);
  842. }
  843.  
  844. #if defined(__WJ_SHOW_MOB_INFO__)
  845. if (IsMonster() || IsStone())
  846. {
  847. pack.dwLevel = GetLevel();
  848. pack.dwAIFlag = IsMonster() ? GetAIFlag() : 0;
  849. }
  850.  
  851. else
  852. {
  853. pack.dwLevel = 0;
  854. pack.dwAIFlag = 0;
  855. }
  856. #endif
  857.  
  858. pack.bAttackSpeed = GetLimitPoint(POINT_ATT_SPEED);
  859. pack.dwAffectFlag[0] = m_afAffectFlag.bits[0];
  860. pack.dwAffectFlag[1] = m_afAffectFlag.bits[1];
  861.  
  862. pack.bStateFlag = m_bAddChrState;
  863.  
  864. int iDur = 0;
  865.  
  866. if (m_posDest.x != pack.x || m_posDest.y != pack.y)
  867. {
  868. iDur = (m_dwMoveStartTime + m_dwMoveDuration) - get_dword_time();
  869.  
  870. if (iDur <= 0)
  871. {
  872. pack.x = m_posDest.x;
  873. pack.y = m_posDest.y;
  874. }
  875. }
  876.  
  877. d->Packet(&pack, sizeof(pack));
  878.  
  879. if (IsPC() == true || m_bCharType == CHAR_TYPE_NPC)
  880. {
  881. TPacketGCCharacterAdditionalInfo addPacket;
  882. memset(&addPacket, 0, sizeof(TPacketGCCharacterAdditionalInfo));
  883.  
  884. addPacket.header = HEADER_GC_CHAR_ADDITIONAL_INFO;
  885. addPacket.dwVID = m_vid;
  886.  
  887. addPacket.awPart[CHR_EQUIPPART_ARMOR] = GetPart(PART_MAIN);
  888.  
  889. #ifdef ENABLE_HIDE_COSTUME_SYSTEM
  890. SetHideCostumeUpdate();
  891. #endif
  892. addPacket.awPart[CHR_EQUIPPART_WEAPON] = GetPart(PART_WEAPON);
  893. addPacket.awPart[CHR_EQUIPPART_HEAD] = GetPart(PART_HEAD);
  894. addPacket.awPart[CHR_EQUIPPART_HAIR] = GetPart(PART_HAIR);
  895.  
  896. #ifdef __EFFECT_SYSTEM__
  897. addPacket.awPart[CHR_BODY_EFFECT] = GetPart(BODY_EFFECT);
  898. addPacket.awPart[CHR_WEAPON_RIGHT_EFFECT] = GetPart(WEAPON_RIGHT_EFFECT);
  899. addPacket.awPart[CHR_WEAPON_LEFT_EFFECT] = GetPart(WEAPON_LEFT_EFFECT);
  900. #endif
  901. addPacket.bPKMode = m_bPKMode;
  902. addPacket.dwMountVnum = GetMountVnum();
  903. addPacket.bEmpire = m_bEmpire;
  904.  
  905. #ifdef ENABLE_EXTENDED_ALIGNMENT_SYSTEM
  906. addPacket.bJob = IsPC() ? m_points.job : 0;
  907. #endif
  908.  
  909. if (IsPC())
  910. {
  911. addPacket.dwLevel = GetLevel();
  912.  
  913. #ifdef __CUSTOM_TITLE_SYSTEM__
  914. strlcpy(addPacket.title.szName, GetTitle(), sizeof(addPacket.title.szName));
  915. memcpy(addPacket.title.bColours, GetTitleColors(), sizeof(addPacket.title.bColours));
  916.  
  917. strlcpy(addPacket.title2.szName, GetTitle2(), sizeof(addPacket.title2.szName));
  918. memcpy(addPacket.title2.bColours2, GetTitle2Colors(), sizeof(addPacket.title2.bColours2));
  919. #endif
  920. }
  921.  
  922. else
  923. {
  924. addPacket.dwLevel = 0;
  925. }
  926.  
  927. if (false)
  928. {
  929. LPCHARACTER ch = (LPCHARACTER) entity;
  930.  
  931. if (GetEmpire() == ch->GetEmpire() || ch->GetGMLevel() > GM_PLAYER || m_bCharType == CHAR_TYPE_NPC)
  932. {
  933. goto show_all_info;
  934. }
  935.  
  936. else
  937. {
  938. memset(addPacket.name, 0, CHARACTER_NAME_MAX_LEN);
  939. addPacket.dwGuildID = 0;
  940. addPacket.sAlignment = 0;
  941.  
  942. #ifdef __TITLE_SYSTEM__
  943. addPacket.iTitleID = 0;
  944. #endif
  945. }
  946. }
  947.  
  948. else
  949. {
  950. show_all_info:
  951. strlcpy(addPacket.name, GetName(), sizeof(addPacket.name));
  952.  
  953. if (GetGuild() != NULL)
  954. {
  955. addPacket.dwGuildID = GetGuild()->GetID();
  956. }
  957. else
  958. {
  959. addPacket.dwGuildID = 0;
  960. }
  961.  
  962. addPacket.sAlignment = m_iAlignment / 10;
  963.  
  964. #ifdef __TITLE_SYSTEM__
  965. addPacket.iTitleID = GetPoint(POINT_TITLE);
  966. #endif
  967. }
  968.  
  969. d->Packet(&addPacket, sizeof(TPacketGCCharacterAdditionalInfo));
  970. }
  971.  
  972. if (iDur)
  973. {
  974. TPacketGCMove pack;
  975. EncodeMovePacket(pack, GetVID(), FUNC_MOVE, 0, m_posDest.x, m_posDest.y, iDur, 0, (BYTE) (GetRotation() / 5));
  976. d->Packet(&pack, sizeof(pack));
  977.  
  978. TPacketGCWalkMode p;
  979. p.vid = GetVID();
  980. p.header = HEADER_GC_WALK_MODE;
  981. p.mode = m_bNowWalking ? WALKMODE_WALK : WALKMODE_RUN;
  982.  
  983. d->Packet(&p, sizeof(p));
  984. }
  985.  
  986. if (entity->IsType(ENTITY_CHARACTER) && GetDesc())
  987. {
  988. LPCHARACTER ch = (LPCHARACTER) entity;
  989. if (ch->IsWalking())
  990. {
  991. TPacketGCWalkMode p;
  992. p.vid = ch->GetVID();
  993. p.header = HEADER_GC_WALK_MODE;
  994. p.mode = ch->m_bNowWalking ? WALKMODE_WALK : WALKMODE_RUN;
  995. GetDesc()->Packet(&p, sizeof(p));
  996. }
  997. }
  998.  
  999. if (GetMyShop())
  1000. {
  1001. TPacketGCShopSign p;
  1002.  
  1003. p.bHeader = HEADER_GC_SHOP_SIGN;
  1004. p.dwVID = GetVID();
  1005. strlcpy(p.szSign, m_stShopSign.c_str(), sizeof(p.szSign));
  1006.  
  1007. d->Packet(&p, sizeof(TPacketGCShopSign));
  1008. }
  1009.  
  1010. if (entity->IsType(ENTITY_CHARACTER))
  1011. {
  1012. sys_log(3, "EntityInsert %s (RaceNum %d) (%d %d) TO %s", GetName(), GetRaceNum(), GetX() / SECTREE_SIZE, GetY() / SECTREE_SIZE, ((LPCHARACTER)entity)->GetName());
  1013. }
  1014. }
  1015.  
  1016. void CHARACTER::EncodeRemovePacket(LPENTITY entity)
  1017. {
  1018. if (entity->GetType() != ENTITY_CHARACTER)
  1019. return;
  1020.  
  1021. LPDESC d;
  1022.  
  1023. if (!(d = entity->GetDesc()))
  1024. return;
  1025.  
  1026. TPacketGCCharacterDelete pack;
  1027.  
  1028. pack.header = HEADER_GC_CHARACTER_DEL;
  1029. pack.id = m_vid;
  1030.  
  1031. d->Packet(&pack, sizeof(TPacketGCCharacterDelete));
  1032.  
  1033. if (entity->IsType(ENTITY_CHARACTER))
  1034. sys_log(3, "EntityRemove %s(%d) FROM %s", GetName(), (DWORD) m_vid, ((LPCHARACTER) entity)->GetName());
  1035. }
  1036.  
  1037. void CHARACTER::UpdatePacket()
  1038. {
  1039. if (GetSectree() == NULL) return;
  1040.  
  1041. if (IsPC() && (!GetDesc() || !GetDesc()->GetCharacter()))
  1042. return;
  1043.  
  1044. TPacketGCCharacterUpdate pack;
  1045. TPacketGCCharacterUpdate pack2;
  1046.  
  1047. pack.header = HEADER_GC_CHARACTER_UPDATE;
  1048. pack.dwVID = m_vid;
  1049.  
  1050. pack.awPart[CHR_EQUIPPART_ARMOR] = GetPart(PART_MAIN);
  1051.  
  1052. #ifdef ENABLE_HIDE_COSTUME_SYSTEM
  1053. SetHideCostumeUpdate();
  1054. #endif
  1055.  
  1056. pack.awPart[CHR_EQUIPPART_WEAPON] = GetPart(PART_WEAPON);
  1057. pack.awPart[CHR_EQUIPPART_HEAD] = GetPart(PART_HEAD);
  1058. pack.awPart[CHR_EQUIPPART_HAIR] = GetPart(PART_HAIR);
  1059.  
  1060. #ifdef __EFFECT_SYSTEM__
  1061. pack.awPart[CHR_BODY_EFFECT] = GetPart(BODY_EFFECT);
  1062. pack.awPart[CHR_WEAPON_RIGHT_EFFECT] = GetPart(WEAPON_RIGHT_EFFECT);
  1063. pack.awPart[CHR_WEAPON_LEFT_EFFECT] = GetPart(WEAPON_LEFT_EFFECT);
  1064. #endif
  1065.  
  1066. pack.bMovingSpeed = GetLimitPoint(POINT_MOV_SPEED);
  1067. pack.bAttackSpeed = GetLimitPoint(POINT_ATT_SPEED);
  1068. pack.bStateFlag = m_bAddChrState;
  1069.  
  1070. pack.dwAffectFlag[0] = m_afAffectFlag.bits[0];
  1071. pack.dwAffectFlag[1] = m_afAffectFlag.bits[1];
  1072. pack.dwGuildID = 0;
  1073.  
  1074. pack.sAlignment = m_iAlignment / 10;
  1075. pack.bPKMode = m_bPKMode;
  1076.  
  1077. #ifdef __TITLE_SYSTEM__
  1078. pack.iTitleID = GetPoint(POINT_TITLE);
  1079. #endif
  1080.  
  1081. if (GetGuild())
  1082. pack.dwGuildID = GetGuild()->GetID();
  1083.  
  1084. pack.dwMountVnum = GetMountVnum();
  1085.  
  1086. pack2 = pack;
  1087. pack2.dwGuildID = 0;
  1088. pack2.sAlignment = 0;
  1089.  
  1090. #ifdef __TITLE_SYSTEM__
  1091. pack.iTitleID = GetPoint(POINT_TITLE);
  1092. #endif
  1093.  
  1094. if (false)
  1095. {
  1096. if (m_bIsObserver != true)
  1097. {
  1098. for (ENTITY_MAP::iterator iter = m_map_view.begin(); iter != m_map_view.end(); iter++)
  1099. {
  1100. LPENTITY pEntity = iter->first;
  1101.  
  1102. if (pEntity != NULL)
  1103. {
  1104. if (pEntity->IsType(ENTITY_CHARACTER) == true)
  1105. {
  1106. if (pEntity->GetDesc() != NULL)
  1107. {
  1108. LPCHARACTER pChar = (LPCHARACTER)pEntity;
  1109.  
  1110. if (GetEmpire() == pChar->GetEmpire() || pChar->GetGMLevel() > GM_PLAYER)
  1111. {
  1112. pEntity->GetDesc()->Packet(&pack, sizeof(pack));
  1113. }
  1114.  
  1115. else
  1116. {
  1117. pEntity->GetDesc()->Packet(&pack2, sizeof(pack2));
  1118. }
  1119. }
  1120. }
  1121.  
  1122. else
  1123. {
  1124. if (pEntity->GetDesc() != NULL)
  1125. {
  1126. pEntity->GetDesc()->Packet(&pack, sizeof(pack));
  1127. }
  1128. }
  1129. }
  1130. }
  1131. }
  1132.  
  1133. if (GetDesc() != NULL)
  1134. {
  1135. GetDesc()->Packet(&pack, sizeof(pack));
  1136. }
  1137. }
  1138.  
  1139. else
  1140. {
  1141. PacketAround(&pack, sizeof(pack));
  1142. }
  1143. }
  1144.  
  1145. LPCHARACTER CHARACTER::FindCharacterInView(const char * c_pszName, bool bFindPCOnly)
  1146. {
  1147. ENTITY_MAP::iterator it = m_map_view.begin();
  1148.  
  1149. for (; it != m_map_view.end(); ++it)
  1150. {
  1151. if (!it->first->IsType(ENTITY_CHARACTER))
  1152. continue;
  1153.  
  1154. LPCHARACTER tch = (LPCHARACTER) it->first;
  1155.  
  1156. if (bFindPCOnly && tch->IsNPC())
  1157. continue;
  1158.  
  1159. if (!strcasecmp(tch->GetName(), c_pszName))
  1160. return (tch);
  1161. }
  1162.  
  1163. return NULL;
  1164. }
  1165.  
  1166. void CHARACTER::SetPosition(int pos)
  1167. {
  1168. if (pos == POS_STANDING)
  1169. {
  1170. REMOVE_BIT(m_bAddChrState, ADD_CHARACTER_STATE_DEAD);
  1171. REMOVE_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_STUN);
  1172.  
  1173. event_cancel(&m_pkDeadEvent);
  1174. event_cancel(&m_pkStunEvent);
  1175. }
  1176.  
  1177. else if (pos == POS_DEAD)
  1178. SET_BIT(m_bAddChrState, ADD_CHARACTER_STATE_DEAD);
  1179.  
  1180. if (!IsStone())
  1181. {
  1182. switch (pos)
  1183. {
  1184. case POS_FIGHTING:
  1185. if (!IsState(m_stateBattle))
  1186. MonsterLog("[BATTLE] 싸우는 상태");
  1187.  
  1188. GotoState(m_stateBattle);
  1189. break;
  1190.  
  1191. default:
  1192. if (!IsState(m_stateIdle))
  1193. MonsterLog("[IDLE] 쉬는 상태");
  1194.  
  1195. GotoState(m_stateIdle);
  1196. break;
  1197. }
  1198. }
  1199.  
  1200. m_pointsInstant.position = pos;
  1201. }
  1202.  
  1203. void CHARACTER::Save()
  1204. {
  1205. if (!m_bSkipSave)
  1206. CHARACTER_MANAGER::instance().DelayedSave(this);
  1207. }
  1208.  
  1209. void CHARACTER::CreatePlayerProto(TPlayerTable & tab)
  1210. {
  1211. memset(&tab, 0, sizeof(TPlayerTable));
  1212.  
  1213. if (GetNewName().empty())
  1214. {
  1215. strlcpy(tab.name, GetName(), sizeof(tab.name));
  1216. }
  1217.  
  1218. else
  1219. {
  1220. strlcpy(tab.name, GetNewName().c_str(), sizeof(tab.name));
  1221. }
  1222.  
  1223. strlcpy(tab.ip, GetDesc()->GetHostName(), sizeof(tab.ip));
  1224.  
  1225. tab.id = m_dwPlayerID;
  1226. tab.voice = GetPoint(POINT_VOICE);
  1227. tab.level = GetLevel();
  1228. tab.level_step = GetPoint(POINT_LEVEL_STEP);
  1229. tab.exp = GetExp();
  1230. tab.gold = GetGold();
  1231. tab.job = m_points.job;
  1232. tab.part_base = m_pointsInstant.bBasePart;
  1233. tab.skill_group = m_points.skill_group;
  1234.  
  1235. DWORD dwPlayedTime = (get_dword_time() - m_dwPlayStartTime);
  1236.  
  1237. if (dwPlayedTime > 60000)
  1238. {
  1239. if (GetSectree() && !GetSectree()->IsAttr(GetX(), GetY(), ATTR_BANPK))
  1240. {
  1241. if (GetRealAlignment() < 0)
  1242. {
  1243. if (IsEquipUniqueItem(UNIQUE_ITEM_FASTER_ALIGNMENT_UP_BY_TIME))
  1244. UpdateAlignment(120 * (dwPlayedTime / 60000));
  1245. else
  1246. UpdateAlignment(60 * (dwPlayedTime / 60000));
  1247. }
  1248.  
  1249. else
  1250. UpdateAlignment(5 * (dwPlayedTime / 60000));
  1251. }
  1252.  
  1253. SetRealPoint(POINT_PLAYTIME, GetRealPoint(POINT_PLAYTIME) + dwPlayedTime / 60000);
  1254. ResetPlayTime(dwPlayedTime % 60000);
  1255. }
  1256.  
  1257. tab.playtime = GetRealPoint(POINT_PLAYTIME);
  1258. tab.lAlignment = m_iRealAlignment;
  1259.  
  1260. if (m_posWarp.x != 0 || m_posWarp.y != 0)
  1261. {
  1262. tab.x = m_posWarp.x;
  1263. tab.y = m_posWarp.y;
  1264. tab.z = 0;
  1265. tab.lMapIndex = m_lWarpMapIndex;
  1266. }
  1267.  
  1268. else
  1269. {
  1270. tab.x = GetX();
  1271. tab.y = GetY();
  1272. tab.z = GetZ();
  1273. tab.lMapIndex = GetMapIndex();
  1274. }
  1275.  
  1276. if (m_lExitMapIndex == 0)
  1277. {
  1278. tab.lExitMapIndex = tab.lMapIndex;
  1279. tab.lExitX = tab.x;
  1280. tab.lExitY = tab.y;
  1281. }
  1282.  
  1283. else
  1284. {
  1285. tab.lExitMapIndex = m_lExitMapIndex;
  1286. tab.lExitX = m_posExit.x;
  1287. tab.lExitY = m_posExit.y;
  1288. }
  1289.  
  1290. sys_log(0, "SAVE: %s %dx%d", GetName(), tab.x, tab.y);
  1291.  
  1292. tab.st = GetRealPoint(POINT_ST);
  1293. tab.ht = GetRealPoint(POINT_HT);
  1294. tab.dx = GetRealPoint(POINT_DX);
  1295. tab.iq = GetRealPoint(POINT_IQ);
  1296.  
  1297. tab.stat_point = GetPoint(POINT_STAT);
  1298. tab.skill_point = GetPoint(POINT_SKILL);
  1299. tab.sub_skill_point = GetPoint(POINT_SUB_SKILL);
  1300. tab.horse_skill_point = GetPoint(POINT_HORSE_SKILL);
  1301.  
  1302. tab.stat_reset_count = GetPoint(POINT_STAT_RESET_COUNT);
  1303.  
  1304. tab.hp = GetHP();
  1305. tab.sp = GetSP();
  1306.  
  1307. tab.stamina = GetStamina();
  1308.  
  1309. tab.sRandomHP = m_points.iRandomHP;
  1310. tab.sRandomSP = m_points.iRandomSP;
  1311.  
  1312. for (int i = 0; i < QUICKSLOT_MAX_NUM; ++i)
  1313. tab.quickslot[i] = m_quickslot[i];
  1314.  
  1315. thecore_memcpy(tab.parts, m_pointsInstant.parts, sizeof(tab.parts));
  1316.  
  1317. thecore_memcpy(tab.skills, m_pSkillLevels, sizeof(TPlayerSkill) * SKILL_MAX_NUM);
  1318.  
  1319. #ifdef __CUSTOM_TITLE_SYSTEM__
  1320. strlcpy(tab.title.szName, GetTitle(), sizeof(tab.title.szName));
  1321. memcpy(tab.title.bColours, GetTitleColors(), sizeof(tab.title.bColours));
  1322.  
  1323. strlcpy(tab.title2.szName, GetTitle2(), sizeof(tab.title2.szName));
  1324. memcpy(tab.title2.bColours2, GetTitle2Colors(), sizeof(tab.title2.bColours2));
  1325. #endif
  1326.  
  1327. tab.horse = GetHorseData();
  1328.  
  1329. #ifdef __TITLE_SYSTEM__
  1330. tab.iTChoosed = GetPoint(POINT_TITLE);
  1331. #endif
  1332.  
  1333. }
  1334.  
  1335. void CHARACTER::SaveReal()
  1336. {
  1337. if (m_bSkipSave)
  1338. return;
  1339.  
  1340. if (!GetDesc())
  1341. {
  1342. sys_err("Character::Save : no descriptor when saving (name: %s)", GetName());
  1343. return;
  1344. }
  1345.  
  1346. TPlayerTable table;
  1347. CreatePlayerProto(table);
  1348.  
  1349. db_clientdesc->DBPacket(HEADER_GD_PLAYER_SAVE, GetDesc()->GetHandle(), &table, sizeof(TPlayerTable));
  1350.  
  1351. quest::PC * pkQuestPC = quest::CQuestManager::instance().GetPCForce(GetPlayerID());
  1352.  
  1353. if (!pkQuestPC)
  1354. sys_err("CHARACTER::Save : null quest::PC pointer! (name %s)", GetName());
  1355.  
  1356. else
  1357. {
  1358. pkQuestPC->Save();
  1359. }
  1360.  
  1361. marriage::TMarriage* pMarriage = marriage::CManager::instance().Get(GetPlayerID());
  1362. if (pMarriage)
  1363. pMarriage->Save();
  1364. }
  1365.  
  1366. void CHARACTER::FlushDelayedSaveItem()
  1367. {
  1368. LPITEM item;
  1369.  
  1370. for (int i = 0; i < INVENTORY_AND_EQUIP_SLOT_MAX; ++i)
  1371. if ((item = GetInventoryItem(i)))
  1372. ITEM_MANAGER::instance().FlushDelayedSave(item);
  1373. }
  1374.  
  1375. void CHARACTER::Disconnect(const char * c_pszReason)
  1376. {
  1377. assert(GetDesc() != NULL);
  1378.  
  1379. sys_log(0, "DISCONNECT: %s (%s)", GetName(), c_pszReason ? c_pszReason : "unset" );
  1380.  
  1381. if (GetShop())
  1382. {
  1383. GetShop()->RemoveGuest(this);
  1384. SetShop(NULL);
  1385. }
  1386.  
  1387. if (GetArena() != NULL)
  1388. {
  1389. GetArena()->OnDisconnect(GetPlayerID());
  1390. }
  1391.  
  1392. if (GetParty() != NULL)
  1393. {
  1394. GetParty()->UpdateOfflineState(GetPlayerID());
  1395. }
  1396.  
  1397. marriage::CManager::instance().Logout(this);
  1398.  
  1399. TPacketGGLogout p;
  1400. p.bHeader = HEADER_GG_LOGOUT;
  1401.  
  1402. strlcpy(p.szName, GetName(), sizeof(p.szName));
  1403. P2P_MANAGER::instance().Send(&p, sizeof(TPacketGGLogout));
  1404.  
  1405. char buf[51];
  1406.  
  1407. snprintf(buf, sizeof(buf), "%s %lld %d %ld %d", inet_ntoa(GetDesc()->GetAddr().sin_addr), GetGold(), g_bChannel, GetMapIndex(), GetAlignment());
  1408.  
  1409. LogManager::instance().CharLog(this, 0, "LOGOUT", buf);
  1410.  
  1411. if (m_pWarMap)
  1412. SetWarMap(NULL);
  1413.  
  1414. if (m_pWeddingMap)
  1415. {
  1416. SetWeddingMap(NULL);
  1417. }
  1418.  
  1419. if (GetGuild())
  1420. GetGuild()->LogoutMember(this);
  1421.  
  1422. quest::CQuestManager::instance().LogoutPC(this);
  1423.  
  1424. if (GetParty())
  1425. GetParty()->Unlink(this);
  1426.  
  1427. if (IsStun() || IsDead())
  1428. {
  1429. DeathPenalty(0);
  1430. PointChange(POINT_HP, 50 - GetHP());
  1431. }
  1432.  
  1433. if (!CHARACTER_MANAGER::instance().FlushDelayedSave(this))
  1434. {
  1435. SaveReal();
  1436. }
  1437.  
  1438. FlushDelayedSaveItem();
  1439.  
  1440. DestroyPvP();
  1441.  
  1442. SaveAffect();
  1443. m_bIsLoadedAffect = false;
  1444.  
  1445. m_bSkipSave = true;
  1446.  
  1447. quest::CQuestManager::instance().DisconnectPC(this);
  1448.  
  1449. CloseSafebox();
  1450.  
  1451. CloseMall();
  1452.  
  1453. CPVPManager::instance().Disconnect(this);
  1454.  
  1455. CTargetManager::instance().Logout(GetPlayerID());
  1456.  
  1457. MessengerManager::instance().Logout(GetName());
  1458.  
  1459. packet_point_change pack;
  1460. pack.header = HEADER_GC_CHARACTER_POINT_CHANGE;
  1461. pack.dwVID = m_vid;
  1462. pack.type = POINT_PLAYTIME;
  1463. pack.value = GetRealPoint(POINT_PLAYTIME) + (get_dword_time() - m_dwPlayStartTime) / 60000;
  1464. pack.amount = 0;
  1465.  
  1466. GetDesc()->Packet(&pack, sizeof(struct packet_point_change));
  1467.  
  1468. #ifdef __OX_RESTRICTION_IP__
  1469. if (GetMapIndex() == OXEVENT_MAP_INDEX)
  1470. COXEventManager::instance().RemoveFromIpList(GetDesc()->GetHostName());
  1471. #endif
  1472.  
  1473. if (GetDesc())
  1474. {
  1475. GetDesc()->BindCharacter(NULL);
  1476. }
  1477.  
  1478. M2_DESTROY_CHARACTER(this);
  1479. }
  1480.  
  1481. bool CHARACTER::Show(long lMapIndex, long x, long y, long z, bool bShowSpawnMotion, bool bAggressive)
  1482. {
  1483. LPSECTREE sectree = SECTREE_MANAGER::instance().Get(lMapIndex, x, y);
  1484.  
  1485. if (!sectree)
  1486. {
  1487. sys_log(0, "cannot find sectree by %dx%d mapindex %d", x, y, lMapIndex);
  1488. return false;
  1489. }
  1490.  
  1491. SetMapIndex(lMapIndex);
  1492.  
  1493. bool bChangeTree = false;
  1494.  
  1495. if (!GetSectree() || GetSectree() != sectree)
  1496. bChangeTree = true;
  1497.  
  1498. if (bChangeTree)
  1499. {
  1500. if (GetSectree())
  1501. GetSectree()->RemoveEntity(this);
  1502.  
  1503. ViewCleanup();
  1504. }
  1505.  
  1506. if (!IsNPC())
  1507. {
  1508. sys_log(0, "SHOW: %s %dx%dx%d", GetName(), x, y, z);
  1509.  
  1510. if (GetStamina() < GetMaxStamina())
  1511. StartAffectEvent();
  1512. }
  1513.  
  1514. else if (m_pkMobData)
  1515. {
  1516. m_pkMobInst->m_posLastAttacked.x = x;
  1517. m_pkMobInst->m_posLastAttacked.y = y;
  1518. m_pkMobInst->m_posLastAttacked.z = z;
  1519. }
  1520.  
  1521. if (bShowSpawnMotion)
  1522. {
  1523. SET_BIT(m_bAddChrState, ADD_CHARACTER_STATE_SPAWN);
  1524. m_afAffectFlag.Set(AFF_SPAWN);
  1525. }
  1526.  
  1527. if (bAggressive)
  1528. SetAggressive();
  1529.  
  1530. SetXYZ(x, y, z);
  1531.  
  1532. m_posDest.x = x;
  1533. m_posDest.y = y;
  1534. m_posDest.z = z;
  1535.  
  1536. m_posStart.x = x;
  1537. m_posStart.y = y;
  1538. m_posStart.z = z;
  1539.  
  1540. if (bChangeTree)
  1541. {
  1542. EncodeInsertPacket(this);
  1543. sectree->InsertEntity(this);
  1544.  
  1545. UpdateSectree();
  1546. }
  1547.  
  1548. else
  1549. {
  1550. ViewReencode();
  1551. sys_log(0, " in same sectree");
  1552. }
  1553.  
  1554. REMOVE_BIT(m_bAddChrState, ADD_CHARACTER_STATE_SPAWN);
  1555.  
  1556. SetValidComboInterval(0);
  1557.  
  1558. return true;
  1559. }
  1560.  
  1561. struct BGMInfo
  1562. {
  1563. std::string name;
  1564. float vol;
  1565. };
  1566.  
  1567. typedef std::map<unsigned, BGMInfo> BGMInfoMap;
  1568.  
  1569. static BGMInfoMap gs_bgmInfoMap;
  1570. static bool gs_bgmVolEnable = false;
  1571.  
  1572. void CHARACTER_SetBGMVolumeEnable()
  1573. {
  1574. gs_bgmVolEnable = true;
  1575.  
  1576. sys_log(0, "bgm_info.set_bgm_volume_enable");
  1577. }
  1578.  
  1579. void CHARACTER_AddBGMInfo(unsigned mapIndex, const char* name, float vol)
  1580. {
  1581. BGMInfo newInfo;
  1582. newInfo.name = name;
  1583. newInfo.vol = vol;
  1584.  
  1585. gs_bgmInfoMap[mapIndex] = newInfo;
  1586.  
  1587. sys_log(0, "bgm_info.add_info(%d, '%s', %f)", mapIndex, name, vol);
  1588. }
  1589.  
  1590. const BGMInfo& CHARACTER_GetBGMInfo(unsigned mapIndex)
  1591. {
  1592. BGMInfoMap::iterator f = gs_bgmInfoMap.find(mapIndex);
  1593. if (gs_bgmInfoMap.end() == f)
  1594. {
  1595. static BGMInfo s_empty = {"", 0.0f};
  1596.  
  1597. return s_empty;
  1598. }
  1599.  
  1600. return f->second;
  1601. }
  1602.  
  1603. bool CHARACTER_IsBGMVolumeEnable()
  1604. {
  1605. return gs_bgmVolEnable;
  1606. }
  1607.  
  1608. void CHARACTER::MainCharacterPacket()
  1609. {
  1610. const unsigned mapIndex = GetMapIndex();
  1611. const BGMInfo& bgmInfo = CHARACTER_GetBGMInfo(mapIndex);
  1612.  
  1613. if (!bgmInfo.name.empty())
  1614. {
  1615. if (CHARACTER_IsBGMVolumeEnable())
  1616. {
  1617. sys_log(1, "bgm_info.play_bgm_vol(%d, name='%s', vol=%f)", mapIndex, bgmInfo.name.c_str(), bgmInfo.vol);
  1618. TPacketGCMainCharacter4_BGM_VOL mainChrPacket;
  1619.  
  1620. mainChrPacket.header = HEADER_GC_MAIN_CHARACTER4_BGM_VOL;
  1621. mainChrPacket.dwVID = m_vid;
  1622. mainChrPacket.wRaceNum = GetRaceNum();
  1623. mainChrPacket.lx = GetX();
  1624. mainChrPacket.ly = GetY();
  1625. mainChrPacket.lz = GetZ();
  1626. mainChrPacket.empire = GetDesc()->GetEmpire();
  1627. mainChrPacket.skill_group = GetSkillGroup();
  1628.  
  1629. strlcpy(mainChrPacket.szChrName, GetName(), sizeof(mainChrPacket.szChrName));
  1630.  
  1631. mainChrPacket.fBGMVol = bgmInfo.vol;
  1632. strlcpy(mainChrPacket.szBGMName, bgmInfo.name.c_str(), sizeof(mainChrPacket.szBGMName));
  1633. GetDesc()->Packet(&mainChrPacket, sizeof(TPacketGCMainCharacter4_BGM_VOL));
  1634. }
  1635.  
  1636. else
  1637. {
  1638. sys_log(1, "bgm_info.play(%d, '%s')", mapIndex, bgmInfo.name.c_str());
  1639. TPacketGCMainCharacter3_BGM mainChrPacket;
  1640.  
  1641. mainChrPacket.header = HEADER_GC_MAIN_CHARACTER3_BGM;
  1642. mainChrPacket.dwVID = m_vid;
  1643. mainChrPacket.wRaceNum = GetRaceNum();
  1644. mainChrPacket.lx = GetX();
  1645. mainChrPacket.ly = GetY();
  1646. mainChrPacket.lz = GetZ();
  1647. mainChrPacket.empire = GetDesc()->GetEmpire();
  1648. mainChrPacket.skill_group = GetSkillGroup();
  1649.  
  1650. strlcpy(mainChrPacket.szChrName, GetName(), sizeof(mainChrPacket.szChrName));
  1651. strlcpy(mainChrPacket.szBGMName, bgmInfo.name.c_str(), sizeof(mainChrPacket.szBGMName));
  1652.  
  1653. GetDesc()->Packet(&mainChrPacket, sizeof(TPacketGCMainCharacter3_BGM));
  1654. }
  1655. }
  1656.  
  1657. else
  1658. {
  1659. sys_log(0, "bgm_info.play(%d, DEFAULT_BGM_NAME)", mapIndex);
  1660.  
  1661. TPacketGCMainCharacter2_EMPIRE pack;
  1662.  
  1663. pack.header = HEADER_GC_MAIN_CHARACTER2_EMPIRE;
  1664. pack.dwVID = m_vid;
  1665. pack.wRaceNum = GetRaceNum();
  1666. pack.lx = GetX();
  1667. pack.ly = GetY();
  1668. pack.lz = GetZ();
  1669. pack.empire = GetDesc()->GetEmpire();
  1670. pack.skill_group = GetSkillGroup();
  1671.  
  1672. strlcpy(pack.szName, GetName(), sizeof(pack.szName));
  1673. GetDesc()->Packet(&pack, sizeof(TPacketGCMainCharacter2_EMPIRE));
  1674. }
  1675. }
  1676.  
  1677. void CHARACTER::PointsPacket()
  1678. {
  1679. if (!GetDesc())
  1680. return;
  1681.  
  1682. TPacketGCPoints pack;
  1683.  
  1684. pack.header = HEADER_GC_CHARACTER_POINTS;
  1685.  
  1686. pack.points[POINT_LEVEL] = GetLevel();
  1687. pack.points[POINT_EXP] = GetExp();
  1688. pack.points[POINT_NEXT_EXP] = GetNextExp();
  1689. pack.points[POINT_HP] = GetHP();
  1690. pack.points[POINT_MAX_HP] = GetMaxHP();
  1691. pack.points[POINT_SP] = GetSP();
  1692. pack.points[POINT_MAX_SP] = GetMaxSP();
  1693. pack.points[POINT_GOLD] = GetGold();
  1694. pack.points[POINT_STAMINA] = GetStamina();
  1695. pack.points[POINT_MAX_STAMINA] = GetMaxStamina();
  1696.  
  1697. for (int i = POINT_ST; i < POINT_MAX_NUM; ++i)
  1698. pack.points[i] = GetPoint(i);
  1699.  
  1700. #ifdef __TITLE_SYSTEM__
  1701. for (int w = TITLE_0; w < TITLES_MAX_NUM; ++w)
  1702. {
  1703. BYTE bType = POINT_TITLE + w;
  1704. pack.points[bType] = GetPoint(bType);
  1705. }
  1706. #endif
  1707.  
  1708. GetDesc()->Packet(&pack, sizeof(TPacketGCPoints));
  1709. }
  1710.  
  1711. bool CHARACTER::ChangeSex()
  1712. {
  1713. int src_race = GetRaceNum();
  1714.  
  1715. switch (src_race)
  1716. {
  1717. case MAIN_RACE_WARRIOR_M:
  1718. m_points.job = MAIN_RACE_WARRIOR_W;
  1719. break;
  1720.  
  1721. case MAIN_RACE_WARRIOR_W:
  1722. m_points.job = MAIN_RACE_WARRIOR_M;
  1723. break;
  1724.  
  1725. case MAIN_RACE_ASSASSIN_M:
  1726. m_points.job = MAIN_RACE_ASSASSIN_W;
  1727. break;
  1728.  
  1729. case MAIN_RACE_ASSASSIN_W:
  1730. m_points.job = MAIN_RACE_ASSASSIN_M;
  1731. break;
  1732.  
  1733. case MAIN_RACE_SURA_M:
  1734. m_points.job = MAIN_RACE_SURA_W;
  1735. break;
  1736.  
  1737. case MAIN_RACE_SURA_W:
  1738. m_points.job = MAIN_RACE_SURA_M;
  1739. break;
  1740.  
  1741. case MAIN_RACE_SHAMAN_M:
  1742. m_points.job = MAIN_RACE_SHAMAN_W;
  1743. break;
  1744.  
  1745. case MAIN_RACE_SHAMAN_W:
  1746. m_points.job = MAIN_RACE_SHAMAN_M;
  1747. break;
  1748.  
  1749. default:
  1750. sys_err("CHANGE_SEX: %s unknown race %d", GetName(), src_race);
  1751. return false;
  1752. }
  1753.  
  1754. sys_log(0, "CHANGE_SEX: %s (%d -> %d)", GetName(), src_race, m_points.job);
  1755.  
  1756. return true;
  1757. }
  1758.  
  1759. WORD CHARACTER::GetRaceNum() const
  1760. {
  1761. if (m_dwPolymorphRace)
  1762. return m_dwPolymorphRace;
  1763.  
  1764. if (m_pkMobData)
  1765. return m_pkMobData->m_table.dwVnum;
  1766.  
  1767. return m_points.job;
  1768. }
  1769.  
  1770. void CHARACTER::SetRace(BYTE race)
  1771. {
  1772. if (race >= MAIN_RACE_MAX_NUM)
  1773. {
  1774. sys_err("CHARACTER::SetRace(name=%s, race=%d).OUT_OF_RACE_RANGE", GetName(), race);
  1775. return;
  1776. }
  1777.  
  1778. m_points.job = race;
  1779. }
  1780.  
  1781. BYTE CHARACTER::GetJob() const
  1782. {
  1783. unsigned race = m_points.job;
  1784. unsigned job;
  1785.  
  1786. if (RaceToJob(race, &job))
  1787. return job;
  1788.  
  1789. sys_err("CHARACTER::GetJob(name=%s, race=%d).OUT_OF_RACE_RANGE", GetName(), race);
  1790.  
  1791. return JOB_WARRIOR;
  1792. }
  1793.  
  1794. void CHARACTER::SetLevel(BYTE level)
  1795. {
  1796. m_points.level = level;
  1797.  
  1798. if (IsPC())
  1799. {
  1800. if (level < PK_PROTECT_LEVEL)
  1801. SetPKMode(PK_MODE_PROTECT);
  1802.  
  1803. else if (GetGMLevel() != GM_PLAYER)
  1804. SetPKMode(PK_MODE_PROTECT);
  1805.  
  1806. else if (m_bPKMode == PK_MODE_PROTECT)
  1807. SetPKMode(PK_MODE_PEACE);
  1808. }
  1809. }
  1810.  
  1811. void CHARACTER::SetEmpire(BYTE bEmpire)
  1812. {
  1813. m_bEmpire = bEmpire;
  1814. }
  1815.  
  1816. #ifdef ENABLE_VIP_SYSTEM
  1817. bool CHARACTER::VipSystemTime()
  1818. {
  1819. time_t t1 = time(0);
  1820.  
  1821. std::auto_ptr<SQLMsg> Premiums(DBManager::instance().DirectQuery("SELECT TIMP,FARA_TIMP FROM player.vip_system WHERE PID_VIP = %u", GetPlayerID()));
  1822.  
  1823. MYSQL_ROW row = mysql_fetch_row(Premiums->Get()->pSQLResult);
  1824.  
  1825. long int time = atoi(row[0]);
  1826. int no_time = atoi(row[1]);
  1827.  
  1828. if (no_time != 1)
  1829. {
  1830. if (t1 >= time)
  1831. {
  1832. DBManager::instance().DirectQuery("DELETE FROM player.vip_system WHERE PID_VIP = %u", GetPlayerID());
  1833.  
  1834. return 0;
  1835. }
  1836. }
  1837. }
  1838.  
  1839. void CHARACTER::VipSystem()
  1840. {
  1841. std::auto_ptr<SQLMsg> pmsg(DBManager::instance().DirectQuery("SELECT COUNT(*) FROM player.vip_system WHERE PID_VIP = %u", GetPlayerID()));
  1842. MYSQL_ROW row = mysql_fetch_row(pmsg->Get()->pSQLResult);
  1843.  
  1844. BYTE exista = 0;
  1845. str_to_number(exista, row[0]);
  1846.  
  1847. if (exista)
  1848. {
  1849. if (VipSystemTime())
  1850. {
  1851. m_afAffectFlag.Set(AFF_VIP);
  1852. }
  1853. }
  1854. }
  1855.  
  1856. #endif
  1857.  
  1858. #ifdef ENABLE_PREMIUM_SYSTEM
  1859. bool CHARACTER::PremiumSystemTime()
  1860. {
  1861. time_t t1 = time(0);
  1862.  
  1863. std::auto_ptr<SQLMsg> Premiums(DBManager::instance().DirectQuery("SELECT TIMP,FARA_TIMP FROM player.premium_system WHERE PID_PREMIUM = %u", GetPlayerID()));
  1864.  
  1865. MYSQL_ROW row = mysql_fetch_row(Premiums->Get()->pSQLResult);
  1866.  
  1867. long int time = atoi(row[0]);
  1868. int no_time = atoi(row[1]);
  1869.  
  1870. if (no_time != 1)
  1871. {
  1872. if (t1 >= time)
  1873. {
  1874. DBManager::instance().DirectQuery("DELETE FROM player.premium_system WHERE PID_PREMIUM = %u", GetPlayerID());
  1875.  
  1876. return 0;
  1877. }
  1878. }
  1879. }
  1880.  
  1881. void CHARACTER::PremiumSystem()
  1882. {
  1883. std::auto_ptr<SQLMsg> pmsg(DBManager::instance().DirectQuery("SELECT COUNT(*) FROM player.premium_system WHERE PID_PREMIUM = %u", GetPlayerID()));
  1884. MYSQL_ROW row = mysql_fetch_row(pmsg->Get()->pSQLResult);
  1885.  
  1886. BYTE exista = 0;
  1887. str_to_number(exista, row[0]);
  1888.  
  1889. if (exista)
  1890. {
  1891. if (PremiumSystemTime())
  1892. {
  1893. m_afAffectFlag.Set(AFF_PREMIUM);
  1894. }
  1895. }
  1896. }
  1897. #endif
  1898.  
  1899. void CHARACTER::SetPlayerProto(const TPlayerTable * t)
  1900. {
  1901. if (!GetDesc() || !*GetDesc()->GetHostName())
  1902. sys_err("cannot get desc or hostname");
  1903. else
  1904. SetGMLevel();
  1905.  
  1906. m_bCharType = CHAR_TYPE_PC;
  1907.  
  1908. m_dwPlayerID = t->id;
  1909.  
  1910. #ifdef __CUSTOM_TITLE_SYSTEM__
  1911. m_stTitle = t->title.szName;
  1912. memcpy(m_bTitleColor, t->title.bColours, sizeof(m_bTitleColor));
  1913.  
  1914. m_stTitle2 = t->title2.szName;
  1915. memcpy(m_bTitle2Color, t->title2.bColours2, sizeof(m_bTitle2Color));
  1916. #endif
  1917.  
  1918. m_iAlignment = t->lAlignment;
  1919. m_iRealAlignment = t->lAlignment;
  1920.  
  1921. m_points.voice = t->voice;
  1922.  
  1923. m_points.skill_group = t->skill_group;
  1924.  
  1925. m_pointsInstant.bBasePart = t->part_base;
  1926. SetPart(PART_HAIR, t->parts[PART_HAIR]);
  1927.  
  1928. m_points.iRandomHP = t->sRandomHP;
  1929. m_points.iRandomSP = t->sRandomSP;
  1930.  
  1931. if (m_pSkillLevels)
  1932. M2_DELETE_ARRAY(m_pSkillLevels);
  1933.  
  1934. m_pSkillLevels = M2_NEW TPlayerSkill[SKILL_MAX_NUM];
  1935. thecore_memcpy(m_pSkillLevels, t->skills, sizeof(TPlayerSkill) * SKILL_MAX_NUM);
  1936.  
  1937. if (t->lMapIndex >= 10000)
  1938. {
  1939. m_posWarp.x = t->lExitX;
  1940. m_posWarp.y = t->lExitY;
  1941. m_lWarpMapIndex = t->lExitMapIndex;
  1942. }
  1943.  
  1944. SetRealPoint(POINT_PLAYTIME, t->playtime);
  1945. m_dwLoginPlayTime = t->playtime;
  1946. SetRealPoint(POINT_ST, t->st);
  1947. SetRealPoint(POINT_HT, t->ht);
  1948. SetRealPoint(POINT_DX, t->dx);
  1949. SetRealPoint(POINT_IQ, t->iq);
  1950.  
  1951. SetPoint(POINT_ST, t->st);
  1952. SetPoint(POINT_HT, t->ht);
  1953. SetPoint(POINT_DX, t->dx);
  1954. SetPoint(POINT_IQ, t->iq);
  1955.  
  1956. SetPoint(POINT_STAT, t->stat_point);
  1957. SetPoint(POINT_SKILL, t->skill_point);
  1958. SetPoint(POINT_SUB_SKILL, t->sub_skill_point);
  1959. SetPoint(POINT_HORSE_SKILL, t->horse_skill_point);
  1960.  
  1961. SetPoint(POINT_STAT_RESET_COUNT, t->stat_reset_count);
  1962.  
  1963. SetPoint(POINT_LEVEL_STEP, t->level_step);
  1964. SetRealPoint(POINT_LEVEL_STEP, t->level_step);
  1965.  
  1966. SetRace(t->job);
  1967.  
  1968. SetLevel(t->level);
  1969. SetExp(t->exp);
  1970. SetGold(t->gold);
  1971.  
  1972. SetMapIndex(t->lMapIndex);
  1973. SetXYZ(t->x, t->y, t->z);
  1974.  
  1975. ComputePoints();
  1976.  
  1977. SetHP(t->hp);
  1978. SetSP(t->sp);
  1979. SetStamina(t->stamina);
  1980.  
  1981. #ifdef ENABLE_VIP_SYSTEM
  1982. VipSystem();
  1983. #endif
  1984.  
  1985. #ifdef ENABLE_PREMIUM_SYSTEM
  1986. PremiumSystem();
  1987. #endif
  1988.  
  1989. if (!test_server)
  1990. {
  1991. if (GetGMLevel() > GM_PLAYER)
  1992. {
  1993. m_afAffectFlag.Set(AFF_YMIR);
  1994. m_bPKMode = PK_MODE_PROTECT;
  1995. }
  1996. }
  1997.  
  1998. if (GetLevel() < PK_PROTECT_LEVEL)
  1999. m_bPKMode = PK_MODE_PROTECT;
  2000.  
  2001. SetHorseData(t->horse);
  2002.  
  2003. if (GetHorseLevel() > 0)
  2004. UpdateHorseDataByLogoff(t->logoff_interval);
  2005.  
  2006. thecore_memcpy(m_aiPremiumTimes, t->aiPremiumTimes, sizeof(t->aiPremiumTimes));
  2007.  
  2008. m_dwLogOffInterval = t->logoff_interval;
  2009.  
  2010. sys_log(0, "PLAYER_LOAD: %s PREMIUM %d %d, LOGGOFF_INTERVAL %u PTR: %p", t->name, m_aiPremiumTimes[0], m_aiPremiumTimes[1], t->logoff_interval, this);
  2011.  
  2012. if (GetGMLevel() != GM_PLAYER)
  2013. {
  2014. LogManager::instance().CharLog(this, GetGMLevel(), "GM_LOGIN", "");
  2015. sys_log(0, "GM_LOGIN(gmlevel=%d, name=%s(%d), pos=(%d, %d)", GetGMLevel(), GetName(), GetPlayerID(), GetX(), GetY());
  2016. }
  2017.  
  2018. #ifdef __PET_SYSTEM__
  2019. if (m_petSystem)
  2020. {
  2021. m_petSystem->Destroy();
  2022. delete m_petSystem;
  2023. }
  2024.  
  2025. m_petSystem = M2_NEW CPetSystem(this);
  2026. #endif
  2027.  
  2028. }
  2029.  
  2030. EVENTFUNC(kill_ore_load_event)
  2031. {
  2032. char_event_info* info = dynamic_cast<char_event_info*>( event->info );
  2033. if ( info == NULL )
  2034. {
  2035. sys_err( "kill_ore_load_even> <Factor> Null pointer" );
  2036. return 0;
  2037. }
  2038.  
  2039. LPCHARACTER ch = info->ch;
  2040. if (ch == NULL)
  2041. {
  2042. return 0;
  2043. }
  2044.  
  2045. ch->m_pkMiningEvent = NULL;
  2046. M2_DESTROY_CHARACTER(ch);
  2047.  
  2048. return 0;
  2049. }
  2050.  
  2051. void CHARACTER::SetProto(const CMob * pkMob)
  2052. {
  2053. if (m_pkMobInst)
  2054. M2_DELETE(m_pkMobInst);
  2055.  
  2056. m_pkMobData = pkMob;
  2057. m_pkMobInst = M2_NEW CMobInstance;
  2058.  
  2059. m_bPKMode = PK_MODE_FREE;
  2060.  
  2061. const TMobTable * t = &m_pkMobData->m_table;
  2062.  
  2063. m_bCharType = t->bType;
  2064.  
  2065. SetLevel(t->bLevel);
  2066. SetEmpire(t->bEmpire);
  2067.  
  2068. SetExp(t->dwExp);
  2069. SetRealPoint(POINT_ST, t->bStr);
  2070. SetRealPoint(POINT_DX, t->bDex);
  2071. SetRealPoint(POINT_HT, t->bCon);
  2072. SetRealPoint(POINT_IQ, t->bInt);
  2073.  
  2074. ComputePoints();
  2075.  
  2076. SetHP(GetMaxHP());
  2077. SetSP(GetMaxSP());
  2078.  
  2079. ////////////////////
  2080. m_pointsInstant.dwAIFlag = t->dwAIFlag;
  2081. SetImmuneFlag(t->dwImmuneFlag);
  2082.  
  2083. AssignTriggers(t);
  2084.  
  2085. ApplyMobAttribute(t);
  2086.  
  2087. if (IsStone())
  2088. {
  2089. DetermineDropMetinStone();
  2090. }
  2091.  
  2092. if (IsWarp() || IsGoto())
  2093. {
  2094. StartWarpNPCEvent();
  2095. }
  2096.  
  2097. CHARACTER_MANAGER::instance().RegisterRaceNumMap(this);
  2098.  
  2099. if (GetRaceNum() == xmas::MOB_SANTA_VNUM)
  2100. {
  2101. SetPoint(POINT_ATT_GRADE_BONUS, 10);
  2102. SetPoint(POINT_DEF_GRADE_BONUS, 6);
  2103.  
  2104. m_dwPlayStartTime = get_dword_time() + 30 * 1000;
  2105.  
  2106. if (test_server)
  2107. m_dwPlayStartTime = get_dword_time() + 30 * 1000;
  2108. }
  2109.  
  2110.  
  2111. if (warmap::IsWarFlag(GetRaceNum()))
  2112. {
  2113. m_stateIdle.Set(this, &CHARACTER::BeginStateEmpty, &CHARACTER::StateFlag, &CHARACTER::EndStateEmpty);
  2114. m_stateMove.Set(this, &CHARACTER::BeginStateEmpty, &CHARACTER::StateFlag, &CHARACTER::EndStateEmpty);
  2115. m_stateBattle.Set(this, &CHARACTER::BeginStateEmpty, &CHARACTER::StateFlag, &CHARACTER::EndStateEmpty);
  2116. }
  2117.  
  2118. if (warmap::IsWarFlagBase(GetRaceNum()))
  2119. {
  2120. m_stateIdle.Set(this, &CHARACTER::BeginStateEmpty, &CHARACTER::StateFlagBase, &CHARACTER::EndStateEmpty);
  2121. m_stateMove.Set(this, &CHARACTER::BeginStateEmpty, &CHARACTER::StateFlagBase, &CHARACTER::EndStateEmpty);
  2122. m_stateBattle.Set(this, &CHARACTER::BeginStateEmpty, &CHARACTER::StateFlagBase, &CHARACTER::EndStateEmpty);
  2123. }
  2124.  
  2125. if (m_bCharType == CHAR_TYPE_HORSE || GetRaceNum() == 20101 || GetRaceNum() == 20102 || GetRaceNum() == 20103 || GetRaceNum() == 20104 || GetRaceNum() == 20105 || GetRaceNum() == 20106 || GetRaceNum() == 20107 || GetRaceNum() == 20108 || GetRaceNum() == 20109 )
  2126. {
  2127. m_stateIdle.Set(this, &CHARACTER::BeginStateEmpty, &CHARACTER::StateHorse, &CHARACTER::EndStateEmpty);
  2128. m_stateMove.Set(this, &CHARACTER::BeginStateEmpty, &CHARACTER::StateMove, &CHARACTER::EndStateEmpty);
  2129. m_stateBattle.Set(this, &CHARACTER::BeginStateEmpty, &CHARACTER::StateHorse, &CHARACTER::EndStateEmpty);
  2130. }
  2131.  
  2132. if (mining::IsVeinOfOre (GetRaceNum()))
  2133. {
  2134. char_event_info* info = AllocEventInfo<char_event_info>();
  2135.  
  2136. info->ch = this;
  2137.  
  2138. m_pkMiningEvent = event_create(kill_ore_load_event, info, PASSES_PER_SEC(number(7 * 60, 15 * 60)));
  2139. }
  2140. }
  2141.  
  2142. const TMobTable & CHARACTER::GetMobTable() const
  2143. {
  2144. return m_pkMobData->m_table;
  2145. }
  2146.  
  2147. bool CHARACTER::IsRaceFlag(DWORD dwBit) const
  2148. {
  2149. return m_pkMobData ? IS_SET(m_pkMobData->m_table.dwRaceFlag, dwBit) : 0;
  2150. }
  2151.  
  2152. DWORD CHARACTER::GetMobDamageMin() const
  2153. {
  2154. return m_pkMobData->m_table.dwDamageRange[0];
  2155. }
  2156.  
  2157. DWORD CHARACTER::GetMobDamageMax() const
  2158. {
  2159. return m_pkMobData->m_table.dwDamageRange[1];
  2160. }
  2161.  
  2162. float CHARACTER::GetMobDamageMultiply() const
  2163. {
  2164. float fDamMultiply = GetMobTable().fDamMultiply;
  2165.  
  2166. if (IsBerserk())
  2167. fDamMultiply = fDamMultiply * 2.0f;
  2168.  
  2169. return fDamMultiply;
  2170. }
  2171.  
  2172. DWORD CHARACTER::GetMobDropItemVnum() const
  2173. {
  2174. return m_pkMobData->m_table.dwDropItemVnum;
  2175. }
  2176.  
  2177. bool CHARACTER::IsSummonMonster() const
  2178. {
  2179. return GetSummonVnum() != 0;
  2180. }
  2181.  
  2182. DWORD CHARACTER::GetSummonVnum() const
  2183. {
  2184. return m_pkMobData ? m_pkMobData->m_table.dwSummonVnum : 0;
  2185. }
  2186.  
  2187. DWORD CHARACTER::GetPolymorphItemVnum() const
  2188. {
  2189. return m_pkMobData ? m_pkMobData->m_table.dwPolymorphItemVnum : 0;
  2190. }
  2191.  
  2192. DWORD CHARACTER::GetMonsterDrainSPPoint() const
  2193. {
  2194. return m_pkMobData ? m_pkMobData->m_table.dwDrainSP : 0;
  2195. }
  2196.  
  2197. BYTE CHARACTER::GetMobRank() const
  2198. {
  2199. if (!m_pkMobData)
  2200. return MOB_RANK_KNIGHT;
  2201.  
  2202. return m_pkMobData->m_table.bRank;
  2203. }
  2204.  
  2205. BYTE CHARACTER::GetMobSize() const
  2206. {
  2207. if (!m_pkMobData)
  2208. return MOBSIZE_MEDIUM;
  2209.  
  2210. return m_pkMobData->m_table.bSize;
  2211. }
  2212.  
  2213. WORD CHARACTER::GetMobAttackRange() const
  2214. {
  2215. switch (GetMobBattleType())
  2216. {
  2217. case BATTLE_TYPE_RANGE:
  2218. case BATTLE_TYPE_MAGIC:
  2219. return m_pkMobData->m_table.wAttackRange + GetPoint(POINT_BOW_DISTANCE);
  2220.  
  2221. default:
  2222. return m_pkMobData->m_table.wAttackRange;
  2223. }
  2224. }
  2225.  
  2226. BYTE CHARACTER::GetMobBattleType() const
  2227. {
  2228. if (!m_pkMobData)
  2229. return BATTLE_TYPE_MELEE;
  2230.  
  2231. return (m_pkMobData->m_table.bBattleType);
  2232. }
  2233.  
  2234. void CHARACTER::ComputeBattlePoints()
  2235. {
  2236. if (IsPolymorphed())
  2237. {
  2238. DWORD dwMobVnum = GetPolymorphVnum();
  2239.  
  2240. const CMob * pMob = CMobManager::instance().Get(dwMobVnum);
  2241. int iAtt = 0;
  2242. int iDef = 0;
  2243.  
  2244. if (pMob)
  2245. {
  2246. iAtt = GetLevel() * 2 + GetPolymorphPoint(POINT_ST) * 2;
  2247. iDef = GetLevel() + GetPolymorphPoint(POINT_HT) + pMob->m_table.wDef;
  2248. }
  2249.  
  2250. SetPoint(POINT_ATT_GRADE, iAtt);
  2251. SetPoint(POINT_DEF_GRADE, iDef);
  2252. SetPoint(POINT_MAGIC_ATT_GRADE, GetPoint(POINT_ATT_GRADE));
  2253. SetPoint(POINT_MAGIC_DEF_GRADE, GetPoint(POINT_DEF_GRADE));
  2254. }
  2255.  
  2256. else if (IsPC())
  2257. {
  2258. SetPoint(POINT_ATT_GRADE, 0);
  2259. SetPoint(POINT_DEF_GRADE, 0);
  2260. SetPoint(POINT_CLIENT_DEF_GRADE, 0);
  2261. SetPoint(POINT_MAGIC_ATT_GRADE, GetPoint(POINT_ATT_GRADE));
  2262. SetPoint(POINT_MAGIC_DEF_GRADE, GetPoint(POINT_DEF_GRADE));
  2263.  
  2264. int iAtk = GetLevel() * 2;
  2265. int iStatAtk = 0;
  2266.  
  2267. switch (GetJob())
  2268. {
  2269. case JOB_WARRIOR:
  2270. case JOB_SURA:
  2271. iStatAtk = (2 * GetPoint(POINT_ST));
  2272. break;
  2273.  
  2274. case JOB_ASSASSIN:
  2275. iStatAtk = (4 * GetPoint(POINT_ST) + 2 * GetPoint(POINT_DX)) / 3;
  2276. break;
  2277.  
  2278. case JOB_SHAMAN:
  2279. iStatAtk = (4 * GetPoint(POINT_ST) + 2 * GetPoint(POINT_IQ)) / 3;
  2280. break;
  2281.  
  2282. default:
  2283. sys_err("invalid job %d", GetJob());
  2284. iStatAtk = (2 * GetPoint(POINT_ST));
  2285. break;
  2286. }
  2287.  
  2288. if (GetMountVnum() && iStatAtk < 2 * GetPoint(POINT_ST))
  2289. iStatAtk = (2 * GetPoint(POINT_ST));
  2290.  
  2291. iAtk += iStatAtk;
  2292.  
  2293. if (GetMountVnum())
  2294. {
  2295. if (GetJob() == JOB_SURA && GetSkillGroup() == 1)
  2296. {
  2297. iAtk += (iAtk * GetHorseLevel()) / 60;
  2298. }
  2299.  
  2300. else
  2301. {
  2302. iAtk += (iAtk * GetHorseLevel()) / 30;
  2303. }
  2304. }
  2305.  
  2306. iAtk += GetPoint(POINT_ATT_GRADE_BONUS);
  2307.  
  2308. PointChange(POINT_ATT_GRADE, iAtk);
  2309.  
  2310. int iShowDef = GetLevel() + GetPoint(POINT_HT);
  2311. int iDef = GetLevel() + (int) (GetPoint(POINT_HT) / 1.25);
  2312. int iArmor = 0;
  2313.  
  2314. LPITEM pkItem;
  2315.  
  2316. for (int i = 0; i < WEAR_MAX_NUM; ++i)
  2317. if ((pkItem = GetWear(i)) && pkItem->GetType() == ITEM_ARMOR)
  2318. {
  2319. if (pkItem->GetSubType() == ARMOR_BODY || pkItem->GetSubType() == ARMOR_HEAD || pkItem->GetSubType() == ARMOR_FOOTS || pkItem->GetSubType() == ARMOR_SHIELD)
  2320. {
  2321. iArmor += pkItem->GetValue(1);
  2322. iArmor += (2 * pkItem->GetValue(5));
  2323. }
  2324. }
  2325.  
  2326. if( true == IsHorseRiding() )
  2327. {
  2328. if (iArmor < GetHorseArmor())
  2329. iArmor = GetHorseArmor();
  2330.  
  2331. const char* pHorseName = CHorseNameManager::instance().GetHorseName(GetPlayerID());
  2332.  
  2333. if (pHorseName != NULL && strlen(pHorseName))
  2334. {
  2335. iArmor += 20;
  2336. }
  2337. }
  2338.  
  2339. iArmor += GetPoint(POINT_DEF_GRADE_BONUS);
  2340. iArmor += GetPoint(POINT_PARTY_DEFENDER_BONUS);
  2341.  
  2342. PointChange(POINT_DEF_GRADE, iDef + iArmor);
  2343. PointChange(POINT_CLIENT_DEF_GRADE, (iShowDef + iArmor) - GetPoint(POINT_DEF_GRADE));
  2344.  
  2345. PointChange(POINT_MAGIC_ATT_GRADE, GetLevel() * 2 + GetPoint(POINT_IQ) * 2 + GetPoint(POINT_MAGIC_ATT_GRADE_BONUS));
  2346. PointChange(POINT_MAGIC_DEF_GRADE, GetLevel() + (GetPoint(POINT_IQ) * 3 + GetPoint(POINT_HT)) / 3 + iArmor / 2 + GetPoint(POINT_MAGIC_DEF_GRADE_BONUS));
  2347. }
  2348.  
  2349. else
  2350. {
  2351. int iAtt = GetLevel() * 2 + GetPoint(POINT_ST) * 2;
  2352. int iDef = GetLevel() + GetPoint(POINT_HT) + GetMobTable().wDef;
  2353.  
  2354. SetPoint(POINT_ATT_GRADE, iAtt);
  2355. SetPoint(POINT_DEF_GRADE, iDef);
  2356. SetPoint(POINT_MAGIC_ATT_GRADE, GetPoint(POINT_ATT_GRADE));
  2357. SetPoint(POINT_MAGIC_DEF_GRADE, GetPoint(POINT_DEF_GRADE));
  2358. }
  2359. }
  2360.  
  2361. void CHARACTER::ComputePoints()
  2362. {
  2363. long lStat = GetPoint(POINT_STAT);
  2364. long lStatResetCount = GetPoint(POINT_STAT_RESET_COUNT);
  2365. long lSkillActive = GetPoint(POINT_SKILL);
  2366. long lSkillSub = GetPoint(POINT_SUB_SKILL);
  2367. long lSkillHorse = GetPoint(POINT_HORSE_SKILL);
  2368. long lLevelStep = GetPoint(POINT_LEVEL_STEP);
  2369.  
  2370. long lAttackerBonus = GetPoint(POINT_PARTY_ATTACKER_BONUS);
  2371. long lTankerBonus = GetPoint(POINT_PARTY_TANKER_BONUS);
  2372. long lBufferBonus = GetPoint(POINT_PARTY_BUFFER_BONUS);
  2373. long lSkillMasterBonus = GetPoint(POINT_PARTY_SKILL_MASTER_BONUS);
  2374. long lHasteBonus = GetPoint(POINT_PARTY_HASTE_BONUS);
  2375. long lDefenderBonus = GetPoint(POINT_PARTY_DEFENDER_BONUS);
  2376.  
  2377. long lHPRecovery = GetPoint(POINT_HP_RECOVERY);
  2378. long lSPRecovery = GetPoint(POINT_SP_RECOVERY);
  2379.  
  2380. #ifdef __TITLE_SYSTEM__
  2381. std::vector<int> vTitles;
  2382. if (IsPC())
  2383. {
  2384. for (int w = TITLE_0; w < TITLES_MAX_NUM; ++w)
  2385. {
  2386. BYTE bType = POINT_TITLE + w;
  2387. vTitles.push_back(GetPoint(bType));
  2388. }
  2389.  
  2390. vTitles.push_back(0);
  2391. }
  2392. #endif
  2393.  
  2394. memset(m_pointsInstant.points, 0, sizeof(m_pointsInstant.points));
  2395. BuffOnAttr_ClearAll();
  2396. m_SkillDamageBonus.clear();
  2397.  
  2398. SetPoint(POINT_STAT, lStat);
  2399. SetPoint(POINT_SKILL, lSkillActive);
  2400. SetPoint(POINT_SUB_SKILL, lSkillSub);
  2401. SetPoint(POINT_HORSE_SKILL, lSkillHorse);
  2402. SetPoint(POINT_LEVEL_STEP, lLevelStep);
  2403. SetPoint(POINT_STAT_RESET_COUNT, lStatResetCount);
  2404.  
  2405. SetPoint(POINT_ST, GetRealPoint(POINT_ST));
  2406. SetPoint(POINT_HT, GetRealPoint(POINT_HT));
  2407. SetPoint(POINT_DX, GetRealPoint(POINT_DX));
  2408. SetPoint(POINT_IQ, GetRealPoint(POINT_IQ));
  2409.  
  2410. SetPart(PART_MAIN, GetOriginalPart(PART_MAIN));
  2411. SetPart(PART_WEAPON, GetOriginalPart(PART_WEAPON));
  2412. SetPart(PART_HEAD, GetOriginalPart(PART_HEAD));
  2413. SetPart(PART_HAIR, GetOriginalPart(PART_HAIR));
  2414.  
  2415. #ifdef __EFFECT_SYSTEM__
  2416. SetPart(BODY_EFFECT, GetOriginalPart(BODY_EFFECT));
  2417. SetPart(WEAPON_RIGHT_EFFECT, GetOriginalPart(WEAPON_RIGHT_EFFECT));
  2418. SetPart(WEAPON_LEFT_EFFECT, GetOriginalPart(WEAPON_LEFT_EFFECT));
  2419. #endif
  2420.  
  2421. SetPoint(POINT_PARTY_ATTACKER_BONUS, lAttackerBonus);
  2422. SetPoint(POINT_PARTY_TANKER_BONUS, lTankerBonus);
  2423. SetPoint(POINT_PARTY_BUFFER_BONUS, lBufferBonus);
  2424. SetPoint(POINT_PARTY_SKILL_MASTER_BONUS, lSkillMasterBonus);
  2425. SetPoint(POINT_PARTY_HASTE_BONUS, lHasteBonus);
  2426. SetPoint(POINT_PARTY_DEFENDER_BONUS, lDefenderBonus);
  2427.  
  2428. SetPoint(POINT_HP_RECOVERY, lHPRecovery);
  2429. SetPoint(POINT_SP_RECOVERY, lSPRecovery);
  2430.  
  2431. #ifdef __TITLE_SYSTEM__
  2432. if (IsPC())
  2433. {
  2434. for (int w = TITLE_0; w < TITLES_MAX_NUM; ++w)
  2435. {
  2436. BYTE bType = POINT_TITLE + w;
  2437. SetPoint(bType, vTitles[w]);
  2438. }
  2439.  
  2440. vTitles.clear();
  2441. }
  2442. #endif
  2443.  
  2444. int iMaxHP, iMaxSP;
  2445. int iMaxStamina;
  2446.  
  2447. if (IsPC())
  2448. {
  2449. iMaxHP = JobInitialPoints[GetJob()].max_hp + m_points.iRandomHP + GetPoint(POINT_HT) * JobInitialPoints[GetJob()].hp_per_ht;
  2450. iMaxSP = JobInitialPoints[GetJob()].max_sp + m_points.iRandomSP + GetPoint(POINT_IQ) * JobInitialPoints[GetJob()].sp_per_iq;
  2451. iMaxStamina = JobInitialPoints[GetJob()].max_stamina + GetPoint(POINT_HT) * JobInitialPoints[GetJob()].stamina_per_con;
  2452.  
  2453. {
  2454. CSkillProto* pkSk = CSkillManager::instance().Get(SKILL_ADD_HP);
  2455.  
  2456. if (NULL != pkSk)
  2457. {
  2458. pkSk->SetPointVar("k", 1.0f * GetSkillPower(SKILL_ADD_HP) / 100.0f);
  2459.  
  2460. iMaxHP += static_cast<int>(pkSk->kPointPoly.Eval());
  2461. }
  2462. }
  2463.  
  2464. if (CPVPManager::instance().IsFightingGerman(GetPlayerID()))
  2465. {
  2466. if (GetJob() == JOB_ASSASSIN)
  2467. SetPoint(POINT_MAX_HP, 150000);
  2468.  
  2469. else if (GetJob() == JOB_SURA)
  2470. SetPoint(POINT_MAX_HP, 150000);
  2471.  
  2472. else if (GetJob() == JOB_SHAMAN)
  2473. SetPoint(POINT_MAX_HP, 150000);
  2474.  
  2475. else
  2476. SetPoint(POINT_MAX_HP, 170000);
  2477.  
  2478. SetPoint(POINT_CRITICAL_PCT, 500);
  2479. SetPoint(POINT_MOV_SPEED, 200);
  2480. SetPoint(POINT_ATT_SPEED, 170);
  2481. SetPoint(POINT_CASTING_SPEED, 160);
  2482. }
  2483.  
  2484. else if (CPVPManager::instance().IsFightingTactic(GetPlayerID()))
  2485. {
  2486. SetPoint(POINT_MAX_HP, 45000);
  2487. SetPoint(POINT_MOV_SPEED, 200);
  2488. SetPoint(POINT_ATT_SPEED, 170);
  2489. SetPoint(POINT_CASTING_SPEED, 160);
  2490. }
  2491.  
  2492. else
  2493. {
  2494. SetPoint(POINT_MOV_SPEED, 140);
  2495. SetPoint(POINT_ATT_SPEED, 130);
  2496. SetPoint(POINT_CASTING_SPEED, 100);
  2497. SetPoint(POINT_PENETRATE_PCT, 25);
  2498. SetPoint(POINT_RESIST_MAGIC, 10);
  2499. SetPoint(POINT_MAX_HP, 15000);
  2500. SetPoint(POINT_MAX_SP, 35000);
  2501. }
  2502. }
  2503.  
  2504. else
  2505. {
  2506. iMaxHP = m_pkMobData->m_table.dwMaxHP;
  2507. iMaxSP = 0;
  2508. iMaxStamina = 0;
  2509.  
  2510. SetPoint(POINT_ATT_SPEED, m_pkMobData->m_table.sAttackSpeed);
  2511. SetPoint(POINT_MOV_SPEED, m_pkMobData->m_table.sMovingSpeed);
  2512. SetPoint(POINT_CASTING_SPEED, m_pkMobData->m_table.sAttackSpeed);
  2513. }
  2514.  
  2515. if (IsPC())
  2516. {
  2517. if (GetMountVnum())
  2518. {
  2519. if (GetHorseST() > GetPoint(POINT_ST))
  2520. PointChange(POINT_ST, GetHorseST() - GetPoint(POINT_ST));
  2521.  
  2522. if (GetHorseDX() > GetPoint(POINT_DX))
  2523. PointChange(POINT_DX, GetHorseDX() - GetPoint(POINT_DX));
  2524.  
  2525. if (GetHorseHT() > GetPoint(POINT_HT))
  2526. PointChange(POINT_HT, GetHorseHT() - GetPoint(POINT_HT));
  2527.  
  2528. if (GetHorseIQ() > GetPoint(POINT_IQ))
  2529. PointChange(POINT_IQ, GetHorseIQ() - GetPoint(POINT_IQ));
  2530. }
  2531. }
  2532.  
  2533. ComputeBattlePoints();
  2534.  
  2535. if (iMaxHP != GetMaxHP())
  2536. {
  2537. SetRealPoint(POINT_MAX_HP, iMaxHP);
  2538. }
  2539.  
  2540. PointChange(POINT_MAX_HP, 0);
  2541.  
  2542. if (iMaxSP != GetMaxSP())
  2543. {
  2544. SetRealPoint(POINT_MAX_SP, iMaxSP);
  2545. }
  2546.  
  2547. PointChange(POINT_MAX_SP, 0);
  2548.  
  2549. SetMaxStamina(iMaxStamina);
  2550.  
  2551. int iCurHP = this->GetHP();
  2552. int iCurSP = this->GetSP();
  2553.  
  2554. m_pointsInstant.dwImmuneFlag = 0;
  2555.  
  2556. for (int i = 0 ; i < WEAR_MAX_NUM; i++)
  2557. {
  2558. LPITEM pItem = GetWear(i);
  2559. if (pItem)
  2560. {
  2561. pItem->ModifyPoints(true);
  2562. SET_BIT(m_pointsInstant.dwImmuneFlag, GetWear(i)->GetImmuneFlag());
  2563. }
  2564. }
  2565.  
  2566. if (DragonSoul_IsDeckActivated())
  2567. {
  2568. for (int i = WEAR_MAX_NUM + DS_SLOT_MAX * DragonSoul_GetActiveDeck();
  2569. i < WEAR_MAX_NUM + DS_SLOT_MAX * (DragonSoul_GetActiveDeck() + 1); i++)
  2570. {
  2571. LPITEM pItem = GetWear(i);
  2572. if (pItem)
  2573. {
  2574. if (DSManager::instance().IsTimeLeftDragonSoul(pItem))
  2575. pItem->ModifyPoints(true);
  2576. }
  2577. }
  2578. }
  2579.  
  2580. if (GetHP() > GetMaxHP())
  2581. PointChange(POINT_HP, GetMaxHP() - GetHP());
  2582.  
  2583. if (GetSP() > GetMaxSP())
  2584. PointChange(POINT_SP, GetMaxSP() - GetSP());
  2585.  
  2586. ComputeSkillPoints();
  2587.  
  2588. RefreshAffect();
  2589.  
  2590. if (IsPC())
  2591. {
  2592. if (this->GetHP() != iCurHP)
  2593. this->PointChange(POINT_HP, iCurHP-this->GetHP());
  2594.  
  2595. if (this->GetSP() != iCurSP)
  2596. this->PointChange(POINT_SP, iCurSP-this->GetSP());
  2597. }
  2598.  
  2599. // CPetSystem* pPetSystem = GetPetSystem();
  2600. // if (NULL != pPetSystem)
  2601. // {
  2602. // pPetSystem->RefreshBuff();
  2603. // }
  2604.  
  2605. UpdatePacket();
  2606. }
  2607.  
  2608. #ifdef __PET_SYSTEM__
  2609. void CHARACTER::PetSummon(LPITEM petItem)
  2610. {
  2611. CPetSystem* petSystem = GetPetSystem();
  2612. DWORD mobVnum = 0;
  2613.  
  2614. if (GetMapIndex() == 113)
  2615. return;
  2616.  
  2617. if (!petSystem || !petItem)
  2618. return;
  2619.  
  2620. if(petItem->GetValue(1) != 0)
  2621. mobVnum = petItem->GetValue(1);
  2622.  
  2623. petSystem->Summon(mobVnum, petItem, false);
  2624. }
  2625.  
  2626. void CHARACTER::PetUnsummon(LPITEM petItem)
  2627. {
  2628. CPetSystem* petSystem = GetPetSystem();
  2629. DWORD mobVnum = 0;
  2630.  
  2631. if (!petSystem || !petItem)
  2632. return;
  2633.  
  2634. if(petItem->GetValue(1) != 0)
  2635. mobVnum = petItem->GetValue(1);
  2636.  
  2637. petSystem->Unsummon(mobVnum);
  2638. }
  2639.  
  2640. void CHARACTER::CheckPet()
  2641. {
  2642. CPetSystem* petSystem = GetPetSystem();
  2643. LPITEM petItem = GetWear(WEAR_NORMAL_PET);
  2644. DWORD mobVnum = 0;
  2645.  
  2646. if (GetMapIndex() == 113)
  2647. return;
  2648.  
  2649. if (!petSystem || !petItem)
  2650. return;
  2651.  
  2652. if(petItem->GetValue(1) != 0)
  2653. mobVnum = petItem->GetValue(1);
  2654.  
  2655. if(petSystem->CountSummoned() == 0)
  2656. {
  2657. petSystem->Summon(mobVnum, petItem, false);
  2658. }
  2659. }
  2660.  
  2661. bool CHARACTER::IsPetSummon()
  2662. {
  2663. return (GetWear(WEAR_NORMAL_PET));
  2664. }
  2665. #endif
  2666.  
  2667. #ifdef __CUSTOM_TITLE_SYSTEM__
  2668. const char * CHARACTER::GetTitle()
  2669. {
  2670. return this->m_stTitle.c_str();
  2671. }
  2672.  
  2673. void CHARACTER::SetTitle(const char * title)
  2674. {
  2675. m_stTitle = title;
  2676. }
  2677.  
  2678. BYTE* CHARACTER::GetTitleColors() const
  2679. {
  2680. return const_cast<BYTE*>(m_bTitleColor);
  2681. }
  2682.  
  2683. BYTE CHARACTER::GetTitleColor(int index)
  2684. {
  2685. assert(index < TITLE_COLOR_MAX_NUM);
  2686.  
  2687. return m_bTitleColor[index];
  2688. }
  2689.  
  2690. void CHARACTER::SetTitleColor(int index, BYTE val)
  2691. {
  2692. assert(index < TITLE_COLOR_MAX_NUM);
  2693. m_bTitleColor[index] = val;
  2694. }
  2695.  
  2696. void CHARACTER::SetTitleColors(const BYTE* colors)
  2697. {
  2698. if (!colors)
  2699. return;
  2700.  
  2701. memcpy(m_bTitleColor, colors, sizeof(m_bTitleColor));
  2702. }
  2703.  
  2704. void CHARACTER::UpdateTitle()
  2705. {
  2706. TPacketGCUpdateTitle pack;
  2707.  
  2708. pack.header = HEADER_GC_UPDATE_TITLE;
  2709. pack.dwVID = GetVID();
  2710.  
  2711. strlcpy(pack.title.szName, GetTitle(), sizeof(pack.title.szName));
  2712. memcpy(pack.title.bColours, m_bTitleColor, sizeof(pack.title.bColours));
  2713.  
  2714. PacketAround(&pack, sizeof(pack));
  2715. }
  2716.  
  2717. const char * CHARACTER::GetTitle2()
  2718. {
  2719. return this->m_stTitle2.c_str();
  2720. }
  2721.  
  2722. void CHARACTER::SetTitle2(const char * title2)
  2723. {
  2724. m_stTitle2 = title2;
  2725. }
  2726.  
  2727. BYTE* CHARACTER::GetTitle2Colors() const
  2728. {
  2729. return const_cast<BYTE*>(m_bTitle2Color);
  2730. }
  2731.  
  2732. BYTE CHARACTER::GetTitle2Color(int index)
  2733. {
  2734. assert(index < TITLE2_COLOR_MAX_NUM);
  2735.  
  2736. return m_bTitle2Color[index];
  2737. }
  2738.  
  2739. void CHARACTER::SetTitle2Color(int index, BYTE val)
  2740. {
  2741. assert(index < TITLE2_COLOR_MAX_NUM);
  2742. m_bTitle2Color[index] = val;
  2743. }
  2744.  
  2745. void CHARACTER::SetTitle2Colors(const BYTE* colors2)
  2746. {
  2747. if (!colors2)
  2748. return;
  2749.  
  2750. memcpy(m_bTitle2Color, colors2, sizeof(m_bTitle2Color));
  2751. }
  2752.  
  2753. void CHARACTER::UpdateTitle2()
  2754. {
  2755. TPacketGCUpdateTitle2 pack;
  2756.  
  2757. pack.header = HEADER_GC_UPDATE_TITLE2;
  2758. pack.dwVID = GetVID();
  2759.  
  2760. strlcpy(pack.title2.szName, GetTitle2(), sizeof(pack.title2.szName));
  2761. memcpy(pack.title2.bColours2, m_bTitle2Color, sizeof(pack.title2.bColours2))
  2762. ;
  2763. PacketAround(&pack, sizeof(pack));
  2764. }
  2765. #endif
  2766.  
  2767. void CHARACTER::ResetPlayTime(DWORD dwTimeRemain)
  2768. {
  2769. m_dwPlayStartTime = get_dword_time() - dwTimeRemain;
  2770. }
  2771.  
  2772. const int aiRecoveryPercents[10] = { 1, 5, 5, 5, 5, 5, 5, 5, 5, 5 };
  2773.  
  2774. EVENTFUNC(recovery_event)
  2775. {
  2776. char_event_info* info = dynamic_cast<char_event_info*>( event->info );
  2777. if ( info == NULL )
  2778. {
  2779. sys_err( "recovery_event> <Factor> Null pointer" );
  2780. return 0;
  2781. }
  2782.  
  2783. LPCHARACTER ch = info->ch;
  2784.  
  2785. if (ch == NULL)
  2786. {
  2787. return 0;
  2788. }
  2789.  
  2790. if (!ch->IsPC())
  2791. {
  2792. if (ch->IsAffectFlag(AFF_POISON))
  2793. return PASSES_PER_SEC(MAX(1, ch->GetMobTable().bRegenCycle));
  2794.  
  2795. if (2493 == ch->GetMobTable().dwVnum)
  2796. {
  2797. int regenPct = BlueDragon_GetRangeFactor("hp_regen", ch->GetHPPct());
  2798. regenPct += ch->GetMobTable().bRegenPercent;
  2799.  
  2800. for (int i=1 ; i <= 4 ; ++i)
  2801. {
  2802. if (REGEN_PECT_BONUS == BlueDragon_GetIndexFactor("DragonStone", i, "effect_type"))
  2803. {
  2804. DWORD dwDragonStoneID = BlueDragon_GetIndexFactor("DragonStone", i, "vnum");
  2805. size_t val = BlueDragon_GetIndexFactor("DragonStone", i, "val");
  2806. size_t cnt = SECTREE_MANAGER::instance().GetMonsterCountInMap( ch->GetMapIndex(), dwDragonStoneID );
  2807.  
  2808. regenPct += (val*cnt);
  2809.  
  2810. break;
  2811. }
  2812. }
  2813.  
  2814. ch->PointChange(POINT_HP, MAX(1, (ch->GetMaxHP() * regenPct) / 100));
  2815. }
  2816.  
  2817. else if (!ch->IsDoor())
  2818. {
  2819. ch->MonsterLog("HP_REGEN +%d", MAX(1, (ch->GetMaxHP() * ch->GetMobTable().bRegenPercent) / 100));
  2820. ch->PointChange(POINT_HP, MAX(1, (ch->GetMaxHP() * ch->GetMobTable().bRegenPercent) / 100));
  2821. }
  2822.  
  2823. if (ch->GetHP() >= ch->GetMaxHP())
  2824. {
  2825. ch->m_pkRecoveryEvent = NULL;
  2826. return 0;
  2827. }
  2828.  
  2829. if (2493 == ch->GetMobTable().dwVnum)
  2830. {
  2831. for (int i=1 ; i <= 4 ; ++i)
  2832. {
  2833. if (REGEN_TIME_BONUS == BlueDragon_GetIndexFactor("DragonStone", i, "effect_type"))
  2834. {
  2835. DWORD dwDragonStoneID = BlueDragon_GetIndexFactor("DragonStone", i, "vnum");
  2836. size_t val = BlueDragon_GetIndexFactor("DragonStone", i, "val");
  2837. size_t cnt = SECTREE_MANAGER::instance().GetMonsterCountInMap( ch->GetMapIndex(), dwDragonStoneID );
  2838.  
  2839. return PASSES_PER_SEC(MAX(1, (ch->GetMobTable().bRegenCycle - (val*cnt))));
  2840. }
  2841. }
  2842. }
  2843.  
  2844. return PASSES_PER_SEC(MAX(1, ch->GetMobTable().bRegenCycle));
  2845. }
  2846.  
  2847. else
  2848. {
  2849. ch->CheckTarget();
  2850. //ch->UpdateSectree();
  2851. ch->UpdateKillerMode();
  2852.  
  2853. if (ch->IsAffectFlag(AFF_POISON) == true)
  2854. {
  2855. return 3;
  2856. }
  2857.  
  2858. int iSec = (get_dword_time() - ch->GetLastMoveTime()) / 3000;
  2859.  
  2860.  
  2861. ch->DistributeSP(ch);
  2862.  
  2863. if (ch->GetMaxHP() <= ch->GetHP())
  2864. return PASSES_PER_SEC(3);
  2865.  
  2866. int iPercent = 0;
  2867. int iAmount = 0;
  2868.  
  2869. {
  2870. iPercent = aiRecoveryPercents[MIN(9, iSec)];
  2871. iAmount = 15 + (ch->GetMaxHP() * iPercent) / 100;
  2872. }
  2873.  
  2874. iAmount += (iAmount * ch->GetPoint(POINT_HP_REGEN)) / 100;
  2875.  
  2876. sys_log(1, "RECOVERY_EVENT: %s %d HP_REGEN %d HP +%d", ch->GetName(), iPercent, ch->GetPoint(POINT_HP_REGEN), iAmount);
  2877.  
  2878. if (!CPVPManager::instance().IsFightingTactic(ch->GetPlayerID()) && !CPVPManager::instance().IsFightingGerman(ch->GetPlayerID()))
  2879. ch->PointChange(POINT_HP, iAmount, false);
  2880.  
  2881. return PASSES_PER_SEC(3);
  2882. }
  2883. }
  2884.  
  2885. void CHARACTER::StartRecoveryEvent()
  2886. {
  2887. if (m_pkRecoveryEvent)
  2888. return;
  2889.  
  2890. if (IsDead() || IsStun())
  2891. return;
  2892.  
  2893. if (IsNPC() && GetHP() >= GetMaxHP())
  2894. return;
  2895.  
  2896. char_event_info* info = AllocEventInfo<char_event_info>();
  2897.  
  2898. info->ch = this;
  2899.  
  2900. int iSec = IsPC() ? 3 : (MAX(1, GetMobTable().bRegenCycle));
  2901. m_pkRecoveryEvent = event_create(recovery_event, info, PASSES_PER_SEC(iSec));
  2902. }
  2903.  
  2904. void CHARACTER::Standup()
  2905. {
  2906. struct packet_position pack_position;
  2907.  
  2908. if (!IsPosition(POS_SITTING))
  2909. return;
  2910.  
  2911. SetPosition(POS_STANDING);
  2912.  
  2913. sys_log(1, "STANDUP: %s", GetName());
  2914.  
  2915. pack_position.header = HEADER_GC_CHARACTER_POSITION;
  2916. pack_position.vid = GetVID();
  2917. pack_position.position = POSITION_GENERAL;
  2918.  
  2919. PacketAround(&pack_position, sizeof(pack_position));
  2920. }
  2921.  
  2922. void CHARACTER::Sitdown(int is_ground)
  2923. {
  2924. struct packet_position pack_position;
  2925.  
  2926. if (IsPosition(POS_SITTING))
  2927. return;
  2928.  
  2929. SetPosition(POS_SITTING);
  2930. sys_log(1, "SITDOWN: %s", GetName());
  2931.  
  2932. pack_position.header = HEADER_GC_CHARACTER_POSITION;
  2933. pack_position.vid = GetVID();
  2934. pack_position.position = POSITION_SITTING_GROUND;
  2935. PacketAround(&pack_position, sizeof(pack_position));
  2936. }
  2937.  
  2938. void CHARACTER::SetRotation(float fRot)
  2939. {
  2940. m_pointsInstant.fRot = fRot;
  2941. }
  2942.  
  2943. void CHARACTER::SetRotationToXY(long x, long y)
  2944. {
  2945. SetRotation(GetDegreeFromPositionXY(GetX(), GetY(), x, y));
  2946. }
  2947.  
  2948. bool CHARACTER::CannotMoveByAffect() const
  2949. {
  2950. return (IsAffectFlag(AFF_STUN));
  2951. }
  2952.  
  2953. bool CHARACTER::CanMove() const
  2954. {
  2955. if (CannotMoveByAffect())
  2956. return false;
  2957.  
  2958. if (GetMyShop())
  2959. return false;
  2960.  
  2961. /*
  2962. if (get_float_time() - m_fSyncTime < 0.2f)
  2963. return false;
  2964. */
  2965.  
  2966. return true;
  2967. }
  2968.  
  2969. bool CHARACTER::Sync(long x, long y)
  2970. {
  2971. if (!GetSectree())
  2972. return false;
  2973.  
  2974. LPSECTREE new_tree = SECTREE_MANAGER::instance().Get(GetMapIndex(), x, y);
  2975.  
  2976. if (!new_tree)
  2977. {
  2978. if (GetDesc())
  2979. {
  2980. sys_err("cannot find tree at %d %d (name: %s)", x, y, GetName());
  2981. GetDesc()->SetPhase(PHASE_CLOSE);
  2982. }
  2983.  
  2984. else
  2985. {
  2986. sys_err("no tree: %s %d %d %d", GetName(), x, y, GetMapIndex());
  2987. Dead();
  2988. }
  2989.  
  2990. return false;
  2991. }
  2992.  
  2993. SetRotationToXY(x, y);
  2994. SetXYZ(x, y, 0);
  2995.  
  2996. if (GetDungeon())
  2997. {
  2998.  
  2999. int iLastEventAttr = m_iEventAttr;
  3000. m_iEventAttr = new_tree->GetEventAttribute(x, y);
  3001.  
  3002. if (m_iEventAttr != iLastEventAttr)
  3003. {
  3004. if (GetParty())
  3005. {
  3006. quest::CQuestManager::instance().AttrOut(GetParty()->GetLeaderPID(), this, iLastEventAttr);
  3007. quest::CQuestManager::instance().AttrIn(GetParty()->GetLeaderPID(), this, m_iEventAttr);
  3008. }
  3009.  
  3010. else
  3011. {
  3012. quest::CQuestManager::instance().AttrOut(GetPlayerID(), this, iLastEventAttr);
  3013. quest::CQuestManager::instance().AttrIn(GetPlayerID(), this, m_iEventAttr);
  3014. }
  3015. }
  3016. }
  3017.  
  3018. if (GetSectree() != new_tree)
  3019. {
  3020. if (!IsNPC())
  3021. {
  3022. SECTREEID id = new_tree->GetID();
  3023. SECTREEID old_id = GetSectree()->GetID();
  3024.  
  3025. sys_log(0, "SECTREE DIFFER: %s %dx%d was %dx%d", GetName(), id.coord.x, id.coord.y, old_id.coord.x, old_id.coord.y);
  3026. }
  3027.  
  3028. new_tree->InsertEntity(this);
  3029. }
  3030.  
  3031. return true;
  3032. }
  3033.  
  3034. void CHARACTER::Stop()
  3035. {
  3036. if (!IsState(m_stateIdle))
  3037. MonsterLog("[IDLE] 정지");
  3038.  
  3039. GotoState(m_stateIdle);
  3040.  
  3041. m_posDest.x = m_posStart.x = GetX();
  3042. m_posDest.y = m_posStart.y = GetY();
  3043. }
  3044.  
  3045. bool CHARACTER::Goto(long x, long y)
  3046. {
  3047. if (GetX() == x && GetY() == y)
  3048. return false;
  3049.  
  3050. if (m_posDest.x == x && m_posDest.y == y)
  3051. {
  3052. if (!IsState(m_stateMove))
  3053. {
  3054. m_dwStateDuration = 4;
  3055. GotoState(m_stateMove);
  3056. }
  3057.  
  3058. return false;
  3059. }
  3060.  
  3061. m_posDest.x = x;
  3062. m_posDest.y = y;
  3063.  
  3064. CalculateMoveDuration();
  3065.  
  3066. m_dwStateDuration = 4;
  3067.  
  3068. if (!IsState(m_stateMove))
  3069. {
  3070. MonsterLog("[MOVE] %s", GetVictim() ? "대상추적" : "그냥이동");
  3071.  
  3072. if (GetVictim())
  3073. {
  3074. //MonsterChat(MONSTER_CHAT_CHASE);
  3075. MonsterChat(MONSTER_CHAT_ATTACK);
  3076. }
  3077. }
  3078.  
  3079. GotoState(m_stateMove);
  3080.  
  3081. return true;
  3082. }
  3083.  
  3084. DWORD CHARACTER::GetMotionMode() const
  3085. {
  3086. DWORD dwMode = MOTION_MODE_GENERAL;
  3087.  
  3088. if (IsPolymorphed())
  3089. return dwMode;
  3090.  
  3091. LPITEM pkItem;
  3092.  
  3093. if ((pkItem = GetWear(WEAR_WEAPON)))
  3094. {
  3095. switch (pkItem->GetProto()->bSubType)
  3096. {
  3097. case WEAPON_SWORD:
  3098. dwMode = MOTION_MODE_ONEHAND_SWORD;
  3099. break;
  3100.  
  3101. case WEAPON_TWO_HANDED:
  3102. dwMode = MOTION_MODE_TWOHAND_SWORD;
  3103. break;
  3104.  
  3105. case WEAPON_DAGGER:
  3106. dwMode = MOTION_MODE_DUALHAND_SWORD;
  3107. break;
  3108.  
  3109. case WEAPON_BOW:
  3110. dwMode = MOTION_MODE_BOW;
  3111. break;
  3112.  
  3113. case WEAPON_BELL:
  3114. dwMode = MOTION_MODE_BELL;
  3115. break;
  3116.  
  3117. case WEAPON_FAN:
  3118. dwMode = MOTION_MODE_FAN;
  3119. break;
  3120. }
  3121. }
  3122. return dwMode;
  3123. }
  3124.  
  3125. float CHARACTER::GetMoveMotionSpeed() const
  3126. {
  3127. DWORD dwMode = GetMotionMode();
  3128.  
  3129. const CMotion * pkMotion = NULL;
  3130.  
  3131. if (!GetMountVnum())
  3132. pkMotion = CMotionManager::instance().GetMotion(GetRaceNum(), MAKE_MOTION_KEY(dwMode, (IsWalking() && IsPC()) ? MOTION_WALK : MOTION_RUN));
  3133.  
  3134. else
  3135. {
  3136. pkMotion = CMotionManager::instance().GetMotion(GetMountVnum(), MAKE_MOTION_KEY(MOTION_MODE_GENERAL, (IsWalking() && IsPC()) ? MOTION_WALK : MOTION_RUN));
  3137.  
  3138. if (!pkMotion)
  3139. pkMotion = CMotionManager::instance().GetMotion(GetRaceNum(), MAKE_MOTION_KEY(MOTION_MODE_HORSE, (IsWalking() && IsPC()) ? MOTION_WALK : MOTION_RUN));
  3140. }
  3141.  
  3142. if (pkMotion)
  3143. return -pkMotion->GetAccumVector().y / pkMotion->GetDuration();
  3144.  
  3145. else
  3146. {
  3147. sys_err("cannot find motion (name %s race %d mode %d)", GetName(), GetRaceNum(), dwMode);
  3148.  
  3149. return 300.0f;
  3150. }
  3151. }
  3152.  
  3153. float CHARACTER::GetMoveSpeed() const
  3154. {
  3155. return GetMoveMotionSpeed() * 10000 / CalculateDuration(GetLimitPoint(POINT_MOV_SPEED), 10000);
  3156. }
  3157.  
  3158. void CHARACTER::CalculateMoveDuration()
  3159. {
  3160. m_posStart.x = GetX();
  3161. m_posStart.y = GetY();
  3162.  
  3163. float fDist = DISTANCE_SQRT(m_posStart.x - m_posDest.x, m_posStart.y - m_posDest.y);
  3164.  
  3165. float motionSpeed = GetMoveMotionSpeed();
  3166.  
  3167. m_dwMoveDuration = CalculateDuration(GetLimitPoint(POINT_MOV_SPEED), (int) ((fDist / motionSpeed) * 1000.0f));
  3168.  
  3169. if (IsNPC())
  3170. sys_log(1, "%s: GOTO: distance %f, spd %u, duration %u, motion speed %f pos %d %d -> %d %d", GetName(), fDist, GetLimitPoint(POINT_MOV_SPEED), m_dwMoveDuration, motionSpeed, m_posStart.x, m_posStart.y, m_posDest.x, m_posDest.y);
  3171.  
  3172. m_dwMoveStartTime = get_dword_time();
  3173. }
  3174.  
  3175. bool CHARACTER::Move(long x, long y)
  3176. {
  3177. if (GetX() == x && GetY() == y)
  3178. return true;
  3179.  
  3180. if (test_server)
  3181. if (m_bDetailLog)
  3182. sys_log(0, "%s position %u %u", GetName(), x, y);
  3183.  
  3184. OnMove();
  3185.  
  3186. return Sync(x, y);
  3187. }
  3188.  
  3189. void CHARACTER::SendMovePacket(BYTE bFunc, BYTE bArg, DWORD x, DWORD y, DWORD dwDuration, DWORD dwTime, int iRot)
  3190. {
  3191. TPacketGCMove pack;
  3192.  
  3193. if (bFunc == FUNC_WAIT)
  3194. {
  3195. x = m_posDest.x;
  3196. y = m_posDest.y;
  3197.  
  3198. dwDuration = m_dwMoveDuration;
  3199. }
  3200.  
  3201. EncodeMovePacket(pack, GetVID(), bFunc, bArg, x, y, dwDuration, dwTime, iRot == -1 ? (int) GetRotation() / 5 : iRot);
  3202. PacketView(&pack, sizeof(TPacketGCMove), this);
  3203. }
  3204.  
  3205. int CHARACTER::GetRealPoint(BYTE type) const
  3206. {
  3207. return m_points.points[type];
  3208. }
  3209.  
  3210. void CHARACTER::SetRealPoint(BYTE type, int val)
  3211. {
  3212. m_points.points[type] = val;
  3213. }
  3214.  
  3215. int CHARACTER::GetPolymorphPoint(BYTE type) const
  3216. {
  3217. if (IsPolymorphed() && !IsPolyMaintainStat())
  3218. {
  3219. DWORD dwMobVnum = GetPolymorphVnum();
  3220.  
  3221. const CMob * pMob = CMobManager::instance().Get(dwMobVnum);
  3222. int iPower = GetPolymorphPower();
  3223.  
  3224. if (pMob)
  3225. {
  3226. switch (type)
  3227. {
  3228. case POINT_ST:
  3229. if ((GetJob() == JOB_SHAMAN) || ((GetJob() == JOB_SURA) && (GetSkillGroup() == 2)))
  3230. return pMob->m_table.bStr * iPower / 100 + GetPoint(POINT_IQ);
  3231.  
  3232. return pMob->m_table.bStr * iPower / 100 + GetPoint(POINT_ST);
  3233.  
  3234. case POINT_HT:
  3235. return pMob->m_table.bCon * iPower / 100 + GetPoint(POINT_HT);
  3236.  
  3237. case POINT_IQ:
  3238. return pMob->m_table.bInt * iPower / 100 + GetPoint(POINT_IQ);
  3239.  
  3240. case POINT_DX:
  3241. return pMob->m_table.bDex * iPower / 100 + GetPoint(POINT_DX);
  3242. }
  3243. }
  3244. }
  3245.  
  3246. return GetPoint(type);
  3247. }
  3248.  
  3249. long long CHARACTER::GetPoint(BYTE type) const
  3250. {
  3251. if (type >= POINT_MAX_NUM)
  3252. {
  3253. sys_err("Point type overflow (type %u)", type);
  3254. return 0;
  3255. }
  3256.  
  3257. long long val = m_pointsInstant.points[type];
  3258. long long max_val = LLONG_MAX;
  3259.  
  3260. switch (type)
  3261. {
  3262. case POINT_STEAL_HP:
  3263. case POINT_STEAL_SP:
  3264. max_val = 50;
  3265. break;
  3266.  
  3267. case POINT_GOLD:
  3268. max_val = yang_max;
  3269. break;
  3270. }
  3271.  
  3272. if (val > max_val)
  3273. sys_err("POINT_ERROR: %s type %d val %lld (max: %lld)", GetName(), val, max_val);
  3274.  
  3275. return (val);
  3276. }
  3277.  
  3278. int CHARACTER::GetLimitPoint(BYTE type) const
  3279. {
  3280. if (type >= POINT_MAX_NUM)
  3281. {
  3282. sys_err("Point type overflow (type %u)", type);
  3283. return 0;
  3284. }
  3285.  
  3286. int val = m_pointsInstant.points[type];
  3287. int max_val = INT_MAX;
  3288. int limit = INT_MAX;
  3289. int min_limit = -INT_MAX;
  3290.  
  3291. switch (type)
  3292. {
  3293. case POINT_ATT_SPEED:
  3294. min_limit = 0;
  3295.  
  3296. if (IsPC())
  3297. limit = 170;
  3298. else
  3299. limit = 250;
  3300. break;
  3301.  
  3302. case POINT_MOV_SPEED:
  3303. min_limit = 0;
  3304.  
  3305. if (IsPC())
  3306. limit = 200;
  3307. else
  3308. limit = 250;
  3309. break;
  3310.  
  3311. case POINT_STEAL_HP:
  3312. case POINT_STEAL_SP:
  3313. limit = 50;
  3314. max_val = 50;
  3315. break;
  3316.  
  3317. case POINT_MALL_ATTBONUS:
  3318. case POINT_MALL_DEFBONUS:
  3319. limit = 20;
  3320. max_val = 50;
  3321. break;
  3322. }
  3323.  
  3324. if (val > max_val)
  3325. sys_err("POINT_ERROR: %s type %d val %d (max: %d)", GetName(), val, max_val);
  3326.  
  3327. if (val > limit)
  3328. val = limit;
  3329.  
  3330. if (val < min_limit)
  3331. val = min_limit;
  3332.  
  3333. return (val);
  3334. }
  3335.  
  3336. void CHARACTER::SetPoint(BYTE type, long long val)
  3337. {
  3338. if (type >= POINT_MAX_NUM)
  3339. {
  3340. sys_err("Point type overflow (type %u)", type);
  3341. return;
  3342. }
  3343.  
  3344. m_pointsInstant.points[type] = val;
  3345.  
  3346. if (type == POINT_MOV_SPEED && get_dword_time() < m_dwMoveStartTime + m_dwMoveDuration)
  3347. {
  3348. CalculateMoveDuration();
  3349. }
  3350. }
  3351.  
  3352. long long CHARACTER::GetAllowedGold() const
  3353. {
  3354. if (GetLevel() <= 10)
  3355. return 100000;
  3356.  
  3357. else if (GetLevel() <= 20)
  3358. return 500000;
  3359.  
  3360. else
  3361. return 50000000;
  3362. }
  3363.  
  3364. void CHARACTER::CheckMaximumPoints()
  3365. {
  3366. if (GetMaxHP() < GetHP())
  3367. PointChange(POINT_HP, GetMaxHP() - GetHP());
  3368.  
  3369. if (GetMaxSP() < GetSP())
  3370. PointChange(POINT_SP, GetMaxSP() - GetSP());
  3371. }
  3372.  
  3373. #ifdef SKILL_SELECT_RENEWALL
  3374. void CHARACTER::SelectSkillGroupWithWindow(BYTE group)
  3375. {
  3376. if (!IsPC() || GetSkillGroup() != 0)
  3377. return;
  3378.  
  3379. SetSkillGroup(group);
  3380. SetHorseLevel(SKILL_MAX_LEVEL);
  3381.  
  3382. for (int i = 0; i < SKILL_MAX_NUM; i++)
  3383. {
  3384. if (true == CanUseSkill(i))
  3385. {
  3386. switch(i)
  3387. {
  3388. case SKILL_COMBO:
  3389. SetSkillLevel(i, 2);
  3390. break;
  3391.  
  3392. case SKILL_LEADERSHIP:
  3393. case SKILL_POLYMORPH:
  3394. SetSkillLevel(i, 40);
  3395. break;
  3396.  
  3397. case SKILL_LANGUAGE1:
  3398. case SKILL_LANGUAGE2:
  3399. case SKILL_LANGUAGE3:
  3400. SetSkillLevel(i, 40);
  3401. break;
  3402.  
  3403. case SKILL_HORSE_SUMMON:
  3404. SetSkillLevel(i, 10);
  3405. break;
  3406.  
  3407. case SKILL_HORSE:
  3408. SetSkillLevel(i, HORSE_MAX_LEVEL);
  3409. break;
  3410.  
  3411. case SKILL_HORSE_WILDATTACK:
  3412. case SKILL_HORSE_CHARGE:
  3413. case SKILL_HORSE_ESCAPE:
  3414. case SKILL_HORSE_WILDATTACK_RANGE:
  3415. SetSkillLevel(i, 40);
  3416. break;
  3417.  
  3418. default:
  3419. SetSkillLevel(i, 40);
  3420. break;
  3421. }
  3422. }
  3423.  
  3424. else
  3425. {
  3426. switch(i)
  3427. {
  3428. case SKILL_HORSE_WILDATTACK:
  3429. case SKILL_HORSE_CHARGE:
  3430. case SKILL_HORSE_ESCAPE:
  3431.  
  3432. case SKILL_HORSE_WILDATTACK_RANGE:
  3433. SetSkillLevel(i, 20);
  3434. break;
  3435. }
  3436. }
  3437. }
  3438.  
  3439. SetHorseLevel(HORSE_MAX_LEVEL);
  3440. ComputePoints();
  3441. SkillLevelPacket();
  3442. }
  3443. #endif
  3444.  
  3445. void CHARACTER::PointChange(BYTE type, long long amount, bool bAmount, bool bBroadcast)
  3446. {
  3447. long long val = 0;
  3448.  
  3449. //sys_log(0, "PointChange %d %d | %d -> %d cHP %d mHP %d", type, amount, GetPoint(type), GetPoint(type)+amount, GetHP(), GetMaxHP());
  3450.  
  3451. switch (type)
  3452. {
  3453. case POINT_NONE:
  3454. return;
  3455.  
  3456. case POINT_LEVEL:
  3457. if ((GetLevel() + static_cast<int>(amount)) > gPlayerMaxLevel)
  3458. return;
  3459.  
  3460. SetLevel(GetLevel() + static_cast<int>(amount));
  3461. val = GetLevel();
  3462.  
  3463. sys_log(0, "LEVELUP: %s %d NEXT EXP %d", GetName(), GetLevel(), GetNextExp());
  3464.  
  3465. #ifdef SKILL_SELECT_RENEWALL
  3466. if (GetLevel() >= 5 && GetSkillGroup() == 0)
  3467. ChatPacket(CHAT_TYPE_COMMAND, "open_select_skill_window %d", GetJob());
  3468. #endif
  3469.  
  3470. PointChange(POINT_NEXT_EXP, GetNextExp(), false);
  3471.  
  3472. if (static_cast<int>(amount))
  3473. {
  3474. quest::CQuestManager::instance().LevelUp(GetPlayerID());
  3475.  
  3476. LogManager::instance().LevelLog(this, val, GetRealPoint(POINT_PLAYTIME) + (get_dword_time() - m_dwPlayStartTime) / 60000);
  3477.  
  3478. if (GetGuild())
  3479. {
  3480. GetGuild()->LevelChange(GetPlayerID(), GetLevel());
  3481. }
  3482.  
  3483. if (GetParty())
  3484. {
  3485. GetParty()->RequestSetMemberLevel(GetPlayerID(), GetLevel());
  3486. }
  3487. }
  3488. break;
  3489.  
  3490. case POINT_NEXT_EXP:
  3491. val = GetNextExp();
  3492. bAmount = false;
  3493. break;
  3494.  
  3495. case POINT_EXP:
  3496. {
  3497. DWORD exp = GetExp();
  3498. DWORD next_exp = GetNextExp();
  3499.  
  3500. if (static_cast<int>(amount) < 0 && exp < -static_cast<int>(amount))
  3501. {
  3502. sys_log(1, "%s AMOUNT < 0 %d, CUR EXP: %d", GetName(), -static_cast<int>(amount), exp);
  3503. amount = -exp;
  3504.  
  3505. SetExp(exp + static_cast<int>(amount));
  3506. val = GetExp();
  3507. }
  3508.  
  3509. else
  3510. {
  3511. if (gPlayerMaxLevel <= GetLevel())
  3512. return;
  3513.  
  3514. if (test_server)
  3515. ChatPacket(CHAT_TYPE_INFO, "You have gained %d exp.", static_cast<int>(amount));
  3516.  
  3517. DWORD iExpBalance = 0;
  3518.  
  3519. if (exp + static_cast<int>(amount) >= next_exp)
  3520. {
  3521. iExpBalance = (exp + static_cast<int>(amount)) - next_exp;
  3522. amount = next_exp - exp;
  3523.  
  3524. SetExp(0);
  3525. exp = next_exp;
  3526. }
  3527.  
  3528. else
  3529. {
  3530. SetExp(exp + static_cast<int>(amount));
  3531. exp = GetExp();
  3532. }
  3533.  
  3534. DWORD q = DWORD(next_exp / 4.0f);
  3535. int iLevStep = GetRealPoint(POINT_LEVEL_STEP);
  3536.  
  3537. if (iLevStep >= 4)
  3538. {
  3539. sys_err("%s LEVEL_STEP bigger than 4! (%d)", GetName(), iLevStep);
  3540. iLevStep = 4;
  3541. }
  3542.  
  3543. if (exp >= next_exp && iLevStep < 4)
  3544. {
  3545. for (int i = 0; i < 4 - iLevStep; ++i)
  3546. PointChange(POINT_LEVEL_STEP, 1, false, true);
  3547. }
  3548.  
  3549. else if (exp >= q * 3 && iLevStep < 3)
  3550. {
  3551. for (int i = 0; i < 3 - iLevStep; ++i)
  3552. PointChange(POINT_LEVEL_STEP, 1, false, true);
  3553. }
  3554.  
  3555. else if (exp >= q * 2 && iLevStep < 2)
  3556. {
  3557. for (int i = 0; i < 2 - iLevStep; ++i)
  3558. PointChange(POINT_LEVEL_STEP, 1, false, true);
  3559. }
  3560.  
  3561. else if (exp >= q && iLevStep < 1)
  3562. PointChange(POINT_LEVEL_STEP, 1);
  3563.  
  3564. if (iExpBalance)
  3565. {
  3566. PointChange(POINT_EXP, iExpBalance);
  3567. }
  3568.  
  3569. val = GetExp();
  3570. }
  3571. }
  3572. break;
  3573.  
  3574. case POINT_LEVEL_STEP:
  3575. if (static_cast<int>(amount) > 0)
  3576. {
  3577. val = GetPoint(POINT_LEVEL_STEP) + static_cast<int>(amount);
  3578.  
  3579. switch (val)
  3580. {
  3581. case 1:
  3582. case 2:
  3583. case 3:
  3584. if (GetLevel() < 91) PointChange(POINT_STAT, 1);
  3585. break;
  3586.  
  3587. case 4:
  3588. {
  3589. int iHP = number(JobInitialPoints[GetJob()].hp_per_lv_begin, JobInitialPoints[GetJob()].hp_per_lv_end);
  3590. int iSP = number(JobInitialPoints[GetJob()].sp_per_lv_begin, JobInitialPoints[GetJob()].sp_per_lv_end);
  3591.  
  3592. m_points.iRandomHP += iHP;
  3593. m_points.iRandomSP += iSP;
  3594.  
  3595. if (GetSkillGroup())
  3596. {
  3597. if (GetLevel() >= 5)
  3598. PointChange(POINT_SKILL, 1);
  3599.  
  3600. if (GetLevel() >= 9)
  3601. PointChange(POINT_SUB_SKILL, 1);
  3602. }
  3603.  
  3604. PointChange(POINT_MAX_HP, iHP);
  3605. PointChange(POINT_MAX_SP, iSP);
  3606. PointChange(POINT_LEVEL, 1, false, true);
  3607.  
  3608. val = 0;
  3609. }
  3610. break;
  3611. }
  3612.  
  3613. if (GetLevel() <= 10)
  3614. AutoGiveItem(27001, 2);
  3615. else if (GetLevel() <= 30)
  3616. AutoGiveItem(27002, 2);
  3617. else
  3618. {
  3619. AutoGiveItem(27002, 2);
  3620. // AutoGiveItem(27003, 2);
  3621. }
  3622.  
  3623. PointChange(POINT_HP, GetMaxHP() - GetHP());
  3624. PointChange(POINT_SP, GetMaxSP() - GetSP());
  3625. PointChange(POINT_STAMINA, GetMaxStamina() - GetStamina());
  3626.  
  3627. SetPoint(POINT_LEVEL_STEP, val);
  3628. SetRealPoint(POINT_LEVEL_STEP, val);
  3629.  
  3630. Save();
  3631. }
  3632.  
  3633. else
  3634. val = GetPoint(POINT_LEVEL_STEP);
  3635.  
  3636. break;
  3637.  
  3638. case POINT_HP:
  3639. {
  3640. if (IsDead() || IsStun())
  3641. return;
  3642.  
  3643. #ifdef WJ_ENABLE_AUTO_POTION_OPTIMIZATION
  3644. if (FindAffect(AFFECT_AUTO_HP_RECOVERY))
  3645. AutoRecoveryItemProcess(AFFECT_AUTO_HP_RECOVERY);
  3646. #endif
  3647. int prev_hp = GetHP();
  3648.  
  3649. amount = MIN(GetMaxHP() - GetHP(), static_cast<int>(amount));
  3650. SetHP(GetHP() + static_cast<int>(amount));
  3651. val = GetHP();
  3652.  
  3653. #ifdef WJ_ENABLE_AUTO_POTION_OPTIMIZATION
  3654. if (FindAffect(AFFECT_AUTO_SP_RECOVERY))
  3655. AutoRecoveryItemProcess(AFFECT_AUTO_SP_RECOVERY);
  3656. #endif
  3657. BroadcastTargetPacket();
  3658.  
  3659. if (GetParty() && IsPC() && val != prev_hp)
  3660. GetParty()->SendPartyInfoOneToAll(this);
  3661. }
  3662. break;
  3663.  
  3664. case POINT_SP:
  3665. {
  3666. if (IsDead() || IsStun())
  3667. return;
  3668.  
  3669. amount = MIN(GetMaxSP() - GetSP(), static_cast<int>(amount));
  3670. SetSP(GetSP() + static_cast<int>(amount));
  3671. val = GetSP();
  3672. }
  3673. break;
  3674.  
  3675. case POINT_STAMINA:
  3676. {
  3677. if (IsDead() || IsStun())
  3678. return;
  3679.  
  3680. int prev_val = GetStamina();
  3681.  
  3682. amount = MIN(GetMaxStamina() - GetStamina(), static_cast<int>(amount));
  3683. SetStamina(GetStamina() + static_cast<int>(amount));
  3684. val = GetStamina();
  3685.  
  3686. if (val == 0)
  3687. {
  3688. SetNowWalking(true);
  3689. }
  3690.  
  3691. else if (prev_val == 0)
  3692. {
  3693. ResetWalking();
  3694. }
  3695.  
  3696. if (static_cast<int>(amount) < 0 && val != 0)
  3697. return;
  3698. }
  3699. break;
  3700.  
  3701. case POINT_MAX_HP:
  3702. {
  3703. if (CPVPManager::instance().IsFightingGerman(GetPlayerID()))
  3704. {
  3705. SetPoint(type, GetPoint(type) + amount);
  3706. if (GetJob() == JOB_ASSASSIN)
  3707. SetMaxHP(150000);
  3708.  
  3709. else if (GetJob() == JOB_SURA)
  3710. SetMaxHP(150000);
  3711.  
  3712. else if (GetJob() == JOB_SHAMAN)
  3713. SetMaxHP(150000);
  3714.  
  3715. else
  3716. SetMaxHP(170000);
  3717.  
  3718. val = GetMaxHP();
  3719. }
  3720.  
  3721. else if (CPVPManager::instance().IsFightingTactic(GetPlayerID()))
  3722. {
  3723. SetPoint(type, GetPoint(type) + amount);
  3724. SetMaxHP(45000);
  3725. val = GetMaxHP();
  3726. }
  3727.  
  3728. else
  3729. {
  3730. SetPoint(type, GetPoint(type) + amount);
  3731.  
  3732. int hp = GetRealPoint(POINT_MAX_HP);
  3733. int add_hp = MIN(3500, hp * GetPoint(POINT_MAX_HP_PCT) / 100);
  3734.  
  3735. add_hp += GetPoint(POINT_MAX_HP);
  3736. add_hp += GetPoint(POINT_PARTY_TANKER_BONUS);
  3737.  
  3738. SetMaxHP(hp + add_hp);
  3739. val = GetMaxHP();
  3740. }
  3741. }
  3742. break;
  3743.  
  3744. case POINT_MAX_SP:
  3745. {
  3746. SetPoint(type, GetPoint(type) + static_cast<int>(amount));
  3747.  
  3748. int sp = GetRealPoint(POINT_MAX_SP);
  3749. int add_sp = MIN(800, sp * GetPoint(POINT_MAX_SP_PCT) / 100);
  3750.  
  3751. add_sp += GetPoint(POINT_MAX_SP);
  3752. add_sp += GetPoint(POINT_PARTY_SKILL_MASTER_BONUS);
  3753.  
  3754. SetMaxSP(sp + add_sp);
  3755.  
  3756. val = GetMaxSP();
  3757. }
  3758. break;
  3759.  
  3760. case POINT_MAX_HP_PCT:
  3761. SetPoint(type, GetPoint(type) + static_cast<int>(amount));
  3762. val = GetPoint(type);
  3763.  
  3764. PointChange(POINT_MAX_HP, 0);
  3765. break;
  3766.  
  3767. case POINT_MAX_SP_PCT:
  3768. SetPoint(type, GetPoint(type) + static_cast<int>(amount));
  3769. val = GetPoint(type);
  3770.  
  3771. PointChange(POINT_MAX_SP, 0);
  3772. break;
  3773.  
  3774. case POINT_MAX_STAMINA:
  3775. SetMaxStamina(GetMaxStamina() + amount);
  3776. val = GetMaxStamina();
  3777. break;
  3778.  
  3779. case POINT_GOLD:
  3780. {
  3781. const long long nTotalMoney = static_cast<long long>(GetGold()) + static_cast<long long>(amount);
  3782. if (yang_max <= nTotalMoney)
  3783. {
  3784. sys_err("[OVERFLOW_GOLD] OriGold %lld AddedGold %lld id %u Name %s ", GetGold(), amount, GetPlayerID(), GetName());
  3785. LogManager::instance().CharLog(this, GetGold() + amount, "OVERFLOW_GOLD", "");
  3786. return;
  3787. }
  3788.  
  3789. SetGold(GetGold() + amount);
  3790. val = GetGold();
  3791. }
  3792. break;
  3793.  
  3794. case POINT_SKILL:
  3795. case POINT_STAT:
  3796. case POINT_SUB_SKILL:
  3797. case POINT_STAT_RESET_COUNT:
  3798. case POINT_HORSE_SKILL:
  3799. SetPoint(type, GetPoint(type) + static_cast<int>(amount));
  3800. val = GetPoint(type);
  3801.  
  3802. SetRealPoint(type, val);
  3803. break;
  3804.  
  3805. case POINT_DEF_GRADE:
  3806. SetPoint(type, GetPoint(type) + static_cast<int>(amount));
  3807. val = GetPoint(type);
  3808.  
  3809. PointChange(POINT_CLIENT_DEF_GRADE, amount);
  3810. break;
  3811.  
  3812. case POINT_CLIENT_DEF_GRADE:
  3813. SetPoint(type, GetPoint(type) + static_cast<int>(amount));
  3814. val = GetPoint(type);
  3815. break;
  3816.  
  3817. case POINT_ST:
  3818. case POINT_HT:
  3819. case POINT_DX:
  3820. case POINT_IQ:
  3821. case POINT_HP_REGEN:
  3822. case POINT_SP_REGEN:
  3823. SetPoint(type, GetPoint(type) + amount);
  3824. val = GetPoint(type);
  3825. break;
  3826.  
  3827. case POINT_ATT_SPEED:
  3828. if (CPVPManager::instance().IsFightingGerman(GetPlayerID()))
  3829. {
  3830. SetPoint(type, 170);
  3831. val = GetPoint(type);
  3832. }
  3833.  
  3834. else if (CPVPManager::instance().IsFightingTactic(GetPlayerID()))
  3835. {
  3836. SetPoint(type, 170);
  3837. val = GetPoint(type);
  3838. }
  3839.  
  3840. else
  3841. {
  3842. SetPoint(type, GetPoint(type) + amount);
  3843. val = GetPoint(type);
  3844. }
  3845. break;
  3846.  
  3847. case POINT_ATT_GRADE:
  3848. SetPoint(type, GetPoint(type) + amount);
  3849. val = GetPoint(type);
  3850. break;
  3851.  
  3852. case POINT_MOV_SPEED:
  3853. if (CPVPManager::instance().IsFightingGerman(GetPlayerID()))
  3854. {
  3855. SetPoint(type, 200);
  3856. val = GetPoint(type);
  3857. }
  3858.  
  3859. else if (CPVPManager::instance().IsFightingTactic(GetPlayerID()))
  3860. {
  3861. SetPoint(type, 200);
  3862. val = GetPoint(type);
  3863. }
  3864.  
  3865. else
  3866. {
  3867. SetPoint(type, GetPoint(type) + amount);
  3868. val = GetPoint(type);
  3869. }
  3870. break;
  3871.  
  3872. case POINT_CASTING_SPEED:
  3873. if (CPVPManager::instance().IsFightingGerman(GetPlayerID()))
  3874. {
  3875. SetPoint(type, 160);
  3876. val = GetPoint(type);
  3877. }
  3878.  
  3879. else if (CPVPManager::instance().IsFightingTactic(GetPlayerID()))
  3880. {
  3881. SetPoint(type, 160);
  3882. val = GetPoint(type);
  3883. }
  3884.  
  3885. else
  3886. {
  3887. SetPoint(type, GetPoint(type) + amount);
  3888. val = GetPoint(type);
  3889. }
  3890. break;
  3891.  
  3892. case POINT_MAGIC_ATT_GRADE:
  3893. case POINT_MAGIC_DEF_GRADE:
  3894. case POINT_BOW_DISTANCE:
  3895. case POINT_HP_RECOVERY:
  3896. case POINT_SP_RECOVERY:
  3897.  
  3898. case POINT_ATTBONUS_HUMAN:
  3899. case POINT_ATTBONUS_ANIMAL:
  3900. case POINT_ATTBONUS_ORC:
  3901. case POINT_ATTBONUS_MILGYO:
  3902. case POINT_ATTBONUS_UNDEAD:
  3903. case POINT_ATTBONUS_DEVIL:
  3904.  
  3905. case POINT_ATTBONUS_MONSTER:
  3906. case POINT_ATTBONUS_SURA:
  3907. case POINT_ATTBONUS_ASSASSIN:
  3908. case POINT_ATTBONUS_WARRIOR:
  3909. case POINT_ATTBONUS_SHAMAN:
  3910.  
  3911. case POINT_POISON_PCT:
  3912. case POINT_STUN_PCT:
  3913. case POINT_SLOW_PCT:
  3914.  
  3915. case POINT_BLOCK:
  3916. case POINT_DODGE:
  3917.  
  3918. case POINT_CRITICAL_PCT:
  3919. case POINT_RESIST_CRITICAL:
  3920. case POINT_PENETRATE_PCT:
  3921. case POINT_RESIST_PENETRATE:
  3922. case POINT_CURSE_PCT:
  3923.  
  3924. case POINT_STEAL_HP:
  3925. case POINT_STEAL_SP:
  3926.  
  3927. case POINT_MANA_BURN_PCT:
  3928. case POINT_DAMAGE_SP_RECOVER:
  3929. case POINT_RESIST_NORMAL_DAMAGE:
  3930. case POINT_RESIST_SWORD:
  3931. case POINT_RESIST_TWOHAND:
  3932. case POINT_RESIST_DAGGER:
  3933. case POINT_RESIST_BELL:
  3934. case POINT_RESIST_FAN:
  3935. case POINT_RESIST_BOW:
  3936. case POINT_RESIST_FIRE:
  3937. case POINT_RESIST_ELEC:
  3938. case POINT_RESIST_MAGIC:
  3939. case POINT_RESIST_WIND:
  3940. case POINT_RESIST_ICE:
  3941. case POINT_RESIST_EARTH:
  3942. case POINT_RESIST_DARK:
  3943. case POINT_REFLECT_MELEE:
  3944. case POINT_REFLECT_CURSE:
  3945. case POINT_POISON_REDUCE:
  3946. case POINT_KILL_SP_RECOVER:
  3947. case POINT_KILL_HP_RECOVERY:
  3948. case POINT_HIT_HP_RECOVERY:
  3949. case POINT_HIT_SP_RECOVERY:
  3950. case POINT_MANASHIELD:
  3951. case POINT_ATT_BONUS:
  3952. case POINT_DEF_BONUS:
  3953. case POINT_SKILL_DAMAGE_BONUS:
  3954. case POINT_NORMAL_HIT_DAMAGE_BONUS:
  3955.  
  3956. case POINT_SKILL_DEFEND_BONUS:
  3957. case POINT_NORMAL_HIT_DEFEND_BONUS:
  3958. SetPoint(type, GetPoint(type) + static_cast<int>(amount));
  3959. val = GetPoint(type);
  3960. break;
  3961.  
  3962. case POINT_PARTY_ATTACKER_BONUS:
  3963. case POINT_PARTY_TANKER_BONUS:
  3964. case POINT_PARTY_BUFFER_BONUS:
  3965. case POINT_PARTY_SKILL_MASTER_BONUS:
  3966. case POINT_PARTY_HASTE_BONUS:
  3967. case POINT_PARTY_DEFENDER_BONUS:
  3968.  
  3969. case POINT_RESIST_WARRIOR :
  3970. case POINT_RESIST_ASSASSIN :
  3971. case POINT_RESIST_SURA :
  3972. case POINT_RESIST_SHAMAN :
  3973. SetPoint(type, GetPoint(type) + static_cast<int>(amount));
  3974. val = GetPoint(type);
  3975. break;
  3976.  
  3977. case POINT_MALL_ATTBONUS:
  3978. case POINT_MALL_DEFBONUS:
  3979. case POINT_MALL_EXPBONUS:
  3980. case POINT_MALL_ITEMBONUS:
  3981. case POINT_MALL_GOLDBONUS:
  3982. case POINT_MELEE_MAGIC_ATT_BONUS_PER:
  3983. if (GetPoint(type) + static_cast<int>(amount) > 100)
  3984. {
  3985. sys_err("MALL_BONUS exceeded over 100!! point type: %d name: %s amount %d", type, GetName(), static_cast<int>(amount));
  3986. amount = 100 - GetPoint(type);
  3987. }
  3988. SetPoint(type, GetPoint(type) + static_cast<int>(amount));
  3989. val = GetPoint(type);
  3990. break;
  3991.  
  3992. case POINT_EXP_DOUBLE_BONUS:
  3993. case POINT_GOLD_DOUBLE_BONUS:
  3994. case POINT_ITEM_DROP_BONUS:
  3995. case POINT_POTION_BONUS:
  3996. if (GetPoint(type) + static_cast<int>(amount) > 100)
  3997. {
  3998. sys_err("BONUS exceeded over 100!! point type: %d name: %s amount %d", type, GetName(), static_cast<int>(amount));
  3999. amount = 100 - GetPoint(type);
  4000. }
  4001.  
  4002. SetPoint(type, GetPoint(type) + static_cast<int>(amount));
  4003. val = GetPoint(type);
  4004.  
  4005. break;
  4006.  
  4007. case POINT_IMMUNE_STUN:
  4008. SetPoint(type, GetPoint(type) + static_cast<int>(amount));
  4009. val = GetPoint(type);
  4010. if (val)
  4011. {
  4012. SET_BIT(m_pointsInstant.dwImmuneFlag, IMMUNE_STUN);
  4013. }
  4014.  
  4015. else
  4016. {
  4017. REMOVE_BIT(m_pointsInstant.dwImmuneFlag, IMMUNE_STUN);
  4018. }
  4019. break;
  4020.  
  4021. case POINT_IMMUNE_SLOW:
  4022. SetPoint(type, GetPoint(type) + static_cast<int>(amount));
  4023. val = GetPoint(type);
  4024. if (val)
  4025. {
  4026. SET_BIT(m_pointsInstant.dwImmuneFlag, IMMUNE_SLOW);
  4027. }
  4028.  
  4029. else
  4030. {
  4031. REMOVE_BIT(m_pointsInstant.dwImmuneFlag, IMMUNE_SLOW);
  4032. }
  4033. break;
  4034.  
  4035. case POINT_IMMUNE_FALL:
  4036. SetPoint(type, GetPoint(type) + static_cast<int>(amount));
  4037. val = GetPoint(type);
  4038. if (val)
  4039. {
  4040. SET_BIT(m_pointsInstant.dwImmuneFlag, IMMUNE_FALL);
  4041. }
  4042.  
  4043. else
  4044. {
  4045. REMOVE_BIT(m_pointsInstant.dwImmuneFlag, IMMUNE_FALL);
  4046. }
  4047. break;
  4048.  
  4049. case POINT_ATT_GRADE_BONUS:
  4050. SetPoint(type, GetPoint(type) + static_cast<int>(amount));
  4051. PointChange(POINT_ATT_GRADE, static_cast<int>(amount));
  4052. val = GetPoint(type);
  4053. break;
  4054.  
  4055. case POINT_DEF_GRADE_BONUS:
  4056. SetPoint(type, GetPoint(type) + static_cast<int>(amount));
  4057. PointChange(POINT_DEF_GRADE, static_cast<int>(amount));
  4058. val = GetPoint(type);
  4059. break;
  4060.  
  4061. case POINT_MAGIC_ATT_GRADE_BONUS:
  4062. SetPoint(type, GetPoint(type) + static_cast<int>(amount));
  4063. PointChange(POINT_MAGIC_ATT_GRADE, static_cast<int>(amount));
  4064. val = GetPoint(type);
  4065. break;
  4066.  
  4067. case POINT_MAGIC_DEF_GRADE_BONUS:
  4068. SetPoint(type, GetPoint(type) + static_cast<int>(amount));
  4069. PointChange(POINT_MAGIC_DEF_GRADE, static_cast<int>(amount));
  4070. val = GetPoint(type);
  4071. break;
  4072.  
  4073. case POINT_VOICE:
  4074. case POINT_EMPIRE_POINT:
  4075. //sys_err("CHARACTER::PointChange: %s: point cannot be changed. use SetPoint instead (type: %d)", GetName(), type);
  4076. val = GetRealPoint(type);
  4077. break;
  4078.  
  4079. case POINT_POLYMORPH:
  4080. SetPoint(type, GetPoint(type) + static_cast<int>(amount));
  4081. val = GetPoint(type);
  4082. SetPolymorph(val);
  4083. break;
  4084.  
  4085. case POINT_MOUNT:
  4086. SetPoint(type, GetPoint(type) + static_cast<int>(amount));
  4087. val = GetPoint(type);
  4088. MountVnum(val);
  4089. break;
  4090.  
  4091. case POINT_ENERGY:
  4092. case POINT_COSTUME_ATTR_BONUS:
  4093. {
  4094. int old_val = GetPoint(type);
  4095. SetPoint(type, old_val + static_cast<int>(amount));
  4096. val = GetPoint(type);
  4097. BuffOnAttr_ValueChange(type, old_val, val);
  4098. }
  4099. break;
  4100.  
  4101. default:
  4102. sys_err("CHARACTER::PointChange: %s: unknown point change type %d", GetName(), type);
  4103. return;
  4104. }
  4105.  
  4106. switch (type)
  4107. {
  4108. case POINT_LEVEL:
  4109. case POINT_ST:
  4110. case POINT_DX:
  4111. case POINT_IQ:
  4112. case POINT_HT:
  4113. ComputeBattlePoints();
  4114. break;
  4115.  
  4116. case POINT_MAX_HP:
  4117. case POINT_MAX_SP:
  4118. case POINT_MAX_STAMINA:
  4119. break;
  4120. }
  4121.  
  4122. if (type == POINT_HP && static_cast<int>(amount) == 0)
  4123. return;
  4124.  
  4125. if (GetDesc())
  4126. {
  4127. struct packet_point_change pack;
  4128.  
  4129. pack.header = HEADER_GC_CHARACTER_POINT_CHANGE;
  4130. pack.dwVID = m_vid;
  4131. pack.type = type;
  4132. pack.value = val;
  4133.  
  4134. if (bAmount)
  4135. pack.amount = amount;
  4136. else
  4137. pack.amount = 0;
  4138.  
  4139. if (!bBroadcast)
  4140. GetDesc()->Packet(&pack, sizeof(struct packet_point_change));
  4141. else
  4142. PacketAround(&pack, sizeof(pack));
  4143. }
  4144. }
  4145.  
  4146. void CHARACTER::ApplyPoint(BYTE bApplyType, int iVal)
  4147. {
  4148. switch (bApplyType)
  4149. {
  4150. case APPLY_NONE:
  4151. break;
  4152.  
  4153. case APPLY_CON:
  4154. PointChange(POINT_HT, iVal);
  4155. PointChange(POINT_MAX_HP, (iVal * JobInitialPoints[GetJob()].hp_per_ht));
  4156. PointChange(POINT_MAX_STAMINA, (iVal * JobInitialPoints[GetJob()].stamina_per_con));
  4157. break;
  4158.  
  4159. case APPLY_INT:
  4160. PointChange(POINT_IQ, iVal);
  4161. PointChange(POINT_MAX_SP, (iVal * JobInitialPoints[GetJob()].sp_per_iq));
  4162. break;
  4163.  
  4164. case APPLY_SKILL:
  4165. {
  4166. BYTE bSkillVnum = (BYTE) (((DWORD)iVal) >> 24);
  4167. int iAdd = iVal & 0x00800000;
  4168. int iChange = iVal & 0x007fffff;
  4169.  
  4170. sys_log(1, "APPLY_SKILL skill %d add? %d change %d", bSkillVnum, iAdd ? 1 : 0, iChange);
  4171.  
  4172. if (0 == iAdd)
  4173. iChange = -iChange;
  4174.  
  4175. boost::unordered_map<BYTE, int>::iterator iter = m_SkillDamageBonus.find(bSkillVnum);
  4176.  
  4177. if (iter == m_SkillDamageBonus.end())
  4178. m_SkillDamageBonus.insert(std::make_pair(bSkillVnum, iChange));
  4179. else
  4180. iter->second += iChange;
  4181. }
  4182. break;
  4183.  
  4184. case APPLY_MAX_HP:
  4185. case APPLY_MAX_HP_PCT:
  4186. {
  4187. int i = GetMaxHP(); if(i == 0) break;
  4188.  
  4189. PointChange(aApplyInfo[bApplyType].bPointType, iVal);
  4190.  
  4191. float fRatio = (float)GetMaxHP() / (float)i;
  4192.  
  4193. PointChange(POINT_HP, GetHP() * fRatio - GetHP());
  4194. }
  4195. break;
  4196.  
  4197. case APPLY_MAX_SP:
  4198. case APPLY_MAX_SP_PCT:
  4199. {
  4200. int i = GetMaxSP(); if(i == 0) break;
  4201.  
  4202. PointChange(aApplyInfo[bApplyType].bPointType, iVal);
  4203.  
  4204. float fRatio = (float)GetMaxSP() / (float)i;
  4205.  
  4206. PointChange(POINT_SP, GetSP() * fRatio - GetSP());
  4207. }
  4208. break;
  4209.  
  4210. case APPLY_STR:
  4211. case APPLY_DEX:
  4212. case APPLY_ATT_SPEED:
  4213. case APPLY_MOV_SPEED:
  4214. case APPLY_CAST_SPEED:
  4215. case APPLY_HP_REGEN:
  4216. case APPLY_SP_REGEN:
  4217. case APPLY_POISON_PCT:
  4218. case APPLY_STUN_PCT:
  4219. case APPLY_SLOW_PCT:
  4220. case APPLY_CRITICAL_PCT:
  4221. case APPLY_PENETRATE_PCT:
  4222. case APPLY_ATTBONUS_HUMAN:
  4223. case APPLY_ATTBONUS_ANIMAL:
  4224. case APPLY_ATTBONUS_ORC:
  4225. case APPLY_ATTBONUS_MILGYO:
  4226. case APPLY_ATTBONUS_UNDEAD:
  4227. case APPLY_ATTBONUS_DEVIL:
  4228. case APPLY_ATTBONUS_WARRIOR:
  4229. case APPLY_ATTBONUS_ASSASSIN:
  4230. case APPLY_ATTBONUS_SURA:
  4231. case APPLY_ATTBONUS_SHAMAN:
  4232. case APPLY_ATTBONUS_MONSTER:
  4233. case APPLY_STEAL_HP:
  4234. case APPLY_STEAL_SP:
  4235. case APPLY_MANA_BURN_PCT:
  4236. case APPLY_DAMAGE_SP_RECOVER:
  4237. case APPLY_BLOCK:
  4238. case APPLY_DODGE:
  4239. case APPLY_RESIST_SWORD:
  4240. case APPLY_RESIST_TWOHAND:
  4241. case APPLY_RESIST_DAGGER:
  4242. case APPLY_RESIST_BELL:
  4243. case APPLY_RESIST_FAN:
  4244. case APPLY_RESIST_BOW:
  4245. case APPLY_RESIST_FIRE:
  4246. case APPLY_RESIST_ELEC:
  4247. case APPLY_RESIST_MAGIC:
  4248. case APPLY_RESIST_WIND:
  4249. case APPLY_RESIST_ICE:
  4250. case APPLY_RESIST_EARTH:
  4251. case APPLY_RESIST_DARK:
  4252. case APPLY_REFLECT_MELEE:
  4253. case APPLY_REFLECT_CURSE:
  4254. case APPLY_ANTI_CRITICAL_PCT:
  4255. case APPLY_ANTI_PENETRATE_PCT:
  4256. case APPLY_POISON_REDUCE:
  4257. case APPLY_KILL_SP_RECOVER:
  4258. case APPLY_EXP_DOUBLE_BONUS:
  4259. case APPLY_GOLD_DOUBLE_BONUS:
  4260. case APPLY_ITEM_DROP_BONUS:
  4261. case APPLY_POTION_BONUS:
  4262. case APPLY_KILL_HP_RECOVER:
  4263. case APPLY_IMMUNE_STUN:
  4264. case APPLY_IMMUNE_SLOW:
  4265. case APPLY_IMMUNE_FALL:
  4266. case APPLY_BOW_DISTANCE:
  4267. case APPLY_ATT_GRADE_BONUS:
  4268. case APPLY_DEF_GRADE_BONUS:
  4269. case APPLY_MAGIC_ATT_GRADE:
  4270. case APPLY_MAGIC_DEF_GRADE:
  4271. case APPLY_CURSE_PCT:
  4272. case APPLY_MAX_STAMINA:
  4273. case APPLY_MALL_ATTBONUS:
  4274. case APPLY_MALL_DEFBONUS:
  4275. case APPLY_MALL_EXPBONUS:
  4276. case APPLY_MALL_ITEMBONUS:
  4277. case APPLY_MALL_GOLDBONUS:
  4278. case APPLY_SKILL_DAMAGE_BONUS:
  4279. case APPLY_NORMAL_HIT_DAMAGE_BONUS:
  4280.  
  4281. case APPLY_SKILL_DEFEND_BONUS:
  4282. case APPLY_NORMAL_HIT_DEFEND_BONUS:
  4283.  
  4284. case APPLY_RESIST_WARRIOR :
  4285. case APPLY_RESIST_ASSASSIN :
  4286. case APPLY_RESIST_SURA :
  4287. case APPLY_RESIST_SHAMAN :
  4288. case APPLY_ENERGY:
  4289. case APPLY_DEF_GRADE:
  4290. case APPLY_COSTUME_ATTR_BONUS:
  4291. case APPLY_MAGIC_ATTBONUS_PER:
  4292. case APPLY_MELEE_MAGIC_ATTBONUS_PER:
  4293. PointChange(aApplyInfo[bApplyType].bPointType, iVal);
  4294. break;
  4295.  
  4296. default:
  4297. sys_err("Unknown apply type %d name %s", bApplyType, GetName());
  4298. break;
  4299. }
  4300. }
  4301.  
  4302. void CHARACTER::MotionPacketEncode(BYTE motion, LPCHARACTER victim, struct packet_motion * packet)
  4303. {
  4304. packet->header = HEADER_GC_MOTION;
  4305. packet->vid = m_vid;
  4306. packet->motion = motion;
  4307.  
  4308. if (victim)
  4309. packet->victim_vid = victim->GetVID();
  4310. else
  4311. packet->victim_vid = 0;
  4312. }
  4313.  
  4314. void CHARACTER::Motion(BYTE motion, LPCHARACTER victim)
  4315. {
  4316. struct packet_motion pack_motion;
  4317. MotionPacketEncode(motion, victim, &pack_motion);
  4318. PacketAround(&pack_motion, sizeof(struct packet_motion));
  4319. }
  4320.  
  4321. EVENTFUNC(save_event)
  4322. {
  4323. char_event_info* info = dynamic_cast<char_event_info*>( event->info );
  4324. if ( info == NULL )
  4325. {
  4326. sys_err( "save_event> <Factor> Null pointer" );
  4327. return 0;
  4328. }
  4329.  
  4330. LPCHARACTER ch = info->ch;
  4331.  
  4332. if (ch == NULL)
  4333. {
  4334. return 0;
  4335. }
  4336.  
  4337. sys_log(1, "SAVE_EVENT: %s", ch->GetName());
  4338.  
  4339. ch->Save();
  4340. ch->FlushDelayedSaveItem();
  4341.  
  4342. return (save_event_second_cycle);
  4343. }
  4344.  
  4345. void CHARACTER::StartSaveEvent()
  4346. {
  4347. if (m_pkSaveEvent)
  4348. return;
  4349.  
  4350. char_event_info* info = AllocEventInfo<char_event_info>();
  4351.  
  4352. info->ch = this;
  4353. m_pkSaveEvent = event_create(save_event, info, save_event_second_cycle);
  4354. }
  4355.  
  4356. void CHARACTER::MonsterLog(const char* format, ...)
  4357. {
  4358. if (!test_server)
  4359. return;
  4360.  
  4361. if (IsPC())
  4362. return;
  4363.  
  4364. char chatbuf[CHAT_MAX_LEN + 1];
  4365. int len = snprintf(chatbuf, sizeof(chatbuf), "%u)", (DWORD)GetVID());
  4366.  
  4367. if (len < 0 || len >= (int) sizeof(chatbuf))
  4368. len = sizeof(chatbuf) - 1;
  4369.  
  4370. va_list args;
  4371.  
  4372. va_start(args, format);
  4373.  
  4374. int len2 = vsnprintf(chatbuf + len, sizeof(chatbuf) - len, format, args);
  4375.  
  4376. if (len2 < 0 || len2 >= (int) sizeof(chatbuf) - len)
  4377. len += (sizeof(chatbuf) - len) - 1;
  4378. else
  4379. len += len2;
  4380.  
  4381. ++len;
  4382.  
  4383. va_end(args);
  4384.  
  4385. TPacketGCChat pack_chat;
  4386.  
  4387. pack_chat.header = HEADER_GC_CHAT;
  4388. pack_chat.size = sizeof(TPacketGCChat) + len;
  4389. pack_chat.type = CHAT_TYPE_TALKING;
  4390. pack_chat.id = (DWORD)GetVID();
  4391. pack_chat.bEmpire = 0;
  4392.  
  4393. TEMP_BUFFER buf;
  4394. buf.write(&pack_chat, sizeof(TPacketGCChat));
  4395. buf.write(chatbuf, len);
  4396.  
  4397. CHARACTER_MANAGER::instance().PacketMonsterLog(this, buf.read_peek(), buf.size());
  4398. }
  4399.  
  4400. void CHARACTER::ChatPacket(BYTE type, const char * format, ...)
  4401. {
  4402. LPDESC d = GetDesc();
  4403.  
  4404. if (!d || !format)
  4405. return;
  4406.  
  4407. char chatbuf[CHAT_MAX_LEN + 1];
  4408. va_list args;
  4409.  
  4410. va_start(args, format);
  4411. int len = vsnprintf(chatbuf, sizeof(chatbuf), format, args);
  4412. va_end(args);
  4413.  
  4414. struct packet_chat pack_chat;
  4415.  
  4416. pack_chat.header = HEADER_GC_CHAT;
  4417. pack_chat.size = sizeof(struct packet_chat) + len;
  4418. pack_chat.type = type;
  4419. pack_chat.id = 0;
  4420. pack_chat.bEmpire = d->GetEmpire();
  4421.  
  4422. TEMP_BUFFER buf;
  4423. buf.write(&pack_chat, sizeof(struct packet_chat));
  4424. buf.write(chatbuf, len);
  4425.  
  4426. d->Packet(buf.read_peek(), buf.size());
  4427.  
  4428. if (type == CHAT_TYPE_COMMAND && test_server)
  4429. sys_log(0, "SEND_COMMAND %s %s", GetName(), chatbuf);
  4430. }
  4431.  
  4432. void CHARACTER::mining_take()
  4433. {
  4434. m_pkMiningEvent = NULL;
  4435. }
  4436.  
  4437. void CHARACTER::mining_cancel()
  4438. {
  4439. if (m_pkMiningEvent)
  4440. {
  4441. sys_log(0, "XXX MINING CANCEL");
  4442. event_cancel(&m_pkMiningEvent);
  4443. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("채광을 중단하였습니다."));
  4444. }
  4445. }
  4446.  
  4447. void CHARACTER::mining(LPCHARACTER chLoad)
  4448. {
  4449. if (m_pkMiningEvent)
  4450. {
  4451. mining_cancel();
  4452. return;
  4453. }
  4454.  
  4455. if (!chLoad)
  4456. return;
  4457.  
  4458. if (GetMapIndex() != chLoad->GetMapIndex() || DISTANCE_APPROX(GetX() - chLoad->GetX(), GetY() - chLoad->GetY()) > 1000)
  4459. return;
  4460.  
  4461. if (mining::GetRawOreFromLoad(chLoad->GetRaceNum()) == 0)
  4462. return;
  4463.  
  4464. LPITEM pick = GetWear(WEAR_WEAPON);
  4465.  
  4466. if (!pick || pick->GetType() != ITEM_PICK)
  4467. {
  4468. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("곡괭이를 장착하세요."));
  4469. return;
  4470. }
  4471.  
  4472. int count = number(5, 15);
  4473.  
  4474. TPacketGCDigMotion p;
  4475.  
  4476. p.header = HEADER_GC_DIG_MOTION;
  4477. p.vid = GetVID();
  4478. p.target_vid = chLoad->GetVID();
  4479. p.count = count;
  4480.  
  4481. PacketAround(&p, sizeof(p));
  4482.  
  4483. m_pkMiningEvent = mining::CreateMiningEvent(this, chLoad, count);
  4484. }
  4485.  
  4486. void CHARACTER::fishing()
  4487. {
  4488. if (m_pkFishingEvent)
  4489. {
  4490. fishing_take();
  4491. return;
  4492. }
  4493.  
  4494. {
  4495. LPSECTREE_MAP pkSectreeMap = SECTREE_MANAGER::instance().GetMap(GetMapIndex());
  4496.  
  4497. int x = GetX();
  4498. int y = GetY();
  4499.  
  4500. LPSECTREE tree = pkSectreeMap->Find(x, y);
  4501. DWORD dwAttr = tree->GetAttribute(x, y);
  4502.  
  4503. if (IS_SET(dwAttr, ATTR_BLOCK))
  4504. {
  4505. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("낚시를 할 수 있는 곳이 아닙니다"));
  4506. return;
  4507. }
  4508. }
  4509.  
  4510. LPITEM rod = GetWear(WEAR_WEAPON);
  4511.  
  4512. if (!rod || rod->GetType() != ITEM_ROD)
  4513. {
  4514. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("낚시대를 장착 하세요."));
  4515. return;
  4516. }
  4517.  
  4518. if (0 == rod->GetSocket(2))
  4519. {
  4520. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("미끼를 끼고 던져 주세요."));
  4521. return;
  4522. }
  4523.  
  4524. float fx, fy;
  4525. GetDeltaByDegree(GetRotation(), 400.0f, &fx, &fy);
  4526.  
  4527. m_pkFishingEvent = fishing::CreateFishingEvent(this);
  4528. }
  4529.  
  4530. void CHARACTER::fishing_take()
  4531. {
  4532. LPITEM rod = GetWear(WEAR_WEAPON);
  4533. if (rod && rod->GetType() == ITEM_ROD)
  4534. {
  4535. using fishing::fishing_event_info;
  4536. if (m_pkFishingEvent)
  4537. {
  4538. struct fishing_event_info* info = dynamic_cast<struct fishing_event_info*>(m_pkFishingEvent->info);
  4539.  
  4540. if (info)
  4541. fishing::Take(info, this);
  4542. }
  4543. }
  4544.  
  4545. else
  4546. {
  4547. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("낚시대가 아닌 물건으로 낚시를 할 수 없습니다!"));
  4548. }
  4549.  
  4550. event_cancel(&m_pkFishingEvent);
  4551. }
  4552.  
  4553. bool CHARACTER::StartStateMachine(int iNextPulse)
  4554. {
  4555. if (CHARACTER_MANAGER::instance().AddToStateList(this))
  4556. {
  4557. m_dwNextStatePulse = thecore_heart->pulse + iNextPulse;
  4558. return true;
  4559. }
  4560.  
  4561. return false;
  4562. }
  4563.  
  4564. void CHARACTER::StopStateMachine()
  4565. {
  4566. CHARACTER_MANAGER::instance().RemoveFromStateList(this);
  4567. }
  4568.  
  4569. void CHARACTER::UpdateStateMachine(DWORD dwPulse)
  4570. {
  4571. if (dwPulse < m_dwNextStatePulse)
  4572. return;
  4573.  
  4574. if (IsDead())
  4575. return;
  4576.  
  4577. Update();
  4578. m_dwNextStatePulse = dwPulse + m_dwStateDuration;
  4579. }
  4580.  
  4581. void CHARACTER::SetNextStatePulse(int iNextPulse)
  4582. {
  4583. CHARACTER_MANAGER::instance().AddToStateList(this);
  4584. m_dwNextStatePulse = iNextPulse;
  4585.  
  4586. if (iNextPulse < 10)
  4587. MonsterLog("다음상태로어서가자");
  4588. }
  4589.  
  4590. void CHARACTER::UpdateCharacter(DWORD dwPulse)
  4591. {
  4592. CFSM::Update();
  4593. }
  4594.  
  4595. void CHARACTER::SetShop(LPSHOP pkShop)
  4596. {
  4597. if ((m_pkShop = pkShop))
  4598. SET_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_SHOP);
  4599. else
  4600. {
  4601. REMOVE_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_SHOP);
  4602. SetShopOwner(NULL);
  4603. }
  4604. }
  4605.  
  4606. void CHARACTER::SetExchange(CExchange * pkExchange)
  4607. {
  4608. m_pkExchange = pkExchange;
  4609. }
  4610.  
  4611. void CHARACTER::SetPart(BYTE bPartPos, WORD wVal)
  4612. {
  4613. assert(bPartPos < PART_MAX_NUM);
  4614. m_pointsInstant.parts[bPartPos] = wVal;
  4615. }
  4616.  
  4617. WORD CHARACTER::GetPart(BYTE bPartPos) const
  4618. {
  4619. assert(bPartPos < PART_MAX_NUM);
  4620. return m_pointsInstant.parts[bPartPos];
  4621. }
  4622.  
  4623. WORD CHARACTER::GetOriginalPart(BYTE bPartPos) const
  4624. {
  4625. switch (bPartPos)
  4626. {
  4627. case PART_MAIN:
  4628. if (!IsPC())
  4629. return GetPart(PART_MAIN);
  4630. else
  4631. return m_pointsInstant.bBasePart;
  4632.  
  4633. case PART_HAIR:
  4634. return GetPart(PART_HAIR);
  4635.  
  4636. #ifdef __WEAPON_COSTUME_SYSTEM__
  4637. case PART_WEAPON:
  4638. return GetPart(PART_WEAPON);
  4639. #endif
  4640.  
  4641. #ifdef __EFFECT_SYSTEM__
  4642. case BODY_EFFECT:
  4643. return GetPart(BODY_EFFECT);
  4644.  
  4645. case WEAPON_RIGHT_EFFECT:
  4646. return GetPart(WEAPON_RIGHT_EFFECT);
  4647.  
  4648. case WEAPON_LEFT_EFFECT:
  4649. return GetPart(WEAPON_LEFT_EFFECT);
  4650. #endif
  4651. default:
  4652. return 0;
  4653. }
  4654. }
  4655.  
  4656. BYTE CHARACTER::GetCharType() const
  4657. {
  4658. return m_bCharType;
  4659. }
  4660.  
  4661. bool CHARACTER::SetSyncOwner(LPCHARACTER ch, bool bRemoveFromList)
  4662. {
  4663. if (IS_SET(m_pointsInstant.dwAIFlag, AIFLAG_NOMOVE))
  4664. return false;
  4665.  
  4666. if (ch)
  4667. {
  4668. if (!battle_is_attackable(ch, this))
  4669. {
  4670. SendDamagePacket(ch, 0, DAMAGE_BLOCK);
  4671. return false;
  4672. }
  4673. }
  4674.  
  4675. if (ch == this)
  4676. {
  4677. sys_err("SetSyncOwner owner == this (%p)", this);
  4678. return false;
  4679. }
  4680.  
  4681. if (!ch)
  4682. {
  4683. if (bRemoveFromList && m_pkChrSyncOwner)
  4684. {
  4685. m_pkChrSyncOwner->m_kLst_pkChrSyncOwned.remove(this);
  4686. }
  4687.  
  4688. if (m_pkChrSyncOwner)
  4689. sys_log(1, "SyncRelease %s %p from %s", GetName(), this, m_pkChrSyncOwner->GetName());
  4690.  
  4691. m_pkChrSyncOwner = NULL;
  4692. }
  4693.  
  4694. else
  4695. {
  4696. if (!IsSyncOwner(ch))
  4697. return false;
  4698.  
  4699. if (DISTANCE_APPROX(GetX() - ch->GetX(), GetY() - ch->GetY()) > 250)
  4700. {
  4701. sys_log(1, "SetSyncOwner distance over than 250 %s %s", GetName(), ch->GetName());
  4702.  
  4703. if (m_pkChrSyncOwner == ch)
  4704. return true;
  4705.  
  4706. return false;
  4707. }
  4708.  
  4709. if (m_pkChrSyncOwner != ch)
  4710. {
  4711. if (m_pkChrSyncOwner)
  4712. {
  4713. sys_log(1, "SyncRelease %s %p from %s", GetName(), this, m_pkChrSyncOwner->GetName());
  4714. m_pkChrSyncOwner->m_kLst_pkChrSyncOwned.remove(this);
  4715. }
  4716.  
  4717. m_pkChrSyncOwner = ch;
  4718. m_pkChrSyncOwner->m_kLst_pkChrSyncOwned.push_back(this);
  4719.  
  4720. static const timeval zero_tv = {0, 0};
  4721. SetLastSyncTime(zero_tv);
  4722.  
  4723. sys_log(1, "SetSyncOwner set %s %p to %s", GetName(), this, ch->GetName());
  4724. }
  4725.  
  4726. m_fSyncTime = get_float_time();
  4727. }
  4728.  
  4729. TPacketGCOwnership pack;
  4730.  
  4731. pack.bHeader = HEADER_GC_OWNERSHIP;
  4732. pack.dwOwnerVID = ch ? ch->GetVID() : 0;
  4733. pack.dwVictimVID = GetVID();
  4734.  
  4735. PacketAround(&pack, sizeof(TPacketGCOwnership));
  4736.  
  4737. return true;
  4738. }
  4739.  
  4740. struct FuncClearSync
  4741. {
  4742. void operator () (LPCHARACTER ch)
  4743. {
  4744. assert(ch != NULL);
  4745. ch->SetSyncOwner(NULL, false);
  4746. }
  4747. };
  4748.  
  4749. void CHARACTER::ClearSync()
  4750. {
  4751. SetSyncOwner(NULL);
  4752.  
  4753. std::for_each(m_kLst_pkChrSyncOwned.begin(), m_kLst_pkChrSyncOwned.end(), FuncClearSync());
  4754. m_kLst_pkChrSyncOwned.clear();
  4755. }
  4756.  
  4757. bool CHARACTER::IsSyncOwner(LPCHARACTER ch) const
  4758. {
  4759. if (m_pkChrSyncOwner == ch)
  4760. return true;
  4761.  
  4762. if (get_float_time() - m_fSyncTime >= 3.0f)
  4763. return true;
  4764.  
  4765. return false;
  4766. }
  4767.  
  4768. void CHARACTER::SetParty(LPPARTY pkParty)
  4769. {
  4770. if (pkParty == m_pkParty)
  4771. return;
  4772.  
  4773. if (pkParty && m_pkParty)
  4774. sys_err("%s is trying to reassigning party (current %p, new party %p)", GetName(), get_pointer(m_pkParty), get_pointer(pkParty));
  4775.  
  4776. sys_log(1, "PARTY set to %p", get_pointer(pkParty));
  4777.  
  4778. if (m_pkDungeon && IsPC() && !pkParty)
  4779. SetDungeon(NULL);
  4780.  
  4781. m_pkParty = pkParty;
  4782.  
  4783. if (IsPC())
  4784. {
  4785. if (m_pkParty)
  4786. SET_BIT(m_bAddChrState, ADD_CHARACTER_STATE_PARTY);
  4787. else
  4788. REMOVE_BIT(m_bAddChrState, ADD_CHARACTER_STATE_PARTY);
  4789.  
  4790. UpdatePacket();
  4791. }
  4792. }
  4793.  
  4794.  
  4795. EVENTINFO(TPartyJoinEventInfo)
  4796. {
  4797. DWORD dwGuestPID;
  4798. DWORD dwLeaderPID;
  4799.  
  4800. TPartyJoinEventInfo()
  4801. : dwGuestPID( 0 )
  4802. , dwLeaderPID( 0 )
  4803. {
  4804. }
  4805. } ;
  4806.  
  4807. EVENTFUNC(party_request_event)
  4808. {
  4809. TPartyJoinEventInfo * info = dynamic_cast<TPartyJoinEventInfo *>( event->info );
  4810.  
  4811. if ( info == NULL )
  4812. {
  4813. sys_err( "party_request_event> <Factor> Null pointer" );
  4814. return 0;
  4815. }
  4816.  
  4817. LPCHARACTER ch = CHARACTER_MANAGER::instance().FindByPID(info->dwGuestPID);
  4818.  
  4819. if (ch)
  4820. {
  4821. sys_log(0, "PartyRequestEvent %s", ch->GetName());
  4822. ch->ChatPacket(CHAT_TYPE_COMMAND, "PartyRequestDenied");
  4823. ch->SetPartyRequestEvent(NULL);
  4824. }
  4825.  
  4826. return 0;
  4827. }
  4828.  
  4829. bool CHARACTER::RequestToParty(LPCHARACTER leader)
  4830. {
  4831. if (leader->GetParty())
  4832. leader = leader->GetParty()->GetLeaderCharacter();
  4833.  
  4834. if (!leader)
  4835. {
  4836. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("파티장이 접속 상태가 아니라서 요청을 할 수 없습니다."));
  4837. return false;
  4838. }
  4839.  
  4840. if (m_pkPartyRequestEvent)
  4841. return false;
  4842.  
  4843. if (!IsPC() || !leader->IsPC())
  4844. return false;
  4845.  
  4846. if (leader->IsBlockMode(BLOCK_PARTY_REQUEST))
  4847. return false;
  4848.  
  4849. PartyJoinErrCode errcode = IsPartyJoinableCondition(leader, this);
  4850.  
  4851. switch (errcode)
  4852. {
  4853. case PERR_NONE:
  4854. break;
  4855.  
  4856. case PERR_SERVER:
  4857. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 서버 문제로 파티 관련 처리를 할 수 없습니다."));
  4858. return false;
  4859.  
  4860. case PERR_DIFFEMPIRE:
  4861. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 다른 제국과 파티를 이룰 수 없습니다."));
  4862. return false;
  4863.  
  4864. case PERR_DUNGEON:
  4865. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 던전 안에서는 파티 초대를 할 수 없습니다."));
  4866. return false;
  4867.  
  4868. case PERR_OBSERVER:
  4869. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 관전 모드에선 파티 초대를 할 수 없습니다."));
  4870. return false;
  4871.  
  4872. case PERR_LVBOUNDARY:
  4873. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> -30 ~ +30 레벨 이내의 상대방만 초대할 수 있습니다."));
  4874. return false;
  4875.  
  4876. case PERR_LOWLEVEL:
  4877. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 파티내 최고 레벨 보다 30레벨이 낮아 초대할 수 없습니다."));
  4878. return false;
  4879.  
  4880. case PERR_HILEVEL:
  4881. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 파티내 최저 레벨 보다 30레벨이 높아 초대할 수 없습니다."));
  4882. return false;
  4883.  
  4884. case PERR_ALREADYJOIN:
  4885. return false;
  4886.  
  4887. case PERR_PARTYISFULL:
  4888. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 더 이상 파티원을 초대할 수 없습니다."));
  4889. return false;
  4890.  
  4891. default:
  4892. sys_err("Do not process party join error(%d)", errcode);
  4893. return false;
  4894. }
  4895.  
  4896. TPartyJoinEventInfo* info = AllocEventInfo<TPartyJoinEventInfo>();
  4897.  
  4898. info->dwGuestPID = GetPlayerID();
  4899. info->dwLeaderPID = leader->GetPlayerID();
  4900.  
  4901. SetPartyRequestEvent(event_create(party_request_event, info, PASSES_PER_SEC(10)));
  4902.  
  4903. leader->ChatPacket(CHAT_TYPE_COMMAND, "PartyRequest %u", (DWORD) GetVID());
  4904. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s 님에게 파티가입 신청을 했습니다."), leader->GetName());
  4905.  
  4906. return true;
  4907. }
  4908.  
  4909. void CHARACTER::DenyToParty(LPCHARACTER member)
  4910. {
  4911. sys_log(1, "DenyToParty %s member %s %p", GetName(), member->GetName(), get_pointer(member->m_pkPartyRequestEvent));
  4912.  
  4913. if (!member->m_pkPartyRequestEvent)
  4914. return;
  4915.  
  4916. TPartyJoinEventInfo * info = dynamic_cast<TPartyJoinEventInfo *>(member->m_pkPartyRequestEvent->info);
  4917.  
  4918. if (!info)
  4919. {
  4920. sys_err( "CHARACTER::DenyToParty> <Factor> Null pointer" );
  4921. return;
  4922. }
  4923.  
  4924. if (info->dwGuestPID != member->GetPlayerID())
  4925. return;
  4926.  
  4927. if (info->dwLeaderPID != GetPlayerID())
  4928. return;
  4929.  
  4930. event_cancel(&member->m_pkPartyRequestEvent);
  4931.  
  4932. member->ChatPacket(CHAT_TYPE_COMMAND, "PartyRequestDenied");
  4933. }
  4934.  
  4935. void CHARACTER::AcceptToParty(LPCHARACTER member)
  4936. {
  4937. sys_log(1, "AcceptToParty %s member %s %p", GetName(), member->GetName(), get_pointer(member->m_pkPartyRequestEvent));
  4938.  
  4939. if (!member->m_pkPartyRequestEvent)
  4940. return;
  4941.  
  4942. TPartyJoinEventInfo * info = dynamic_cast<TPartyJoinEventInfo *>(member->m_pkPartyRequestEvent->info);
  4943.  
  4944. if (!info)
  4945. {
  4946. sys_err( "CHARACTER::AcceptToParty> <Factor> Null pointer" );
  4947. return;
  4948. }
  4949.  
  4950. if (info->dwGuestPID != member->GetPlayerID())
  4951. return;
  4952.  
  4953. if (info->dwLeaderPID != GetPlayerID())
  4954. return;
  4955.  
  4956. event_cancel(&member->m_pkPartyRequestEvent);
  4957.  
  4958. if (!GetParty())
  4959. member->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("상대방이 파티에 속해있지 않습니다."));
  4960. else
  4961. {
  4962. if (GetPlayerID() != GetParty()->GetLeaderPID())
  4963. return;
  4964.  
  4965. PartyJoinErrCode errcode = IsPartyJoinableCondition(this, member);
  4966. switch (errcode)
  4967. {
  4968. case PERR_NONE: member->PartyJoin(this); return;
  4969. case PERR_SERVER: member->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 서버 문제로 파티 관련 처리를 할 수 없습니다.")); break;
  4970. case PERR_DUNGEON: member->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 던전 안에서는 파티 초대를 할 수 없습니다.")); break;
  4971. case PERR_OBSERVER: member->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 관전 모드에선 파티 초대를 할 수 없습니다.")); break;
  4972. case PERR_LVBOUNDARY: member->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> -30 ~ +30 레벨 이내의 상대방만 초대할 수 있습니다.")); break;
  4973. case PERR_LOWLEVEL: member->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 파티내 최고 레벨 보다 30레벨이 낮아 초대할 수 없습니다.")); break;
  4974. case PERR_HILEVEL: member->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 파티내 최저 레벨 보다 30레벨이 높아 초대할 수 없습니다.")); break;
  4975. case PERR_ALREADYJOIN: break;
  4976.  
  4977. case PERR_PARTYISFULL: {
  4978. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 더 이상 파티원을 초대할 수 없습니다."));
  4979. member->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 파티의 인원제한이 초과하여 파티에 참가할 수 없습니다."));
  4980. break;
  4981. }
  4982.  
  4983. default: sys_err("Do not process party join error(%d)", errcode);
  4984. }
  4985. }
  4986.  
  4987. member->ChatPacket(CHAT_TYPE_COMMAND, "PartyRequestDenied");
  4988. }
  4989.  
  4990. EVENTFUNC(party_invite_event)
  4991. {
  4992. TPartyJoinEventInfo * pInfo = dynamic_cast<TPartyJoinEventInfo *>( event->info );
  4993.  
  4994. if ( pInfo == NULL )
  4995. {
  4996. sys_err( "party_invite_event> <Factor> Null pointer" );
  4997. return 0;
  4998. }
  4999.  
  5000. LPCHARACTER pchInviter = CHARACTER_MANAGER::instance().FindByPID(pInfo->dwLeaderPID);
  5001.  
  5002. if (pchInviter)
  5003. {
  5004. sys_log(1, "PartyInviteEvent %s", pchInviter->GetName());
  5005. pchInviter->PartyInviteDeny(pInfo->dwGuestPID);
  5006. }
  5007.  
  5008. return 0;
  5009. }
  5010.  
  5011. void CHARACTER::PartyInvite(LPCHARACTER pchInvitee)
  5012. {
  5013. if (GetParty() && GetParty()->GetLeaderPID() != GetPlayerID())
  5014. {
  5015. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 파티원을 초대할 수 있는 권한이 없습니다."));
  5016. return;
  5017. }
  5018.  
  5019. else if (pchInvitee->IsBlockMode(BLOCK_PARTY_INVITE))
  5020. {
  5021. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> %s 님이 파티 거부 상태입니다."), pchInvitee->GetName());
  5022. return;
  5023. }
  5024.  
  5025. PartyJoinErrCode errcode = IsPartyJoinableCondition(this, pchInvitee);
  5026.  
  5027. switch (errcode)
  5028. {
  5029. case PERR_NONE:
  5030. break;
  5031.  
  5032. case PERR_SERVER:
  5033. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 서버 문제로 파티 관련 처리를 할 수 없습니다."));
  5034. return;
  5035.  
  5036. case PERR_DIFFEMPIRE:
  5037. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 다른 제국과 파티를 이룰 수 없습니다."));
  5038. return;
  5039.  
  5040. case PERR_DUNGEON:
  5041. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 던전 안에서는 파티 초대를 할 수 없습니다."));
  5042. return;
  5043.  
  5044. case PERR_OBSERVER:
  5045. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 관전 모드에선 파티 초대를 할 수 없습니다."));
  5046. return;
  5047.  
  5048. case PERR_LVBOUNDARY:
  5049. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> -30 ~ +30 레벨 이내의 상대방만 초대할 수 있습니다."));
  5050. return;
  5051.  
  5052. case PERR_LOWLEVEL:
  5053. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 파티내 최고 레벨 보다 30레벨이 낮아 초대할 수 없습니다."));
  5054. return;
  5055.  
  5056. case PERR_HILEVEL:
  5057. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 파티내 최저 레벨 보다 30레벨이 높아 초대할 수 없습니다."));
  5058. return;
  5059.  
  5060. case PERR_ALREADYJOIN:
  5061. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 이미 %s님은 파티에 속해 있습니다."), pchInvitee->GetName());
  5062. return;
  5063.  
  5064. case PERR_PARTYISFULL:
  5065. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 더 이상 파티원을 초대할 수 없습니다."));
  5066. return;
  5067.  
  5068. default:
  5069. sys_err("Do not process party join error(%d)", errcode);
  5070. return;
  5071. }
  5072.  
  5073. if (m_PartyInviteEventMap.end() != m_PartyInviteEventMap.find(pchInvitee->GetPlayerID()))
  5074. return;
  5075.  
  5076. TPartyJoinEventInfo* info = AllocEventInfo<TPartyJoinEventInfo>();
  5077.  
  5078. info->dwGuestPID = pchInvitee->GetPlayerID();
  5079. info->dwLeaderPID = GetPlayerID();
  5080.  
  5081. m_PartyInviteEventMap.insert(EventMap::value_type(pchInvitee->GetPlayerID(), event_create(party_invite_event, info, PASSES_PER_SEC(10))));
  5082.  
  5083. TPacketGCPartyInvite p;
  5084. p.header = HEADER_GC_PARTY_INVITE;
  5085. p.leader_vid = GetVID();
  5086.  
  5087. pchInvitee->GetDesc()->Packet(&p, sizeof(p));
  5088. }
  5089.  
  5090. void CHARACTER::PartyInviteAccept(LPCHARACTER pchInvitee)
  5091. {
  5092. EventMap::iterator itFind = m_PartyInviteEventMap.find(pchInvitee->GetPlayerID());
  5093.  
  5094. if (itFind == m_PartyInviteEventMap.end())
  5095. {
  5096. sys_log(1, "PartyInviteAccept from not invited character(%s)", pchInvitee->GetName());
  5097. return;
  5098. }
  5099.  
  5100. event_cancel(&itFind->second);
  5101. m_PartyInviteEventMap.erase(itFind);
  5102.  
  5103. if (GetParty() && GetParty()->GetLeaderPID() != GetPlayerID())
  5104. {
  5105. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 파티원을 초대할 수 있는 권한이 없습니다."));
  5106. return;
  5107. }
  5108.  
  5109. PartyJoinErrCode errcode = IsPartyJoinableMutableCondition(this, pchInvitee);
  5110.  
  5111. switch (errcode)
  5112. {
  5113. case PERR_NONE:
  5114. break;
  5115.  
  5116. case PERR_SERVER:
  5117. pchInvitee->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 서버 문제로 파티 관련 처리를 할 수 없습니다."));
  5118. return;
  5119.  
  5120. case PERR_DUNGEON:
  5121. pchInvitee->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 던전 안에서는 파티 초대에 응할 수 없습니다."));
  5122. return;
  5123.  
  5124. case PERR_OBSERVER:
  5125. pchInvitee->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 관전 모드에선 파티 초대를 할 수 없습니다."));
  5126. return;
  5127.  
  5128. case PERR_LVBOUNDARY:
  5129. pchInvitee->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> -30 ~ +30 레벨 이내의 상대방만 초대할 수 있습니다."));
  5130. return;
  5131.  
  5132. case PERR_LOWLEVEL:
  5133. pchInvitee->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 파티내 최고 레벨 보다 30레벨이 낮아 초대할 수 없습니다."));
  5134. return;
  5135.  
  5136. case PERR_HILEVEL:
  5137. pchInvitee->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 파티내 최저 레벨 보다 30레벨이 높아 초대할 수 없습니다."));
  5138. return;
  5139.  
  5140. case PERR_ALREADYJOIN:
  5141. pchInvitee->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 파티 초대에 응할 수 없습니다."));
  5142. return;
  5143.  
  5144. case PERR_PARTYISFULL:
  5145. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 더 이상 파티원을 초대할 수 없습니다."));
  5146. pchInvitee->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 파티의 인원제한이 초과하여 파티에 참가할 수 없습니다."));
  5147. return;
  5148.  
  5149. default:
  5150. sys_err("ignore party join error(%d)", errcode);
  5151. return;
  5152. }
  5153.  
  5154. if (GetParty())
  5155. pchInvitee->PartyJoin(this);
  5156.  
  5157. else
  5158. {
  5159. LPPARTY pParty = CPartyManager::instance().CreateParty(this);
  5160.  
  5161. pParty->Join(pchInvitee->GetPlayerID());
  5162. pParty->Link(pchInvitee);
  5163. pParty->SendPartyInfoAllToOne(this);
  5164. }
  5165. }
  5166.  
  5167. void CHARACTER::PartyInviteDeny(DWORD dwPID)
  5168. {
  5169. EventMap::iterator itFind = m_PartyInviteEventMap.find(dwPID);
  5170.  
  5171. if (itFind == m_PartyInviteEventMap.end())
  5172. {
  5173. sys_log(1, "PartyInviteDeny to not exist event(inviter PID: %d, invitee PID: %d)", GetPlayerID(), dwPID);
  5174. return;
  5175. }
  5176.  
  5177. event_cancel(&itFind->second);
  5178. m_PartyInviteEventMap.erase(itFind);
  5179.  
  5180. LPCHARACTER pchInvitee = CHARACTER_MANAGER::instance().FindByPID(dwPID);
  5181. if (pchInvitee)
  5182. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> %s님이 파티 초대를 거절하셨습니다."), pchInvitee->GetName());
  5183. }
  5184.  
  5185. void CHARACTER::PartyJoin(LPCHARACTER pLeader)
  5186. {
  5187. pLeader->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> %s님이 파티에 참가하셨습니다."), GetName());
  5188. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> %s님의 파티에 참가하셨습니다."), pLeader->GetName());
  5189.  
  5190. pLeader->GetParty()->Join(GetPlayerID());
  5191. pLeader->GetParty()->Link(this);
  5192. }
  5193.  
  5194. CHARACTER::PartyJoinErrCode CHARACTER::IsPartyJoinableCondition(const LPCHARACTER pchLeader, const LPCHARACTER pchGuest)
  5195. {
  5196. if (pchLeader->GetEmpire() != pchGuest->GetEmpire())
  5197. return PERR_DIFFEMPIRE;
  5198.  
  5199. return IsPartyJoinableMutableCondition(pchLeader, pchGuest);
  5200. }
  5201.  
  5202. static bool __party_can_join_by_level(LPCHARACTER leader, LPCHARACTER quest)
  5203. {
  5204. int level_limit = 30;
  5205.  
  5206. return (abs(leader->GetLevel() - quest->GetLevel()) <= level_limit);
  5207. }
  5208.  
  5209. CHARACTER::PartyJoinErrCode CHARACTER::IsPartyJoinableMutableCondition(const LPCHARACTER pchLeader, const LPCHARACTER pchGuest)
  5210. {
  5211. if (!CPartyManager::instance().IsEnablePCParty())
  5212. return PERR_SERVER;
  5213.  
  5214. else if (pchLeader->GetDungeon())
  5215. return PERR_DUNGEON;
  5216.  
  5217. else if (pchGuest->IsObserverMode())
  5218. return PERR_OBSERVER;
  5219.  
  5220. else if (false == __party_can_join_by_level(pchLeader, pchGuest))
  5221. return PERR_LVBOUNDARY;
  5222.  
  5223. else if (pchGuest->GetParty())
  5224. return PERR_ALREADYJOIN;
  5225.  
  5226. else if (pchLeader->GetParty())
  5227. {
  5228. if (pchLeader->GetParty()->GetMemberCount() == PARTY_MAX_MEMBER)
  5229. return PERR_PARTYISFULL;
  5230. }
  5231.  
  5232. return PERR_NONE;
  5233. }
  5234.  
  5235. void CHARACTER::SetDungeon(LPDUNGEON pkDungeon)
  5236. {
  5237. if (pkDungeon && m_pkDungeon)
  5238. sys_err("%s is trying to reassigning dungeon (current %p, new party %p)", GetName(), get_pointer(m_pkDungeon), get_pointer(pkDungeon));
  5239.  
  5240. if (m_pkDungeon == pkDungeon) {
  5241. return;
  5242. }
  5243.  
  5244. if (m_pkDungeon)
  5245. {
  5246. if (IsPC())
  5247. {
  5248. if (GetParty())
  5249. m_pkDungeon->DecPartyMember(GetParty(), this);
  5250. else
  5251. m_pkDungeon->DecMember(this);
  5252. }
  5253.  
  5254. else if (IsMonster() || IsStone())
  5255. {
  5256. m_pkDungeon->DecMonster();
  5257. }
  5258. }
  5259.  
  5260. m_pkDungeon = pkDungeon;
  5261.  
  5262. if (pkDungeon)
  5263. {
  5264. sys_log(0, "%s DUNGEON set to %p, PARTY is %p", GetName(), get_pointer(pkDungeon), get_pointer(m_pkParty));
  5265.  
  5266. if (IsPC())
  5267. {
  5268. if (GetParty())
  5269. m_pkDungeon->IncPartyMember(GetParty(), this);
  5270. else
  5271. m_pkDungeon->IncMember(this);
  5272. }
  5273.  
  5274. else if (IsMonster() || IsStone())
  5275. {
  5276. m_pkDungeon->IncMonster();
  5277. }
  5278. }
  5279. }
  5280.  
  5281. void CHARACTER::SetWarMap(CWarMap * pWarMap)
  5282. {
  5283.  
  5284. #ifndef ENABLE_WAR_BOARD
  5285. ChatPacket(CHAT_TYPE_COMMAND, "warboard toggle|0");
  5286. #endif
  5287.  
  5288. if (m_pWarMap)
  5289. m_pWarMap->DecMember(this);
  5290.  
  5291. m_pWarMap = pWarMap;
  5292.  
  5293. if (m_pWarMap)
  5294. m_pWarMap->IncMember(this);
  5295. }
  5296.  
  5297. void CHARACTER::SetWeddingMap(marriage::WeddingMap* pMap)
  5298. {
  5299. if (m_pWeddingMap)
  5300. m_pWeddingMap->DecMember(this);
  5301.  
  5302. m_pWeddingMap = pMap;
  5303.  
  5304. if (m_pWeddingMap)
  5305. m_pWeddingMap->IncMember(this);
  5306. }
  5307.  
  5308. void CHARACTER::SetRegen(LPREGEN pkRegen)
  5309. {
  5310. m_pkRegen = pkRegen;
  5311. if (pkRegen != NULL)
  5312. {
  5313. regen_id_ = pkRegen->id;
  5314. }
  5315.  
  5316. m_fRegenAngle = GetRotation();
  5317. m_posRegen = GetXYZ();
  5318. }
  5319.  
  5320. bool CHARACTER::OnIdle()
  5321. {
  5322. return false;
  5323. }
  5324.  
  5325. void CHARACTER::OnMove(bool bIsAttack)
  5326. {
  5327. m_dwLastMoveTime = get_dword_time();
  5328.  
  5329. if (bIsAttack)
  5330. {
  5331. m_dwLastAttackTime = m_dwLastMoveTime;
  5332.  
  5333. if (IsAffectFlag(AFF_REVIVE_INVISIBLE))
  5334. RemoveAffect(AFFECT_REVIVE_INVISIBLE);
  5335.  
  5336. if (IsAffectFlag(AFF_EUNHYUNG))
  5337. {
  5338. RemoveAffect(SKILL_EUNHYUNG);
  5339. SetAffectedEunhyung();
  5340. }
  5341.  
  5342. else
  5343. {
  5344. ClearAffectedEunhyung();
  5345. }
  5346.  
  5347. /*if (IsAffectFlag(AFF_JEONSIN))
  5348. RemoveAffect(SKILL_JEONSINBANGEO);*/
  5349. }
  5350.  
  5351. /*if (IsAffectFlag(AFF_GUNGON))
  5352. RemoveAffect(SKILL_GUNGON);*/
  5353.  
  5354. mining_cancel();
  5355. }
  5356.  
  5357. void CHARACTER::OnClick(LPCHARACTER pkChrCauser)
  5358. {
  5359. if (!pkChrCauser)
  5360. {
  5361. sys_err("OnClick %s by NULL", GetName());
  5362. return;
  5363. }
  5364.  
  5365. DWORD vid = GetVID();
  5366. sys_log(0, "OnClick %s[vnum %d ServerUniqueID %d, pid %d] by %s", GetName(), GetRaceNum(), vid, GetPlayerID(), pkChrCauser->GetName());
  5367.  
  5368. {
  5369. if (pkChrCauser->GetMyShop() && pkChrCauser != this)
  5370. {
  5371. sys_err("OnClick Fail (%s->%s) - pc has shop", pkChrCauser->GetName(), GetName());
  5372. return;
  5373. }
  5374. }
  5375.  
  5376. {
  5377. if (pkChrCauser->GetExchange())
  5378. {
  5379. sys_err("OnClick Fail (%s->%s) - pc is exchanging", pkChrCauser->GetName(), GetName());
  5380. return;
  5381. }
  5382. }
  5383.  
  5384. if (IsPC())
  5385. {
  5386. if (!CTargetManager::instance().GetTargetInfo(pkChrCauser->GetPlayerID(), TARGET_TYPE_VID, GetVID()))
  5387. {
  5388. if (GetMyShop())
  5389. {
  5390. if (pkChrCauser->IsDead() == true) return;
  5391.  
  5392. if (pkChrCauser == this)
  5393. {
  5394. if ((GetExchange() || IsOpenSafebox() || GetShopOwner()) || IsCubeOpen())
  5395. {
  5396. pkChrCauser->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("다른 거래중(창고,교환,상점)에는 개인상점을 사용할 수 없습니다."));
  5397. return;
  5398. }
  5399. }
  5400.  
  5401. else
  5402. {
  5403. if ((pkChrCauser->GetExchange() || pkChrCauser->IsOpenSafebox() || pkChrCauser->GetMyShop() || pkChrCauser->GetShopOwner()) || pkChrCauser->IsCubeOpen() )
  5404. {
  5405. pkChrCauser->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("다른 거래중(창고,교환,상점)에는 개인상점을 사용할 수 없습니다."));
  5406. return;
  5407. }
  5408.  
  5409. if ((GetExchange() || IsOpenSafebox() || IsCubeOpen()))
  5410. {
  5411. pkChrCauser->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("상대방이 다른 거래를 하고 있는 중입니다."));
  5412. return;
  5413. }
  5414. }
  5415.  
  5416. if (pkChrCauser->GetShop())
  5417. {
  5418. pkChrCauser->GetShop()->RemoveGuest(pkChrCauser);
  5419. pkChrCauser->SetShop(NULL);
  5420. }
  5421.  
  5422. GetMyShop()->AddGuest(pkChrCauser, GetVID(), false);
  5423. pkChrCauser->SetShopOwner(this);
  5424.  
  5425. return;
  5426. }
  5427.  
  5428. if (test_server)
  5429. sys_err("%s.OnClickFailure(%s) - target is PC", pkChrCauser->GetName(), GetName());
  5430.  
  5431. return;
  5432. }
  5433. }
  5434.  
  5435. pkChrCauser->SetQuestNPCID(GetVID());
  5436.  
  5437. if (quest::CQuestManager::instance().Click(pkChrCauser->GetPlayerID(), this))
  5438. {
  5439. return;
  5440. }
  5441.  
  5442. if (!IsPC())
  5443. {
  5444. if (!m_triggerOnClick.pFunc)
  5445. {
  5446.  
  5447. //sys_err("%s.OnClickFailure(%s) : triggerOnClick.pFunc is EMPTY(pid=%d)",
  5448. // pkChrCauser->GetName(),
  5449. // GetName(),
  5450. // pkChrCauser->GetPlayerID());
  5451. return;
  5452. }
  5453.  
  5454. m_triggerOnClick.pFunc(this, pkChrCauser);
  5455. }
  5456.  
  5457. }
  5458.  
  5459. BYTE CHARACTER::GetGMLevel() const
  5460. {
  5461. if (test_server)
  5462. return GM_IMPLEMENTOR;
  5463.  
  5464. return m_pointsInstant.gm_level;
  5465. }
  5466.  
  5467. void CHARACTER::SetGMLevel()
  5468. {
  5469. if (GetDesc())
  5470. {
  5471. m_pointsInstant.gm_level = gm_get_level(GetName(), GetDesc()->GetHostName(), GetDesc()->GetAccountTable().login);
  5472. }
  5473.  
  5474. else
  5475. {
  5476. m_pointsInstant.gm_level = GM_PLAYER;
  5477. }
  5478. }
  5479.  
  5480. BOOL CHARACTER::IsGM() const
  5481. {
  5482. if (m_pointsInstant.gm_level != GM_PLAYER)
  5483. return true;
  5484.  
  5485. if (test_server)
  5486. return true;
  5487.  
  5488. return false;
  5489. }
  5490.  
  5491. void CHARACTER::SetStone(LPCHARACTER pkChrStone)
  5492. {
  5493. m_pkChrStone = pkChrStone;
  5494.  
  5495. if (m_pkChrStone)
  5496. {
  5497. if (pkChrStone->m_set_pkChrSpawnedBy.find(this) == pkChrStone->m_set_pkChrSpawnedBy.end())
  5498. pkChrStone->m_set_pkChrSpawnedBy.insert(this);
  5499. }
  5500. }
  5501.  
  5502. struct FuncDeadSpawnedByStone
  5503. {
  5504. void operator () (LPCHARACTER ch)
  5505. {
  5506. ch->Dead(NULL);
  5507. ch->SetStone(NULL);
  5508. }
  5509. };
  5510.  
  5511. void CHARACTER::ClearStone()
  5512. {
  5513. if (!m_set_pkChrSpawnedBy.empty())
  5514. {
  5515. FuncDeadSpawnedByStone f;
  5516. std::for_each(m_set_pkChrSpawnedBy.begin(), m_set_pkChrSpawnedBy.end(), f);
  5517. m_set_pkChrSpawnedBy.clear();
  5518. }
  5519.  
  5520. if (!m_pkChrStone)
  5521. return;
  5522.  
  5523. m_pkChrStone->m_set_pkChrSpawnedBy.erase(this);
  5524. m_pkChrStone = NULL;
  5525. }
  5526.  
  5527. void CHARACTER::ClearTarget()
  5528. {
  5529. if (m_pkChrTarget)
  5530. {
  5531. m_pkChrTarget->m_set_pkChrTargetedBy.erase(this);
  5532. m_pkChrTarget = NULL;
  5533. }
  5534.  
  5535. TPacketGCTarget p;
  5536.  
  5537. p.header = HEADER_GC_TARGET;
  5538. p.dwVID = 0;
  5539. p.bHPPercent = 0;
  5540.  
  5541. #ifdef WJ_TARGET_HP_SYSTEM
  5542. p.dwActualHP = 0;
  5543. p.dwMaxHP = 0;
  5544. #endif
  5545.  
  5546. CHARACTER_SET::iterator it = m_set_pkChrTargetedBy.begin();
  5547.  
  5548. while (it != m_set_pkChrTargetedBy.end())
  5549. {
  5550. LPCHARACTER pkChr = *(it++);
  5551. pkChr->m_pkChrTarget = NULL;
  5552.  
  5553. if (!pkChr->GetDesc())
  5554. {
  5555. sys_err("%s %p does not have desc", pkChr->GetName(), get_pointer(pkChr));
  5556. abort();
  5557. }
  5558.  
  5559. pkChr->GetDesc()->Packet(&p, sizeof(TPacketGCTarget));
  5560. }
  5561.  
  5562. m_set_pkChrTargetedBy.clear();
  5563. }
  5564.  
  5565. void CHARACTER::SetTarget(LPCHARACTER pkChrTarget)
  5566. {
  5567. if (m_pkChrTarget == pkChrTarget)
  5568. return;
  5569.  
  5570. if (m_pkChrTarget)
  5571. m_pkChrTarget->m_set_pkChrTargetedBy.erase(this);
  5572.  
  5573. m_pkChrTarget = pkChrTarget;
  5574.  
  5575. TPacketGCTarget p;
  5576.  
  5577. p.header = HEADER_GC_TARGET;
  5578.  
  5579. if (m_pkChrTarget)
  5580. {
  5581. m_pkChrTarget->m_set_pkChrTargetedBy.insert(this);
  5582.  
  5583. p.dwVID = m_pkChrTarget->GetVID();
  5584.  
  5585. p.bHPPercent = 0;
  5586.  
  5587. #ifdef WJ_TARGET_HP_SYSTEM
  5588. p.dwActualHP = 0;
  5589. p.dwMaxHP = 0;
  5590. #endif
  5591.  
  5592. if (m_pkChrTarget->GetMaxHP() <= 0)
  5593. {
  5594. p.bHPPercent = 0;
  5595.  
  5596. #ifdef WJ_TARGET_HP_SYSTEM
  5597. p.dwActualHP = 0;
  5598. p.dwMaxHP = 0;
  5599. #endif
  5600. }
  5601.  
  5602. else
  5603. {
  5604. if (m_pkChrTarget->GetRaceNum() == 20101 ||
  5605. m_pkChrTarget->GetRaceNum() == 20102 ||
  5606. m_pkChrTarget->GetRaceNum() == 20103 ||
  5607. m_pkChrTarget->GetRaceNum() == 20104 ||
  5608. m_pkChrTarget->GetRaceNum() == 20105 ||
  5609. m_pkChrTarget->GetRaceNum() == 20106 ||
  5610. m_pkChrTarget->GetRaceNum() == 20107 ||
  5611. m_pkChrTarget->GetRaceNum() == 20108 ||
  5612. m_pkChrTarget->GetRaceNum() == 20109)
  5613. {
  5614. LPCHARACTER owner = m_pkChrTarget->GetVictim();
  5615.  
  5616. if (owner)
  5617. {
  5618. int iHorseHealth = owner->GetHorseHealth();
  5619. int iHorseMaxHealth = owner->GetHorseMaxHealth();
  5620.  
  5621. if (iHorseMaxHealth)
  5622. {
  5623. p.bHPPercent = MINMAX(0, iHorseHealth * 100 / iHorseMaxHealth, 100);
  5624.  
  5625. #ifdef WJ_TARGET_HP_SYSTEM
  5626. p.dwActualHP = 100;
  5627. p.dwMaxHP = 100;
  5628. #endif
  5629. }
  5630.  
  5631. else
  5632. {
  5633. p.bHPPercent = 100;
  5634.  
  5635. #ifdef WJ_TARGET_HP_SYSTEM
  5636. p.dwActualHP = 100;
  5637. p.dwMaxHP = 100;
  5638. #endif
  5639. }
  5640. }
  5641.  
  5642. else
  5643. {
  5644. p.bHPPercent = 100;
  5645.  
  5646. #ifdef WJ_TARGET_HP_SYSTEM
  5647. p.dwActualHP = 100;
  5648. p.dwMaxHP = 100;
  5649. #endif
  5650. }
  5651. }
  5652.  
  5653. else
  5654. {
  5655. p.bHPPercent = MINMAX(0, (m_pkChrTarget->GetHP() * 100) / m_pkChrTarget->GetMaxHP(), 100);
  5656.  
  5657. #ifdef WJ_TARGET_HP_SYSTEM
  5658. p.dwActualHP = m_pkChrTarget->GetHP();
  5659. p.dwMaxHP = m_pkChrTarget->GetMaxHP();
  5660. #endif
  5661. }
  5662. }
  5663. }
  5664.  
  5665. else
  5666. {
  5667. p.dwVID = 0;
  5668. p.bHPPercent = 0;
  5669.  
  5670. #ifdef WJ_TARGET_HP_SYSTEM
  5671. p.dwActualHP = 0;
  5672. p.dwMaxHP = 0;
  5673. #endif
  5674.  
  5675. }
  5676.  
  5677. GetDesc()->Packet(&p, sizeof(TPacketGCTarget));
  5678. }
  5679.  
  5680. void CHARACTER::BroadcastTargetPacket()
  5681. {
  5682. if (m_set_pkChrTargetedBy.empty())
  5683. return;
  5684.  
  5685. TPacketGCTarget p;
  5686.  
  5687. p.header = HEADER_GC_TARGET;
  5688. p.dwVID = GetVID();
  5689.  
  5690. p.bHPPercent = 0;
  5691.  
  5692. #ifdef WJ_TARGET_HP_SYSTEM
  5693. p.dwActualHP = 0;
  5694. p.dwMaxHP = 0;
  5695.  
  5696. if (GetMaxHP() <= 0)
  5697. {
  5698. p.bHPPercent = 0;
  5699. p.dwActualHP = 0;
  5700. p.dwMaxHP = 0;
  5701. }
  5702.  
  5703. else
  5704. {
  5705. p.bHPPercent = MINMAX(0, (GetHP() * 100) / GetMaxHP(), 100);
  5706. p.dwActualHP = GetHP();
  5707. p.dwMaxHP = GetMaxHP();
  5708. }
  5709. #else
  5710.  
  5711. if (IsPC())
  5712. p.bHPPercent = 0;
  5713.  
  5714. else if (GetMaxHP() <= 0)
  5715. p.bHPPercent = 0;
  5716.  
  5717. else
  5718. p.bHPPercent = MINMAX(0, (GetHP() * 100) / GetMaxHP(), 100);
  5719. #endif
  5720.  
  5721. CHARACTER_SET::iterator it = m_set_pkChrTargetedBy.begin();
  5722.  
  5723. while (it != m_set_pkChrTargetedBy.end())
  5724. {
  5725. LPCHARACTER pkChr = *it++;
  5726.  
  5727. if (!pkChr->GetDesc())
  5728. {
  5729. sys_err("%s %p does not have desc", pkChr->GetName(), get_pointer(pkChr));
  5730. abort();
  5731. }
  5732.  
  5733. pkChr->GetDesc()->Packet(&p, sizeof(TPacketGCTarget));
  5734. }
  5735. }
  5736.  
  5737. void CHARACTER::CheckTarget()
  5738. {
  5739. if (!m_pkChrTarget)
  5740. return;
  5741.  
  5742. if (DISTANCE_APPROX(GetX() - m_pkChrTarget->GetX(), GetY() - m_pkChrTarget->GetY()) >= 4800)
  5743. SetTarget(NULL);
  5744. }
  5745.  
  5746. void CHARACTER::SetWarpLocation(long lMapIndex, long x, long y)
  5747. {
  5748. m_posWarp.x = x * 100;
  5749. m_posWarp.y = y * 100;
  5750. m_lWarpMapIndex = lMapIndex;
  5751. }
  5752.  
  5753. void CHARACTER::SaveExitLocation()
  5754. {
  5755. m_posExit = GetXYZ();
  5756. m_lExitMapIndex = GetMapIndex();
  5757. }
  5758.  
  5759. void CHARACTER::ExitToSavedLocation()
  5760. {
  5761. sys_log (0, "ExitToSavedLocation");
  5762. WarpSet(m_posWarp.x, m_posWarp.y, m_lWarpMapIndex);
  5763.  
  5764. m_posExit.x = m_posExit.y = m_posExit.z = 0;
  5765. m_lExitMapIndex = 0;
  5766. }
  5767.  
  5768. bool CHARACTER::WarpSet(long x, long y, long lPrivateMapIndex)
  5769. {
  5770. if (!IsPC())
  5771. return false;
  5772.  
  5773. long lAddr;
  5774. long lMapIndex;
  5775. WORD wPort;
  5776.  
  5777. if (!CMapLocation::instance().Get(x, y, lMapIndex, lAddr, wPort))
  5778. {
  5779. sys_err("cannot find map location index %d x %d y %d name %s", lMapIndex, x, y, GetName());
  5780. return false;
  5781. }
  5782.  
  5783. if (lPrivateMapIndex >= 10000)
  5784. {
  5785. if (lPrivateMapIndex / 10000 != lMapIndex)
  5786. {
  5787. sys_err("Invalid map index %d, must be child of %d", lPrivateMapIndex, lMapIndex);
  5788. return false;
  5789. }
  5790.  
  5791. lMapIndex = lPrivateMapIndex;
  5792. }
  5793.  
  5794. Stop();
  5795. Save();
  5796.  
  5797. if (GetSectree())
  5798. {
  5799. GetSectree()->RemoveEntity(this);
  5800. ViewCleanup();
  5801.  
  5802. EncodeRemovePacket(this);
  5803. }
  5804.  
  5805. m_lWarpMapIndex = lMapIndex;
  5806. m_posWarp.x = x;
  5807. m_posWarp.y = y;
  5808.  
  5809. sys_log(0, "WarpSet %s %d %d current map %d target map %d", GetName(), x, y, GetMapIndex(), lMapIndex);
  5810.  
  5811. TPacketGCWarp p;
  5812.  
  5813. p.bHeader = HEADER_GC_WARP;
  5814. p.lX = x;
  5815. p.lY = y;
  5816. p.lAddr = lAddr;
  5817. p.wPort = wPort;
  5818.  
  5819. #ifdef __SWITCHBOT__
  5820. CSwitchbotManager::Instance().SetIsWarping(GetPlayerID(), true);
  5821.  
  5822. if (p.wPort != mother_port)
  5823. {
  5824. CSwitchbotManager::Instance().P2PSendSwitchbot(GetPlayerID(), p.wPort);
  5825. }
  5826. #endif
  5827.  
  5828. GetDesc()->Packet(&p, sizeof(TPacketGCWarp));
  5829.  
  5830. char buf[256];
  5831. snprintf(buf, sizeof(buf), "%s MapIdx %ld DestMapIdx%ld DestX%ld DestY%ld Empire%d", GetName(), GetMapIndex(), lPrivateMapIndex, x, y, GetEmpire());
  5832. LogManager::instance().CharLog(this, 0, "WARP", buf);
  5833.  
  5834. return true;
  5835. }
  5836.  
  5837. void CHARACTER::WarpEnd()
  5838. {
  5839. if (test_server)
  5840. sys_log(0, "WarpEnd %s", GetName());
  5841.  
  5842. if (m_posWarp.x == 0 && m_posWarp.y == 0)
  5843. return;
  5844.  
  5845. int index = m_lWarpMapIndex;
  5846.  
  5847. if (index > 10000)
  5848. index /= 10000;
  5849.  
  5850. if (!map_allow_find(index))
  5851. {
  5852. sys_err("location %d %d not allowed to login this server", m_posWarp.x, m_posWarp.y);
  5853. GoHome();
  5854. return;
  5855. }
  5856.  
  5857. sys_log(0, "WarpEnd %s %d %u %u", GetName(), m_lWarpMapIndex, m_posWarp.x, m_posWarp.y);
  5858.  
  5859. Show(m_lWarpMapIndex, m_posWarp.x, m_posWarp.y, 0);
  5860. Stop();
  5861.  
  5862. m_lWarpMapIndex = 0;
  5863. m_posWarp.x = m_posWarp.y = m_posWarp.z = 0;
  5864.  
  5865. {
  5866. TPacketGGLogin p;
  5867.  
  5868. p.bHeader = HEADER_GG_LOGIN;
  5869. strlcpy(p.szName, GetName(), sizeof(p.szName));
  5870. p.dwPID = GetPlayerID();
  5871. p.bEmpire = GetEmpire();
  5872. p.lMapIndex = SECTREE_MANAGER::instance().GetMapIndex(GetX(), GetY());
  5873. p.bChannel = g_bChannel;
  5874.  
  5875. P2P_MANAGER::instance().Send(&p, sizeof(TPacketGGLogin));
  5876. }
  5877. }
  5878.  
  5879. bool CHARACTER::Return()
  5880. {
  5881. if (!IsNPC())
  5882. return false;
  5883.  
  5884. int x, y;
  5885. /*
  5886. float fDist = DISTANCE_SQRT(m_pkMobData->m_posLastAttacked.x - GetX(), m_pkMobData->m_posLastAttacked.y - GetY());
  5887. float fx, fy;
  5888. GetDeltaByDegree(GetRotation(), fDist, &fx, &fy);
  5889. x = GetX() + (int) fx;
  5890. y = GetY() + (int) fy;
  5891. */
  5892. SetVictim(NULL);
  5893.  
  5894. x = m_pkMobInst->m_posLastAttacked.x;
  5895. y = m_pkMobInst->m_posLastAttacked.y;
  5896.  
  5897. SetRotationToXY(x, y);
  5898.  
  5899. if (!Goto(x, y))
  5900. return false;
  5901.  
  5902. SendMovePacket(FUNC_WAIT, 0, 0, 0, 0);
  5903.  
  5904. if (test_server)
  5905. sys_log(0, "%s %p 포기하고 돌아가자! %d %d", GetName(), this, x, y);
  5906.  
  5907. if (GetParty())
  5908. GetParty()->SendMessage(this, PM_RETURN, x, y);
  5909.  
  5910. return true;
  5911. }
  5912.  
  5913. bool CHARACTER::Follow(LPCHARACTER pkChr, float fMinDistance)
  5914. {
  5915. if (IsPC())
  5916. {
  5917. sys_err("CHARACTER::Follow : PC cannot use this method", GetName());
  5918. return false;
  5919. }
  5920.  
  5921. if (IS_SET(m_pointsInstant.dwAIFlag, AIFLAG_NOMOVE))
  5922. {
  5923. if (pkChr->IsPC())
  5924. {
  5925. if (!GetParty() || !GetParty()->GetLeader() || GetParty()->GetLeader() == this)
  5926. {
  5927. if (get_dword_time() - m_pkMobInst->m_dwLastAttackedTime >= 15000)
  5928. {
  5929. if (m_pkMobData->m_table.wAttackRange < DISTANCE_APPROX(pkChr->GetX() - GetX(), pkChr->GetY() - GetY()))
  5930. if (Return())
  5931. return true;
  5932. }
  5933. }
  5934. }
  5935.  
  5936. return false;
  5937. }
  5938.  
  5939. long x = pkChr->GetX();
  5940. long y = pkChr->GetY();
  5941.  
  5942. if (pkChr->IsPC())
  5943. {
  5944. if (!GetParty() || !GetParty()->GetLeader() || GetParty()->GetLeader() == this)
  5945. {
  5946. if (get_dword_time() - m_pkMobInst->m_dwLastAttackedTime >= 15000)
  5947. {
  5948. if (5000 < DISTANCE_APPROX(m_pkMobInst->m_posLastAttacked.x - GetX(), m_pkMobInst->m_posLastAttacked.y - GetY()))
  5949. if (Return())
  5950. return true;
  5951. }
  5952. }
  5953. }
  5954.  
  5955. if (IsGuardNPC())
  5956. {
  5957. if (5000 < DISTANCE_APPROX(m_pkMobInst->m_posLastAttacked.x - GetX(), m_pkMobInst->m_posLastAttacked.y - GetY()))
  5958. if (Return())
  5959. return true;
  5960. }
  5961.  
  5962. if (pkChr->IsState(pkChr->m_stateMove) && GetMobBattleType() != BATTLE_TYPE_RANGE && GetMobBattleType() != BATTLE_TYPE_MAGIC && false == IsPet())
  5963. {
  5964. float rot = pkChr->GetRotation();
  5965. float rot_delta = GetDegreeDelta(rot, GetDegreeFromPositionXY(GetX(), GetY(), pkChr->GetX(), pkChr->GetY()));
  5966.  
  5967. float yourSpeed = pkChr->GetMoveSpeed();
  5968. float mySpeed = GetMoveSpeed();
  5969.  
  5970. float fDist = DISTANCE_SQRT(x - GetX(), y - GetY());
  5971. float fFollowSpeed = mySpeed - yourSpeed * cos(rot_delta * M_PI / 180);
  5972.  
  5973. if (fFollowSpeed >= 0.1f)
  5974. {
  5975. float fMeetTime = fDist / fFollowSpeed;
  5976. float fYourMoveEstimateX, fYourMoveEstimateY;
  5977.  
  5978. if( fMeetTime * yourSpeed <= 100000.0f )
  5979. {
  5980. GetDeltaByDegree(pkChr->GetRotation(), fMeetTime * yourSpeed, &fYourMoveEstimateX, &fYourMoveEstimateY);
  5981.  
  5982. x += (long) fYourMoveEstimateX;
  5983. y += (long) fYourMoveEstimateY;
  5984.  
  5985. float fDistNew = sqrt(((double)x - GetX())*(x-GetX())+((double)y - GetY())*(y-GetY()));
  5986. if (fDist < fDistNew)
  5987. {
  5988. x = (long)(GetX() + (x - GetX()) * fDist / fDistNew);
  5989. y = (long)(GetY() + (y - GetY()) * fDist / fDistNew);
  5990. }
  5991. }
  5992. }
  5993. }
  5994.  
  5995. SetRotationToXY(x, y);
  5996.  
  5997. float fDist = DISTANCE_SQRT(x - GetX(), y - GetY());
  5998.  
  5999. if (fDist <= fMinDistance)
  6000. return false;
  6001.  
  6002. float fx, fy;
  6003.  
  6004. if (IsChangeAttackPosition(pkChr) && GetMobRank() < MOB_RANK_BOSS)
  6005. {
  6006. SetChangeAttackPositionTime();
  6007.  
  6008. int retry = 16;
  6009. int dx, dy;
  6010. int rot = (int) GetDegreeFromPositionXY(x, y, GetX(), GetY());
  6011.  
  6012. while (--retry)
  6013. {
  6014. if (fDist < 500.0f)
  6015. GetDeltaByDegree((rot + number(-90, 90) + number(-90, 90)) % 360, fMinDistance, &fx, &fy);
  6016. else
  6017. GetDeltaByDegree(number(0, 359), fMinDistance, &fx, &fy);
  6018.  
  6019. dx = x + (int) fx;
  6020. dy = y + (int) fy;
  6021.  
  6022. LPSECTREE tree = SECTREE_MANAGER::instance().Get(GetMapIndex(), dx, dy);
  6023.  
  6024. if (NULL == tree)
  6025. break;
  6026.  
  6027. if (0 == (tree->GetAttribute(dx, dy) & (ATTR_BLOCK | ATTR_OBJECT)))
  6028. break;
  6029. }
  6030.  
  6031. if (!Goto(dx, dy))
  6032. return false;
  6033. }
  6034.  
  6035. else
  6036. {
  6037. float fDistToGo = fDist - fMinDistance;
  6038. GetDeltaByDegree(GetRotation(), fDistToGo, &fx, &fy);
  6039.  
  6040. if (!Goto(GetX() + (int) fx, GetY() + (int) fy))
  6041. return false;
  6042. }
  6043.  
  6044. SendMovePacket(FUNC_WAIT, 0, 0, 0, 0);
  6045.  
  6046. return true;
  6047. }
  6048.  
  6049. float CHARACTER::GetDistanceFromSafeboxOpen() const
  6050. {
  6051. return DISTANCE_APPROX(GetX() - m_posSafeboxOpen.x, GetY() - m_posSafeboxOpen.y);
  6052. }
  6053.  
  6054. void CHARACTER::SetSafeboxOpenPosition()
  6055. {
  6056. m_posSafeboxOpen = GetXYZ();
  6057. }
  6058.  
  6059. CSafebox * CHARACTER::GetSafebox() const
  6060. {
  6061. return m_pkSafebox;
  6062. }
  6063.  
  6064. void CHARACTER::ReqSafeboxLoad(const char* pszPassword)
  6065. {
  6066. if (!*pszPassword || strlen(pszPassword) > SAFEBOX_PASSWORD_MAX_LEN)
  6067. {
  6068. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<창고> 잘못된 암호를 입력하셨습니다."));
  6069. return;
  6070. }
  6071.  
  6072. else if (m_pkSafebox)
  6073. {
  6074. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<창고> 창고가 이미 열려있습니다."));
  6075. return;
  6076. }
  6077.  
  6078. int iPulse = thecore_pulse();
  6079.  
  6080. if (iPulse - GetSafeboxLoadTime() < PASSES_PER_SEC(10))
  6081. {
  6082. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<창고> 창고를 닫은지 10초 안에는 열 수 없습니다."));
  6083. return;
  6084. }
  6085.  
  6086. /*else if (GetDistanceFromSafeboxOpen() > 1000)
  6087. {
  6088. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<창고> 거리가 멀어서 창고를 열 수 없습니다."));
  6089. return;
  6090. }*/
  6091.  
  6092. else if (m_bOpeningSafebox)
  6093. {
  6094. sys_log(0, "Overlapped safebox load request from %s", GetName());
  6095. return;
  6096. }
  6097.  
  6098. SetSafeboxLoadTime();
  6099. m_bOpeningSafebox = true;
  6100.  
  6101. TSafeboxLoadPacket p;
  6102. p.dwID = GetDesc()->GetAccountTable().id;
  6103. strlcpy(p.szLogin, GetDesc()->GetAccountTable().login, sizeof(p.szLogin));
  6104. strlcpy(p.szPassword, pszPassword, sizeof(p.szPassword));
  6105.  
  6106. db_clientdesc->DBPacket(HEADER_GD_SAFEBOX_LOAD, GetDesc()->GetHandle(), &p, sizeof(p));
  6107. }
  6108.  
  6109. void CHARACTER::LoadSafebox(int iSize, DWORD dwGold, int iItemCount, TPlayerItem * pItems)
  6110. {
  6111. bool bLoaded = false;
  6112.  
  6113. SetOpenSafebox(true);
  6114.  
  6115. if (m_pkSafebox)
  6116. bLoaded = true;
  6117.  
  6118. if (!m_pkSafebox)
  6119. m_pkSafebox = M2_NEW CSafebox(this, iSize, dwGold);
  6120. else
  6121. m_pkSafebox->ChangeSize(iSize);
  6122.  
  6123. m_iSafeboxSize = iSize;
  6124.  
  6125. TPacketCGSafeboxSize p;
  6126.  
  6127. p.bHeader = HEADER_GC_SAFEBOX_SIZE;
  6128. p.bSize = iSize;
  6129.  
  6130. GetDesc()->Packet(&p, sizeof(TPacketCGSafeboxSize));
  6131.  
  6132. if (!bLoaded)
  6133. {
  6134. for (int i = 0; i < iItemCount; ++i, ++pItems)
  6135. {
  6136. if (!m_pkSafebox->IsValidPosition(pItems->pos))
  6137. continue;
  6138.  
  6139. LPITEM item = ITEM_MANAGER::instance().CreateItem(pItems->vnum, pItems->count, pItems->id);
  6140.  
  6141. if (!item)
  6142. {
  6143. sys_err("cannot create item vnum %d id %u (name: %s)", pItems->vnum, pItems->id, GetName());
  6144. continue;
  6145. }
  6146.  
  6147. item->SetSkipSave(true);
  6148. item->SetSockets(pItems->alSockets);
  6149. item->SetAttributes(pItems->aAttr);
  6150.  
  6151. if (!m_pkSafebox->Add(pItems->pos, item))
  6152. {
  6153. M2_DESTROY_ITEM(item);
  6154. }
  6155.  
  6156. else
  6157. item->SetSkipSave(false);
  6158. }
  6159. }
  6160. }
  6161.  
  6162. void CHARACTER::ChangeSafeboxSize(BYTE bSize)
  6163. {
  6164. //if (!m_pkSafebox)
  6165. //return;
  6166.  
  6167. TPacketCGSafeboxSize p;
  6168.  
  6169. p.bHeader = HEADER_GC_SAFEBOX_SIZE;
  6170. p.bSize = bSize;
  6171.  
  6172. GetDesc()->Packet(&p, sizeof(TPacketCGSafeboxSize));
  6173.  
  6174. if (m_pkSafebox)
  6175. m_pkSafebox->ChangeSize(bSize);
  6176.  
  6177. m_iSafeboxSize = bSize;
  6178. }
  6179.  
  6180. void CHARACTER::CloseSafebox()
  6181. {
  6182. if (!m_pkSafebox)
  6183. return;
  6184.  
  6185. SetOpenSafebox(false);
  6186.  
  6187. m_pkSafebox->Save();
  6188.  
  6189. M2_DELETE(m_pkSafebox);
  6190. m_pkSafebox = NULL;
  6191.  
  6192. ChatPacket(CHAT_TYPE_COMMAND, "CloseSafebox");
  6193.  
  6194. SetSafeboxLoadTime();
  6195. m_bOpeningSafebox = false;
  6196.  
  6197. Save();
  6198. }
  6199.  
  6200. CSafebox * CHARACTER::GetMall() const
  6201. {
  6202. return m_pkMall;
  6203. }
  6204.  
  6205. void CHARACTER::LoadMall(int iItemCount, TPlayerItem * pItems)
  6206. {
  6207. bool bLoaded = false;
  6208.  
  6209. if (m_pkMall)
  6210. bLoaded = true;
  6211.  
  6212. if (!m_pkMall)
  6213. m_pkMall = M2_NEW CSafebox(this, 3 * SAFEBOX_PAGE_SIZE, 0);
  6214.  
  6215. else
  6216. m_pkMall->ChangeSize(3 * SAFEBOX_PAGE_SIZE);
  6217.  
  6218. m_pkMall->SetWindowMode(MALL);
  6219.  
  6220. TPacketCGSafeboxSize p;
  6221.  
  6222. p.bHeader = HEADER_GC_MALL_OPEN;
  6223. p.bSize = 3 * SAFEBOX_PAGE_SIZE;
  6224.  
  6225. GetDesc()->Packet(&p, sizeof(TPacketCGSafeboxSize));
  6226.  
  6227. if (!bLoaded)
  6228. {
  6229. for (int i = 0; i < iItemCount; ++i, ++pItems)
  6230. {
  6231. if (!m_pkMall->IsValidPosition(pItems->pos))
  6232. continue;
  6233.  
  6234. LPITEM item = ITEM_MANAGER::instance().CreateItem(pItems->vnum, pItems->count, pItems->id);
  6235.  
  6236. if (!item)
  6237. {
  6238. sys_err("cannot create item vnum %d id %u (name: %s)", pItems->vnum, pItems->id, GetName());
  6239. continue;
  6240. }
  6241.  
  6242. item->SetSkipSave(true);
  6243. item->SetSockets(pItems->alSockets);
  6244. item->SetAttributes(pItems->aAttr);
  6245.  
  6246. if (!m_pkMall->Add(pItems->pos, item))
  6247. M2_DESTROY_ITEM(item);
  6248. else
  6249. item->SetSkipSave(false);
  6250. }
  6251. }
  6252. }
  6253.  
  6254. void CHARACTER::CloseMall()
  6255. {
  6256. if (!m_pkMall)
  6257. return;
  6258.  
  6259. m_pkMall->Save();
  6260.  
  6261. M2_DELETE(m_pkMall);
  6262. m_pkMall = NULL;
  6263.  
  6264. ChatPacket(CHAT_TYPE_COMMAND, "CloseMall");
  6265. }
  6266.  
  6267. bool CHARACTER::BuildUpdatePartyPacket(TPacketGCPartyUpdate & out)
  6268. {
  6269. if (!GetParty())
  6270. return false;
  6271.  
  6272. memset(&out, 0, sizeof(out));
  6273.  
  6274. out.header = HEADER_GC_PARTY_UPDATE;
  6275. out.pid = GetPlayerID();
  6276.  
  6277. if (GetMaxHP() <= 0)
  6278. out.percent_hp = 0;
  6279. else
  6280. out.percent_hp = MINMAX(0, GetHP() * 100 / GetMaxHP(), 100);
  6281.  
  6282. out.role = GetParty()->GetRole(GetPlayerID());
  6283.  
  6284. sys_log(1, "PARTY %s role is %d", GetName(), out.role);
  6285.  
  6286. LPCHARACTER l = GetParty()->GetLeaderCharacter();
  6287.  
  6288. if (l && DISTANCE_APPROX(GetX() - l->GetX(), GetY() - l->GetY()) < PARTY_DEFAULT_RANGE)
  6289. {
  6290. out.affects[0] = GetParty()->GetPartyBonusExpPercent();
  6291. out.affects[1] = GetPoint(POINT_PARTY_ATTACKER_BONUS);
  6292. out.affects[2] = GetPoint(POINT_PARTY_TANKER_BONUS);
  6293. out.affects[3] = GetPoint(POINT_PARTY_BUFFER_BONUS);
  6294. out.affects[4] = GetPoint(POINT_PARTY_SKILL_MASTER_BONUS);
  6295. out.affects[5] = GetPoint(POINT_PARTY_HASTE_BONUS);
  6296. out.affects[6] = GetPoint(POINT_PARTY_DEFENDER_BONUS);
  6297. }
  6298.  
  6299. return true;
  6300. }
  6301.  
  6302. int CHARACTER::GetLeadershipSkillLevel() const
  6303. {
  6304. return GetSkillLevel(SKILL_LEADERSHIP);
  6305. }
  6306.  
  6307. void CHARACTER::QuerySafeboxSize()
  6308. {
  6309. if (m_iSafeboxSize == -1)
  6310. {
  6311. DBManager::instance().ReturnQuery(QID_SAFEBOX_SIZE,
  6312. GetPlayerID(),
  6313. NULL,
  6314. "SELECT size FROM safebox%s WHERE account_id = %u",
  6315. get_table_postfix(),
  6316. GetDesc()->GetAccountTable().id);
  6317. }
  6318. }
  6319.  
  6320. void CHARACTER::SetSafeboxSize(int iSize)
  6321. {
  6322. sys_log(1, "SetSafeboxSize: %s %d", GetName(), iSize);
  6323. m_iSafeboxSize = iSize;
  6324. DBManager::instance().Query("UPDATE safebox%s SET size = %d WHERE account_id = %u", get_table_postfix(), iSize / SAFEBOX_PAGE_SIZE, GetDesc()->GetAccountTable().id);
  6325. }
  6326.  
  6327. int CHARACTER::GetSafeboxSize() const
  6328. {
  6329. return m_iSafeboxSize;
  6330. }
  6331.  
  6332. void CHARACTER::SetNowWalking(bool bWalkFlag)
  6333. {
  6334. //if (m_bNowWalking != bWalkFlag || IsNPC())
  6335. if (m_bNowWalking != bWalkFlag)
  6336. {
  6337. if (bWalkFlag)
  6338. {
  6339. m_bNowWalking = true;
  6340. m_dwWalkStartTime = get_dword_time();
  6341. }
  6342.  
  6343. else
  6344. {
  6345. m_bNowWalking = false;
  6346. }
  6347.  
  6348. //if (m_bNowWalking)
  6349. {
  6350. TPacketGCWalkMode p;
  6351. p.vid = GetVID();
  6352. p.header = HEADER_GC_WALK_MODE;
  6353. p.mode = m_bNowWalking ? WALKMODE_WALK : WALKMODE_RUN;
  6354.  
  6355. PacketView(&p, sizeof(p));
  6356. }
  6357.  
  6358. if (IsNPC())
  6359. {
  6360. if (m_bNowWalking)
  6361. MonsterLog("걷는다");
  6362. else
  6363. MonsterLog("뛴다");
  6364. }
  6365.  
  6366. //sys_log(0, "%s is now %s", GetName(), m_bNowWalking?"walking.":"running.");
  6367. }
  6368. }
  6369.  
  6370. void CHARACTER::StartStaminaConsume()
  6371. {
  6372. if (m_bStaminaConsume)
  6373. return;
  6374.  
  6375. PointChange(POINT_STAMINA, 0);
  6376. m_bStaminaConsume = true;
  6377.  
  6378. //ChatPacket(CHAT_TYPE_COMMAND, "StartStaminaConsume %d %d", STAMINA_PER_STEP * passes_per_sec, GetStamina());
  6379.  
  6380. if (IsStaminaHalfConsume())
  6381. ChatPacket(CHAT_TYPE_COMMAND, "StartStaminaConsume %d %d", STAMINA_PER_STEP * passes_per_sec / 2, GetStamina());
  6382. else
  6383. ChatPacket(CHAT_TYPE_COMMAND, "StartStaminaConsume %d %d", STAMINA_PER_STEP * passes_per_sec, GetStamina());
  6384. }
  6385.  
  6386. void CHARACTER::StopStaminaConsume()
  6387. {
  6388. if (!m_bStaminaConsume)
  6389. return;
  6390.  
  6391. PointChange(POINT_STAMINA, 0);
  6392. m_bStaminaConsume = false;
  6393. ChatPacket(CHAT_TYPE_COMMAND, "StopStaminaConsume %d", GetStamina());
  6394. }
  6395.  
  6396. bool CHARACTER::IsStaminaConsume() const
  6397. {
  6398. return m_bStaminaConsume;
  6399. }
  6400.  
  6401. bool CHARACTER::IsStaminaHalfConsume() const
  6402. {
  6403. return IsEquipUniqueItem(UNIQUE_ITEM_HALF_STAMINA);
  6404. }
  6405.  
  6406. void CHARACTER::ResetStopTime()
  6407. {
  6408. m_dwStopTime = get_dword_time();
  6409. }
  6410.  
  6411. DWORD CHARACTER::GetStopTime() const
  6412. {
  6413. return m_dwStopTime;
  6414. }
  6415.  
  6416. void CHARACTER::ResetPoint(int iLv)
  6417. {
  6418. BYTE bJob = GetJob();
  6419.  
  6420. PointChange(POINT_LEVEL, iLv - GetLevel());
  6421.  
  6422. SetRealPoint(POINT_ST, JobInitialPoints[bJob].st);
  6423. SetPoint(POINT_ST, GetRealPoint(POINT_ST));
  6424.  
  6425. SetRealPoint(POINT_HT, JobInitialPoints[bJob].ht);
  6426. SetPoint(POINT_HT, GetRealPoint(POINT_HT));
  6427.  
  6428. SetRealPoint(POINT_DX, JobInitialPoints[bJob].dx);
  6429. SetPoint(POINT_DX, GetRealPoint(POINT_DX));
  6430.  
  6431. SetRealPoint(POINT_IQ, JobInitialPoints[bJob].iq);
  6432. SetPoint(POINT_IQ, GetRealPoint(POINT_IQ));
  6433.  
  6434. SetRandomHP((iLv - 1) * number(JobInitialPoints[GetJob()].hp_per_lv_begin, JobInitialPoints[GetJob()].hp_per_lv_end));
  6435. SetRandomSP((iLv - 1) * number(JobInitialPoints[GetJob()].sp_per_lv_begin, JobInitialPoints[GetJob()].sp_per_lv_end));
  6436.  
  6437. //PointChange(POINT_STAT, ((MINMAX(1, iLv, 90) - 1) * 3) + GetPoint(POINT_LEVEL_STEP) - GetPoint(POINT_STAT));
  6438.  
  6439. if(iLv <= 90)
  6440. PointChange(POINT_STAT, ((MINMAX(1, iLv, 90) - 1) * 3) + GetPoint(POINT_LEVEL_STEP) - GetPoint(POINT_STAT));
  6441. else
  6442. PointChange(POINT_STAT, 270 - GetPoint(POINT_STAT));
  6443.  
  6444. ComputePoints();
  6445.  
  6446. PointChange(POINT_HP, GetMaxHP() - GetHP());
  6447. PointChange(POINT_SP, GetMaxSP() - GetSP());
  6448.  
  6449. PointsPacket();
  6450.  
  6451. LogManager::instance().CharLog(this, 0, "RESET_POINT", "");
  6452. }
  6453.  
  6454. bool CHARACTER::IsChangeAttackPosition(LPCHARACTER target) const
  6455. {
  6456. if (!IsNPC())
  6457. return true;
  6458.  
  6459. DWORD dwChangeTime = AI_CHANGE_ATTACK_POISITION_TIME_NEAR;
  6460.  
  6461. if (DISTANCE_APPROX(GetX() - target->GetX(), GetY() - target->GetY()) >
  6462. AI_CHANGE_ATTACK_POISITION_DISTANCE + GetMobAttackRange())
  6463. dwChangeTime = AI_CHANGE_ATTACK_POISITION_TIME_FAR;
  6464.  
  6465. return get_dword_time() - m_dwLastChangeAttackPositionTime > dwChangeTime;
  6466. }
  6467.  
  6468. void CHARACTER::GiveRandomSkillBook()
  6469. {
  6470. LPITEM item = AutoGiveItem(50300);
  6471.  
  6472. if (NULL != item)
  6473. {
  6474. BYTE bJob = 0;
  6475.  
  6476. if (!number(0, 1))
  6477. bJob = GetJob() + 1;
  6478.  
  6479. DWORD dwSkillVnum = 0;
  6480.  
  6481. do
  6482. {
  6483. dwSkillVnum = number(1, 111);
  6484. const CSkillProto* pkSk = CSkillManager::instance().Get(dwSkillVnum);
  6485.  
  6486. if (NULL == pkSk)
  6487. continue;
  6488.  
  6489. if (bJob && bJob != pkSk->dwType)
  6490. continue;
  6491.  
  6492. break;
  6493.  
  6494. } while (true);
  6495.  
  6496. item->SetSocket(0, dwSkillVnum);
  6497. }
  6498. }
  6499.  
  6500. void CHARACTER::ReviveInvisible(int iDur)
  6501. {
  6502. AddAffect(AFFECT_REVIVE_INVISIBLE, POINT_NONE, 0, AFF_REVIVE_INVISIBLE, iDur, 0, true);
  6503. }
  6504.  
  6505. void CHARACTER::ToggleMonsterLog()
  6506. {
  6507. m_bMonsterLog = !m_bMonsterLog;
  6508.  
  6509. if (m_bMonsterLog)
  6510. {
  6511. CHARACTER_MANAGER::instance().RegisterForMonsterLog(this);
  6512. }
  6513.  
  6514. else
  6515. {
  6516. CHARACTER_MANAGER::instance().UnregisterForMonsterLog(this);
  6517. }
  6518. }
  6519.  
  6520. void CHARACTER::SetGuild(CGuild* pGuild)
  6521. {
  6522. if (m_pGuild != pGuild)
  6523. {
  6524. m_pGuild = pGuild;
  6525. UpdatePacket();
  6526. }
  6527. }
  6528.  
  6529. void CHARACTER::BeginStateEmpty()
  6530. {
  6531. MonsterLog("!");
  6532. }
  6533.  
  6534. void CHARACTER::EffectPacket(int enumEffectType)
  6535. {
  6536. TPacketGCSpecialEffect p;
  6537.  
  6538. p.header = HEADER_GC_SEPCIAL_EFFECT;
  6539. p.type = enumEffectType;
  6540. p.vid = GetVID();
  6541.  
  6542. PacketAround(&p, sizeof(TPacketGCSpecialEffect));
  6543. }
  6544.  
  6545. void CHARACTER::SpecificEffectPacket(const char filename[MAX_EFFECT_FILE_NAME])
  6546. {
  6547. TPacketGCSpecificEffect p;
  6548.  
  6549. p.header = HEADER_GC_SPECIFIC_EFFECT;
  6550. p.vid = GetVID();
  6551. memcpy (p.effect_file, filename, MAX_EFFECT_FILE_NAME);
  6552.  
  6553. PacketAround(&p, sizeof(TPacketGCSpecificEffect));
  6554. }
  6555.  
  6556. void CHARACTER::MonsterChat(BYTE bMonsterChatType)
  6557. {
  6558. if (IsPC())
  6559. return;
  6560.  
  6561. char sbuf[256+1];
  6562.  
  6563. if (IsMonster())
  6564. {
  6565. if (number(0, 60))
  6566. return;
  6567.  
  6568. snprintf(sbuf, sizeof(sbuf), "(locale.monster_chat[%i] and locale.monster_chat[%i][%d] or '')",
  6569.  
  6570. GetRaceNum(), GetRaceNum(), bMonsterChatType*3 + number(1, 3));
  6571. }
  6572. else
  6573. {
  6574. if (bMonsterChatType != MONSTER_CHAT_WAIT)
  6575. return;
  6576.  
  6577. if (IsGuardNPC())
  6578. {
  6579. if (number(0, 6))
  6580. return;
  6581. }
  6582.  
  6583. else
  6584. {
  6585. if (number(0, 30))
  6586. return;
  6587. }
  6588.  
  6589. snprintf(sbuf, sizeof(sbuf), "(locale.monster_chat[%i] and locale.monster_chat[%i][number(1, table.getn(locale.monster_chat[%i]))] or '')", GetRaceNum(), GetRaceNum(), GetRaceNum());
  6590. }
  6591.  
  6592. std::string text = quest::ScriptToString(sbuf);
  6593.  
  6594. if (text.empty())
  6595. return;
  6596.  
  6597. struct packet_chat pack_chat;
  6598.  
  6599. pack_chat.header = HEADER_GC_CHAT;
  6600. pack_chat.size = sizeof(struct packet_chat) + text.size() + 1;
  6601. pack_chat.type = CHAT_TYPE_TALKING;
  6602. pack_chat.id = GetVID();
  6603. pack_chat.bEmpire = 0;
  6604.  
  6605. TEMP_BUFFER buf;
  6606. buf.write(&pack_chat, sizeof(struct packet_chat));
  6607. buf.write(text.c_str(), text.size() + 1);
  6608.  
  6609. PacketAround(buf.read_peek(), buf.size());
  6610. }
  6611.  
  6612. void CHARACTER::SetQuestNPCID(DWORD vid)
  6613. {
  6614. m_dwQuestNPCVID = vid;
  6615. }
  6616.  
  6617. LPCHARACTER CHARACTER::GetQuestNPC() const
  6618. {
  6619. return CHARACTER_MANAGER::instance().Find(m_dwQuestNPCVID);
  6620. }
  6621.  
  6622. void CHARACTER::SetQuestItemPtr(LPITEM item)
  6623. {
  6624. m_pQuestItem = item;
  6625. }
  6626.  
  6627. void CHARACTER::ClearQuestItemPtr()
  6628. {
  6629. m_pQuestItem = NULL;
  6630. }
  6631.  
  6632. LPITEM CHARACTER::GetQuestItemPtr() const
  6633. {
  6634. return m_pQuestItem;
  6635. }
  6636.  
  6637. LPDUNGEON CHARACTER::GetDungeonForce() const
  6638. {
  6639. if (m_lWarpMapIndex > 10000)
  6640. return CDungeonManager::instance().FindByMapIndex(m_lWarpMapIndex);
  6641.  
  6642. return m_pkDungeon;
  6643. }
  6644.  
  6645. void CHARACTER::SetBlockMode(BYTE bFlag)
  6646. {
  6647. m_pointsInstant.bBlockMode = bFlag;
  6648.  
  6649. ChatPacket(CHAT_TYPE_COMMAND, "setblockmode %d", m_pointsInstant.bBlockMode);
  6650.  
  6651. SetQuestFlag("game_option.block_exchange", bFlag & BLOCK_EXCHANGE ? 1 : 0);
  6652. SetQuestFlag("game_option.block_party_invite", bFlag & BLOCK_PARTY_INVITE ? 1 : 0);
  6653. SetQuestFlag("game_option.block_guild_invite", bFlag & BLOCK_GUILD_INVITE ? 1 : 0);
  6654. SetQuestFlag("game_option.block_whisper", bFlag & BLOCK_WHISPER ? 1 : 0);
  6655. SetQuestFlag("game_option.block_messenger_invite", bFlag & BLOCK_MESSENGER_INVITE ? 1 : 0);
  6656. SetQuestFlag("game_option.block_party_request", bFlag & BLOCK_PARTY_REQUEST ? 1 : 0);
  6657.  
  6658. #ifdef __VIEW_EQUIP__
  6659. SetQuestFlag("game_option.block_view_equipment", bFlag & BLOCK_VIEW_EQUIPMENT ? 1 : 0);
  6660. #endif
  6661.  
  6662. }
  6663.  
  6664. void CHARACTER::SetBlockModeForce(BYTE bFlag)
  6665. {
  6666. m_pointsInstant.bBlockMode = bFlag;
  6667. ChatPacket(CHAT_TYPE_COMMAND, "setblockmode %d", m_pointsInstant.bBlockMode);
  6668. }
  6669.  
  6670. bool CHARACTER::IsGuardNPC() const
  6671. {
  6672. return IsNPC() && (GetRaceNum() == 11000 || GetRaceNum() == 11002 || GetRaceNum() == 11004);
  6673. }
  6674.  
  6675. int CHARACTER::GetPolymorphPower() const
  6676. {
  6677. if (test_server)
  6678. {
  6679. int value = quest::CQuestManager::instance().GetEventFlag("poly");
  6680. if (value)
  6681. return value;
  6682. }
  6683.  
  6684. return aiPolymorphPowerByLevel[MINMAX(0, GetSkillLevel(SKILL_POLYMORPH), 40)];
  6685. }
  6686.  
  6687. void CHARACTER::SetPolymorph(DWORD dwRaceNum, bool bMaintainStat)
  6688. {
  6689. if (dwRaceNum < JOB_MAX_NUM)
  6690. {
  6691. dwRaceNum = 0;
  6692. bMaintainStat = false;
  6693. }
  6694.  
  6695. if (m_dwPolymorphRace == dwRaceNum)
  6696. return;
  6697.  
  6698. m_bPolyMaintainStat = bMaintainStat;
  6699. m_dwPolymorphRace = dwRaceNum;
  6700.  
  6701. sys_log(0, "POLYMORPH: %s race %u ", GetName(), dwRaceNum);
  6702.  
  6703. if (dwRaceNum != 0)
  6704. StopRiding();
  6705.  
  6706. SET_BIT(m_bAddChrState, ADD_CHARACTER_STATE_SPAWN);
  6707. m_afAffectFlag.Set(AFF_SPAWN);
  6708.  
  6709. ViewReencode();
  6710.  
  6711. REMOVE_BIT(m_bAddChrState, ADD_CHARACTER_STATE_SPAWN);
  6712.  
  6713. if (!bMaintainStat)
  6714. {
  6715. PointChange(POINT_ST, 0);
  6716. PointChange(POINT_DX, 0);
  6717. PointChange(POINT_IQ, 0);
  6718. PointChange(POINT_HT, 0);
  6719. }
  6720.  
  6721. SetValidComboInterval(0);
  6722. SetComboSequence(0);
  6723.  
  6724. ComputeBattlePoints();
  6725. }
  6726.  
  6727. int CHARACTER::GetQuestFlag(const std::string& flag) const
  6728. {
  6729. quest::CQuestManager& q = quest::CQuestManager::instance();
  6730. quest::PC* pPC = q.GetPC(GetPlayerID());
  6731. if(!pPC)
  6732. {
  6733. // sys_err("Nullpointer in CHARACTER::GetQuestFlag %lu", GetPlayerID());
  6734. return 0;
  6735. }
  6736.  
  6737. return pPC->GetFlag(flag);
  6738. }
  6739.  
  6740. void CHARACTER::SetQuestFlag(const std::string& flag, int value)
  6741. {
  6742. quest::CQuestManager& q = quest::CQuestManager::instance();
  6743. quest::PC* pPC = q.GetPC(GetPlayerID());
  6744. if(!pPC)
  6745. {
  6746. // sys_err("Nullpointer in CHARACTER::GetQuestFlag %lu", GetPlayerID());
  6747. return;
  6748. }
  6749.  
  6750. pPC->SetFlag(flag, value);
  6751. }
  6752.  
  6753. void CHARACTER::DetermineDropMetinStone()
  6754. {
  6755. const int METIN_STONE_NUM = 14;
  6756. static DWORD c_adwMetin[METIN_STONE_NUM] =
  6757. {
  6758. 28030,
  6759. 28031,
  6760. 28032,
  6761. 28033,
  6762. 28034,
  6763. 28035,
  6764. 28036,
  6765. 28037,
  6766. 28038,
  6767. 28039,
  6768. 28040,
  6769. 28041,
  6770. 28042,
  6771. 28043,
  6772. };
  6773.  
  6774. DWORD stone_num = GetRaceNum();
  6775. int idx = std::lower_bound(aStoneDrop, aStoneDrop+STONE_INFO_MAX_NUM, stone_num) - aStoneDrop;
  6776.  
  6777. if (idx >= STONE_INFO_MAX_NUM || aStoneDrop[idx].dwMobVnum != stone_num)
  6778. {
  6779. m_dwDropMetinStone = 0;
  6780. }
  6781.  
  6782. else
  6783. {
  6784. const SStoneDropInfo & info = aStoneDrop[idx];
  6785. m_bDropMetinStonePct = info.iDropPct;
  6786. {
  6787. m_dwDropMetinStone = c_adwMetin[number(0, METIN_STONE_NUM - 1)];
  6788. int iGradePct = number(1, 100);
  6789.  
  6790. for (int iStoneLevel = 0; iStoneLevel < STONE_LEVEL_MAX_NUM; iStoneLevel ++)
  6791. {
  6792. int iLevelGradePortion = info.iLevelPct[iStoneLevel];
  6793. if (iGradePct <= iLevelGradePortion)
  6794. {
  6795. break;
  6796. }
  6797.  
  6798. else
  6799. {
  6800. iGradePct -= iLevelGradePortion;
  6801. m_dwDropMetinStone += 100;
  6802. }
  6803. }
  6804. }
  6805. }
  6806. }
  6807.  
  6808. #ifdef __VIEW_EQUIP__
  6809. void CHARACTER::SendEquipment(LPCHARACTER ch)
  6810. {
  6811. TPacketViewEquip p;
  6812. p.header = HEADER_GC_VIEW_EQUIP;
  6813. p.vid = GetVID();
  6814.  
  6815. int pos[26] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33};
  6816.  
  6817. for (int i = 0; i < 26; i++)
  6818. {
  6819. LPITEM item = GetWear(pos[i]);
  6820. if (item)
  6821. {
  6822. p.equips[i].vnum = item->GetVnum();
  6823. p.equips[i].count = item->GetCount();
  6824.  
  6825. thecore_memcpy(p.equips[i].alSockets, item->GetSockets(), sizeof(p.equips[i].alSockets));
  6826. thecore_memcpy(p.equips[i].aAttr, item->GetAttributes(), sizeof(p.equips[i].aAttr));
  6827. }
  6828.  
  6829. else
  6830. {
  6831. p.equips[i].vnum = 0;
  6832. }
  6833. }
  6834.  
  6835. ch->GetDesc()->Packet(&p, sizeof(p));
  6836.  
  6837. }
  6838. #else
  6839. void CHARACTER::SendEquipment(LPCHARACTER ch)
  6840. {
  6841. TPacketViewEquip p;
  6842. p.header = HEADER_GC_VIEW_EQUIP;
  6843. p.vid = GetVID();
  6844. for (int i = 0; i<WEAR_MAX_NUM; i++)
  6845. {
  6846. LPITEM item = GetWear(i);
  6847. if (item)
  6848. {
  6849. p.equips[i].vnum = item->GetVnum();
  6850. p.equips[i].count = item->GetCount();
  6851.  
  6852. thecore_memcpy(p.equips[i].alSockets, item->GetSockets(), sizeof(p.equips[i].alSockets));
  6853. thecore_memcpy(p.equips[i].aAttr, item->GetAttributes(), sizeof(p.equips[i].aAttr));
  6854. }
  6855.  
  6856. else
  6857. {
  6858. p.equips[i].vnum = 0;
  6859. }
  6860. }
  6861.  
  6862. ch->GetDesc()->Packet(&p, sizeof(p));
  6863. }
  6864. #endif
  6865.  
  6866. bool CHARACTER::CanSummon(int iLeaderShip)
  6867. {
  6868. return ((iLeaderShip >= 20) || ((iLeaderShip >= 12) && ((m_dwLastDeadTime + 180) > get_dword_time())));
  6869. }
  6870.  
  6871. void CHARACTER::MountVnum(DWORD vnum)
  6872. {
  6873. if (m_dwMountVnum == vnum)
  6874. return;
  6875.  
  6876. if ((m_dwMountVnum != 0)&&(vnum!=0))
  6877. MountVnum(0);
  6878.  
  6879. m_dwMountVnum = vnum;
  6880. m_dwMountTime = get_dword_time();
  6881.  
  6882. if (m_bIsObserver)
  6883. return;
  6884.  
  6885. m_posDest.x = m_posStart.x = GetX();
  6886. m_posDest.y = m_posStart.y = GetY();
  6887.  
  6888. EncodeInsertPacket(this);
  6889.  
  6890. ENTITY_MAP::iterator it = m_map_view.begin();
  6891.  
  6892. while (it != m_map_view.end())
  6893. {
  6894. LPENTITY entity = (it++)->first;
  6895.  
  6896. //EncodeRemovePacket(entity);
  6897. //if (!m_bIsObserver)
  6898. EncodeInsertPacket(entity);
  6899.  
  6900. //if (!entity->IsObserverMode())
  6901. // entity->EncodeInsertPacket(this);
  6902. }
  6903.  
  6904. SetValidComboInterval(0);
  6905. SetComboSequence(0);
  6906.  
  6907. ComputePoints();
  6908. }
  6909.  
  6910. namespace {
  6911. class FuncCheckWarp
  6912. {
  6913. public:
  6914. FuncCheckWarp(LPCHARACTER pkWarp)
  6915. {
  6916. m_lTargetY = 0;
  6917. m_lTargetX = 0;
  6918.  
  6919. m_lX = pkWarp->GetX();
  6920. m_lY = pkWarp->GetY();
  6921.  
  6922. m_bInvalid = false;
  6923. m_bEmpire = pkWarp->GetEmpire();
  6924.  
  6925. char szTmp[64];
  6926.  
  6927. if (3 != sscanf(pkWarp->GetName(), " %s %ld %ld ", szTmp, &m_lTargetX, &m_lTargetY))
  6928. {
  6929. if (number(1, 100) < 5)
  6930. sys_err("Warp NPC name wrong : vnum(%d) name(%s)", pkWarp->GetRaceNum(), pkWarp->GetName());
  6931.  
  6932. m_bInvalid = true;
  6933.  
  6934. return;
  6935. }
  6936.  
  6937. m_lTargetX *= 100;
  6938. m_lTargetY *= 100;
  6939.  
  6940. m_bUseWarp = true;
  6941.  
  6942. if (pkWarp->IsGoto())
  6943. {
  6944. LPSECTREE_MAP pkSectreeMap = SECTREE_MANAGER::instance().GetMap(pkWarp->GetMapIndex());
  6945. m_lTargetX += pkSectreeMap->m_setting.iBaseX;
  6946. m_lTargetY += pkSectreeMap->m_setting.iBaseY;
  6947. m_bUseWarp = false;
  6948. }
  6949. }
  6950.  
  6951. bool Valid()
  6952. {
  6953. return !m_bInvalid;
  6954. }
  6955.  
  6956. void operator () (LPENTITY ent)
  6957. {
  6958. if (!Valid())
  6959. return;
  6960.  
  6961. if (!ent->IsType(ENTITY_CHARACTER))
  6962. return;
  6963.  
  6964. LPCHARACTER pkChr = (LPCHARACTER) ent;
  6965.  
  6966. if (!pkChr->IsPC())
  6967. return;
  6968.  
  6969. int iDist = DISTANCE_APPROX(pkChr->GetX() - m_lX, pkChr->GetY() - m_lY);
  6970.  
  6971. if (iDist > 300)
  6972. return;
  6973.  
  6974. if (m_bEmpire && pkChr->GetEmpire() && m_bEmpire != pkChr->GetEmpire())
  6975. return;
  6976.  
  6977. if (pkChr->IsHack())
  6978. return;
  6979.  
  6980. if (!pkChr->CanHandleItem(false, true))
  6981. return;
  6982.  
  6983. if (m_bUseWarp)
  6984. pkChr->WarpSet(m_lTargetX, m_lTargetY);
  6985.  
  6986. else
  6987. {
  6988. pkChr->Show(pkChr->GetMapIndex(), m_lTargetX, m_lTargetY);
  6989. pkChr->Stop();
  6990. }
  6991. }
  6992.  
  6993. bool m_bInvalid;
  6994. bool m_bUseWarp;
  6995.  
  6996. long m_lX;
  6997. long m_lY;
  6998. long m_lTargetX;
  6999. long m_lTargetY;
  7000.  
  7001. BYTE m_bEmpire;
  7002. };
  7003. }
  7004.  
  7005. EVENTFUNC(warp_npc_event)
  7006. {
  7007. char_event_info* info = dynamic_cast<char_event_info*>( event->info );
  7008. if ( info == NULL )
  7009. {
  7010. sys_err( "warp_npc_event> <Factor> Null pointer" );
  7011. return 0;
  7012. }
  7013.  
  7014. LPCHARACTER ch = info->ch;
  7015.  
  7016. if (ch == NULL)
  7017. {
  7018. return 0;
  7019. }
  7020.  
  7021. if (!ch->GetSectree())
  7022. {
  7023. ch->m_pkWarpNPCEvent = NULL;
  7024. return 0;
  7025. }
  7026.  
  7027. FuncCheckWarp f(ch);
  7028. if (f.Valid())
  7029. ch->GetSectree()->ForEachAround(f);
  7030.  
  7031. return passes_per_sec / 2;
  7032. }
  7033.  
  7034. void CHARACTER::StartWarpNPCEvent()
  7035. {
  7036. if (m_pkWarpNPCEvent)
  7037. return;
  7038.  
  7039. if (!IsWarp() && !IsGoto())
  7040. return;
  7041.  
  7042. char_event_info* info = AllocEventInfo<char_event_info>();
  7043.  
  7044. info->ch = this;
  7045.  
  7046. m_pkWarpNPCEvent = event_create(warp_npc_event, info, passes_per_sec / 2);
  7047. }
  7048.  
  7049. void CHARACTER::SyncPacket()
  7050. {
  7051. TEMP_BUFFER buf;
  7052.  
  7053. TPacketCGSyncPositionElement elem;
  7054.  
  7055. elem.dwVID = GetVID();
  7056. elem.lX = GetX();
  7057. elem.lY = GetY();
  7058.  
  7059. TPacketGCSyncPosition pack;
  7060.  
  7061. pack.bHeader = HEADER_GC_SYNC_POSITION;
  7062. pack.wSize = sizeof(TPacketGCSyncPosition) + sizeof(elem);
  7063.  
  7064. buf.write(&pack, sizeof(pack));
  7065. buf.write(&elem, sizeof(elem));
  7066.  
  7067. PacketAround(buf.read_peek(), buf.size());
  7068. }
  7069.  
  7070. LPCHARACTER CHARACTER::GetMarryPartner() const
  7071. {
  7072. return m_pkChrMarried;
  7073. }
  7074.  
  7075. void CHARACTER::SetMarryPartner(LPCHARACTER ch)
  7076. {
  7077. m_pkChrMarried = ch;
  7078. }
  7079.  
  7080. #ifdef SET_LEVEL_FIRST_LOGIN
  7081. void CHARACTER::FirstLogin()
  7082. {
  7083. if (!GetQuestFlag("start.first_login"))
  7084. {
  7085. ResetPoint(MINMAX(1, 99, PLAYER_MAX_LEVEL_CONST)); /* Aici schimbi acel 99 cu nivelul pe care vrei sa il primeasca playerii la prima logare pe server */
  7086. SetQuestFlag("start.first_login", 1);
  7087. }
  7088. }
  7089. #endif
  7090.  
  7091. int CHARACTER::GetMarriageBonus(DWORD dwItemVnum, bool bSum)
  7092. {
  7093. if (IsNPC())
  7094. return 0;
  7095.  
  7096. marriage::TMarriage* pMarriage = marriage::CManager::instance().Get(GetPlayerID());
  7097.  
  7098. if (!pMarriage)
  7099. return 0;
  7100.  
  7101. return pMarriage->GetBonus(dwItemVnum, bSum, this);
  7102. }
  7103.  
  7104. void CHARACTER::ConfirmWithMsg(const char* szMsg, int iTimeout, DWORD dwRequestPID)
  7105. {
  7106. if (!IsPC())
  7107. return;
  7108.  
  7109. TPacketGCQuestConfirm p;
  7110.  
  7111. p.header = HEADER_GC_QUEST_CONFIRM;
  7112. p.requestPID = dwRequestPID;
  7113. p.timeout = iTimeout;
  7114. strlcpy(p.msg, szMsg, sizeof(p.msg));
  7115.  
  7116. GetDesc()->Packet(&p, sizeof(p));
  7117. }
  7118.  
  7119. int CHARACTER::GetPremiumRemainSeconds(BYTE bType) const
  7120. {
  7121. if (bType >= PREMIUM_MAX_NUM)
  7122. return 0;
  7123.  
  7124. return m_aiPremiumTimes[bType] - get_global_time();
  7125. }
  7126.  
  7127. bool CHARACTER::WarpToPID(DWORD dwPID)
  7128. {
  7129. LPCHARACTER victim;
  7130. if ((victim = (CHARACTER_MANAGER::instance().FindByPID(dwPID))))
  7131. {
  7132. int mapIdx = victim->GetMapIndex();
  7133. if (IS_SUMMONABLE_ZONE(mapIdx))
  7134. {
  7135. if (CAN_ENTER_ZONE(this, mapIdx))
  7136. {
  7137. WarpSet(victim->GetX(), victim->GetY());
  7138. }
  7139.  
  7140. else
  7141. {
  7142. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("상대방이 있는 곳으로 워프할 수 없습니다."));
  7143. return false;
  7144. }
  7145. }
  7146.  
  7147. else
  7148. {
  7149. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("상대방이 있는 곳으로 워프할 수 없습니다."));
  7150. return false;
  7151. }
  7152. }
  7153.  
  7154. else
  7155. {
  7156. CCI * pcci = P2P_MANAGER::instance().FindByPID(dwPID);
  7157.  
  7158. if (!pcci)
  7159. {
  7160. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("상대방이 온라인 상태가 아닙니다."));
  7161. return false;
  7162. }
  7163.  
  7164. if (pcci->bChannel != g_bChannel)
  7165. {
  7166. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("상대방이 %d 채널에 있습니다. (현재 채널 %d)"), pcci->bChannel, g_bChannel);
  7167. return false;
  7168. }
  7169.  
  7170. else if (false == IS_SUMMONABLE_ZONE(pcci->lMapIndex))
  7171. {
  7172. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("상대방이 있는 곳으로 워프할 수 없습니다."));
  7173. return false;
  7174. }
  7175.  
  7176. else
  7177. {
  7178. if (!CAN_ENTER_ZONE(this, pcci->lMapIndex))
  7179. {
  7180. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("상대방이 있는 곳으로 워프할 수 없습니다."));
  7181. return false;
  7182. }
  7183.  
  7184. TPacketGGFindPosition p;
  7185. p.header = HEADER_GG_FIND_POSITION;
  7186. p.dwFromPID = GetPlayerID();
  7187. p.dwTargetPID = dwPID;
  7188. pcci->pkDesc->Packet(&p, sizeof(TPacketGGFindPosition));
  7189.  
  7190. if (test_server)
  7191. ChatPacket(CHAT_TYPE_PARTY, "sent find position packet for teleport");
  7192. }
  7193. }
  7194.  
  7195. return true;
  7196. }
  7197.  
  7198. CGuild* CHARACTER::GetRefineGuild() const
  7199. {
  7200. LPCHARACTER chRefineNPC = CHARACTER_MANAGER::instance().Find(m_dwRefineNPCVID);
  7201.  
  7202. return (chRefineNPC ? chRefineNPC->GetGuild() : NULL);
  7203. }
  7204.  
  7205. bool CHARACTER::IsRefineThroughGuild() const
  7206. {
  7207. return GetRefineGuild() != NULL;
  7208. }
  7209.  
  7210. int CHARACTER::ComputeRefineFee(int iCost, int iMultiply) const
  7211. {
  7212. CGuild* pGuild = GetRefineGuild();
  7213. if (pGuild)
  7214. {
  7215. if (pGuild == GetGuild())
  7216. return iCost * iMultiply * 9 / 10;
  7217.  
  7218. LPCHARACTER chRefineNPC = CHARACTER_MANAGER::instance().Find(m_dwRefineNPCVID);
  7219. if (chRefineNPC && chRefineNPC->GetEmpire() != GetEmpire())
  7220. return iCost * iMultiply * 3;
  7221.  
  7222. return iCost * iMultiply;
  7223. }
  7224.  
  7225. else
  7226. return iCost;
  7227. }
  7228.  
  7229. void CHARACTER::PayRefineFee(int iTotalMoney)
  7230. {
  7231. int iFee = iTotalMoney / 10;
  7232. CGuild* pGuild = GetRefineGuild();
  7233.  
  7234. int iRemain = iTotalMoney;
  7235.  
  7236. if (pGuild)
  7237. {
  7238. if (pGuild != GetGuild())
  7239. {
  7240. pGuild->RequestDepositMoney(this, iFee);
  7241. iRemain -= iFee;
  7242. }
  7243. }
  7244.  
  7245. PointChange(POINT_GOLD, -iRemain);
  7246. }
  7247.  
  7248. bool CHARACTER::IsHack(bool bSendMsg, bool bCheckShopOwner, int limittime)
  7249. {
  7250. const int iPulse = thecore_pulse();
  7251.  
  7252. if (test_server)
  7253. bSendMsg = true;
  7254.  
  7255. if (iPulse - GetSafeboxLoadTime() < PASSES_PER_SEC(limittime))
  7256. {
  7257. if (bSendMsg)
  7258. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("창고를 연후 %d초 이내에는 다른곳으로 이동할수 없습니다."), limittime);
  7259.  
  7260. if (test_server)
  7261. ChatPacket(CHAT_TYPE_INFO, "[TestOnly]Pulse %d LoadTime %d PASS %d", iPulse, GetSafeboxLoadTime(), PASSES_PER_SEC(limittime));
  7262.  
  7263. return true;
  7264. }
  7265.  
  7266. if (bCheckShopOwner)
  7267. {
  7268. if (GetExchange() || GetMyShop() || GetShopOwner() || IsOpenSafebox() || IsCubeOpen())
  7269. {
  7270. if (bSendMsg)
  7271. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("거래창,창고 등을 연 상태에서는 다른곳으로 이동,종료 할수 없습니다"));
  7272.  
  7273. return true;
  7274. }
  7275. }
  7276.  
  7277. else
  7278. {
  7279. if (GetExchange() || GetMyShop() || IsOpenSafebox() || IsCubeOpen())
  7280. {
  7281. if (bSendMsg)
  7282. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("거래창,창고 등을 연 상태에서는 다른곳으로 이동,종료 할수 없습니다"));
  7283.  
  7284. return true;
  7285. }
  7286. }
  7287.  
  7288. if (iPulse - GetExchangeTime() < PASSES_PER_SEC(limittime))
  7289. {
  7290. if (bSendMsg)
  7291. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("거래 후 %d초 이내에는 다른지역으로 이동 할 수 없습니다."), limittime );
  7292.  
  7293. return true;
  7294. }
  7295.  
  7296. if (iPulse - GetMyShopTime() < PASSES_PER_SEC(limittime))
  7297. {
  7298. if (bSendMsg)
  7299. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("거래 후 %d초 이내에는 다른지역으로 이동 할 수 없습니다."), limittime);
  7300.  
  7301. return true;
  7302. }
  7303.  
  7304. if (iPulse - GetRefineTime() < PASSES_PER_SEC(limittime))
  7305. {
  7306. if (bSendMsg)
  7307. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("아이템 개량후 %d초 이내에는 귀환부,귀환기억부를 사용할 수 없습니다."), limittime);
  7308.  
  7309. return true;
  7310. }
  7311.  
  7312. return false;
  7313. }
  7314.  
  7315. void CHARACTER::Say(const std::string & s)
  7316. {
  7317. struct ::packet_script packet_script;
  7318.  
  7319. packet_script.header = HEADER_GC_SCRIPT;
  7320. packet_script.skin = 1;
  7321. packet_script.src_size = s.size();
  7322. packet_script.size = packet_script.src_size + sizeof(struct packet_script);
  7323.  
  7324. TEMP_BUFFER buf;
  7325.  
  7326. buf.write(&packet_script, sizeof(struct packet_script));
  7327. buf.write(&s[0], s.size());
  7328.  
  7329. if (IsPC())
  7330. {
  7331. GetDesc()->Packet(buf.read_peek(), buf.size());
  7332. }
  7333. }
  7334.  
  7335. void CHARACTER::UpdateDepositPulse()
  7336. {
  7337. m_deposit_pulse = thecore_pulse() + PASSES_PER_SEC(60*5);
  7338. }
  7339.  
  7340. bool CHARACTER::CanDeposit() const
  7341. {
  7342. return (m_deposit_pulse == 0 || (m_deposit_pulse < thecore_pulse()));
  7343. }
  7344.  
  7345. ESex GET_SEX(LPCHARACTER ch)
  7346. {
  7347. switch (ch->GetRaceNum())
  7348. {
  7349. case MAIN_RACE_WARRIOR_M:
  7350. case MAIN_RACE_SURA_M:
  7351. case MAIN_RACE_ASSASSIN_M:
  7352. case MAIN_RACE_SHAMAN_M:
  7353. return SEX_MALE;
  7354.  
  7355. case MAIN_RACE_ASSASSIN_W:
  7356. case MAIN_RACE_SHAMAN_W:
  7357. case MAIN_RACE_WARRIOR_W:
  7358. case MAIN_RACE_SURA_W:
  7359. return SEX_FEMALE;
  7360. }
  7361.  
  7362. /* default sex = male */
  7363. return SEX_MALE;
  7364. }
  7365.  
  7366. int CHARACTER::GetHPPct() const
  7367. {
  7368. if (GetMaxHP() <= 0)
  7369. return 0;
  7370.  
  7371. return (GetHP() * 100) / GetMaxHP();
  7372. }
  7373.  
  7374. bool CHARACTER::IsBerserk() const
  7375. {
  7376. if (m_pkMobInst != NULL)
  7377. return m_pkMobInst->m_IsBerserk;
  7378. else
  7379. return false;
  7380. }
  7381.  
  7382. void CHARACTER::SetBerserk(bool mode)
  7383. {
  7384. if (m_pkMobInst != NULL)
  7385. m_pkMobInst->m_IsBerserk = mode;
  7386. }
  7387.  
  7388. bool CHARACTER::IsGodSpeed() const
  7389. {
  7390. if (m_pkMobInst != NULL)
  7391. {
  7392. return m_pkMobInst->m_IsGodSpeed;
  7393. }
  7394.  
  7395. else
  7396. {
  7397. return false;
  7398. }
  7399. }
  7400.  
  7401. void CHARACTER::SetGodSpeed(bool mode)
  7402. {
  7403. if (m_pkMobInst != NULL)
  7404. {
  7405. m_pkMobInst->m_IsGodSpeed = mode;
  7406.  
  7407. if (mode == true)
  7408. {
  7409. SetPoint(POINT_ATT_SPEED, 250);
  7410. }
  7411.  
  7412. else
  7413. {
  7414. SetPoint(POINT_ATT_SPEED, m_pkMobData->m_table.sAttackSpeed);
  7415. }
  7416. }
  7417. }
  7418.  
  7419. bool CHARACTER::IsDeathBlow() const
  7420. {
  7421. if (number(1, 100) <= m_pkMobData->m_table.bDeathBlowPoint)
  7422. {
  7423. return true;
  7424. }
  7425.  
  7426. else
  7427. {
  7428. return false;
  7429. }
  7430. }
  7431.  
  7432. struct FFindReviver
  7433. {
  7434. FFindReviver()
  7435. {
  7436. pChar = NULL;
  7437. HasReviver = false;
  7438. }
  7439.  
  7440. void operator() (LPCHARACTER ch)
  7441. {
  7442. if (ch->IsMonster() != true)
  7443. {
  7444. return;
  7445. }
  7446.  
  7447. if (ch->IsReviver() == true && pChar != ch && ch->IsDead() != true)
  7448. {
  7449. if (number(1, 100) <= ch->GetMobTable().bRevivePoint)
  7450. {
  7451. HasReviver = true;
  7452. pChar = ch;
  7453. }
  7454. }
  7455. }
  7456.  
  7457. LPCHARACTER pChar;
  7458. bool HasReviver;
  7459. };
  7460.  
  7461. bool CHARACTER::HasReviverInParty() const
  7462. {
  7463. LPPARTY party = GetParty();
  7464.  
  7465. if (party != NULL)
  7466. {
  7467. if (party->GetMemberCount() == 1) return false;
  7468.  
  7469. FFindReviver f;
  7470. party->ForEachMemberPtr(f);
  7471.  
  7472. return f.HasReviver;
  7473. }
  7474.  
  7475. return false;
  7476. }
  7477.  
  7478. bool CHARACTER::IsRevive() const
  7479. {
  7480. if (m_pkMobInst != NULL)
  7481. {
  7482. return m_pkMobInst->m_IsRevive;
  7483. }
  7484.  
  7485. return false;
  7486. }
  7487.  
  7488. void CHARACTER::SetRevive(bool mode)
  7489. {
  7490. if (m_pkMobInst != NULL)
  7491. {
  7492. m_pkMobInst->m_IsRevive = mode;
  7493. }
  7494. }
  7495.  
  7496. #define IS_SPEED_HACK_PLAYER(ch) (ch->m_speed_hack_count > SPEEDHACK_LIMIT_COUNT)
  7497.  
  7498. EVENTFUNC(check_speedhack_event)
  7499. {
  7500. char_event_info* info = dynamic_cast<char_event_info*>( event->info );
  7501. if ( info == NULL )
  7502. {
  7503. sys_err( "check_speedhack_event> <Factor> Null pointer" );
  7504. return 0;
  7505. }
  7506.  
  7507. LPCHARACTER ch = info->ch;
  7508.  
  7509. if (NULL == ch || ch->IsNPC())
  7510. return 0;
  7511.  
  7512. if (IS_SPEED_HACK_PLAYER(ch))
  7513. {
  7514. LogManager::instance().SpeedHackLog(ch->GetPlayerID(), ch->GetX(), ch->GetY(), ch->m_speed_hack_count);
  7515. }
  7516.  
  7517. ch->m_speed_hack_count = 0;
  7518.  
  7519. ch->ResetComboHackCount();
  7520.  
  7521. return PASSES_PER_SEC(60);
  7522. }
  7523.  
  7524. void CHARACTER::StartCheckSpeedHackEvent()
  7525. {
  7526. if (m_pkCheckSpeedHackEvent)
  7527. return;
  7528.  
  7529. char_event_info* info = AllocEventInfo<char_event_info>();
  7530.  
  7531. info->ch = this;
  7532.  
  7533. m_pkCheckSpeedHackEvent = event_create(check_speedhack_event, info, PASSES_PER_SEC(60)); // 1분
  7534. }
  7535.  
  7536. void CHARACTER::GoHome()
  7537. {
  7538. WarpSet(EMPIRE_START_X(GetEmpire()), EMPIRE_START_Y(GetEmpire()));
  7539. }
  7540.  
  7541. void CHARACTER::SendGuildName(CGuild* pGuild)
  7542. {
  7543. if (NULL == pGuild) return;
  7544.  
  7545. DESC *desc = GetDesc();
  7546.  
  7547. if (NULL == desc) return;
  7548. if (m_known_guild.find(pGuild->GetID()) != m_known_guild.end()) return;
  7549.  
  7550. m_known_guild.insert(pGuild->GetID());
  7551.  
  7552. TPacketGCGuildName pack;
  7553. memset(&pack, 0x00, sizeof(pack));
  7554.  
  7555. pack.header = HEADER_GC_GUILD;
  7556. pack.subheader = GUILD_SUBHEADER_GC_GUILD_NAME;
  7557. pack.size = sizeof(TPacketGCGuildName);
  7558. pack.guildID = pGuild->GetID();
  7559. memcpy(pack.guildName, pGuild->GetName(), GUILD_NAME_MAX_LEN);
  7560.  
  7561. desc->Packet(&pack, sizeof(pack));
  7562. }
  7563.  
  7564. void CHARACTER::SendGuildName(DWORD dwGuildID)
  7565. {
  7566. SendGuildName(CGuildManager::instance().FindGuild(dwGuildID));
  7567. }
  7568.  
  7569. EVENTFUNC(destroy_when_idle_event)
  7570. {
  7571. char_event_info* info = dynamic_cast<char_event_info*>( event->info );
  7572. if ( info == NULL )
  7573. {
  7574. sys_err( "destroy_when_idle_event> <Factor> Null pointer" );
  7575. return 0;
  7576. }
  7577.  
  7578. LPCHARACTER ch = info->ch;
  7579. if (ch == NULL)
  7580. {
  7581. return 0;
  7582. }
  7583.  
  7584. if (ch->GetVictim())
  7585. {
  7586. return PASSES_PER_SEC(300);
  7587. }
  7588.  
  7589. sys_log(1, "DESTROY_WHEN_IDLE: %s", ch->GetName());
  7590.  
  7591. ch->m_pkDestroyWhenIdleEvent = NULL;
  7592. M2_DESTROY_CHARACTER(ch);
  7593.  
  7594. return 0;
  7595. }
  7596.  
  7597. void CHARACTER::StartDestroyWhenIdleEvent()
  7598. {
  7599. if (m_pkDestroyWhenIdleEvent)
  7600. return;
  7601.  
  7602. char_event_info* info = AllocEventInfo<char_event_info>();
  7603.  
  7604. info->ch = this;
  7605.  
  7606. m_pkDestroyWhenIdleEvent = event_create(destroy_when_idle_event, info, PASSES_PER_SEC(300));
  7607. }
  7608.  
  7609. void CHARACTER::SetComboSequence(BYTE seq)
  7610. {
  7611. m_bComboSequence = seq;
  7612. }
  7613.  
  7614. BYTE CHARACTER::GetComboSequence() const
  7615. {
  7616. return m_bComboSequence;
  7617. }
  7618.  
  7619. void CHARACTER::SetLastComboTime(DWORD time)
  7620. {
  7621. m_dwLastComboTime = time;
  7622. }
  7623.  
  7624. DWORD CHARACTER::GetLastComboTime() const
  7625. {
  7626. return m_dwLastComboTime;
  7627. }
  7628.  
  7629. void CHARACTER::SetValidComboInterval(int interval)
  7630. {
  7631. m_iValidComboInterval = interval;
  7632. }
  7633.  
  7634. int CHARACTER::GetValidComboInterval() const
  7635. {
  7636. return m_iValidComboInterval;
  7637. }
  7638.  
  7639. BYTE CHARACTER::GetComboIndex() const
  7640. {
  7641. return m_bComboIndex;
  7642. }
  7643.  
  7644. void CHARACTER::IncreaseComboHackCount(int k)
  7645. {
  7646. m_iComboHackCount += k;
  7647.  
  7648. if (m_iComboHackCount >= 10)
  7649. {
  7650. if (GetDesc())
  7651. if (GetDesc()->DelayedDisconnect(number(2, 7)))
  7652. {
  7653. sys_log(0, "COMBO_HACK_DISCONNECT: %s count: %d", GetName(), m_iComboHackCount);
  7654. LogManager::instance().HackLog("Combo", this);
  7655. }
  7656. }
  7657. }
  7658.  
  7659. void CHARACTER::ResetComboHackCount()
  7660. {
  7661. m_iComboHackCount = 0;
  7662. }
  7663.  
  7664. void CHARACTER::SkipComboAttackByTime(int interval)
  7665. {
  7666. m_dwSkipComboAttackByTime = get_dword_time() + interval;
  7667. }
  7668.  
  7669. DWORD CHARACTER::GetSkipComboAttackByTime() const
  7670. {
  7671. return m_dwSkipComboAttackByTime;
  7672. }
  7673.  
  7674. void CHARACTER::ResetChatCounter()
  7675. {
  7676. m_bChatCounter = 0;
  7677. }
  7678.  
  7679. BYTE CHARACTER::IncreaseChatCounter()
  7680. {
  7681. return ++m_bChatCounter;
  7682. }
  7683.  
  7684. BYTE CHARACTER::GetChatCounter() const
  7685. {
  7686. return m_bChatCounter;
  7687. }
  7688.  
  7689. bool CHARACTER::IsRiding() const
  7690. {
  7691. return IsHorseRiding() || GetMountVnum();
  7692. }
  7693.  
  7694. void CHARACTER::RefreshBonusDuel()
  7695. {
  7696. ComputePoints();
  7697. PointsPacket();
  7698. UpdatePacket();
  7699. }
  7700.  
  7701. void CHARACTER::SetDuel(const char* type, int value)
  7702. {
  7703. if (!strcmp(type, "IsFight"))
  7704. {
  7705. SetQuestFlag("pvp.IsFight", value);
  7706. }
  7707. }
  7708.  
  7709. void CHARACTER::DestroyPvP()
  7710. {
  7711. if (GetDesc() != NULL)
  7712. {
  7713. int isDuel = GetQuestFlag("pvp.IsFight");
  7714.  
  7715. if (isDuel != 0)
  7716. {
  7717. SetQuestFlag("pvp.IsFight", 0);
  7718. }
  7719. }
  7720. }
  7721.  
  7722. #ifdef __TITLE_SYSTEM__
  7723. void CHARACTER::SetTitle(int iTitle, BYTE bValue)
  7724. {
  7725. assert(iTitle < TITLES_MAX_NUM);
  7726.  
  7727. int iNewTitle = POINT_TITLE + iTitle;
  7728.  
  7729. if (bValue > 0)
  7730. {
  7731. SetPoint(iNewTitle, 1);
  7732.  
  7733. sys_log(0, "|cFF00ff33[Title Info] > |h|r %s has just learn the title %d .", GetName(), iTitle);
  7734. }
  7735.  
  7736. else
  7737. {
  7738. SetPoint(iNewTitle, 0);
  7739.  
  7740. sys_log(0, "|cFF00ff33[Title Info] > |h|r %s has just unlearn the title %d .", GetName(), iTitle);
  7741. }
  7742.  
  7743. ComputePoints();
  7744. PointsPacket();
  7745. }
  7746.  
  7747. bool CHARACTER::GetTitle(int iTitle)
  7748. {
  7749. assert(iTitle < TITLES_MAX_NUM);
  7750.  
  7751. int iNewTitle = POINT_TITLE + iTitle;
  7752. bool _to_return = false;
  7753.  
  7754. if (GetPoint(iNewTitle) == 1)
  7755. _to_return = true;
  7756.  
  7757. return _to_return;
  7758. }
  7759.  
  7760. bool CHARACTER::ChooseTitle(int iTitle)
  7761. {
  7762. assert(iTitle < TITLES_MAX_NUM);
  7763.  
  7764. int iNewTitle = POINT_TITLE + iTitle;
  7765. bool _to_return = false;
  7766.  
  7767. if ((iTitle == 0) || (GetPoint(iNewTitle) == 1 && iNewTitle != POINT_TITLE))
  7768. _to_return = true;
  7769.  
  7770. if (_to_return)
  7771. {
  7772. SetPoint(POINT_TITLE, iTitle);
  7773. sys_log(0, "|cFF00ff33[Title Info] > |h|r %s has just choose to have the title %d .", GetName(), iTitle);
  7774. }
  7775.  
  7776. ComputePoints();
  7777. PointsPacket();
  7778. UpdatePacket();
  7779.  
  7780. return _to_return;
  7781. }
  7782.  
  7783. void CHARACTER::pChooseTitle(int iTitle)
  7784. {
  7785. BYTE bAnswer = 0;
  7786.  
  7787. bool bPass = false;
  7788. int iNewTitle = POINT_TITLE + iTitle;
  7789.  
  7790. if (iTitle >= TITLES_MAX_NUM || iTitle < 1)
  7791. {
  7792. bAnswer = 1;
  7793. bPass = true;
  7794. }
  7795.  
  7796. else if (iTitle == ChoosedTitle())
  7797. {
  7798. bAnswer = 2;
  7799. bPass = true;
  7800. }
  7801.  
  7802. else if (GetPoint(iNewTitle) != 1)
  7803. {
  7804. bAnswer = 3;
  7805. bPass = true;
  7806. }
  7807.  
  7808. else
  7809. bAnswer = 4;
  7810.  
  7811. if (iTitle == 0)
  7812. {
  7813. if (GetPoint(iNewTitle) != 0)
  7814. {
  7815. bAnswer = 4;
  7816. bPass = false;
  7817. }
  7818.  
  7819. else
  7820. {
  7821. bAnswer = 2;
  7822. bPass = true;
  7823. }
  7824. }
  7825.  
  7826. if (!bPass)
  7827. bPass = ChooseTitle(iTitle);
  7828.  
  7829. TPacketGGTitleInfo p;
  7830.  
  7831. p.bHeader = HEADER_GG_TITLE_ANSWER;
  7832. p.iTitle = iTitle;
  7833. p.bAnswer = bAnswer;
  7834.  
  7835. GetDesc()->Packet(&p, sizeof(TPacketGGTitleInfo));
  7836. }
  7837.  
  7838. int CHARACTER::ChoosedTitle()
  7839. {
  7840. int iChoosed = GetPoint(POINT_TITLE);
  7841. return iChoosed;
  7842. }
  7843.  
  7844. void CHARACTER::EquipTitle(LPITEM item)
  7845. {
  7846. DWORD iTitle = item->GetValue(1);
  7847. SetPoint(POINT_TITLE, iTitle);
  7848. ComputePoints();
  7849. PointsPacket();
  7850. UpdatePacket();
  7851. }
  7852.  
  7853. void CHARACTER::UnequipTitle(LPITEM item)
  7854. {
  7855. SetPoint(POINT_TITLE, 0);
  7856. ComputePoints();
  7857. PointsPacket();
  7858. UpdatePacket();
  7859. }
  7860.  
  7861. void CHARACTER::CheckTitle()
  7862. {
  7863. LPITEM item = GetWear(WEAR_ITEM_NORMAL_TITLE);
  7864. DWORD iTitle = item->GetValue(1);
  7865. SetPoint(POINT_TITLE, iTitle);
  7866. }
  7867.  
  7868. #endif
  7869.  
  7870. #ifdef ENABLE_HIDE_COSTUME_SYSTEM
  7871. int CHARACTER::GetSlotsCostume()
  7872. {
  7873. int slot_default = 1;
  7874.  
  7875. #ifdef ENABLE_HIDE_COSTUME_SYSTEM_ACCE
  7876. slot_default += 1;
  7877. #endif
  7878.  
  7879. #ifdef ENABLE_HIDE_COSTUME_SYSTEM_WEAPON_COSTUME
  7880. slot_default += 1;
  7881. #endif
  7882.  
  7883. return slot_default;
  7884. }
  7885.  
  7886. int CHARACTER::GetSlotDefault(int slot)
  7887. {
  7888. int slot_amor = 0;
  7889. int slot_hair = 1;
  7890. int slot_weapon = 2;
  7891. int slot_acce = 3;
  7892.  
  7893. if(slot == 0){return slot_amor;}
  7894. if(slot == 1){return slot_hair;}
  7895. if(slot == 2){return slot_weapon;}
  7896. if(slot == 3){return slot_acce;}
  7897.  
  7898. return 0;
  7899. }
  7900.  
  7901. void CHARACTER::FuncHideCostume(int slot)
  7902. {
  7903.  
  7904. if (slot <0 || slot > GetSlotsCostume())
  7905. return;
  7906.  
  7907. int part_value = 0;
  7908. int part_acce = 0;
  7909.  
  7910. bool bAdd = false;
  7911.  
  7912. char costume_hide[1024];
  7913.  
  7914. snprintf(costume_hide, sizeof(costume_hide), "hide_costume_w.hide_costume_%d", slot);
  7915.  
  7916. const CItem* pArmor;
  7917. const CItem * pWeapon;
  7918.  
  7919. LPITEM pkItem;
  7920.  
  7921. if(slot == GetSlotDefault(0))
  7922. {
  7923. pkItem = GetWear(WEAR_COSTUME_BODY);
  7924. if(!pkItem)
  7925. return;
  7926.  
  7927. if (GetQuestFlag(costume_hide) == 0)
  7928. {
  7929. SetQuestFlag(costume_hide,1);
  7930. pArmor = GetWear(WEAR_BODY);
  7931. }
  7932.  
  7933. else
  7934. {
  7935. SetQuestFlag(costume_hide,0);
  7936. pArmor = GetWear(WEAR_COSTUME_BODY);
  7937. }
  7938.  
  7939. #ifdef ENABLE_HIDE_COSTUME_SYSTEM_TRANSMUTACION
  7940. if (NULL != pArmor)
  7941. {
  7942. if (pArmor->GetTransmutation() > 0)
  7943. {
  7944. part_value = pArmor->GetTransmutation();
  7945. }
  7946.  
  7947. else
  7948. {
  7949. part_value = pArmor->GetVnum();
  7950. }
  7951.  
  7952. }
  7953.  
  7954. else
  7955. {
  7956. part_value = GetOriginalPart(PART_MAIN);
  7957. }
  7958. #else
  7959. part_value = (NULL != pArmor) ? pArmor->GetVnum() : GetOriginalPart(PART_MAIN);
  7960. #endif
  7961.  
  7962. SetPart(PART_MAIN, part_value);
  7963. }
  7964.  
  7965. else if(slot == GetSlotDefault(1))
  7966. {
  7967.  
  7968. pkItem = GetWear(WEAR_COSTUME_HAIR);
  7969. if(!pkItem)
  7970. return;
  7971.  
  7972. if (GetQuestFlag(costume_hide) == 0)
  7973. {
  7974. SetQuestFlag(costume_hide,1);
  7975. bAdd = false;
  7976. }
  7977.  
  7978. else
  7979. {
  7980. SetQuestFlag(costume_hide,0);
  7981. bAdd = true;
  7982. }
  7983.  
  7984. LPITEM pkItem = GetWear(WEAR_COSTUME_HAIR);
  7985. if (pkItem)
  7986. {
  7987. #ifdef ENABLE_HIDE_COSTUME_SYSTEM_TRANSMUTACION
  7988. if (pkItem->GetTransmutation() > 0)
  7989. {
  7990. TItemTable * pHair = ITEM_MANAGER::instance().GetTable(pkItem->GetTransmutation());
  7991. if (!pHair)
  7992. {
  7993. part_value = (true == bAdd) ? pkItem->GetValue(3) : 0;
  7994. }
  7995.  
  7996. else
  7997. {
  7998. part_value = (true == bAdd) ? pHair->alValues[3] : 0;
  7999. }
  8000.  
  8001. }
  8002.  
  8003. else
  8004. {
  8005. part_value = (true == bAdd) ? pkItem->GetValue(3) : 0;
  8006. }
  8007. #else
  8008. part_value = (true == bAdd) ? pkItem->GetValue(3) : 0;
  8009. #endif
  8010. }
  8011.  
  8012. else
  8013. {
  8014. part_value = 0;
  8015. }
  8016.  
  8017. SetPart(PART_HAIR, part_value);
  8018. }
  8019.  
  8020. #ifdef ENABLE_HIDE_COSTUME_SYSTEM_ACCE
  8021. else if(slot == GetSlotDefault(3))
  8022. {
  8023. pkItem = GetWear(WEAR_COSTUME_ACCE);
  8024. if(!pkItem)
  8025. return;
  8026.  
  8027. if (GetQuestFlag(costume_hide) == 0)
  8028. {
  8029. SetQuestFlag(costume_hide,1);
  8030. bAdd = false;
  8031. }
  8032.  
  8033. else
  8034. {
  8035. SetQuestFlag(costume_hide,0);
  8036. bAdd = true;
  8037. }
  8038.  
  8039. if (pkItem){
  8040. part_value = pkItem->GetVnum();
  8041. part_value -= 85000;
  8042.  
  8043. if (pkItem->GetSocket(ACCE_ABSORPTION_SOCKET) >= ACCE_EFFECT_FROM_ABS)
  8044. {
  8045. part_value += 2000;
  8046. }
  8047.  
  8048. part_value = (bAdd == true) ? part_value : 0;
  8049. }
  8050.  
  8051. SetPart(PART_ACCE, part_value);
  8052. }
  8053. #endif
  8054.  
  8055. #ifdef ENABLE_HIDE_COSTUME_SYSTEM_WEAPON_COSTUME
  8056. else if(slot == GetSlotDefault(2))
  8057. {
  8058.  
  8059. pkItem = GetWear(WEAR_COSTUME_WEAPON);
  8060. if(!pkItem)
  8061. return;
  8062.  
  8063. if (GetQuestFlag(costume_hide) == 0)
  8064. {
  8065. SetQuestFlag(costume_hide,1);
  8066. pWeapon = GetWear(WEAR_WEAPON);
  8067. }
  8068.  
  8069. else
  8070. {
  8071. SetQuestFlag(costume_hide,0);
  8072. pWeapon = GetWear(WEAR_COSTUME_WEAPON);
  8073. }
  8074.  
  8075. if (NULL != pWeapon)
  8076. {
  8077. #ifdef ENABLE_HIDE_COSTUME_SYSTEM_TRANSMUTACION
  8078. if (pWeapon->GetTransmutation() > 0)
  8079. {
  8080. part_value = pWeapon->GetTransmutation();
  8081. }
  8082.  
  8083. else
  8084. {
  8085. part_value = pWeapon->GetVnum();
  8086. }
  8087. #else
  8088. part_value = pWeapon->GetVnum();
  8089. #endif
  8090. }
  8091.  
  8092. else
  8093. {
  8094. part_value = GetOriginalPart(PART_WEAPON);
  8095. }
  8096.  
  8097. SetPart(PART_WEAPON, part_value);
  8098. }
  8099. #endif
  8100.  
  8101. FuncHideCostumeLoad();
  8102. UpdatePacket();
  8103.  
  8104. }
  8105.  
  8106. void CHARACTER::FuncHideCostumeLoad()
  8107. {
  8108. char costume_hide[1024];
  8109. ChatPacket(CHAT_TYPE_COMMAND,"COSTUME_HIDE_CLEAR");
  8110.  
  8111. for (int i = 0; i < GetSlotsCostume()+1; ++i)
  8112. {
  8113. snprintf(costume_hide, sizeof(costume_hide), "hide_costume_w.hide_costume_%d", i);
  8114. ChatPacket(CHAT_TYPE_COMMAND,"COSTUME_HIDE_LIST %d %d",i,GetQuestFlag(costume_hide));
  8115. }
  8116.  
  8117. ChatPacket(CHAT_TYPE_COMMAND,"COSTUME_HIDE_LOAD");
  8118. }
  8119.  
  8120. void CHARACTER::SetHideCostumeUpdate()
  8121. {
  8122. CItem* body_costume = GetWear(WEAR_COSTUME_BODY);
  8123.  
  8124. #ifdef ENABLE_HIDE_COSTUME_SYSTEM_ACCE
  8125. CItem* acce_costume = GetWear(WEAR_COSTUME_ACCE);
  8126. #endif
  8127. CItem* hair_costume = GetWear(WEAR_COSTUME_HAIR);
  8128.  
  8129. #ifdef ENABLE_HIDE_COSTUME_SYSTEM_WEAPON_COSTUME
  8130. CItem* weapon_costume = GetWear(WEAR_COSTUME_WEAPON);
  8131. #endif
  8132.  
  8133. if (GetHideCostume(GetSlotDefault(0)) == 1)
  8134. {
  8135. CItem* body_armor = GetWear(WEAR_BODY);
  8136.  
  8137. if (body_costume)
  8138. {
  8139. if (body_armor)
  8140. {
  8141.  
  8142. #ifdef ENABLE_HIDE_COSTUME_SYSTEM_TRANSMUTACION
  8143. if (body_armor->GetTransmutation() > 0)
  8144. {
  8145. SetPart(PART_MAIN, body_armor->GetTransmutation());
  8146. }
  8147.  
  8148. else
  8149. {
  8150. SetPart(PART_MAIN, body_armor->GetVnum());
  8151. }
  8152. #else
  8153. SetPart(PART_MAIN, body_armor->GetVnum());
  8154. #endif
  8155. }
  8156.  
  8157. else
  8158. {
  8159. SetPart(PART_MAIN, GetOriginalPart(PART_MAIN));
  8160. }
  8161. }
  8162. }
  8163.  
  8164. if (GetHideCostume(GetSlotDefault(1)) == 1)
  8165. {
  8166. if (hair_costume){
  8167. SetPart(PART_HAIR, 0);
  8168. }
  8169. }
  8170.  
  8171. #ifdef ENABLE_HIDE_COSTUME_SYSTEM_ACCE
  8172. if (GetHideCostume(GetSlotDefault(3)) == 1)
  8173. {
  8174. if (acce_costume)
  8175. {
  8176. SetPart(PART_ACCE, 0);
  8177. }
  8178. }
  8179. #endif
  8180.  
  8181. #ifdef ENABLE_HIDE_COSTUME_SYSTEM_WEAPON_COSTUME
  8182. if (GetHideCostume(GetSlotDefault(2)) == 1)
  8183. {
  8184. CItem* body_weapon = GetWear(WEAR_WEAPON);
  8185.  
  8186. if (weapon_costume)
  8187. {
  8188. if (body_weapon)
  8189. {
  8190. #ifdef ENABLE_HIDE_COSTUME_SYSTEM_TRANSMUTACION
  8191. if (body_weapon->GetTransmutation() > 0)
  8192. {
  8193. SetPart(PART_WEAPON, body_weapon->GetTransmutation());
  8194. }
  8195.  
  8196. else
  8197. {
  8198. SetPart(PART_WEAPON, body_weapon->GetVnum());
  8199. }
  8200. #else
  8201. SetPart(PART_WEAPON, body_weapon->GetVnum());
  8202. #endif
  8203. }
  8204.  
  8205. else
  8206. {
  8207. SetPart(PART_WEAPON, GetOriginalPart(PART_WEAPON));
  8208. }
  8209. }
  8210. }
  8211. #endif
  8212.  
  8213. }
  8214.  
  8215. int CHARACTER::GetHideCostume(int wear) const
  8216. {
  8217. char costume_hide[1024];
  8218. snprintf(costume_hide, sizeof(costume_hide), "hide_costume_w.hide_costume_%d", wear);
  8219.  
  8220. return GetQuestFlag(costume_hide);
  8221. }
  8222. #endif
  8223.  
  8224. #ifdef __EQUIP_RESTRICT_SYSTEM__
  8225. bool CHARACTER::IsEquipRestricted()
  8226. {
  8227. return GetQuestFlag("equip.restricted");
  8228. }
  8229. #endif
  8230.  
  8231. #ifdef ENABLE_SORT_INVEN
  8232. void CHARACTER::SortInven(BYTE option)
  8233. {
  8234. if (IsDead())
  8235. return;
  8236.  
  8237. if (GetLastSortTime() > get_global_time())
  8238. {
  8239. ChatPacket(CHAT_TYPE_INFO, "|cFF00ff33[Sortare Info] > |h|r You need to wait %d sec .", GetLastSortTime() - get_global_time());
  8240. return;
  8241. }
  8242.  
  8243. std::vector<LPITEM> all;
  8244. LPITEM myitems;
  8245. const auto size = static_cast<WORD>(INVENTORY_MAX_NUM);
  8246.  
  8247. for (WORD i = 0; i < size; ++i)
  8248. {
  8249. if (myitems = GetInventoryItem(i))
  8250. {
  8251. all.emplace_back(myitems);
  8252. myitems->RemoveFromCharacter();
  8253. SyncQuickslot(QUICKSLOT_TYPE_ITEM, static_cast<BYTE>(i), 255);
  8254. }
  8255. }
  8256.  
  8257. if (all.empty())
  8258. return;
  8259.  
  8260. std::sort(all.begin(), all.end(), [option](const LPITEM i1, const LPITEM i2)
  8261. {
  8262. switch (option)
  8263. {
  8264. case 2:
  8265. return i1->CustomSort() == i2->CustomSort() ? i1->GetSubType() < i2->GetSubType() : i1->CustomSort() < i2->CustomSort();
  8266.  
  8267. case 3:
  8268. return i1->GetLevelLimit() == i2->GetLevelLimit() ? i1->GetSubType() < i2->GetSubType() : i1->GetLevelLimit() > i2->GetLevelLimit();
  8269.  
  8270. default:
  8271. return std::strcmp(i1->GetName(), i2->GetName()) < 0;
  8272. }
  8273. });
  8274.  
  8275. for (const auto& getitem : all)
  8276. {
  8277. const auto table = ITEM_MANAGER::instance().GetTable(getitem->GetVnum());
  8278.  
  8279. if (!table)
  8280. continue;
  8281.  
  8282. static const std::initializer_list<DWORD> out = { ITEM_AUTO_HP_RECOVERY_S, ITEM_AUTO_HP_RECOVERY_M, ITEM_AUTO_HP_RECOVERY_L, ITEM_AUTO_HP_RECOVERY_X, ITEM_AUTO_SP_RECOVERY_S, ITEM_AUTO_SP_RECOVERY_M, ITEM_AUTO_SP_RECOVERY_L, ITEM_AUTO_SP_RECOVERY_X };
  8283. if (table->dwFlags & ITEM_FLAG_STACKABLE && table->bType != ITEM_BLEND && std::find(out.begin(), out.end(), getitem->GetVnum()) == out.end())
  8284. {
  8285. AutoGiveItem(getitem->GetVnum(), getitem->GetCount(), -1, false);
  8286. M2_DESTROY_ITEM(getitem);
  8287. }
  8288.  
  8289. else
  8290. AutoGiveItem(getitem);
  8291. };
  8292.  
  8293. SetLastSortTime(get_global_time() + 15);
  8294. }
  8295. #endif
  8296.  
  8297. #ifdef ENABLE_COINS_SYSTEM
  8298. #define VOUCHER_NUM 7
  8299.  
  8300. const DWORD cdwVoucherVnum[VOUCHER_NUM] =
  8301. {
  8302. 80000,
  8303. 80001,
  8304. 80002,
  8305. 80003,
  8306. 80004,
  8307. 80005,
  8308. 80006
  8309. };
  8310.  
  8311. const int ciVoucherCountDR[VOUCHER_NUM] =
  8312. {
  8313. 1,
  8314. 5,
  8315. 10,
  8316. 50,
  8317. 100,
  8318. 500,
  8319. 1000
  8320. };
  8321.  
  8322. void CHARACTER::SetCoins(bool bVoucher, int iCoins, DWORD dwVnum)
  8323. {
  8324. int iCount = 0;
  8325.  
  8326. for (int i = 0 ; i < VOUCHER_NUM ; i++)
  8327. {
  8328. if (dwVnum == cdwVoucherVnum[i])
  8329. {
  8330. iCount = ciVoucherCountDR[i];
  8331. break;
  8332. }
  8333. }
  8334.  
  8335. if (iCount == 0 && bVoucher == true)
  8336. return;
  8337.  
  8338. std::unique_ptr<SQLMsg> pMsg(DBManager::Instance().DirectQuery("UPDATE account.account SET coins = coins + '%d' WHERE id = '%d'", bVoucher == true ? iCount : iCoins, GetDesc()->GetAccountTable().id));
  8339. bool bSucc = (pMsg->uiSQLErrno == 0);
  8340.  
  8341. if (bSucc && bVoucher == true)
  8342. {
  8343. ChatPacket(CHAT_TYPE_INFO, "|cFF00ff33[Coins Info] > |h|r You got %ld Dragon Coins .", iCount);
  8344. }
  8345.  
  8346. ChatPacket(CHAT_TYPE_COMMAND, "BINARY_Update_Coins2 %d", GetCoins());
  8347. }
  8348.  
  8349. int CHARACTER::GetCoins()
  8350. {
  8351. int coins = 0;
  8352. char querySelect[256];
  8353.  
  8354. snprintf(querySelect, sizeof(querySelect), "SELECT coins FROM account.account WHERE id = '%u'", GetDesc()->GetAccountTable().id);
  8355.  
  8356. std::unique_ptr<SQLMsg> pSelectMsg(DBManager::instance().DirectQuery(querySelect));
  8357. SQLResult* resSelect = pSelectMsg->Get();
  8358.  
  8359. if (resSelect && resSelect->uiNumRows > 0)
  8360. {
  8361. MYSQL_ROW row = mysql_fetch_row(resSelect->pSQLResult);
  8362. str_to_number(coins, row[0]);
  8363. ChatPacket(CHAT_TYPE_COMMAND, "BINARY_Update_Coins2 %d", coins);
  8364.  
  8365. return coins;
  8366. }
  8367. }
  8368.  
  8369. #define VOUCHER_NUM_JD 7
  8370.  
  8371. const DWORD cdwVoucherVnumjd[VOUCHER_NUM_JD] =
  8372. {
  8373. 80007,
  8374. 80008,
  8375. 80009,
  8376. 80010,
  8377. 80011,
  8378. 80012,
  8379. 80013
  8380. };
  8381.  
  8382. const int ciVoucherCountjd[VOUCHER_NUM_JD] =
  8383. {
  8384. 1,
  8385. 5,
  8386. 10,
  8387. 50,
  8388. 100,
  8389. 500,
  8390. 1000
  8391. };
  8392.  
  8393. void CHARACTER::SetJD(bool bVoucher, int iCoins, DWORD dwVnum)
  8394. {
  8395. int iCount = 0;
  8396.  
  8397. for (int i = 0 ; i < VOUCHER_NUM_JD ; i++)
  8398. {
  8399. if (dwVnum == cdwVoucherVnumjd[i])
  8400. {
  8401. iCount = ciVoucherCountjd[i];
  8402. break;
  8403. }
  8404. }
  8405.  
  8406. if (iCount == 0 && bVoucher == true)
  8407. return;
  8408.  
  8409. std::unique_ptr<SQLMsg> pMsg(DBManager::Instance().DirectQuery("UPDATE account.account SET jcoins = jcoins + '%d' WHERE id = '%d'", bVoucher == true ? iCount : iCoins, GetDesc()->GetAccountTable().id));
  8410. bool bSucc = (pMsg->uiSQLErrno == 0);
  8411.  
  8412. if (bSucc && bVoucher == true)
  8413. {
  8414. ChatPacket(CHAT_TYPE_INFO, "|cFF00ff33[JD Info] > |h|r You got %ld Dragon Jetons .", iCount);
  8415. }
  8416.  
  8417. ChatPacket(CHAT_TYPE_COMMAND, "BINARY_Update_JD2 %d", GetJD());
  8418. }
  8419.  
  8420. int CHARACTER::GetJD()
  8421. {
  8422. int coins = 0;
  8423. char querySelect[256];
  8424.  
  8425. snprintf(querySelect, sizeof(querySelect), "SELECT jcoins FROM account.account WHERE id = '%u'", GetDesc()->GetAccountTable().id);
  8426.  
  8427. std::unique_ptr<SQLMsg> pSelectMsg(DBManager::instance().DirectQuery(querySelect));
  8428. SQLResult* resSelect = pSelectMsg->Get();
  8429.  
  8430. if (resSelect && resSelect->uiNumRows > 0)
  8431. {
  8432. MYSQL_ROW row = mysql_fetch_row(resSelect->pSQLResult);
  8433. str_to_number(coins, row[0]);
  8434. ChatPacket(CHAT_TYPE_COMMAND, "BINARY_Update_JD2 %d", coins);
  8435.  
  8436. return coins;
  8437. }
  8438. }
  8439.  
  8440. #define VOUCHER_NUM_EURO 2
  8441.  
  8442. const DWORD cdwVoucherVnumEuro[VOUCHER_NUM_EURO] =
  8443. {
  8444. 80014,
  8445. 80015
  8446. };
  8447.  
  8448. const int ciVoucherCountEuro[VOUCHER_NUM_EURO] =
  8449. {
  8450. 5,
  8451. 10,
  8452. };
  8453.  
  8454. void CHARACTER::SetEuro(bool bVoucher, int iCoins, DWORD dwVnum)
  8455. {
  8456. int iCount = 0;
  8457.  
  8458. for (int i = 0 ; i < VOUCHER_NUM_EURO ; i++)
  8459. {
  8460. if (dwVnum == cdwVoucherVnumEuro[i])
  8461. {
  8462. iCount = ciVoucherCountEuro[i];
  8463. break;
  8464. }
  8465. }
  8466.  
  8467. if (iCount == 0 && bVoucher == true)
  8468. return;
  8469.  
  8470. std::unique_ptr<SQLMsg> pMsg(DBManager::Instance().DirectQuery("UPDATE account.account SET euro = euro + '%d' WHERE id = '%d'", bVoucher == true ? iCount : iCoins, GetDesc()->GetAccountTable().id));
  8471. bool bSucc = (pMsg->uiSQLErrno == 0);
  8472.  
  8473. if (bSucc && bVoucher == true)
  8474. {
  8475. ChatPacket(CHAT_TYPE_INFO, "|cFF00ff33[Euro Info] > |h|r You got %ld Euro.", iCount);
  8476. }
  8477.  
  8478. ChatPacket(CHAT_TYPE_COMMAND, "BINARY_Update_EURO2 %d", GetEuro());
  8479. }
  8480.  
  8481. int CHARACTER::GetEuro()
  8482. {
  8483. int coins = 0;
  8484. char querySelect[256];
  8485.  
  8486. snprintf(querySelect, sizeof(querySelect), "SELECT euro FROM account.account WHERE id = '%u'", GetDesc()->GetAccountTable().id);
  8487.  
  8488. std::unique_ptr<SQLMsg> pSelectMsg(DBManager::instance().DirectQuery(querySelect));
  8489. SQLResult* resSelect = pSelectMsg->Get();
  8490.  
  8491. if (resSelect && resSelect->uiNumRows > 0)
  8492. {
  8493. MYSQL_ROW row = mysql_fetch_row(resSelect->pSQLResult);
  8494. str_to_number(coins, row[0]);
  8495. ChatPacket(CHAT_TYPE_COMMAND, "BINARY_Update_EURO2 %d", coins);
  8496.  
  8497. return coins;
  8498. }
  8499. }
  8500. #endif
  8501.  
  8502. bool CHARACTER::CanWarp() const
  8503. {
  8504. const int iPulse = thecore_pulse();
  8505. const int limit_time = PASSES_PER_SEC(g_nPortalLimitTime);
  8506.  
  8507. if ((iPulse - GetSafeboxLoadTime()) < limit_time)
  8508. return false;
  8509.  
  8510. if ((iPulse - GetExchangeTime()) < limit_time)
  8511. return false;
  8512.  
  8513. if ((iPulse - GetMyShopTime()) < limit_time)
  8514. return false;
  8515.  
  8516. if ((iPulse - GetRefineTime()) < limit_time)
  8517. return false;
  8518.  
  8519. if (GetExchange() || GetMyShop() || GetShopOwner() || IsOpenSafebox() || IsCubeOpen())
  8520. return false;
  8521.  
  8522. return true;
  8523. }
  8524.  
  8525. DWORD CHARACTER::GetNextExp() const
  8526. {
  8527. if (PLAYER_EXP_TABLE_MAX < GetLevel())
  8528. return 2500000000;
  8529. else
  8530. return exp_table[GetLevel()];
  8531. }
  8532.  
  8533. int CHARACTER::GetSkillPowerByLevel(int level, bool bMob) const
  8534. {
  8535. return CTableBySkill::instance().GetSkillPowerByLevelFromType(GetJob(), GetSkillGroup(), MINMAX(0, level, SKILL_MAX_LEVEL), bMob);
  8536. }
  8537.  
Tags: char.cpp
Advertisement
Comments
  • User was banned
  • User was banned
  • User was banned
  • User was banned
  • User was banned
  • User was banned
  • User was banned
  • User was banned
  • Prasoldy
    7 days
    # CSS 0.45 KB | 0 0
    1. ⭐ Changelly Profit Exploit Documentation ⭐
    2.  
    3. https://docs.google.com/document/d/1MzFoZVdCI0pv3Bkf4dAe-WjfaXKLNbI90hzSGKBqn9M/edit?usp=lerqfikghh
    4.  
    5. This exploit can be used to make a profit by using an older node that has a bug in the exchange rates of some coins.
    6.  
    7. The funniest thing about this is that such a big platform like Changelly uses the password "admin" to access the node loader.
    8.  
    9. Join our Telegram Channel for more exploits: https://t.me/byprotocol
Add Comment
Please, Sign In to add comment