1. #include "stdafx.h"
  2. #include "../../common/teen_packet.h"
  3. #include "../../common/VnumHelper.h"
  4. #include "char.h"
  5. #include "config.h"
  6. #include "utils.h"
  7. #include "crc32.h"
  8. #include "char_manager.h"
  9. #include "desc_client.h"
  10. #include "desc_manager.h"
  11. #include "buffer_manager.h"
  12. #include "item_manager.h"
  13. #include "motion.h"
  14. #include "vector.h"
  15. #include "packet.h"
  16. #include "cmd.h"
  17. #include "fishing.h"
  18. #include "exchange.h"
  19. #include "battle.h"
  20. #include "affect.h"
  21. #include "shop.h"
  22. #include "shop_manager.h"
  23. #include "safebox.h"
  24. #include "regen.h"
  25. #include "pvp.h"
  26. #include "party.h"
  27. #include "start_position.h"
  28. #include "questmanager.h"
  29. #include "log.h"
  30. #include "p2p.h"
  31. #include "guild.h"
  32. #include "guild_manager.h"
  33. #include "dungeon.h"
  34. #include "messenger_manager.h"
  35. #include "unique_item.h"
  36. #include "priv_manager.h"
  37. #include "war_map.h"
  38. #include "xmas_event.h"
  39. #include "banword.h"
  40. #include "target.h"
  41. #include "wedding.h"
  42. #include "mob_manager.h"
  43. #include "mining.h"
  44. #include "monarch.h"
  45. #include "castle.h"
  46. #include "arena.h"
  47. #include "dev_log.h"
  48. #include "horsename_manager.h"
  49. #include "pcbang.h"
  50. #include "gm.h"
  51. #include "map_location.h"
  52. #include "BlueDragon_Binder.h"
  53. #include "HackShield.h"
  54. #include "skill_power.h"
  55. #include "XTrapManager.h"
  56. #include "buff_on_attributes.h"
  57. #ifdef __SEND_TARGET_INFO__
  58. #include <algorithm>
  59. #include <iterator>
  60. using namespace std;
  61. #endif
  62. #ifdef __PET_SYSTEM__
  63. #include "PetSystem.h"
  64. #endif
  65. #include "DragonSoul.h"
  66. #include "../../common/CommonDefines.h"
  67. #include "../../common/service.h"
  68. #ifdef ENABLE_OFFLINE_SHOP_SYSTEM
  69. #include "offline_shop.h"
  70. #include "offlineshop_manager.h"
  71. #include "offlineshop_config.h"
  72. #endif
  73. extern bool offlineshop_map_allow_find(int mapIndex);
  74. extern const BYTE g_aBuffOnAttrPoints;
  75. extern bool RaceToJob(unsigned race, unsigned *ret_job);
  76. extern bool IS_SUMMONABLE_ZONE(int map_index); // char_item.cpp
  77. bool CAN_ENTER_ZONE(const LPCHARACTER& ch, int map_index);
  78. bool CAN_ENTER_ZONE(const LPCHARACTER& ch, int map_index)
  79. {
  80. switch (map_index)
  81. {
  82. case 301:
  83. case 302:
  84. case 303:
  85. case 304:
  86. if (ch->GetLevel() < 90)
  87. return false;
  88. }
  89. return true;
  90. }
  91. #ifdef NEW_ICEDAMAGE_SYSTEM
  92. const DWORD CHARACTER::GetNoDamageRaceFlag()
  93. {
  94. return m_dwNDRFlag;
  95. }
  96. void CHARACTER::SetNoDamageRaceFlag(DWORD dwRaceFlag)
  97. {
  98. if (dwRaceFlag>=MAIN_RACE_MAX_NUM) return;
  99. if (IS_SET(m_dwNDRFlag, 1<<dwRaceFlag)) return;
  100. SET_BIT(m_dwNDRFlag, 1<<dwRaceFlag);
  101. }
  102. void CHARACTER::UnsetNoDamageRaceFlag(DWORD dwRaceFlag)
  103. {
  104. if (dwRaceFlag>=MAIN_RACE_MAX_NUM) return;
  105. if (!IS_SET(m_dwNDRFlag, 1<<dwRaceFlag)) return;
  106. REMOVE_BIT(m_dwNDRFlag, 1<<dwRaceFlag);
  107. }
  108. void CHARACTER::ResetNoDamageRaceFlag()
  109. {
  110. m_dwNDRFlag = 0;
  111. }
  112. const std::set<DWORD> & CHARACTER::GetNoDamageAffectFlag()
  113. {
  114. return m_setNDAFlag;
  115. }
  116. void CHARACTER::SetNoDamageAffectFlag(DWORD dwAffectFlag)
  117. {
  118. m_setNDAFlag.insert(dwAffectFlag);
  119. }
  120. void CHARACTER::UnsetNoDamageAffectFlag(DWORD dwAffectFlag)
  121. {
  122. m_setNDAFlag.erase(dwAffectFlag);
  123. }
  124. void CHARACTER::ResetNoDamageAffectFlag()
  125. {
  126. m_setNDAFlag.clear();
  127. }
  128. #endif
  129. // <Factor> DynamicCharacterPtr member function definitions
  130. LPCHARACTER DynamicCharacterPtr::Get() const {
  131. LPCHARACTER p = NULL;
  132. if (is_pc) {
  133. p = CHARACTER_MANAGER::instance().FindByPID(id);
  134. } else {
  135. p = CHARACTER_MANAGER::instance().Find(id);
  136. }
  137. return p;
  138. }
  139. DynamicCharacterPtr& DynamicCharacterPtr::operator=(LPCHARACTER character) {
  140. if (character == NULL) {
  141. Reset();
  142. return *this;
  143. }
  144. if (character->IsPC()) {
  145. is_pc = true;
  146. id = character->GetPlayerID();
  147. } else {
  148. is_pc = false;
  149. id = character->GetVID();
  150. }
  151. return *this;
  152. }
  153. CHARACTER::CHARACTER()
  154. {
  155. m_stateIdle.Set(this, &CHARACTER::BeginStateEmpty, &CHARACTER::StateIdle, &CHARACTER::EndStateEmpty);
  156. m_stateMove.Set(this, &CHARACTER::BeginStateEmpty, &CHARACTER::StateMove, &CHARACTER::EndStateEmpty);
  157. m_stateBattle.Set(this, &CHARACTER::BeginStateEmpty, &CHARACTER::StateBattle, &CHARACTER::EndStateEmpty);
  158. Initialize();
  159. }
  160. CHARACTER::~CHARACTER()
  161. {
  162. Destroy();
  163. }
  164. void CHARACTER::Initialize()
  165. {
  166. CEntity::Initialize(ENTITY_CHARACTER);
  167. m_bNoOpenedShop = true;
  168. m_bOpeningSafebox = false;
  169. m_fSyncTime = get_float_time()-3;
  170. m_dwPlayerID = 0;
  171. m_dwKillerPID = 0;
  172. #ifdef __SEND_TARGET_INFO__
  173. dwLastTargetInfoPulse = 0;
  174. #endif
  175. m_iMoveCount = 0;
  176. m_pkRegen = NULL;
  177. regen_id_ = 0;
  178. m_posRegen.x = m_posRegen.y = m_posRegen.z = 0;
  179. m_posStart.x = m_posStart.y = 0;
  180. m_posDest.x = m_posDest.y = 0;
  181. m_fRegenAngle = 0.0f;
  182. m_pkMobData = NULL;
  183. m_pkMobInst = NULL;
  184. m_pkShop = NULL;
  185. m_pkChrShopOwner = NULL;
  186. m_pkMyShop = NULL;
  187. m_pkExchange = NULL;
  188. m_pkParty = NULL;
  189. m_pkPartyRequestEvent = NULL;
  190. #ifdef ENABLE_OFFLINE_SHOP_SYSTEM
  191. m_pkOfflineShop = NULL;
  192. m_pkChrOfflineShopOwner = NULL;
  193. m_pkOfflineShopUpdateEvent = NULL;
  194. m_bOfflineShopStatus = 0;
  195. #endif
  196. m_pGuild = NULL;
  197. m_pkChrTarget = NULL;
  198. m_pkMuyeongEvent = NULL;
  199. m_pkWarpNPCEvent = NULL;
  200. m_pkDeadEvent = NULL;
  201. m_pkStunEvent = NULL;
  202. m_pkSaveEvent = NULL;
  203. m_pkRecoveryEvent = NULL;
  204. m_pkTimedEvent = NULL;
  205. m_pkFishingEvent = NULL;
  206. m_pkWarpEvent = NULL;
  207. // MINING
  208. m_pkMiningEvent = NULL;
  209. // END_OF_MINING
  210. m_pkPoisonEvent = NULL;
  211. #ifdef ENABLE_WOLFMAN_CHARACTER
  212. m_pkBleedingEvent = NULL;
  213. #endif
  214. m_pkFireEvent = NULL;
  215. m_pkCheckSpeedHackEvent = NULL;
  216. m_speed_hack_count = 0;
  217. m_pkAffectEvent = NULL;
  218. m_afAffectFlag = TAffectFlag(0, 0);
  219. m_pkDestroyWhenIdleEvent = NULL;
  220. m_pkChrSyncOwner = NULL;
  221. memset(&m_points, 0, sizeof(m_points));
  222. memset(&m_pointsInstant, 0, sizeof(m_pointsInstant));
  223. memset(&m_quickslot, 0, sizeof(m_quickslot));
  224. m_bCharType = CHAR_TYPE_MONSTER;
  225. SetPosition(POS_STANDING);
  226. m_dwPlayStartTime = m_dwLastMoveTime = get_dword_time();
  227. GotoState(m_stateIdle);
  228. m_dwStateDuration = 1;
  229. m_dwLastAttackTime = get_dword_time() - 20000;
  230. m_bAddChrState = 0;
  231. m_pkChrStone = NULL;
  232. m_pkSafebox = NULL;
  233. m_iSafeboxSize = -1;
  234. m_iSafeboxLoadTime = 0;
  235. m_pkMall = NULL;
  236. m_iMallLoadTime = 0;
  237. m_posWarp.x = m_posWarp.y = m_posWarp.z = 0;
  238. m_lWarpMapIndex = 0;
  239. m_posExit.x = m_posExit.y = m_posExit.z = 0;
  240. m_lExitMapIndex = 0;
  241. m_pSkillLevels = NULL;
  242. m_dwMoveStartTime = 0;
  243. m_dwMoveDuration = 0;
  244. m_dwFlyTargetID = 0;
  245. m_dwNextStatePulse = 0;
  246. m_dwLastDeadTime = get_dword_time()-180000;
  247. m_bSkipSave = false;
  248. m_bItemLoaded = false;
  249. m_bHasPoisoned = false;
  250. #ifdef ENABLE_WOLFMAN_CHARACTER
  251. m_bHasBled = false;
  252. #endif
  253. m_pkDungeon = NULL;
  254. m_iEventAttr = 0;
  255. m_kAttackLog.dwVID = 0;
  256. m_kAttackLog.dwTime = 0;
  257. m_bNowWalking = m_bWalking = false;
  258. ResetChangeAttackPositionTime();
  259. m_bDetailLog = false;
  260. m_bMonsterLog = false;
  261. m_bDisableCooltime = false;
  262. m_iAlignment = 0;
  263. m_iRealAlignment = 0;
  264. m_iKillerModePulse = 0;
  265. m_bPKMode = PK_MODE_PEACE;
  266. m_dwQuestNPCVID = 0;
  267. m_dwQuestByVnum = 0;
  268. m_pQuestItem = NULL;
  269. m_szMobileAuth[0] = '\0';
  270. m_dwUnderGuildWarInfoMessageTime = get_dword_time()-60000;
  271. m_bUnderRefine = false;
  272. // REFINE_NPC
  273. m_dwRefineNPCVID = 0;
  274. // END_OF_REFINE_NPC
  275. m_dwPolymorphRace = 0;
  276. m_bStaminaConsume = false;
  277. ResetChainLightningIndex();
  278. m_dwMountVnum = 0;
  279. m_chHorse = NULL;
  280. m_chRider = NULL;
  281. m_pWarMap = NULL;
  282. m_pWeddingMap = NULL;
  283. m_bChatCounter = 0;
  284. ResetStopTime();
  285. m_dwLastVictimSetTime = get_dword_time() - 3000;
  286. m_iMaxAggro = -100;
  287. m_bSendHorseLevel = 0;
  288. m_bSendHorseHealthGrade = 0;
  289. m_bSendHorseStaminaGrade = 0;
  290. m_dwLoginPlayTime = 0;
  291. m_pkChrMarried = NULL;
  292. m_posSafeboxOpen.x = -1000;
  293. m_posSafeboxOpen.y = -1000;
  294. // EQUIP_LAST_SKILL_DELAY
  295. m_dwLastSkillTime = get_dword_time();
  296. // END_OF_EQUIP_LAST_SKILL_DELAY
  297. // MOB_SKILL_COOLTIME
  298. memset(m_adwMobSkillCooltime, 0, sizeof(m_adwMobSkillCooltime));
  299. // END_OF_MOB_SKILL_COOLTIME
  300. m_isinPCBang = false;
  301. // ARENA
  302. m_pArena = NULL;
  303. m_nPotionLimit = quest::CQuestManager::instance().GetEventFlag("arena_potion_limit_count");
  304. // END_ARENA
  305. //PREVENT_TRADE_WINDOW
  306. m_isOpenSafebox = 0;
  307. //END_PREVENT_TRADE_WINDOW
  308. //PREVENT_REFINE_HACK
  309. m_iRefineTime = 0;
  310. //END_PREVENT_REFINE_HACK
  311. //RESTRICT_USE_SEED_OR_MOONBOTTLE
  312. m_iSeedTime = 0;
  313. //END_RESTRICT_USE_SEED_OR_MOONBOTTLE
  314. //PREVENT_PORTAL_AFTER_EXCHANGE
  315. m_iExchangeTime = 0;
  316. //END_PREVENT_PORTAL_AFTER_EXCHANGE
  317. //
  318. m_iSafeboxLoadTime = 0;
  319. m_iMyShopTime = 0;
  320. InitMC();
  321. m_deposit_pulse = 0;
  322. SET_OVER_TIME(this, OT_NONE);
  323. m_strNewName = "";
  324. m_known_guild.clear();
  325. m_dwLogOffInterval = 0;
  326. m_bComboSequence = 0;
  327. m_dwLastComboTime = 0;
  328. m_bComboIndex = 0;
  329. m_iComboHackCount = 0;
  330. m_dwSkipComboAttackByTime = 0;
  331. m_dwMountTime = 0;
  332. m_dwLastGoldDropTime = 0;
  333. #ifdef ENABLE_NEWSTUFF
  334. m_dwLastItemDropTime = 0;
  335. m_dwLastBoxUseTime = 0;
  336. m_dwLastBuySellTime = 0;
  337. #endif
  338. m_HackShieldCheckEvent = NULL;
  339. m_HackShieldCheckMode = false;
  340. m_bIsLoadedAffect = false;
  341. cannot_dead = false;
  342. #ifdef __PET_SYSTEM__
  343. m_petSystem = 0;
  344. m_bIsPet = false;
  345. #endif
  346. #ifdef NEW_ICEDAMAGE_SYSTEM
  347. m_dwNDRFlag = 0;
  348. m_setNDAFlag.clear();
  349. #endif
  350. m_fAttMul = 1.0f;
  351. m_fDamMul = 1.0f;
  352. m_pointsInstant.iDragonSoulActiveDeck = -1;
  353. #ifdef ENABLE_ANTI_CMD_FLOOD
  354. m_dwCmdAntiFloodCount = 0;
  355. m_dwCmdAntiFloodPulse = 0;
  356. #endif
  357. memset(&m_tvLastSyncTime, 0, sizeof(m_tvLastSyncTime));
  358. m_iSyncHackCount = 0;
  359. #ifdef __SASH_SYSTEM__
  360. m_bSashCombination = false;
  361. m_bSashAbsorption = false;
  362. #endif
  363. #ifdef __CHANGELOOK_SYSTEM__
  364. m_bChangeLook = false;
  365. #endif
  366. }
  367. void CHARACTER::Create(const char * c_pszName, DWORD vid, bool isPC)
  368. {
  369. static int s_crc = 172814;
  370. char crc_string[128+1];
  371. snprintf(crc_string, sizeof(crc_string), "%s%p%d", c_pszName, this, ++s_crc);
  372. m_vid = VID(vid, GetCRC32(crc_string, strlen(crc_string)));
  373. if (isPC)
  374. m_stName = c_pszName;
  375. }
  376. void CHARACTER::Destroy()
  377. {
  378. CloseMyShop();
  379. if (m_pkRegen)
  380. {
  381. if (m_pkDungeon) {
  382. // Dungeon regen may not be valid at this point
  383. if (m_pkDungeon->IsValidRegen(m_pkRegen, regen_id_)) {
  384. --m_pkRegen->count;
  385. }
  386. } else {
  387. // Is this really safe?
  388. --m_pkRegen->count;
  389. }
  390. m_pkRegen = NULL;
  391. }
  392. if (m_pkDungeon)
  393. {
  394. SetDungeon(NULL);
  395. }
  396. #ifdef __PET_SYSTEM__
  397. if (m_petSystem)
  398. {
  399. m_petSystem->Destroy();
  400. delete m_petSystem;
  401. m_petSystem = 0;
  402. }
  403. #endif
  404. HorseSummon(false);
  405. if (GetRider())
  406. GetRider()->ClearHorseInfo();
  407. if( IsPC() )
  408. {
  409. if (isHackShieldEnable)
  410. {
  411. CHackShieldManager::instance().DeleteClientHandle(GetPlayerID());
  412. }
  413. }
  414. if (GetDesc())
  415. {
  416. GetDesc()->BindCharacter(NULL);
  417. // BindDesc(NULL);
  418. }
  419. if (m_pkExchange)
  420. m_pkExchange->Cancel();
  421. SetVictim(NULL);
  422. if (GetShop())
  423. {
  424. GetShop()->RemoveGuest(this);
  425. SetShop(NULL);
  426. }
  427. ClearStone();
  428. ClearSync();
  429. ClearTarget();
  430. if (NULL == m_pkMobData)
  431. {
  432. DragonSoul_CleanUp();
  433. ClearItem();
  434. }
  435. // <Factor> m_pkParty becomes NULL after CParty destructor call!
  436. LPPARTY party = m_pkParty;
  437. if (party)
  438. {
  439. if (party->GetLeaderPID() == GetVID() && !IsPC())
  440. {
  441. M2_DELETE(party);
  442. }
  443. else
  444. {
  445. party->Unlink(this);
  446. if (!IsPC())
  447. party->Quit(GetVID());
  448. }
  449. SetParty(NULL);
  450. }
  451. if (m_pkMobInst)
  452. {
  453. M2_DELETE(m_pkMobInst);
  454. m_pkMobInst = NULL;
  455. }
  456. m_pkMobData = NULL;
  457. if (m_pkSafebox)
  458. {
  459. M2_DELETE(m_pkSafebox);
  460. m_pkSafebox = NULL;
  461. }
  462. if (m_pkMall)
  463. {
  464. M2_DELETE(m_pkMall);
  465. m_pkMall = NULL;
  466. }
  467. for (TMapBuffOnAttrs::iterator it = m_map_buff_on_attrs.begin(); it != m_map_buff_on_attrs.end(); it++)
  468. {
  469. if (NULL != it->second)
  470. {
  471. M2_DELETE(it->second);
  472. }
  473. }
  474. m_map_buff_on_attrs.clear();
  475. m_set_pkChrSpawnedBy.clear();
  476. StopMuyeongEvent();
  477. event_cancel(&m_pkWarpNPCEvent);
  478. event_cancel(&m_pkRecoveryEvent);
  479. event_cancel(&m_pkDeadEvent);
  480. event_cancel(&m_pkSaveEvent);
  481. event_cancel(&m_pkTimedEvent);
  482. event_cancel(&m_pkStunEvent);
  483. event_cancel(&m_pkFishingEvent);
  484. event_cancel(&m_pkPoisonEvent);
  485. #ifdef ENABLE_WOLFMAN_CHARACTER
  486. event_cancel(&m_pkBleedingEvent);
  487. #endif
  488. event_cancel(&m_pkFireEvent);
  489. event_cancel(&m_pkPartyRequestEvent);
  490. //DELAYED_WARP
  491. event_cancel(&m_pkWarpEvent);
  492. event_cancel(&m_pkCheckSpeedHackEvent);
  493. //END_DELAYED_WARP
  494. // RECALL_DELAY
  495. //event_cancel(&m_pkRecallEvent);
  496. // END_OF_RECALL_DELAY
  497. // MINING
  498. event_cancel(&m_pkMiningEvent);
  499. // END_OF_MINING
  500. StopHackShieldCheckCycle();
  501. for (itertype(m_mapMobSkillEvent) it = m_mapMobSkillEvent.begin(); it != m_mapMobSkillEvent.end(); ++it)
  502. {
  503. LPEVENT pkEvent = it->second;
  504. event_cancel(&pkEvent);
  505. }
  506. m_mapMobSkillEvent.clear();
  507. //event_cancel(&m_pkAffectEvent);
  508. ClearAffect();
  509. event_cancel(&m_pkDestroyWhenIdleEvent);
  510. if (m_pSkillLevels)
  511. {
  512. M2_DELETE_ARRAY(m_pSkillLevels);
  513. m_pSkillLevels = NULL;
  514. }
  515. CEntity::Destroy();
  516. if (GetSectree())
  517. GetSectree()->RemoveEntity(this);
  518. if (m_bMonsterLog)
  519. CHARACTER_MANAGER::instance().UnregisterForMonsterLog(this);
  520. }
  521. const char * CHARACTER::GetName() const
  522. {
  523. return m_stName.empty() ? (m_pkMobData ? m_pkMobData->m_table.szLocaleName : "") : m_stName.c_str();
  524. }
  525. void CHARACTER::OpenMyShop(const char * c_pszSign, TShopItemTable * pTable, BYTE bItemCount)
  526. {
  527. if (GetPart(PART_MAIN) > 2)
  528. {
  529. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("°©¿ÊÀ» ¹ş¾î¾ß °³ÀÎ »óÁ¡À» ¿­ ¼ö ÀÖ½À´Ï´Ù."));
  530. return;
  531. }
  532. if (GetMyShop())
  533. {
  534. CloseMyShop();
  535. return;
  536. }
  537. quest::PC * pPC = quest::CQuestManager::instance().GetPCForce(GetPlayerID());
  538. if (pPC->IsRunning())
  539. return;
  540. if (bItemCount == 0)
  541. return;
  542. int64_t nTotalMoney = 0;
  543. for (int n = 0; n < bItemCount; ++n)
  544. {
  545. nTotalMoney += static_cast<int64_t>((pTable+n)->price);
  546. }
  547. nTotalMoney += static_cast<int64_t>(GetGold());
  548. if (GOLD_MAX <= nTotalMoney)
  549. {
  550. sys_err("[OVERFLOW_GOLD] Overflow (GOLD_MAX) id %u name %s", GetPlayerID(), GetName());
  551. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("20¾ï ³ÉÀ» ÃʰúÇÏ¿© »óÁ¡À» ¿­¼ö°¡ ¾ø½À´Ï´Ù"));
  552. return;
  553. }
  554. char szSign[SHOP_SIGN_MAX_LEN+1];
  555. strlcpy(szSign, c_pszSign, sizeof(szSign));
  556. if (strlen(szSign) == 0)
  557. {
  558. ChatPacket(CHAT_TYPE_INFO, "Gecersiz cevrimdisi pazar ismi girdiniz!");
  559. return;
  560. }
  561. if (strstr(szSign, "%") || strstr(szSign, "'"))
  562. {
  563. ChatPacket(CHAT_TYPE_INFO, "Gecersiz cevrimdisi pazar ismi girdiniz!");
  564. return;
  565. }
  566. m_stShopSign = szSign;
  567. if (m_stShopSign.length() == 0)
  568. return;
  569. if (CBanwordManager::instance().CheckString(m_stShopSign.c_str(), m_stShopSign.length()))
  570. {
  571. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("ºñ¼Ó¾î³ª Àº¾î°¡ Æ÷ÇÔµÈ »óÁ¡ À̸§À¸·Î »óÁ¡À» ¿­ ¼ö ¾ø½À´Ï´Ù."));
  572. return;
  573. }
  574. // MYSHOP_PRICE_LIST
  575. std::map<DWORD, DWORD> itemkind;
  576. // END_OF_MYSHOP_PRICE_LIST
  577. std::set<TItemPos> cont;
  578. for (BYTE i = 0; i < bItemCount; ++i)
  579. {
  580. if (cont.find((pTable + i)->pos) != cont.end())
  581. {
  582. sys_err("MYSHOP: duplicate shop item detected! (name: %s)", GetName());
  583. return;
  584. }
  585. // ANTI_GIVE, ANTI_MYSHOP check
  586. LPITEM pkItem = GetItem((pTable + i)->pos);
  587. if (pkItem)
  588. {
  589. const TItemTable * item_table = pkItem->GetProto();
  590. if (item_table && (IS_SET(item_table->dwAntiFlags, ITEM_ANTIFLAG_GIVE | ITEM_ANTIFLAG_MYSHOP)))
  591. {
  592. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("À¯·áÈ­ ¾ÆÀÌÅÛÀº °³ÀλóÁ¡¿¡¼­ ÆÇ¸ÅÇÒ ¼ö ¾ø½À´Ï´Ù."));
  593. return;
  594. }
  595. if (pkItem->IsEquipped() == true)
  596. {
  597. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("ÀåºñÁßÀÎ ¾ÆÀÌÅÛÀº °³ÀλóÁ¡¿¡¼­ ÆÇ¸ÅÇÒ ¼ö ¾ø½À´Ï´Ù."));
  598. return;
  599. }
  600. if (true == pkItem->isLocked())
  601. {
  602. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("»ç¿ëÁßÀÎ ¾ÆÀÌÅÛÀº °³ÀλóÁ¡¿¡¼­ ÆÇ¸ÅÇÒ ¼ö ¾ø½À´Ï´Ù."));
  603. return;
  604. }
  605. #ifdef __SOULBINDING_SYSTEM__
  606. if (pkItem->IsBind() || pkItem->IsUntilBind())
  607. {
  608. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You can't sell this item because is binded!"));
  609. return;
  610. }
  611. #endif
  612. // MYSHOP_PRICE_LIST
  613. itemkind[pkItem->GetVnum()] = (pTable + i)->price / pkItem->GetCount();
  614. // END_OF_MYSHOP_PRICE_LIST
  615. }
  616. cont.insert((pTable + i)->pos);
  617. }
  618. // MYSHOP_PRICE_LIST
  619. if (CountSpecifyItem(71049)) {
  620. TPacketMyshopPricelistHeader header;
  621. TItemPriceInfo info;
  622. header.dwOwnerID = GetPlayerID();
  623. header.byCount = itemkind.size();
  624. TEMP_BUFFER buf;
  625. buf.write(&header, sizeof(header));
  626. for (itertype(itemkind) it = itemkind.begin(); it != itemkind.end(); ++it)
  627. {
  628. info.dwVnum = it->first;
  629. info.dwPrice = it->second;
  630. buf.write(&info, sizeof(info));
  631. }
  632. db_clientdesc->DBPacket(HEADER_GD_MYSHOP_PRICELIST_UPDATE, 0, buf.read_peek(), buf.size());
  633. }
  634. // END_OF_MYSHOP_PRICE_LIST
  635. else if (CountSpecifyItem(50200))
  636. RemoveSpecifyItem(50200, 1);
  637. else
  638. return;
  639. if (m_pkExchange)
  640. m_pkExchange->Cancel();
  641. TPacketGCShopSign p;
  642. p.bHeader = HEADER_GC_SHOP_SIGN;
  643. p.dwVID = GetVID();
  644. strlcpy(p.szSign, c_pszSign, sizeof(p.szSign));
  645. PacketAround(&p, sizeof(TPacketGCShopSign));
  646. m_pkMyShop = CShopManager::instance().CreatePCShop(this, pTable, bItemCount);
  647. if (IsPolymorphed() == true)
  648. {
  649. RemoveAffect(AFFECT_POLYMORPH);
  650. }
  651. if (GetHorse())
  652. {
  653. HorseSummon( false, true );
  654. }
  655. else if (GetMountVnum())
  656. {
  657. RemoveAffect(AFFECT_MOUNT);
  658. RemoveAffect(AFFECT_MOUNT_BONUS);
  659. }
  660. SetPolymorph(30000, true);
  661. }
  662. void CHARACTER::CloseMyShop()
  663. {
  664. if (GetMyShop())
  665. {
  666. m_stShopSign.clear();
  667. CShopManager::instance().DestroyPCShop(this);
  668. m_pkMyShop = NULL;
  669. TPacketGCShopSign p;
  670. p.bHeader = HEADER_GC_SHOP_SIGN;
  671. p.dwVID = GetVID();
  672. p.szSign[0] = '\0';
  673. PacketAround(&p, sizeof(p));
  674. #ifdef ENABLE_WOLFMAN_CHARACTER
  675. SetPolymorph(m_points.job, true);
  676. // SetPolymorph(0, true);
  677. #else
  678. SetPolymorph(GetJob(), true);
  679. #endif
  680. }
  681. }
  682. void EncodeMovePacket(TPacketGCMove & pack, DWORD dwVID, BYTE bFunc, BYTE bArg, DWORD x, DWORD y, DWORD dwDuration, DWORD dwTime, BYTE bRot)
  683. {
  684. pack.bHeader = HEADER_GC_MOVE;
  685. pack.bFunc = bFunc;
  686. pack.bArg = bArg;
  687. pack.dwVID = dwVID;
  688. pack.dwTime = dwTime ? dwTime : get_dword_time();
  689. pack.bRot = bRot;
  690. pack.lX = x;
  691. pack.lY = y;
  692. pack.dwDuration = dwDuration;
  693. }
  694. void CHARACTER::RestartAtSamePos()
  695. {
  696. if (m_bIsObserver)
  697. return;
  698. EncodeRemovePacket(this);
  699. EncodeInsertPacket(this);
  700. ENTITY_MAP::iterator it = m_map_view.begin();
  701. while (it != m_map_view.end())
  702. {
  703. LPENTITY entity = (it++)->first;
  704. EncodeRemovePacket(entity);
  705. if (!m_bIsObserver)
  706. EncodeInsertPacket(entity);
  707. if( entity->IsType(ENTITY_CHARACTER) )
  708. {
  709. LPCHARACTER lpChar = (LPCHARACTER)entity;
  710. if( lpChar->IsPC() || lpChar->IsNPC() || lpChar->IsMonster() )
  711. {
  712. if (!entity->IsObserverMode())
  713. entity->EncodeInsertPacket(this);
  714. }
  715. }
  716. else
  717. {
  718. if( !entity->IsObserverMode())
  719. {
  720. entity->EncodeInsertPacket(this);
  721. }
  722. }
  723. }
  724. }
  725. // #define ENABLE_SHOWNPCLEVEL
  726. void CHARACTER::EncodeInsertPacket(LPENTITY entity)
  727. {
  728. LPDESC d;
  729. if (!(d = entity->GetDesc()))
  730. return;
  731. LPCHARACTER ch = (LPCHARACTER) entity;
  732. ch->SendGuildName(GetGuild());
  733. TPacketGCCharacterAdd pack;
  734. pack.header = HEADER_GC_CHARACTER_ADD;
  735. pack.dwVID = m_vid;
  736. pack.bType = GetCharType();
  737. pack.angle = GetRotation();
  738. pack.x = GetX();
  739. pack.y = GetY();
  740. pack.z = GetZ();
  741. pack.wRaceNum = GetRaceNum();
  742. if (IsPet())
  743. {
  744. pack.bMovingSpeed = 150;
  745. }
  746. else
  747. {
  748. pack.bMovingSpeed = GetLimitPoint(POINT_MOV_SPEED);
  749. }
  750. pack.bAttackSpeed = GetLimitPoint(POINT_ATT_SPEED);
  751. pack.dwAffectFlag[0] = m_afAffectFlag.bits[0];
  752. pack.dwAffectFlag[1] = m_afAffectFlag.bits[1];
  753. pack.bStateFlag = m_bAddChrState;
  754. int iDur = 0;
  755. if (m_posDest.x != pack.x || m_posDest.y != pack.y)
  756. {
  757. iDur = (m_dwMoveStartTime + m_dwMoveDuration) - get_dword_time();
  758. if (iDur <= 0)
  759. {
  760. pack.x = m_posDest.x;
  761. pack.y = m_posDest.y;
  762. }
  763. }
  764. d->Packet(&pack, sizeof(pack));
  765. if (IsPC() == true || m_bCharType == CHAR_TYPE_NPC)
  766. {
  767. TPacketGCCharacterAdditionalInfo addPacket;
  768. memset(&addPacket, 0, sizeof(TPacketGCCharacterAdditionalInfo));
  769. addPacket.header = HEADER_GC_CHAR_ADDITIONAL_INFO;
  770. addPacket.dwVID = m_vid;
  771. addPacket.awPart[CHR_EQUIPPART_ARMOR] = GetPart(PART_MAIN);
  772. addPacket.awPart[CHR_EQUIPPART_WEAPON] = GetPart(PART_WEAPON);
  773. addPacket.awPart[CHR_EQUIPPART_HEAD] = GetPart(PART_HEAD);
  774. addPacket.awPart[CHR_EQUIPPART_HAIR] = GetPart(PART_HAIR);
  775. #ifdef __SASH_SYSTEM__
  776. addPacket.awPart[CHR_EQUIPPART_SASH] = GetPart(PART_SASH);
  777. #endif
  778. addPacket.bPKMode = m_bPKMode;
  779. addPacket.dwMountVnum = GetMountVnum();
  780. addPacket.bEmpire = m_bEmpire;
  781. #ifdef ENABLE_SHOWNPCLEVEL
  782. if (1)
  783. #else
  784. if (IsPC() == true)
  785. #endif
  786. {
  787. addPacket.dwLevel = GetLevel();
  788. }
  789. else
  790. {
  791. addPacket.dwLevel = 0;
  792. }
  793. #ifdef ENABLE_RARITY_SYSTEM
  794. LPITEM weapon = GetWear(WEAR_WEAPON);
  795. addPacket.lWeaponRarity = weapon ? weapon->GetAttributeValue(6) : 0;
  796. #endif
  797. if (false)
  798. {
  799. LPCHARACTER ch = (LPCHARACTER) entity;
  800. if (GetEmpire() == ch->GetEmpire() || ch->GetGMLevel() > GM_PLAYER || m_bCharType == CHAR_TYPE_NPC)
  801. {
  802. goto show_all_info;
  803. }
  804. else
  805. {
  806. memset(addPacket.name, 0, CHARACTER_NAME_MAX_LEN);
  807. addPacket.dwGuildID = 0;
  808. addPacket.sAlignment = 0;
  809. }
  810. }
  811. else
  812. {
  813. show_all_info:
  814. strlcpy(addPacket.name, GetName(), sizeof(addPacket.name));
  815. if (GetGuild() != NULL)
  816. {
  817. addPacket.dwGuildID = GetGuild()->GetID();
  818. #ifdef ENABLE_LEADER_SYSTEM
  819. CGuild* pGuild = this->GetGuild();
  820. if (pGuild->GetMasterPID() == GetPlayerID())
  821. addPacket.dwNewIsGuildName = 3;
  822. else if (pGuild->NewIsGuildGeneral(GetPlayerID()) == true)
  823. addPacket.dwNewIsGuildName = 2;
  824. else
  825. addPacket.dwNewIsGuildName = 1;
  826. #endif
  827. }
  828. else
  829. {
  830. addPacket.dwGuildID = 0;
  831. #ifdef ENABLE_LEADER_SYSTEM
  832. addPacket.dwNewIsGuildName = 0;
  833. #endif
  834. }
  835. addPacket.sAlignment = m_iAlignment / 10;
  836. }
  837. d->Packet(&addPacket, sizeof(TPacketGCCharacterAdditionalInfo));
  838. }
  839. if (iDur)
  840. {
  841. TPacketGCMove pack;
  842. EncodeMovePacket(pack, GetVID(), FUNC_MOVE, 0, m_posDest.x, m_posDest.y, iDur, 0, (BYTE) (GetRotation() / 5));
  843. d->Packet(&pack, sizeof(pack));
  844. TPacketGCWalkMode p;
  845. p.vid = GetVID();
  846. p.header = HEADER_GC_WALK_MODE;
  847. p.mode = m_bNowWalking ? WALKMODE_WALK : WALKMODE_RUN;
  848. d->Packet(&p, sizeof(p));
  849. }
  850. if (entity->IsType(ENTITY_CHARACTER) && GetDesc())
  851. {
  852. LPCHARACTER ch = (LPCHARACTER) entity;
  853. if (ch->IsWalking())
  854. {
  855. TPacketGCWalkMode p;
  856. p.vid = ch->GetVID();
  857. p.header = HEADER_GC_WALK_MODE;
  858. p.mode = ch->m_bNowWalking ? WALKMODE_WALK : WALKMODE_RUN;
  859. GetDesc()->Packet(&p, sizeof(p));
  860. }
  861. }
  862. if (GetMyShop())
  863. {
  864. TPacketGCShopSign p;
  865. p.bHeader = HEADER_GC_SHOP_SIGN;
  866. p.dwVID = GetVID();
  867. strlcpy(p.szSign, m_stShopSign.c_str(), sizeof(p.szSign));
  868. d->Packet(&p, sizeof(TPacketGCShopSign));
  869. }
  870. #ifdef ENABLE_OFFLINE_SHOP_SYSTEM
  871. if (IsOfflineShopNPC() && GetRaceNum() == 30000)
  872. {
  873. TPacketGCShopSign p;
  874. p.bHeader = HEADER_GC_OFFLINE_SHOP_SIGN;
  875. p.dwVID = GetVID();
  876. if (m_stOfflineShopSign.empty())
  877. {
  878. std::auto_ptr<SQLMsg> pMsg(DBManager::instance().DirectQuery("SELECT sign FROM player.offline_shop_npc WHERE owner_id = %u", GetOfflineShopRealOwner()));
  879. if (pMsg->Get()->uiNumRows > 0)
  880. {
  881. MYSQL_ROW row = mysql_fetch_row(pMsg->Get()->pSQLResult);
  882. strlcpy(p.szSign, row[0], sizeof(p.szSign));
  883. }
  884. }
  885. else
  886. {
  887. strlcpy(p.szSign, m_stOfflineShopSign.c_str(), sizeof(p.szSign));
  888. }
  889. d->Packet(&p, sizeof(TPacketGCShopSign));
  890. }
  891. #endif
  892. if (entity->IsType(ENTITY_CHARACTER))
  893. {
  894. sys_log(3, "EntityInsert %s (RaceNum %d) (%d %d) TO %s",
  895. GetName(), GetRaceNum(), GetX() / SECTREE_SIZE, GetY() / SECTREE_SIZE, ((LPCHARACTER)entity)->GetName());
  896. }
  897. }
  898. void CHARACTER::EncodeRemovePacket(LPENTITY entity)
  899. {
  900. if (entity->GetType() != ENTITY_CHARACTER)
  901. return;
  902. LPDESC d;
  903. if (!(d = entity->GetDesc()))
  904. return;
  905. TPacketGCCharacterDelete pack;
  906. pack.header = HEADER_GC_CHARACTER_DEL;
  907. pack.id = m_vid;
  908. d->Packet(&pack, sizeof(TPacketGCCharacterDelete));
  909. if (entity->IsType(ENTITY_CHARACTER))
  910. sys_log(3, "EntityRemove %s(%d) FROM %s", GetName(), (DWORD) m_vid, ((LPCHARACTER) entity)->GetName());
  911. }
  912. void CHARACTER::UpdatePacket()
  913. {
  914. if (GetSectree() == NULL) return;
  915. TPacketGCCharacterUpdate pack;
  916. TPacketGCCharacterUpdate pack2;
  917. pack.header = HEADER_GC_CHARACTER_UPDATE;
  918. pack.dwVID = m_vid;
  919. pack.awPart[CHR_EQUIPPART_ARMOR] = GetPart(PART_MAIN);
  920. pack.awPart[CHR_EQUIPPART_WEAPON] = GetPart(PART_WEAPON);
  921. pack.awPart[CHR_EQUIPPART_HEAD] = GetPart(PART_HEAD);
  922. pack.awPart[CHR_EQUIPPART_HAIR] = GetPart(PART_HAIR);
  923. #ifdef __SASH_SYSTEM__
  924. pack.awPart[CHR_EQUIPPART_SASH] = GetPart(PART_SASH);
  925. #endif
  926. pack.bMovingSpeed = GetLimitPoint(POINT_MOV_SPEED);
  927. pack.bAttackSpeed = GetLimitPoint(POINT_ATT_SPEED);
  928. pack.bStateFlag = m_bAddChrState;
  929. pack.dwAffectFlag[0] = m_afAffectFlag.bits[0];
  930. pack.dwAffectFlag[1] = m_afAffectFlag.bits[1];
  931. pack.dwGuildID = 0;
  932. pack.sAlignment = m_iAlignment / 10;
  933. pack.bPKMode = m_bPKMode;
  934. if (GetGuild())
  935. pack.dwGuildID = GetGuild()->GetID();
  936. pack.dwMountVnum = GetMountVnum();
  937. #ifdef ENABLE_LEADER_SYSTEM
  938. CGuild* pGuild = this->GetGuild();
  939. if (pGuild)
  940. {
  941. if (pGuild->GetMasterPID() == GetPlayerID())
  942. pack.dwNewIsGuildName = 3;
  943. else if (pGuild->NewIsGuildGeneral(GetPlayerID()) == true)
  944. pack.dwNewIsGuildName = 2;
  945. else
  946. pack.dwNewIsGuildName = 1;
  947. }
  948. else
  949. {
  950. pack.dwNewIsGuildName = 0;
  951. }
  952. #endif
  953. #ifdef ENABLE_RARITY_SYSTEM
  954. LPITEM weapon = GetWear(WEAR_WEAPON);
  955. pack.lWeaponRarity = weapon ? weapon->GetAttributeValue(6) : 0;
  956. #endif
  957. pack2 = pack;
  958. pack2.dwGuildID = 0;
  959. pack2.sAlignment = 0;
  960. if (false)
  961. {
  962. if (m_bIsObserver != true)
  963. {
  964. for (ENTITY_MAP::iterator iter = m_map_view.begin(); iter != m_map_view.end(); iter++)
  965. {
  966. LPENTITY pEntity = iter->first;
  967. if (pEntity != NULL)
  968. {
  969. if (pEntity->IsType(ENTITY_CHARACTER) == true)
  970. {
  971. if (pEntity->GetDesc() != NULL)
  972. {
  973. LPCHARACTER pChar = (LPCHARACTER)pEntity;
  974. if (GetEmpire() == pChar->GetEmpire() || pChar->GetGMLevel() > GM_PLAYER)
  975. {
  976. pEntity->GetDesc()->Packet(&pack, sizeof(pack));
  977. }
  978. else
  979. {
  980. pEntity->GetDesc()->Packet(&pack2, sizeof(pack2));
  981. }
  982. }
  983. }
  984. else
  985. {
  986. if (pEntity->GetDesc() != NULL)
  987. {
  988. pEntity->GetDesc()->Packet(&pack, sizeof(pack));
  989. }
  990. }
  991. }
  992. }
  993. }
  994. if (GetDesc() != NULL)
  995. {
  996. GetDesc()->Packet(&pack, sizeof(pack));
  997. }
  998. }
  999. else
  1000. {
  1001. PacketAround(&pack, sizeof(pack));
  1002. }
  1003. }
  1004. LPCHARACTER CHARACTER::FindCharacterInView(const char * c_pszName, bool bFindPCOnly)
  1005. {
  1006. ENTITY_MAP::iterator it = m_map_view.begin();
  1007. for (; it != m_map_view.end(); ++it)
  1008. {
  1009. if (!it->first->IsType(ENTITY_CHARACTER))
  1010. continue;
  1011. LPCHARACTER tch = (LPCHARACTER) it->first;
  1012. if (bFindPCOnly && tch->IsNPC())
  1013. continue;
  1014. if (!strcasecmp(tch->GetName(), c_pszName))
  1015. return (tch);
  1016. }
  1017. return NULL;
  1018. }
  1019. void CHARACTER::SetPosition(int pos)
  1020. {
  1021. if (pos == POS_STANDING)
  1022. {
  1023. REMOVE_BIT(m_bAddChrState, ADD_CHARACTER_STATE_DEAD);
  1024. REMOVE_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_STUN);
  1025. event_cancel(&m_pkDeadEvent);
  1026. event_cancel(&m_pkStunEvent);
  1027. }
  1028. else if (pos == POS_DEAD)
  1029. SET_BIT(m_bAddChrState, ADD_CHARACTER_STATE_DEAD);
  1030. if (!IsStone())
  1031. {
  1032. switch (pos)
  1033. {
  1034. case POS_FIGHTING:
  1035. if (!IsState(m_stateBattle))
  1036. MonsterLog("[BATTLE] ½Î¿ì´Â »óÅÂ");
  1037. GotoState(m_stateBattle);
  1038. break;
  1039. default:
  1040. if (!IsState(m_stateIdle))
  1041. MonsterLog("[IDLE] ½¬´Â »óÅÂ");
  1042. GotoState(m_stateIdle);
  1043. break;
  1044. }
  1045. }
  1046. m_pointsInstant.position = pos;
  1047. }
  1048. void CHARACTER::Save()
  1049. {
  1050. if (!m_bSkipSave)
  1051. CHARACTER_MANAGER::instance().DelayedSave(this);
  1052. }
  1053. void CHARACTER::CreatePlayerProto(TPlayerTable & tab)
  1054. {
  1055. memset(&tab, 0, sizeof(TPlayerTable));
  1056. if (GetNewName().empty())
  1057. {
  1058. strlcpy(tab.name, GetName(), sizeof(tab.name));
  1059. }
  1060. else
  1061. {
  1062. strlcpy(tab.name, GetNewName().c_str(), sizeof(tab.name));
  1063. }
  1064. strlcpy(tab.ip, GetDesc()->GetHostName(), sizeof(tab.ip));
  1065. tab.id = m_dwPlayerID;
  1066. tab.voice = GetPoint(POINT_VOICE);
  1067. tab.level = GetLevel();
  1068. tab.level_step = GetPoint(POINT_LEVEL_STEP);
  1069. tab.exp = GetExp();
  1070. tab.gold = GetGold();
  1071. tab.job = m_points.job;
  1072. tab.part_base = m_pointsInstant.bBasePart;
  1073. tab.skill_group = m_points.skill_group;
  1074. DWORD dwPlayedTime = (get_dword_time() - m_dwPlayStartTime);
  1075. if (dwPlayedTime > 60000)
  1076. {
  1077. if (GetSectree() && !GetSectree()->IsAttr(GetX(), GetY(), ATTR_BANPK))
  1078. {
  1079. if (GetRealAlignment() < 0)
  1080. {
  1081. if (IsEquipUniqueItem(UNIQUE_ITEM_FASTER_ALIGNMENT_UP_BY_TIME))
  1082. UpdateAlignment(120 * (dwPlayedTime / 60000));
  1083. else
  1084. UpdateAlignment(60 * (dwPlayedTime / 60000));
  1085. }
  1086. else
  1087. UpdateAlignment(5 * (dwPlayedTime / 60000));
  1088. }
  1089. SetRealPoint(POINT_PLAYTIME, GetRealPoint(POINT_PLAYTIME) + dwPlayedTime / 60000);
  1090. ResetPlayTime(dwPlayedTime % 60000);
  1091. }
  1092. tab.playtime = GetRealPoint(POINT_PLAYTIME);
  1093. tab.lAlignment = m_iRealAlignment;
  1094. if (m_posWarp.x != 0 || m_posWarp.y != 0)
  1095. {
  1096. tab.x = m_posWarp.x;
  1097. tab.y = m_posWarp.y;
  1098. tab.z = 0;
  1099. tab.lMapIndex = m_lWarpMapIndex;
  1100. }
  1101. else
  1102. {
  1103. tab.x = GetX();
  1104. tab.y = GetY();
  1105. tab.z = GetZ();
  1106. tab.lMapIndex = GetMapIndex();
  1107. }
  1108. if (m_lExitMapIndex == 0)
  1109. {
  1110. tab.lExitMapIndex = tab.lMapIndex;
  1111. tab.lExitX = tab.x;
  1112. tab.lExitY = tab.y;
  1113. }
  1114. else
  1115. {
  1116. tab.lExitMapIndex = m_lExitMapIndex;
  1117. tab.lExitX = m_posExit.x;
  1118. tab.lExitY = m_posExit.y;
  1119. }
  1120. sys_log(0, "SAVE: %s %dx%d", GetName(), tab.x, tab.y);
  1121. tab.st = GetRealPoint(POINT_ST);
  1122. tab.ht = GetRealPoint(POINT_HT);
  1123. tab.dx = GetRealPoint(POINT_DX);
  1124. tab.iq = GetRealPoint(POINT_IQ);
  1125. tab.stat_point = GetPoint(POINT_STAT);
  1126. tab.skill_point = GetPoint(POINT_SKILL);
  1127. tab.sub_skill_point = GetPoint(POINT_SUB_SKILL);
  1128. tab.horse_skill_point = GetPoint(POINT_HORSE_SKILL);
  1129. tab.stat_reset_count = GetPoint(POINT_STAT_RESET_COUNT);
  1130. tab.hp = GetHP();
  1131. tab.sp = GetSP();
  1132. tab.stamina = GetStamina();
  1133. tab.sRandomHP = m_points.iRandomHP;
  1134. tab.sRandomSP = m_points.iRandomSP;
  1135. for (int i = 0; i < QUICKSLOT_MAX_NUM; ++i)
  1136. tab.quickslot[i] = m_quickslot[i];
  1137. if (m_stMobile.length() && !*m_szMobileAuth)
  1138. strlcpy(tab.szMobile, m_stMobile.c_str(), sizeof(tab.szMobile));
  1139. thecore_memcpy(tab.parts, m_pointsInstant.parts, sizeof(tab.parts));
  1140. // REMOVE_REAL_SKILL_LEVLES
  1141. thecore_memcpy(tab.skills, m_pSkillLevels, sizeof(TPlayerSkill) * SKILL_MAX_NUM);
  1142. // END_OF_REMOVE_REAL_SKILL_LEVLES
  1143. tab.horse = GetHorseData();
  1144. }
  1145. void CHARACTER::SaveReal()
  1146. {
  1147. if (m_bSkipSave)
  1148. return;
  1149. if (!GetDesc())
  1150. {
  1151. sys_err("Character::Save : no descriptor when saving (name: %s)", GetName());
  1152. return;
  1153. }
  1154. TPlayerTable table;
  1155. CreatePlayerProto(table);
  1156. db_clientdesc->DBPacket(HEADER_GD_PLAYER_SAVE, GetDesc()->GetHandle(), &table, sizeof(TPlayerTable));
  1157. quest::PC * pkQuestPC = quest::CQuestManager::instance().GetPCForce(GetPlayerID());
  1158. if (!pkQuestPC)
  1159. sys_err("CHARACTER::Save : null quest::PC pointer! (name %s)", GetName());
  1160. else
  1161. {
  1162. pkQuestPC->Save();
  1163. }
  1164. marriage::TMarriage* pMarriage = marriage::CManager::instance().Get(GetPlayerID());
  1165. if (pMarriage)
  1166. pMarriage->Save();
  1167. }
  1168. void CHARACTER::FlushDelayedSaveItem()
  1169. {
  1170. LPITEM item;
  1171. for (int i = 0; i < INVENTORY_AND_EQUIP_SLOT_MAX; ++i)
  1172. if ((item = GetInventoryItem(i)))
  1173. ITEM_MANAGER::instance().FlushDelayedSave(item);
  1174. }
  1175. void CHARACTER::Disconnect(const char * c_pszReason)
  1176. {
  1177. assert(GetDesc() != NULL);
  1178. sys_log(0, "DISCONNECT: %s (%s)", GetName(), c_pszReason ? c_pszReason : "unset" );
  1179. if (GetShop())
  1180. {
  1181. GetShop()->RemoveGuest(this);
  1182. SetShop(NULL);
  1183. }
  1184. #ifdef ENABLE_OFFLINE_SHOP_SYSTEM
  1185. if (GetOfflineShop())
  1186. {
  1187. GetOfflineShop()->RemoveGuest(this);
  1188. SetOfflineShop(NULL);
  1189. }
  1190. #endif
  1191. if (GetArena() != NULL)
  1192. {
  1193. GetArena()->OnDisconnect(GetPlayerID());
  1194. }
  1195. if (GetParty() != NULL)
  1196. {
  1197. GetParty()->UpdateOfflineState(GetPlayerID());
  1198. }
  1199. marriage::CManager::instance().Logout(this);
  1200. // P2P Logout
  1201. TPacketGGLogout p;
  1202. p.bHeader = HEADER_GG_LOGOUT;
  1203. strlcpy(p.szName, GetName(), sizeof(p.szName));
  1204. P2P_MANAGER::instance().Send(&p, sizeof(TPacketGGLogout));
  1205. LogManager::instance().CharLog(this, 0, "LOGOUT", "");
  1206. #ifdef ENABLE_PCBANG_FEATURE
  1207. {
  1208. long playTime = GetRealPoint(POINT_PLAYTIME) - m_dwLoginPlayTime;
  1209. LogManager::instance().LoginLog(false, GetDesc()->GetAccountTable().id, GetPlayerID(), GetLevel(), GetJob(), playTime);
  1210. if (0)
  1211. CPCBangManager::instance().Log(GetDesc()->GetHostName(), GetPlayerID(), playTime);
  1212. }
  1213. #endif
  1214. if (m_pWarMap)
  1215. SetWarMap(NULL);
  1216. if (m_pWeddingMap)
  1217. {
  1218. SetWeddingMap(NULL);
  1219. }
  1220. if (GetGuild())
  1221. GetGuild()->LogoutMember(this);
  1222. quest::CQuestManager::instance().LogoutPC(this);
  1223. if (GetParty())
  1224. GetParty()->Unlink(this);
  1225. if (IsStun() || IsDead())
  1226. {
  1227. DeathPenalty(0);
  1228. PointChange(POINT_HP, 50 - GetHP());
  1229. }
  1230. if (!CHARACTER_MANAGER::instance().FlushDelayedSave(this))
  1231. {
  1232. SaveReal();
  1233. }
  1234. FlushDelayedSaveItem();
  1235. SaveAffect();
  1236. m_bIsLoadedAffect = false;
  1237. m_bSkipSave = true;
  1238. quest::CQuestManager::instance().DisconnectPC(this);
  1239. CloseSafebox();
  1240. CloseMall();
  1241. CPVPManager::instance().Disconnect(this);
  1242. CTargetManager::instance().Logout(GetPlayerID());
  1243. MessengerManager::instance().Logout(GetName());
  1244. if (g_TeenDesc)
  1245. {
  1246. int offset = 0;
  1247. char buf[245] = {0};
  1248. buf[0] = HEADER_GT_LOGOUT;
  1249. offset += 1;
  1250. memset(buf+offset, 0x00, 2);
  1251. offset += 2;
  1252. TAccountTable &acc_table = GetDesc()->GetAccountTable();
  1253. memcpy(buf+offset, &acc_table.id, 4);
  1254. offset += 4;
  1255. g_TeenDesc->Packet(buf, offset);
  1256. }
  1257. if (GetDesc())
  1258. {
  1259. GetDesc()->BindCharacter(NULL);
  1260. // BindDesc(NULL);
  1261. }
  1262. CXTrapManager::instance().DestroyClientSession(this);
  1263. M2_DESTROY_CHARACTER(this);
  1264. }
  1265. bool CHARACTER::Show(long lMapIndex, long x, long y, long z, bool bShowSpawnMotion/* = false */)
  1266. {
  1267. LPSECTREE sectree = SECTREE_MANAGER::instance().Get(lMapIndex, x, y);
  1268. if (!sectree)
  1269. {
  1270. sys_log(0, "cannot find sectree by %dx%d mapindex %d", x, y, lMapIndex);
  1271. return false;
  1272. }
  1273. SetMapIndex(lMapIndex);
  1274. bool bChangeTree = false;
  1275. if (!GetSectree() || GetSectree() != sectree)
  1276. bChangeTree = true;
  1277. if (bChangeTree)
  1278. {
  1279. if (GetSectree())
  1280. GetSectree()->RemoveEntity(this);
  1281. ViewCleanup();
  1282. }
  1283. if (!IsNPC())
  1284. {
  1285. sys_log(0, "SHOW: %s %dx%dx%d", GetName(), x, y, z);
  1286. if (GetStamina() < GetMaxStamina())
  1287. StartAffectEvent();
  1288. }
  1289. else if (m_pkMobData)
  1290. {
  1291. m_pkMobInst->m_posLastAttacked.x = x;
  1292. m_pkMobInst->m_posLastAttacked.y = y;
  1293. m_pkMobInst->m_posLastAttacked.z = z;
  1294. }
  1295. if (bShowSpawnMotion)
  1296. {
  1297. SET_BIT(m_bAddChrState, ADD_CHARACTER_STATE_SPAWN);
  1298. m_afAffectFlag.Set(AFF_SPAWN);
  1299. }
  1300. SetXYZ(x, y, z);
  1301. m_posDest.x = x;
  1302. m_posDest.y = y;
  1303. m_posDest.z = z;
  1304. m_posStart.x = x;
  1305. m_posStart.y = y;
  1306. m_posStart.z = z;
  1307. if (bChangeTree)
  1308. {
  1309. EncodeInsertPacket(this);
  1310. sectree->InsertEntity(this);
  1311. UpdateSectree();
  1312. }
  1313. else
  1314. {
  1315. ViewReencode();
  1316. sys_log(0, " in same sectree");
  1317. }
  1318. REMOVE_BIT(m_bAddChrState, ADD_CHARACTER_STATE_SPAWN);
  1319. SetValidComboInterval(0);
  1320. return true;
  1321. }
  1322. // BGM_INFO
  1323. struct BGMInfo
  1324. {
  1325. std::string name;
  1326. float vol;
  1327. };
  1328. typedef std::map<unsigned, BGMInfo> BGMInfoMap;
  1329. static BGMInfoMap gs_bgmInfoMap;
  1330. static bool gs_bgmVolEnable = false;
  1331. void CHARACTER_SetBGMVolumeEnable()
  1332. {
  1333. gs_bgmVolEnable = true;
  1334. sys_log(0, "bgm_info.set_bgm_volume_enable");
  1335. }
  1336. void CHARACTER_AddBGMInfo(unsigned mapIndex, const char* name, float vol)
  1337. {
  1338. BGMInfo newInfo;
  1339. newInfo.name = name;
  1340. newInfo.vol = vol;
  1341. gs_bgmInfoMap[mapIndex] = newInfo;
  1342. sys_log(0, "bgm_info.add_info(%d, '%s', %f)", mapIndex, name, vol);
  1343. }
  1344. const BGMInfo& CHARACTER_GetBGMInfo(unsigned mapIndex)
  1345. {
  1346. BGMInfoMap::iterator f = gs_bgmInfoMap.find(mapIndex);
  1347. if (gs_bgmInfoMap.end() == f)
  1348. {
  1349. static BGMInfo s_empty = {"", 0.0f};
  1350. return s_empty;
  1351. }
  1352. return f->second;
  1353. }
  1354. bool CHARACTER_IsBGMVolumeEnable()
  1355. {
  1356. return gs_bgmVolEnable;
  1357. }
  1358. // END_OF_BGM_INFO
  1359. void CHARACTER::MainCharacterPacket()
  1360. {
  1361. const unsigned mapIndex = GetMapIndex();
  1362. const BGMInfo& bgmInfo = CHARACTER_GetBGMInfo(mapIndex);
  1363. // SUPPORT_BGM
  1364. if (!bgmInfo.name.empty())
  1365. {
  1366. if (CHARACTER_IsBGMVolumeEnable())
  1367. {
  1368. sys_log(1, "bgm_info.play_bgm_vol(%d, name='%s', vol=%f)", mapIndex, bgmInfo.name.c_str(), bgmInfo.vol);
  1369. TPacketGCMainCharacter4_BGM_VOL mainChrPacket;
  1370. mainChrPacket.header = HEADER_GC_MAIN_CHARACTER4_BGM_VOL;
  1371. mainChrPacket.dwVID = m_vid;
  1372. mainChrPacket.wRaceNum = GetRaceNum();
  1373. mainChrPacket.lx = GetX();
  1374. mainChrPacket.ly = GetY();
  1375. mainChrPacket.lz = GetZ();
  1376. mainChrPacket.empire = GetDesc()->GetEmpire();
  1377. mainChrPacket.skill_group = GetSkillGroup();
  1378. strlcpy(mainChrPacket.szChrName, GetName(), sizeof(mainChrPacket.szChrName));
  1379. mainChrPacket.fBGMVol = bgmInfo.vol;
  1380. strlcpy(mainChrPacket.szBGMName, bgmInfo.name.c_str(), sizeof(mainChrPacket.szBGMName));
  1381. GetDesc()->Packet(&mainChrPacket, sizeof(TPacketGCMainCharacter4_BGM_VOL));
  1382. }
  1383. else
  1384. {
  1385. sys_log(1, "bgm_info.play(%d, '%s')", mapIndex, bgmInfo.name.c_str());
  1386. TPacketGCMainCharacter3_BGM mainChrPacket;
  1387. mainChrPacket.header = HEADER_GC_MAIN_CHARACTER3_BGM;
  1388. mainChrPacket.dwVID = m_vid;
  1389. mainChrPacket.wRaceNum = GetRaceNum();
  1390. mainChrPacket.lx = GetX();
  1391. mainChrPacket.ly = GetY();
  1392. mainChrPacket.lz = GetZ();
  1393. mainChrPacket.empire = GetDesc()->GetEmpire();
  1394. mainChrPacket.skill_group = GetSkillGroup();
  1395. strlcpy(mainChrPacket.szChrName, GetName(), sizeof(mainChrPacket.szChrName));
  1396. strlcpy(mainChrPacket.szBGMName, bgmInfo.name.c_str(), sizeof(mainChrPacket.szBGMName));
  1397. GetDesc()->Packet(&mainChrPacket, sizeof(TPacketGCMainCharacter3_BGM));
  1398. }
  1399. //if (m_stMobile.length())
  1400. // ChatPacket(CHAT_TYPE_COMMAND, "sms");
  1401. }
  1402. // END_OF_SUPPORT_BGM
  1403. else
  1404. {
  1405. sys_log(0, "bgm_info.play(%d, DEFAULT_BGM_NAME)", mapIndex);
  1406. TPacketGCMainCharacter pack;
  1407. pack.header = HEADER_GC_MAIN_CHARACTER;
  1408. pack.dwVID = m_vid;
  1409. pack.wRaceNum = GetRaceNum();
  1410. pack.lx = GetX();
  1411. pack.ly = GetY();
  1412. pack.lz = GetZ();
  1413. pack.empire = GetDesc()->GetEmpire();
  1414. pack.skill_group = GetSkillGroup();
  1415. strlcpy(pack.szName, GetName(), sizeof(pack.szName));
  1416. GetDesc()->Packet(&pack, sizeof(TPacketGCMainCharacter));
  1417. if (m_stMobile.length())
  1418. ChatPacket(CHAT_TYPE_COMMAND, "sms");
  1419. }
  1420. }
  1421. void CHARACTER::PointsPacket()
  1422. {
  1423. if (!GetDesc())
  1424. return;
  1425. TPacketGCPoints pack;
  1426. pack.header = HEADER_GC_CHARACTER_POINTS;
  1427. pack.points[POINT_LEVEL] = GetLevel();
  1428. pack.points[POINT_EXP] = GetExp();
  1429. pack.points[POINT_NEXT_EXP] = GetNextExp();
  1430. pack.points[POINT_HP] = GetHP();
  1431. pack.points[POINT_MAX_HP] = GetMaxHP();
  1432. pack.points[POINT_SP] = GetSP();
  1433. pack.points[POINT_MAX_SP] = GetMaxSP();
  1434. pack.points[POINT_GOLD] = GetGold();
  1435. #ifdef __COINS_SYSTEM__
  1436. pack.points[POINT_COINS] = GetCoins();
  1437. #endif
  1438. pack.points[POINT_STAMINA] = GetStamina();
  1439. pack.points[POINT_MAX_STAMINA] = GetMaxStamina();
  1440. for (int i = POINT_ST; i < POINT_MAX_NUM; ++i)
  1441. pack.points[i] = GetPoint(i);
  1442. GetDesc()->Packet(&pack, sizeof(TPacketGCPoints));
  1443. }
  1444. bool CHARACTER::ChangeSex()
  1445. {
  1446. int src_race = GetRaceNum();
  1447. switch (src_race)
  1448. {
  1449. case MAIN_RACE_WARRIOR_M:
  1450. m_points.job = MAIN_RACE_WARRIOR_W;
  1451. break;
  1452. case MAIN_RACE_WARRIOR_W:
  1453. m_points.job = MAIN_RACE_WARRIOR_M;
  1454. break;
  1455. case MAIN_RACE_ASSASSIN_M:
  1456. m_points.job = MAIN_RACE_ASSASSIN_W;
  1457. break;
  1458. case MAIN_RACE_ASSASSIN_W:
  1459. m_points.job = MAIN_RACE_ASSASSIN_M;
  1460. break;
  1461. case MAIN_RACE_SURA_M:
  1462. m_points.job = MAIN_RACE_SURA_W;
  1463. break;
  1464. case MAIN_RACE_SURA_W:
  1465. m_points.job = MAIN_RACE_SURA_M;
  1466. break;
  1467. case MAIN_RACE_SHAMAN_M:
  1468. m_points.job = MAIN_RACE_SHAMAN_W;
  1469. break;
  1470. case MAIN_RACE_SHAMAN_W:
  1471. m_points.job = MAIN_RACE_SHAMAN_M;
  1472. break;
  1473. #ifdef ENABLE_WOLFMAN_CHARACTER
  1474. case MAIN_RACE_WOLFMAN_M:
  1475. m_points.job = MAIN_RACE_WOLFMAN_M;
  1476. break;
  1477. #endif
  1478. default:
  1479. sys_err("CHANGE_SEX: %s unknown race %d", GetName(), src_race);
  1480. return false;
  1481. }
  1482. sys_log(0, "CHANGE_SEX: %s (%d -> %d)", GetName(), src_race, m_points.job);
  1483. return true;
  1484. }
  1485. WORD CHARACTER::GetRaceNum() const
  1486. {
  1487. if (m_dwPolymorphRace)
  1488. return m_dwPolymorphRace;
  1489. if (m_pkMobData)
  1490. return m_pkMobData->m_table.dwVnum;
  1491. return m_points.job;
  1492. }
  1493. void CHARACTER::SetRace(BYTE race)
  1494. {
  1495. if (race >= MAIN_RACE_MAX_NUM)
  1496. {
  1497. sys_err("CHARACTER::SetRace(name=%s, race=%d).OUT_OF_RACE_RANGE", GetName(), race);
  1498. return;
  1499. }
  1500. m_points.job = race;
  1501. }
  1502. BYTE CHARACTER::GetJob() const
  1503. {
  1504. unsigned race = m_points.job;
  1505. unsigned job;
  1506. if (RaceToJob(race, &job))
  1507. return job;
  1508. sys_err("CHARACTER::GetJob(name=%s, race=%d).OUT_OF_RACE_RANGE", GetName(), race);
  1509. return JOB_WARRIOR;
  1510. }
  1511. void CHARACTER::SetLevel(BYTE level)
  1512. {
  1513. m_points.level = level;
  1514. if (IsPC())
  1515. {
  1516. if (level < PK_PROTECT_LEVEL)
  1517. SetPKMode(PK_MODE_PROTECT);
  1518. else if (GetGMLevel() != GM_PLAYER)
  1519. SetPKMode(PK_MODE_PROTECT);
  1520. else if (m_bPKMode == PK_MODE_PROTECT)
  1521. SetPKMode(PK_MODE_PEACE);
  1522. }
  1523. }
  1524. void CHARACTER::SetEmpire(BYTE bEmpire)
  1525. {
  1526. m_bEmpire = bEmpire;
  1527. }
  1528. #ifdef __COINS_SYSTEM__
  1529. long CHARACTER::GetEp() const
  1530. {
  1531. std::auto_ptr<SQLMsg> pMsg(DBManager::instance().DirectQuery("SELECT coins FROM account.account WHERE id = '%d';", GetDesc()->GetAccountTable().id));
  1532. if (pMsg->Get()->uiNumRows == 0)
  1533. return 0;
  1534. MYSQL_ROW row = mysql_fetch_row(pMsg->Get()->pSQLResult);
  1535. DWORD ep = 0;
  1536. str_to_number(ep, row[0]);
  1537. return ep;
  1538. }
  1539. void CHARACTER::SetCoins(long coins)
  1540. {
  1541. DBManager::instance().DirectQuery("UPDATE account.account SET coins = '%d' WHERE id = '%d';", coins, GetDesc()->GetAccountTable().id);
  1542. m_coins = coins;
  1543. }
  1544. void CHARACTER::SetEp(long coins)
  1545. {
  1546. m_coins = coins;
  1547. SetPoint(POINT_COINS, coins);
  1548. }
  1549. #endif
  1550. void CHARACTER::SetPlayerProto(const TPlayerTable * t)
  1551. {
  1552. if (!GetDesc() || !*GetDesc()->GetHostName())
  1553. sys_err("cannot get desc or hostname");
  1554. else
  1555. SetGMLevel();
  1556. m_bCharType = CHAR_TYPE_PC;
  1557. m_dwPlayerID = t->id;
  1558. m_iAlignment = t->lAlignment;
  1559. m_iRealAlignment = t->lAlignment;
  1560. m_points.voice = t->voice;
  1561. m_points.skill_group = t->skill_group;
  1562. m_pointsInstant.bBasePart = t->part_base;
  1563. SetPart(PART_HAIR, t->parts[PART_HAIR]);
  1564. #ifdef __SASH_SYSTEM__
  1565. SetPart(PART_SASH, t->parts[PART_SASH]);
  1566. #endif
  1567. m_points.iRandomHP = t->sRandomHP;
  1568. m_points.iRandomSP = t->sRandomSP;
  1569. // REMOVE_REAL_SKILL_LEVLES
  1570. if (m_pSkillLevels)
  1571. M2_DELETE_ARRAY(m_pSkillLevels);
  1572. m_pSkillLevels = M2_NEW TPlayerSkill[SKILL_MAX_NUM];
  1573. thecore_memcpy(m_pSkillLevels, t->skills, sizeof(TPlayerSkill) * SKILL_MAX_NUM);
  1574. // END_OF_REMOVE_REAL_SKILL_LEVLES
  1575. if (t->lMapIndex >= 10000)
  1576. {
  1577. m_posWarp.x = t->lExitX;
  1578. m_posWarp.y = t->lExitY;
  1579. m_lWarpMapIndex = t->lExitMapIndex;
  1580. }
  1581. SetRealPoint(POINT_PLAYTIME, t->playtime);
  1582. m_dwLoginPlayTime = t->playtime;
  1583. SetRealPoint(POINT_ST, t->st);
  1584. SetRealPoint(POINT_HT, t->ht);
  1585. SetRealPoint(POINT_DX, t->dx);
  1586. SetRealPoint(POINT_IQ, t->iq);
  1587. SetPoint(POINT_ST, t->st);
  1588. SetPoint(POINT_HT, t->ht);
  1589. SetPoint(POINT_DX, t->dx);
  1590. SetPoint(POINT_IQ, t->iq);
  1591. SetPoint(POINT_STAT, t->stat_point);
  1592. SetPoint(POINT_SKILL, t->skill_point);
  1593. SetPoint(POINT_SUB_SKILL, t->sub_skill_point);
  1594. SetPoint(POINT_HORSE_SKILL, t->horse_skill_point);
  1595. SetPoint(POINT_STAT_RESET_COUNT, t->stat_reset_count);
  1596. SetPoint(POINT_LEVEL_STEP, t->level_step);
  1597. SetRealPoint(POINT_LEVEL_STEP, t->level_step);
  1598. SetRace(t->job);
  1599. SetLevel(t->level);
  1600. SetExp(t->exp);
  1601. SetGold(t->gold);
  1602. SetMapIndex(t->lMapIndex);
  1603. SetXYZ(t->x, t->y, t->z);
  1604. ComputePoints();
  1605. SetHP(t->hp);
  1606. SetSP(t->sp);
  1607. SetStamina(t->stamina);
  1608. if (!test_server)
  1609. {
  1610. if (GetGMLevel() > GM_LOW_WIZARD)
  1611. {
  1612. m_afAffectFlag.Set(AFF_YMIR);
  1613. m_bPKMode = PK_MODE_PROTECT;
  1614. }
  1615. }
  1616. if (GetLevel() < PK_PROTECT_LEVEL)
  1617. m_bPKMode = PK_MODE_PROTECT;
  1618. m_stMobile = t->szMobile;
  1619. SetHorseData(t->horse);
  1620. if (GetHorseLevel() > 0)
  1621. UpdateHorseDataByLogoff(t->logoff_interval);
  1622. thecore_memcpy(m_aiPremiumTimes, t->aiPremiumTimes, sizeof(t->aiPremiumTimes));
  1623. m_dwLogOffInterval = t->logoff_interval;
  1624. 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);
  1625. if (GetGMLevel() != GM_PLAYER)
  1626. {
  1627. LogManager::instance().CharLog(this, GetGMLevel(), "GM_LOGIN", "");
  1628. sys_log(0, "GM_LOGIN(gmlevel=%d, name=%s(%d), pos=(%d, %d)", GetGMLevel(), GetName(), GetPlayerID(), GetX(), GetY());
  1629. }
  1630. #ifdef __PET_SYSTEM__
  1631. if (m_petSystem)
  1632. {
  1633. m_petSystem->Destroy();
  1634. delete m_petSystem;
  1635. }
  1636. m_petSystem = M2_NEW CPetSystem(this);
  1637. #endif
  1638. SetOfflineShopVID(COfflineShopManager::instance().FindMyOfflineShop(GetPlayerID()));
  1639. }
  1640. EVENTFUNC(kill_ore_load_event)
  1641. {
  1642. char_event_info* info = dynamic_cast<char_event_info*>( event->info );
  1643. if ( info == NULL )
  1644. {
  1645. sys_err( "kill_ore_load_even> <Factor> Null pointer" );
  1646. return 0;
  1647. }
  1648. LPCHARACTER ch = info->ch;
  1649. if (ch == NULL) {
  1650. return 0;
  1651. }
  1652. ch->m_pkMiningEvent = NULL;
  1653. M2_DESTROY_CHARACTER(ch);
  1654. return 0;
  1655. }
  1656. void CHARACTER::SetProto(const CMob * pkMob)
  1657. {
  1658. if (m_pkMobInst)
  1659. M2_DELETE(m_pkMobInst);
  1660. m_pkMobData = pkMob;
  1661. m_pkMobInst = M2_NEW CMobInstance;
  1662. m_bPKMode = PK_MODE_FREE;
  1663. const TMobTable * t = &m_pkMobData->m_table;
  1664. m_bCharType = t->bType;
  1665. SetLevel(t->bLevel);
  1666. SetEmpire(t->bEmpire);
  1667. SetExp(t->dwExp);
  1668. SetRealPoint(POINT_ST, t->bStr);
  1669. SetRealPoint(POINT_DX, t->bDex);
  1670. SetRealPoint(POINT_HT, t->bCon);
  1671. SetRealPoint(POINT_IQ, t->bInt);
  1672. ComputePoints();
  1673. SetHP(GetMaxHP());
  1674. SetSP(GetMaxSP());
  1675. ////////////////////
  1676. m_pointsInstant.dwAIFlag = t->dwAIFlag;
  1677. SetImmuneFlag(t->dwImmuneFlag);
  1678. AssignTriggers(t);
  1679. ApplyMobAttribute(t);
  1680. if (IsStone())
  1681. {
  1682. DetermineDropMetinStone();
  1683. }
  1684. if (IsWarp() || IsGoto())
  1685. {
  1686. StartWarpNPCEvent();
  1687. }
  1688. CHARACTER_MANAGER::instance().RegisterRaceNumMap(this);
  1689. if (GetRaceNum() == xmas::MOB_SANTA_VNUM)
  1690. {
  1691. SetPoint(POINT_ATT_GRADE_BONUS, 10);
  1692. SetPoint(POINT_DEF_GRADE_BONUS, 6);
  1693. m_dwPlayStartTime = get_dword_time() + 30 * 1000;
  1694. if (test_server)
  1695. m_dwPlayStartTime = get_dword_time() + 30 * 1000;
  1696. }
  1697. if (warmap::IsWarFlag(GetRaceNum()))
  1698. {
  1699. m_stateIdle.Set(this, &CHARACTER::BeginStateEmpty, &CHARACTER::StateFlag, &CHARACTER::EndStateEmpty);
  1700. m_stateMove.Set(this, &CHARACTER::BeginStateEmpty, &CHARACTER::StateFlag, &CHARACTER::EndStateEmpty);
  1701. m_stateBattle.Set(this, &CHARACTER::BeginStateEmpty, &CHARACTER::StateFlag, &CHARACTER::EndStateEmpty);
  1702. }
  1703. if (warmap::IsWarFlagBase(GetRaceNum()))
  1704. {
  1705. m_stateIdle.Set(this, &CHARACTER::BeginStateEmpty, &CHARACTER::StateFlagBase, &CHARACTER::EndStateEmpty);
  1706. m_stateMove.Set(this, &CHARACTER::BeginStateEmpty, &CHARACTER::StateFlagBase, &CHARACTER::EndStateEmpty);
  1707. m_stateBattle.Set(this, &CHARACTER::BeginStateEmpty, &CHARACTER::StateFlagBase, &CHARACTER::EndStateEmpty);
  1708. }
  1709. if (m_bCharType == CHAR_TYPE_HORSE ||
  1710. GetRaceNum() == 20101 ||
  1711. GetRaceNum() == 20102 ||
  1712. GetRaceNum() == 20103 ||
  1713. GetRaceNum() == 20104 ||
  1714. GetRaceNum() == 20105 ||
  1715. GetRaceNum() == 20106 ||
  1716. GetRaceNum() == 20107 ||
  1717. GetRaceNum() == 20108 ||
  1718. GetRaceNum() == 20109
  1719. )
  1720. {
  1721. m_stateIdle.Set(this, &CHARACTER::BeginStateEmpty, &CHARACTER::StateHorse, &CHARACTER::EndStateEmpty);
  1722. m_stateMove.Set(this, &CHARACTER::BeginStateEmpty, &CHARACTER::StateMove, &CHARACTER::EndStateEmpty);
  1723. m_stateBattle.Set(this, &CHARACTER::BeginStateEmpty, &CHARACTER::StateHorse, &CHARACTER::EndStateEmpty);
  1724. }
  1725. // MINING
  1726. if (mining::IsVeinOfOre (GetRaceNum()))
  1727. {
  1728. char_event_info* info = AllocEventInfo<char_event_info>();
  1729. info->ch = this;
  1730. m_pkMiningEvent = event_create(kill_ore_load_event, info, PASSES_PER_SEC(number(7 * 60, 15 * 60)));
  1731. }
  1732. // END_OF_MINING
  1733. }
  1734. const TMobTable & CHARACTER::GetMobTable() const
  1735. {
  1736. return m_pkMobData->m_table;
  1737. }
  1738. bool CHARACTER::IsRaceFlag(DWORD dwBit) const
  1739. {
  1740. return m_pkMobData ? IS_SET(m_pkMobData->m_table.dwRaceFlag, dwBit) : 0;
  1741. }
  1742. DWORD CHARACTER::GetMobDamageMin() const
  1743. {
  1744. return m_pkMobData->m_table.dwDamageRange[0];
  1745. }
  1746. DWORD CHARACTER::GetMobDamageMax() const
  1747. {
  1748. return m_pkMobData->m_table.dwDamageRange[1];
  1749. }
  1750. float CHARACTER::GetMobDamageMultiply() const
  1751. {
  1752. float fDamMultiply = GetMobTable().fDamMultiply;
  1753. if (IsBerserk())
  1754. fDamMultiply = fDamMultiply * 2.0f;
  1755. return fDamMultiply;
  1756. }
  1757. DWORD CHARACTER::GetMobDropItemVnum() const
  1758. {
  1759. return m_pkMobData->m_table.dwDropItemVnum;
  1760. }
  1761. bool CHARACTER::IsSummonMonster() const
  1762. {
  1763. return GetSummonVnum() != 0;
  1764. }
  1765. DWORD CHARACTER::GetSummonVnum() const
  1766. {
  1767. return m_pkMobData ? m_pkMobData->m_table.dwSummonVnum : 0;
  1768. }
  1769. DWORD CHARACTER::GetPolymorphItemVnum() const
  1770. {
  1771. return m_pkMobData ? m_pkMobData->m_table.dwPolymorphItemVnum : 0;
  1772. }
  1773. DWORD CHARACTER::GetMonsterDrainSPPoint() const
  1774. {
  1775. return m_pkMobData ? m_pkMobData->m_table.dwDrainSP : 0;
  1776. }
  1777. BYTE CHARACTER::GetMobRank() const
  1778. {
  1779. if (!m_pkMobData)
  1780. return MOB_RANK_KNIGHT;
  1781. return m_pkMobData->m_table.bRank;
  1782. }
  1783. BYTE CHARACTER::GetMobSize() const
  1784. {
  1785. if (!m_pkMobData)
  1786. return MOBSIZE_MEDIUM;
  1787. return m_pkMobData->m_table.bSize;
  1788. }
  1789. WORD CHARACTER::GetMobAttackRange() const
  1790. {
  1791. switch (GetMobBattleType())
  1792. {
  1793. case BATTLE_TYPE_RANGE:
  1794. case BATTLE_TYPE_MAGIC:
  1795. return m_pkMobData->m_table.wAttackRange + GetPoint(POINT_BOW_DISTANCE);
  1796. default:
  1797. return m_pkMobData->m_table.wAttackRange;
  1798. }
  1799. }
  1800. BYTE CHARACTER::GetMobBattleType() const
  1801. {
  1802. if (!m_pkMobData)
  1803. return BATTLE_TYPE_MELEE;
  1804. return (m_pkMobData->m_table.bBattleType);
  1805. }
  1806. void CHARACTER::ComputeBattlePoints()
  1807. {
  1808. if (IsPolymorphed())
  1809. {
  1810. DWORD dwMobVnum = GetPolymorphVnum();
  1811. const CMob * pMob = CMobManager::instance().Get(dwMobVnum);
  1812. int iAtt = 0;
  1813. int iDef = 0;
  1814. if (pMob)
  1815. {
  1816. iAtt = GetLevel() * 2 + GetPolymorphPoint(POINT_ST) * 2;
  1817. iDef = GetLevel() + GetPolymorphPoint(POINT_HT) + pMob->m_table.wDef;
  1818. }
  1819. SetPoint(POINT_ATT_GRADE, iAtt);
  1820. SetPoint(POINT_DEF_GRADE, iDef);
  1821. SetPoint(POINT_MAGIC_ATT_GRADE, GetPoint(POINT_ATT_GRADE));
  1822. SetPoint(POINT_MAGIC_DEF_GRADE, GetPoint(POINT_DEF_GRADE));
  1823. }
  1824. else if (IsPC())
  1825. {
  1826. SetPoint(POINT_ATT_GRADE, 0);
  1827. SetPoint(POINT_DEF_GRADE, 0);
  1828. SetPoint(POINT_CLIENT_DEF_GRADE, 0);
  1829. SetPoint(POINT_MAGIC_ATT_GRADE, GetPoint(POINT_ATT_GRADE));
  1830. SetPoint(POINT_MAGIC_DEF_GRADE, GetPoint(POINT_DEF_GRADE));
  1831. int iAtk = GetLevel() * 2;
  1832. int iStatAtk = 0;
  1833. switch (GetJob())
  1834. {
  1835. case JOB_WARRIOR:
  1836. case JOB_SURA:
  1837. iStatAtk = (2 * GetPoint(POINT_ST));
  1838. break;
  1839. case JOB_ASSASSIN:
  1840. iStatAtk = (4 * GetPoint(POINT_ST) + 2 * GetPoint(POINT_DX)) / 3;
  1841. break;
  1842. case JOB_SHAMAN:
  1843. iStatAtk = (4 * GetPoint(POINT_ST) + 2 * GetPoint(POINT_IQ)) / 3;
  1844. break;
  1845. #ifdef ENABLE_WOLFMAN_CHARACTER
  1846. case JOB_WOLFMAN:
  1847. iStatAtk = (2 * GetPoint(POINT_ST));
  1848. break;
  1849. #endif
  1850. default:
  1851. sys_err("invalid job %d", GetJob());
  1852. iStatAtk = (2 * GetPoint(POINT_ST));
  1853. break;
  1854. }
  1855. if (GetMountVnum() && iStatAtk < 2 * GetPoint(POINT_ST))
  1856. iStatAtk = (2 * GetPoint(POINT_ST));
  1857. iAtk += iStatAtk;
  1858. if (GetMountVnum())
  1859. {
  1860. if (GetJob() == JOB_SURA && GetSkillGroup() == 1)
  1861. {
  1862. iAtk += (iAtk * GetHorseLevel()) / 60;
  1863. }
  1864. else
  1865. {
  1866. iAtk += (iAtk * GetHorseLevel()) / 30;
  1867. }
  1868. }
  1869. //
  1870. // ATK Setting
  1871. //
  1872. iAtk += GetPoint(POINT_ATT_GRADE_BONUS);
  1873. PointChange(POINT_ATT_GRADE, iAtk);
  1874. // DEF = LEV + CON + ARMOR
  1875. int iShowDef = GetLevel() + GetPoint(POINT_HT);
  1876. int iDef = GetLevel() + (int) (GetPoint(POINT_HT) / 1.25);
  1877. int iArmor = 0;
  1878. LPITEM pkItem;
  1879. for (int i = 0; i < WEAR_MAX_NUM; ++i)
  1880. if ((pkItem = GetWear(i)) && pkItem->GetType() == ITEM_ARMOR)
  1881. {
  1882. if (pkItem->GetSubType() == ARMOR_BODY || pkItem->GetSubType() == ARMOR_HEAD || pkItem->GetSubType() == ARMOR_FOOTS || pkItem->GetSubType() == ARMOR_SHIELD)
  1883. {
  1884. iArmor += pkItem->GetValue(1);
  1885. iArmor += (2 * pkItem->GetValue(5));
  1886. }
  1887. }
  1888. if( true == IsHorseRiding() )
  1889. {
  1890. if (iArmor < GetHorseArmor())
  1891. iArmor = GetHorseArmor();
  1892. const char* pHorseName = CHorseNameManager::instance().GetHorseName(GetPlayerID());
  1893. if (pHorseName != NULL && strlen(pHorseName))
  1894. {
  1895. iArmor += 20;
  1896. }
  1897. }
  1898. iArmor += GetPoint(POINT_DEF_GRADE_BONUS);
  1899. iArmor += GetPoint(POINT_PARTY_DEFENDER_BONUS);
  1900. // INTERNATIONAL_VERSION
  1901. PointChange(POINT_DEF_GRADE, iDef + iArmor);
  1902. PointChange(POINT_CLIENT_DEF_GRADE, (iShowDef + iArmor) - GetPoint(POINT_DEF_GRADE));
  1903. // END_OF_INTERNATIONAL_VERSION
  1904. PointChange(POINT_MAGIC_ATT_GRADE, GetLevel() * 2 + GetPoint(POINT_IQ) * 2 + GetPoint(POINT_MAGIC_ATT_GRADE_BONUS));
  1905. PointChange(POINT_MAGIC_DEF_GRADE, GetLevel() + (GetPoint(POINT_IQ) * 3 + GetPoint(POINT_HT)) / 3 + iArmor / 2 + GetPoint(POINT_MAGIC_DEF_GRADE_BONUS));
  1906. }
  1907. else
  1908. {
  1909. int iAtt = GetLevel() * 2 + GetPoint(POINT_ST) * 2;
  1910. int iDef = GetLevel() + GetPoint(POINT_HT) + GetMobTable().wDef;
  1911. SetPoint(POINT_ATT_GRADE, iAtt);
  1912. SetPoint(POINT_DEF_GRADE, iDef);
  1913. SetPoint(POINT_MAGIC_ATT_GRADE, GetPoint(POINT_ATT_GRADE));
  1914. SetPoint(POINT_MAGIC_DEF_GRADE, GetPoint(POINT_DEF_GRADE));
  1915. }
  1916. }
  1917. void CHARACTER::ComputePoints()
  1918. {
  1919. long lStat = GetPoint(POINT_STAT);
  1920. long lStatResetCount = GetPoint(POINT_STAT_RESET_COUNT);
  1921. long lSkillActive = GetPoint(POINT_SKILL);
  1922. long lSkillSub = GetPoint(POINT_SUB_SKILL);
  1923. long lSkillHorse = GetPoint(POINT_HORSE_SKILL);
  1924. long lLevelStep = GetPoint(POINT_LEVEL_STEP);
  1925. long lAttackerBonus = GetPoint(POINT_PARTY_ATTACKER_BONUS);
  1926. long lTankerBonus = GetPoint(POINT_PARTY_TANKER_BONUS);
  1927. long lBufferBonus = GetPoint(POINT_PARTY_BUFFER_BONUS);
  1928. long lSkillMasterBonus = GetPoint(POINT_PARTY_SKILL_MASTER_BONUS);
  1929. long lHasteBonus = GetPoint(POINT_PARTY_HASTE_BONUS);
  1930. long lDefenderBonus = GetPoint(POINT_PARTY_DEFENDER_BONUS);
  1931. long lHPRecovery = GetPoint(POINT_HP_RECOVERY);
  1932. long lSPRecovery = GetPoint(POINT_SP_RECOVERY);
  1933. #ifdef __COINS_SYSTEM__
  1934. long lcoins = GetCoins();
  1935. #endif
  1936. memset(m_pointsInstant.points, 0, sizeof(m_pointsInstant.points));
  1937. BuffOnAttr_ClearAll();
  1938. m_SkillDamageBonus.clear();
  1939. SetPoint(POINT_STAT, lStat);
  1940. SetPoint(POINT_SKILL, lSkillActive);
  1941. SetPoint(POINT_SUB_SKILL, lSkillSub);
  1942. SetPoint(POINT_HORSE_SKILL, lSkillHorse);
  1943. SetPoint(POINT_LEVEL_STEP, lLevelStep);
  1944. SetPoint(POINT_STAT_RESET_COUNT, lStatResetCount);
  1945. SetPoint(POINT_ST, GetRealPoint(POINT_ST));
  1946. SetPoint(POINT_HT, GetRealPoint(POINT_HT));
  1947. SetPoint(POINT_DX, GetRealPoint(POINT_DX));
  1948. SetPoint(POINT_IQ, GetRealPoint(POINT_IQ));
  1949. SetPart(PART_MAIN, GetOriginalPart(PART_MAIN));
  1950. SetPart(PART_WEAPON, GetOriginalPart(PART_WEAPON));
  1951. SetPart(PART_HEAD, GetOriginalPart(PART_HEAD));
  1952. SetPart(PART_HAIR, GetOriginalPart(PART_HAIR));
  1953. #ifdef __SASH_SYSTEM__
  1954. SetPart(PART_SASH, GetOriginalPart(PART_SASH));
  1955. #endif
  1956. SetPoint(POINT_PARTY_ATTACKER_BONUS, lAttackerBonus);
  1957. SetPoint(POINT_PARTY_TANKER_BONUS, lTankerBonus);
  1958. SetPoint(POINT_PARTY_BUFFER_BONUS, lBufferBonus);
  1959. SetPoint(POINT_PARTY_SKILL_MASTER_BONUS, lSkillMasterBonus);
  1960. SetPoint(POINT_PARTY_HASTE_BONUS, lHasteBonus);
  1961. SetPoint(POINT_PARTY_DEFENDER_BONUS, lDefenderBonus);
  1962. SetPoint(POINT_HP_RECOVERY, lHPRecovery);
  1963. SetPoint(POINT_SP_RECOVERY, lSPRecovery);
  1964. #ifdef __COINS_SYSTEM__
  1965. SetPoint(POINT_COINS, lcoins);
  1966. #endif
  1967. // PC_BANG_ITEM_ADD
  1968. SetPoint(POINT_PC_BANG_EXP_BONUS, 0);
  1969. SetPoint(POINT_PC_BANG_DROP_BONUS, 0);
  1970. // END_PC_BANG_ITEM_ADD
  1971. int iMaxHP, iMaxSP;
  1972. int iMaxStamina;
  1973. if (IsPC())
  1974. {
  1975. iMaxHP = JobInitialPoints[GetJob()].max_hp + m_points.iRandomHP + GetPoint(POINT_HT) * JobInitialPoints[GetJob()].hp_per_ht;
  1976. iMaxSP = JobInitialPoints[GetJob()].max_sp + m_points.iRandomSP + GetPoint(POINT_IQ) * JobInitialPoints[GetJob()].sp_per_iq;
  1977. iMaxStamina = JobInitialPoints[GetJob()].max_stamina + GetPoint(POINT_HT) * JobInitialPoints[GetJob()].stamina_per_con;
  1978. {
  1979. CSkillProto* pkSk = CSkillManager::instance().Get(SKILL_ADD_HP);
  1980. if (NULL != pkSk)
  1981. {
  1982. pkSk->SetPointVar("k", 1.0f * GetSkillPower(SKILL_ADD_HP) / 100.0f);
  1983. iMaxHP += static_cast<int>(pkSk->kPointPoly.Eval());
  1984. }
  1985. }
  1986. SetPoint(POINT_MOV_SPEED, 100);
  1987. SetPoint(POINT_ATT_SPEED, 100);
  1988. PointChange(POINT_ATT_SPEED, GetPoint(POINT_PARTY_HASTE_BONUS));
  1989. SetPoint(POINT_CASTING_SPEED, 100);
  1990. }
  1991. else
  1992. {
  1993. iMaxHP = m_pkMobData->m_table.dwMaxHP;
  1994. iMaxSP = 0;
  1995. iMaxStamina = 0;
  1996. SetPoint(POINT_ATT_SPEED, m_pkMobData->m_table.sAttackSpeed);
  1997. SetPoint(POINT_MOV_SPEED, m_pkMobData->m_table.sMovingSpeed);
  1998. SetPoint(POINT_CASTING_SPEED, m_pkMobData->m_table.sAttackSpeed);
  1999. }
  2000. if (IsPC())
  2001. {
  2002. if (GetMountVnum())
  2003. {
  2004. if (GetHorseST() > GetPoint(POINT_ST))
  2005. PointChange(POINT_ST, GetHorseST() - GetPoint(POINT_ST));
  2006. if (GetHorseDX() > GetPoint(POINT_DX))
  2007. PointChange(POINT_DX, GetHorseDX() - GetPoint(POINT_DX));
  2008. if (GetHorseHT() > GetPoint(POINT_HT))
  2009. PointChange(POINT_HT, GetHorseHT() - GetPoint(POINT_HT));
  2010. if (GetHorseIQ() > GetPoint(POINT_IQ))
  2011. PointChange(POINT_IQ, GetHorseIQ() - GetPoint(POINT_IQ));
  2012. }
  2013. }
  2014. ComputeBattlePoints();
  2015. if (iMaxHP != GetMaxHP())
  2016. {
  2017. SetRealPoint(POINT_MAX_HP, iMaxHP);
  2018. }
  2019. PointChange(POINT_MAX_HP, 0);
  2020. if (iMaxSP != GetMaxSP())
  2021. {
  2022. SetRealPoint(POINT_MAX_SP, iMaxSP);
  2023. }
  2024. PointChange(POINT_MAX_SP, 0);
  2025. SetMaxStamina(iMaxStamina);
  2026. int iCurHP = this->GetHP();
  2027. int iCurSP = this->GetSP();
  2028. m_pointsInstant.dwImmuneFlag = 0;
  2029. for (int i = 0 ; i < WEAR_MAX_NUM; i++)
  2030. {
  2031. LPITEM pItem = GetWear(i);
  2032. if (pItem)
  2033. {
  2034. pItem->ModifyPoints(true);
  2035. SET_BIT(m_pointsInstant.dwImmuneFlag, GetWear(i)->GetImmuneFlag());
  2036. }
  2037. }
  2038. if (DragonSoul_IsDeckActivated())
  2039. {
  2040. for (int i = WEAR_MAX_NUM + DS_SLOT_MAX * DragonSoul_GetActiveDeck();
  2041. i < WEAR_MAX_NUM + DS_SLOT_MAX * (DragonSoul_GetActiveDeck() + 1); i++)
  2042. {
  2043. LPITEM pItem = GetWear(i);
  2044. if (pItem)
  2045. {
  2046. if (DSManager::instance().IsTimeLeftDragonSoul(pItem))
  2047. pItem->ModifyPoints(true);
  2048. }
  2049. }
  2050. }
  2051. /*if (GetHP() > GetMaxHP())
  2052. PointChange(POINT_HP, GetMaxHP() - GetHP());
  2053. if (GetSP() > GetMaxSP())
  2054. PointChange(POINT_SP, GetMaxSP() - GetSP()); */
  2055. ComputeSkillPoints();
  2056. RefreshAffect();
  2057. if (IsPC())
  2058. {
  2059. if (this->GetHP() != iCurHP)
  2060. this->PointChange(POINT_HP, iCurHP-this->GetHP());
  2061. if (this->GetSP() != iCurSP)
  2062. this->PointChange(POINT_SP, iCurSP-this->GetSP());
  2063. }
  2064. CPetSystem* pPetSystem = GetPetSystem();
  2065. if (NULL != pPetSystem)
  2066. {
  2067. pPetSystem->RefreshBuff();
  2068. }
  2069. UpdatePacket();
  2070. if (GetHP() > GetMaxHP())
  2071. PointChange(POINT_HP, GetMaxHP() - GetHP());
  2072. if (GetSP() > GetMaxSP())
  2073. PointChange(POINT_SP, GetMaxSP() - GetSP());
  2074. }
  2075. void CHARACTER::ResetPlayTime(DWORD dwTimeRemain)
  2076. {
  2077. m_dwPlayStartTime = get_dword_time() - dwTimeRemain;
  2078. }
  2079. const int aiRecoveryPercents[10] = { 1, 5, 5, 5, 5, 5, 5, 5, 5, 5 };
  2080. EVENTFUNC(recovery_event)
  2081. {
  2082. char_event_info* info = dynamic_cast<char_event_info*>( event->info );
  2083. if ( info == NULL )
  2084. {
  2085. sys_err( "recovery_event> <Factor> Null pointer" );
  2086. return 0;
  2087. }
  2088. LPCHARACTER ch = info->ch;
  2089. if (ch == NULL) {
  2090. return 0;
  2091. }
  2092. if (!ch->IsPC())
  2093. {
  2094. if (ch->IsAffectFlag(AFF_POISON))
  2095. return PASSES_PER_SEC(MAX(1, ch->GetMobTable().bRegenCycle));
  2096. #ifdef ENABLE_WOLFMAN_CHARACTER
  2097. if (ch->IsAffectFlag(AFF_BLEEDING))
  2098. return PASSES_PER_SEC(MAX(1, ch->GetMobTable().bRegenCycle));
  2099. #endif
  2100. if (2493 == ch->GetMobTable().dwVnum)
  2101. {
  2102. int regenPct = BlueDragon_GetRangeFactor("hp_regen", ch->GetHPPct());
  2103. regenPct += ch->GetMobTable().bRegenPercent;
  2104. for (int i=1 ; i <= 4 ; ++i)
  2105. {
  2106. if (REGEN_PECT_BONUS == BlueDragon_GetIndexFactor("DragonStone", i, "effect_type"))
  2107. {
  2108. DWORD dwDragonStoneID = BlueDragon_GetIndexFactor("DragonStone", i, "vnum");
  2109. size_t val = BlueDragon_GetIndexFactor("DragonStone", i, "val");
  2110. size_t cnt = SECTREE_MANAGER::instance().GetMonsterCountInMap( ch->GetMapIndex(), dwDragonStoneID );
  2111. regenPct += (val*cnt);
  2112. break;
  2113. }
  2114. }
  2115. ch->PointChange(POINT_HP, MAX(1, (ch->GetMaxHP() * regenPct) / 100));
  2116. }
  2117. else if (!ch->IsDoor())
  2118. {
  2119. ch->MonsterLog("HP_REGEN +%d", MAX(1, (ch->GetMaxHP() * ch->GetMobTable().bRegenPercent) / 100));
  2120. ch->PointChange(POINT_HP, MAX(1, (ch->GetMaxHP() * ch->GetMobTable().bRegenPercent) / 100));
  2121. }
  2122. if (ch->GetHP() >= ch->GetMaxHP())
  2123. {
  2124. ch->m_pkRecoveryEvent = NULL;
  2125. return 0;
  2126. }
  2127. if (2493 == ch->GetMobTable().dwVnum)
  2128. {
  2129. for (int i=1 ; i <= 4 ; ++i)
  2130. {
  2131. if (REGEN_TIME_BONUS == BlueDragon_GetIndexFactor("DragonStone", i, "effect_type"))
  2132. {
  2133. DWORD dwDragonStoneID = BlueDragon_GetIndexFactor("DragonStone", i, "vnum");
  2134. size_t val = BlueDragon_GetIndexFactor("DragonStone", i, "val");
  2135. size_t cnt = SECTREE_MANAGER::instance().GetMonsterCountInMap( ch->GetMapIndex(), dwDragonStoneID );
  2136. return PASSES_PER_SEC(MAX(1, (ch->GetMobTable().bRegenCycle - (val*cnt))));
  2137. }
  2138. }
  2139. }
  2140. return PASSES_PER_SEC(MAX(1, ch->GetMobTable().bRegenCycle));
  2141. }
  2142. else
  2143. {
  2144. ch->CheckTarget();
  2145. //ch->UpdateSectree();
  2146. ch->UpdateKillerMode();
  2147. if (ch->IsAffectFlag(AFF_POISON) == true)
  2148. {
  2149. return 3;
  2150. }
  2151. #ifdef ENABLE_WOLFMAN_CHARACTER
  2152. if (ch->IsAffectFlag(AFF_BLEEDING))
  2153. return 3;
  2154. #endif
  2155. int iSec = (get_dword_time() - ch->GetLastMoveTime()) / 3000;
  2156. ch->DistributeSP(ch);
  2157. if (ch->GetMaxHP() <= ch->GetHP())
  2158. return PASSES_PER_SEC(3);
  2159. int iPercent = 0;
  2160. int iAmount = 0;
  2161. {
  2162. iPercent = aiRecoveryPercents[MIN(9, iSec)];
  2163. iAmount = 15 + (ch->GetMaxHP() * iPercent) / 100;
  2164. }
  2165. iAmount += (iAmount * ch->GetPoint(POINT_HP_REGEN)) / 100;
  2166. sys_log(1, "RECOVERY_EVENT: %s %d HP_REGEN %d HP +%d", ch->GetName(), iPercent, ch->GetPoint(POINT_HP_REGEN), iAmount);
  2167. ch->PointChange(POINT_HP, iAmount, false);
  2168. return PASSES_PER_SEC(3);
  2169. }
  2170. }
  2171. void CHARACTER::StartRecoveryEvent()
  2172. {
  2173. if (m_pkRecoveryEvent)
  2174. return;
  2175. if (IsDead() || IsStun())
  2176. return;
  2177. if (IsNPC() && GetHP() >= GetMaxHP())
  2178. return;
  2179. char_event_info* info = AllocEventInfo<char_event_info>();
  2180. info->ch = this;
  2181. int iSec = IsPC() ? 3 : (MAX(1, GetMobTable().bRegenCycle));
  2182. m_pkRecoveryEvent = event_create(recovery_event, info, PASSES_PER_SEC(iSec));
  2183. }
  2184. void CHARACTER::Standup()
  2185. {
  2186. struct packet_position pack_position;
  2187. if (!IsPosition(POS_SITTING))
  2188. return;
  2189. SetPosition(POS_STANDING);
  2190. sys_log(1, "STANDUP: %s", GetName());
  2191. pack_position.header = HEADER_GC_CHARACTER_POSITION;
  2192. pack_position.vid = GetVID();
  2193. pack_position.position = POSITION_GENERAL;
  2194. PacketAround(&pack_position, sizeof(pack_position));
  2195. }
  2196. void CHARACTER::Sitdown(int is_ground)
  2197. {
  2198. struct packet_position pack_position;
  2199. if (IsPosition(POS_SITTING))
  2200. return;
  2201. SetPosition(POS_SITTING);
  2202. sys_log(1, "SITDOWN: %s", GetName());
  2203. pack_position.header = HEADER_GC_CHARACTER_POSITION;
  2204. pack_position.vid = GetVID();
  2205. pack_position.position = POSITION_SITTING_GROUND;
  2206. PacketAround(&pack_position, sizeof(pack_position));
  2207. }
  2208. void CHARACTER::SetRotation(float fRot)
  2209. {
  2210. m_pointsInstant.fRot = fRot;
  2211. }
  2212. void CHARACTER::SetRotationToXY(long x, long y)
  2213. {
  2214. SetRotation(GetDegreeFromPositionXY(GetX(), GetY(), x, y));
  2215. }
  2216. bool CHARACTER::CannotMoveByAffect() const
  2217. {
  2218. return (IsAffectFlag(AFF_STUN));
  2219. }
  2220. bool CHARACTER::CanMove() const
  2221. {
  2222. if (CannotMoveByAffect())
  2223. return false;
  2224. if (GetMyShop())
  2225. return false;
  2226. return true;
  2227. }
  2228. bool CHARACTER::Sync(long x, long y)
  2229. {
  2230. if (!GetSectree())
  2231. return false;
  2232. LPSECTREE new_tree = SECTREE_MANAGER::instance().Get(GetMapIndex(), x, y);
  2233. if (!new_tree)
  2234. {
  2235. if (GetDesc())
  2236. {
  2237. sys_err("cannot find tree at %d %d (name: %s)", x, y, GetName());
  2238. //GetDesc()->SetPhase(PHASE_CLOSE);
  2239. }
  2240. else
  2241. {
  2242. sys_err("no tree: %s %d %d %d", GetName(), x, y, GetMapIndex());
  2243. Dead();
  2244. }
  2245. return false;
  2246. }
  2247. SetRotationToXY(x, y);
  2248. SetXYZ(x, y, 0);
  2249. if (GetDungeon())
  2250. {
  2251. int iLastEventAttr = m_iEventAttr;
  2252. m_iEventAttr = new_tree->GetEventAttribute(x, y);
  2253. if (m_iEventAttr != iLastEventAttr)
  2254. {
  2255. if (GetParty())
  2256. {
  2257. quest::CQuestManager::instance().AttrOut(GetParty()->GetLeaderPID(), this, iLastEventAttr);
  2258. quest::CQuestManager::instance().AttrIn(GetParty()->GetLeaderPID(), this, m_iEventAttr);
  2259. }
  2260. else
  2261. {
  2262. quest::CQuestManager::instance().AttrOut(GetPlayerID(), this, iLastEventAttr);
  2263. quest::CQuestManager::instance().AttrIn(GetPlayerID(), this, m_iEventAttr);
  2264. }
  2265. }
  2266. }
  2267. if (GetSectree() != new_tree)
  2268. {
  2269. if (!IsNPC())
  2270. {
  2271. SECTREEID id = new_tree->GetID();
  2272. SECTREEID old_id = GetSectree()->GetID();
  2273. const float fDist = DISTANCE_SQRT(id.coord.x - old_id.coord.x, id.coord.y - old_id.coord.y);
  2274. sys_log(0, "SECTREE DIFFER: %s %dx%d was %dx%d dist %.1fm",
  2275. GetName(),
  2276. id.coord.x,
  2277. id.coord.y,
  2278. old_id.coord.x,
  2279. old_id.coord.y,
  2280. fDist);
  2281. }
  2282. new_tree->InsertEntity(this);
  2283. }
  2284. return true;
  2285. }
  2286. void CHARACTER::Stop()
  2287. {
  2288. if (!IsState(m_stateIdle))
  2289. MonsterLog("[IDLE] Á¤Áö");
  2290. GotoState(m_stateIdle);
  2291. m_posDest.x = m_posStart.x = GetX();
  2292. m_posDest.y = m_posStart.y = GetY();
  2293. }
  2294. bool CHARACTER::Goto(long x, long y)
  2295. {
  2296. if (GetX() == x && GetY() == y)
  2297. return false;
  2298. if (m_posDest.x == x && m_posDest.y == y)
  2299. {
  2300. if (!IsState(m_stateMove))
  2301. {
  2302. m_dwStateDuration = 4;
  2303. GotoState(m_stateMove);
  2304. }
  2305. return false;
  2306. }
  2307. m_posDest.x = x;
  2308. m_posDest.y = y;
  2309. CalculateMoveDuration();
  2310. m_dwStateDuration = 4;
  2311. if (!IsState(m_stateMove))
  2312. {
  2313. MonsterLog("[MOVE] %s", GetVictim() ? "´ë»óÃßÀû" : "±×³ÉÀ̵¿");
  2314. if (GetVictim())
  2315. {
  2316. //MonsterChat(MONSTER_CHAT_CHASE);
  2317. MonsterChat(MONSTER_CHAT_ATTACK);
  2318. }
  2319. }
  2320. GotoState(m_stateMove);
  2321. return true;
  2322. }
  2323. DWORD CHARACTER::GetMotionMode() const
  2324. {
  2325. DWORD dwMode = MOTION_MODE_GENERAL;
  2326. if (IsPolymorphed())
  2327. return dwMode;
  2328. LPITEM pkItem;
  2329. if ((pkItem = GetWear(WEAR_WEAPON)))
  2330. {
  2331. switch (pkItem->GetProto()->bSubType)
  2332. {
  2333. case WEAPON_SWORD:
  2334. dwMode = MOTION_MODE_ONEHAND_SWORD;
  2335. break;
  2336. case WEAPON_TWO_HANDED:
  2337. dwMode = MOTION_MODE_TWOHAND_SWORD;
  2338. break;
  2339. case WEAPON_DAGGER:
  2340. dwMode = MOTION_MODE_DUALHAND_SWORD;
  2341. break;
  2342. case WEAPON_BOW:
  2343. dwMode = MOTION_MODE_BOW;
  2344. break;
  2345. case WEAPON_BELL:
  2346. dwMode = MOTION_MODE_BELL;
  2347. break;
  2348. case WEAPON_FAN:
  2349. dwMode = MOTION_MODE_FAN;
  2350. break;
  2351. #ifdef ENABLE_WOLFMAN_CHARACTER
  2352. case WEAPON_CLAW:
  2353. dwMode = MOTION_MODE_CLAW;
  2354. break;
  2355. #endif
  2356. }
  2357. }
  2358. return dwMode;
  2359. }
  2360. float CHARACTER::GetMoveMotionSpeed() const
  2361. {
  2362. DWORD dwMode = GetMotionMode();
  2363. const CMotion * pkMotion = NULL;
  2364. if (!GetMountVnum())
  2365. pkMotion = CMotionManager::instance().GetMotion(GetRaceNum(), MAKE_MOTION_KEY(dwMode, (IsWalking() && IsPC()) ? MOTION_WALK : MOTION_RUN));
  2366. else
  2367. {
  2368. pkMotion = CMotionManager::instance().GetMotion(GetMountVnum(), MAKE_MOTION_KEY(MOTION_MODE_GENERAL, (IsWalking() && IsPC()) ? MOTION_WALK : MOTION_RUN));
  2369. if (!pkMotion)
  2370. pkMotion = CMotionManager::instance().GetMotion(GetRaceNum(), MAKE_MOTION_KEY(MOTION_MODE_HORSE, (IsWalking() && IsPC()) ? MOTION_WALK : MOTION_RUN));
  2371. }
  2372. if (pkMotion)
  2373. return -pkMotion->GetAccumVector().y / pkMotion->GetDuration();
  2374. else
  2375. {
  2376. sys_err("cannot find motion (name %s race %d mode %d)", GetName(), GetRaceNum(), dwMode);
  2377. return 300.0f;
  2378. }
  2379. }
  2380. float CHARACTER::GetMoveSpeed() const
  2381. {
  2382. return GetMoveMotionSpeed() * 10000 / CalculateDuration(GetLimitPoint(POINT_MOV_SPEED), 10000);
  2383. }
  2384. void CHARACTER::CalculateMoveDuration()
  2385. {
  2386. m_posStart.x = GetX();
  2387. m_posStart.y = GetY();
  2388. float fDist = DISTANCE_SQRT(m_posStart.x - m_posDest.x, m_posStart.y - m_posDest.y);
  2389. float motionSpeed = GetMoveMotionSpeed();
  2390. m_dwMoveDuration = CalculateDuration(GetLimitPoint(POINT_MOV_SPEED),
  2391. (int) ((fDist / motionSpeed) * 1000.0f));
  2392. if (IsNPC())
  2393. sys_log(1, "%s: GOTO: distance %f, spd %u, duration %u, motion speed %f pos %d %d -> %d %d",
  2394. GetName(), fDist, GetLimitPoint(POINT_MOV_SPEED), m_dwMoveDuration, motionSpeed,
  2395. m_posStart.x, m_posStart.y, m_posDest.x, m_posDest.y);
  2396. m_dwMoveStartTime = get_dword_time();
  2397. }
  2398. bool CHARACTER::Move(long x, long y)
  2399. {
  2400. if (GetX() == x && GetY() == y)
  2401. return true;
  2402. if (test_server)
  2403. if (m_bDetailLog)
  2404. sys_log(0, "%s position %u %u", GetName(), x, y);
  2405. OnMove();
  2406. return Sync(x, y);
  2407. }
  2408. void CHARACTER::SendMovePacket(BYTE bFunc, BYTE bArg, DWORD x, DWORD y, DWORD dwDuration, DWORD dwTime, int iRot)
  2409. {
  2410. TPacketGCMove pack;
  2411. if (bFunc == FUNC_WAIT)
  2412. {
  2413. x = m_posDest.x;
  2414. y = m_posDest.y;
  2415. dwDuration = m_dwMoveDuration;
  2416. }
  2417. EncodeMovePacket(pack, GetVID(), bFunc, bArg, x, y, dwDuration, dwTime, iRot == -1 ? (int) GetRotation() / 5 : iRot);
  2418. PacketView(&pack, sizeof(TPacketGCMove), this);
  2419. }
  2420. int CHARACTER::GetRealPoint(BYTE type) const
  2421. {
  2422. return m_points.points[type];
  2423. }
  2424. void CHARACTER::SetRealPoint(BYTE type, int val)
  2425. {
  2426. m_points.points[type] = val;
  2427. }
  2428. int CHARACTER::GetPolymorphPoint(BYTE type) const
  2429. {
  2430. if (IsPolymorphed() && !IsPolyMaintainStat())
  2431. {
  2432. DWORD dwMobVnum = GetPolymorphVnum();
  2433. const CMob * pMob = CMobManager::instance().Get(dwMobVnum);
  2434. int iPower = GetPolymorphPower();
  2435. if (pMob)
  2436. {
  2437. switch (type)
  2438. {
  2439. case POINT_ST:
  2440. if ((GetJob() == JOB_SHAMAN) || ((GetJob() == JOB_SURA) && (GetSkillGroup() == 2)))
  2441. return pMob->m_table.bStr * iPower / 100 + GetPoint(POINT_IQ);
  2442. return pMob->m_table.bStr * iPower / 100 + GetPoint(POINT_ST);
  2443. case POINT_HT:
  2444. return pMob->m_table.bCon * iPower / 100 + GetPoint(POINT_HT);
  2445. case POINT_IQ:
  2446. return pMob->m_table.bInt * iPower / 100 + GetPoint(POINT_IQ);
  2447. case POINT_DX:
  2448. return pMob->m_table.bDex * iPower / 100 + GetPoint(POINT_DX);
  2449. }
  2450. }
  2451. }
  2452. return GetPoint(type);
  2453. }
  2454. int CHARACTER::GetPoint(BYTE type) const
  2455. {
  2456. if (type >= POINT_MAX_NUM)
  2457. {
  2458. sys_err("Point type overflow (type %u)", type);
  2459. return 0;
  2460. }
  2461. int val = m_pointsInstant.points[type];
  2462. int max_val = INT_MAX;
  2463. switch (type)
  2464. {
  2465. case POINT_STEAL_HP:
  2466. case POINT_STEAL_SP:
  2467. max_val = 50;
  2468. break;
  2469. }
  2470. if (val > max_val)
  2471. sys_err("POINT_ERROR: %s type %d val %d (max: %d)", GetName(), val, max_val);
  2472. return (val);
  2473. }
  2474. int CHARACTER::GetLimitPoint(BYTE type) const
  2475. {
  2476. if (type >= POINT_MAX_NUM)
  2477. {
  2478. sys_err("Point type overflow (type %u)", type);
  2479. return 0;
  2480. }
  2481. int val = m_pointsInstant.points[type];
  2482. int max_val = INT_MAX;
  2483. int limit = INT_MAX;
  2484. int min_limit = -INT_MAX;
  2485. switch (type)
  2486. {
  2487. case POINT_ATT_SPEED:
  2488. min_limit = 0;
  2489. if (IsPC())
  2490. limit = 170;
  2491. else
  2492. limit = 250;
  2493. break;
  2494. case POINT_MOV_SPEED:
  2495. min_limit = 0;
  2496. if (IsPC())
  2497. limit = 200;
  2498. else
  2499. limit = 250;
  2500. break;
  2501. case POINT_STEAL_HP:
  2502. case POINT_STEAL_SP:
  2503. limit = 50;
  2504. max_val = 50;
  2505. break;
  2506. case POINT_MALL_ATTBONUS:
  2507. case POINT_MALL_DEFBONUS:
  2508. limit = 20;
  2509. max_val = 50;
  2510. break;
  2511. }
  2512. if (val > max_val)
  2513. sys_err("POINT_ERROR: %s type %d val %d (max: %d)", GetName(), val, max_val);
  2514. if (val > limit)
  2515. val = limit;
  2516. if (val < min_limit)
  2517. val = min_limit;
  2518. return (val);
  2519. }
  2520. void CHARACTER::SetPoint(BYTE type, int val)
  2521. {
  2522. if (type >= POINT_MAX_NUM)
  2523. {
  2524. sys_err("Point type overflow (type %u)", type);
  2525. return;
  2526. }
  2527. m_pointsInstant.points[type] = val;
  2528. if (type == POINT_MOV_SPEED && get_dword_time() < m_dwMoveStartTime + m_dwMoveDuration)
  2529. {
  2530. CalculateMoveDuration();
  2531. }
  2532. }
  2533. INT CHARACTER::GetAllowedGold() const
  2534. {
  2535. if (GetLevel() <= 10)
  2536. return 100000;
  2537. else if (GetLevel() <= 20)
  2538. return 500000;
  2539. else
  2540. return 50000000;
  2541. }
  2542. void CHARACTER::CheckMaximumPoints()
  2543. {
  2544. if (GetMaxHP() < GetHP())
  2545. PointChange(POINT_HP, GetMaxHP() - GetHP());
  2546. if (GetMaxSP() < GetSP())
  2547. PointChange(POINT_SP, GetMaxSP() - GetSP());
  2548. }
  2549. void CHARACTER::PointChange(BYTE type, int amount, bool bAmount, bool bBroadcast)
  2550. {
  2551. int val = 0;
  2552. //sys_log(0, "PointChange %d %d | %d -> %d cHP %d mHP %d", type, amount, GetPoint(type), GetPoint(type)+amount, GetHP(), GetMaxHP());
  2553. switch (type)
  2554. {
  2555. case POINT_NONE:
  2556. return;
  2557. case POINT_LEVEL:
  2558. if ((GetLevel() + amount) > gPlayerMaxLevel)
  2559. return;
  2560. SetLevel(GetLevel() + amount);
  2561. val = GetLevel();
  2562. sys_log(0, "LEVELUP: %s %d NEXT EXP %d", GetName(), GetLevel(), GetNextExp());
  2563. if (amount)
  2564. {
  2565. quest::CQuestManager::instance().LevelUp(GetPlayerID());
  2566. int biodurum = GetQuestFlag("bio.durum");
  2567. if (biodurum == 0 && GetLevel() >= 30)
  2568. {
  2569. SetQuestFlag("bio.durum",1);
  2570. SetQuestFlag("bio.verilen",0);
  2571. SetQuestFlag("bio.ruhtasi",0);
  2572. SetQuestFlag("bio.kalan",get_global_time());
  2573. int bioverilen = GetQuestFlag("bio.verilen");
  2574. int biokalan = GetQuestFlag("bio.kalan");
  2575. biodurum = GetQuestFlag("bio.durum");
  2576. ChatPacket(CHAT_TYPE_COMMAND, "biyolog %d %d %d %d ", BiyologSistemi[biodurum][0], bioverilen, BiyologSistemi[biodurum][1], biokalan);
  2577. }
  2578. else if (biodurum == 31 && GetLevel() >= 40)
  2579. {
  2580. SetQuestFlag("bio.durum",2);
  2581. SetQuestFlag("bio.verilen",0);
  2582. SetQuestFlag("bio.ruhtasi",0);
  2583. SetQuestFlag("bio.kalan",get_global_time());
  2584. int bioverilen = GetQuestFlag("bio.verilen");
  2585. int biokalan = GetQuestFlag("bio.kalan");
  2586. biodurum = GetQuestFlag("bio.durum");
  2587. ChatPacket(CHAT_TYPE_COMMAND, "biyolog %d %d %d %d ", BiyologSistemi[biodurum][0], bioverilen, BiyologSistemi[biodurum][1], biokalan);
  2588. }
  2589. else if (biodurum == 41 && GetLevel() >= 50)
  2590. {
  2591. SetQuestFlag("bio.durum",3);
  2592. SetQuestFlag("bio.verilen",0);
  2593. SetQuestFlag("bio.ruhtasi",0);
  2594. SetQuestFlag("bio.kalan",get_global_time());
  2595. int bioverilen = GetQuestFlag("bio.verilen");
  2596. int biokalan = GetQuestFlag("bio.kalan");
  2597. biodurum = GetQuestFlag("bio.durum");
  2598. ChatPacket(CHAT_TYPE_COMMAND, "biyolog %d %d %d %d ", BiyologSistemi[biodurum][0], bioverilen, BiyologSistemi[biodurum][1], biokalan);
  2599. }
  2600. else if (biodurum == 51 && GetLevel() >= 60)
  2601. {
  2602. SetQuestFlag("bio.durum",4);
  2603. SetQuestFlag("bio.verilen",0);
  2604. SetQuestFlag("bio.ruhtasi",0);
  2605. SetQuestFlag("bio.kalan",get_global_time());
  2606. int bioverilen = GetQuestFlag("bio.verilen");
  2607. int biokalan = GetQuestFlag("bio.kalan");
  2608. biodurum = GetQuestFlag("bio.durum");
  2609. ChatPacket(CHAT_TYPE_COMMAND, "biyolog %d %d %d %d ", BiyologSistemi[biodurum][0], bioverilen, BiyologSistemi[biodurum][1], biokalan);
  2610. }
  2611. else if (biodurum == 61 && GetLevel() >= 70)
  2612. {
  2613. SetQuestFlag("bio.durum",5);
  2614. SetQuestFlag("bio.verilen",0);
  2615. SetQuestFlag("bio.ruhtasi",0);
  2616. SetQuestFlag("bio.kalan",get_global_time());
  2617. int bioverilen = GetQuestFlag("bio.verilen");
  2618. int biokalan = GetQuestFlag("bio.kalan");
  2619. biodurum = GetQuestFlag("bio.durum");
  2620. ChatPacket(CHAT_TYPE_COMMAND, "biyolog %d %d %d %d ", BiyologSistemi[biodurum][0], bioverilen, BiyologSistemi[biodurum][1], biokalan);
  2621. }
  2622. else if (biodurum == 71 && GetLevel() >= 80)
  2623. {
  2624. SetQuestFlag("bio.durum",6);
  2625. SetQuestFlag("bio.verilen",0);
  2626. SetQuestFlag("bio.ruhtasi",0);
  2627. SetQuestFlag("bio.kalan",get_global_time());
  2628. int bioverilen = GetQuestFlag("bio.verilen");
  2629. int biokalan = GetQuestFlag("bio.kalan");
  2630. biodurum = GetQuestFlag("bio.durum");
  2631. ChatPacket(CHAT_TYPE_COMMAND, "biyolog %d %d %d %d ", BiyologSistemi[biodurum][0], bioverilen, BiyologSistemi[biodurum][1], biokalan);
  2632. }
  2633. else if (biodurum == 81 && GetLevel() >= 85)
  2634. {
  2635. SetQuestFlag("bio.durum",7);
  2636. SetQuestFlag("bio.verilen",0);
  2637. SetQuestFlag("bio.ruhtasi",0);
  2638. SetQuestFlag("bio.kalan",get_global_time());
  2639. int bioverilen = GetQuestFlag("bio.verilen");
  2640. int biokalan = GetQuestFlag("bio.kalan");
  2641. biodurum = GetQuestFlag("bio.durum");
  2642. ChatPacket(CHAT_TYPE_COMMAND, "biyolog %d %d %d %d ", BiyologSistemi[biodurum][0], bioverilen, BiyologSistemi[biodurum][1], biokalan);
  2643. }
  2644. else if (biodurum == 86 && GetLevel() >= 90)
  2645. {
  2646. SetQuestFlag("bio.durum",8);
  2647. SetQuestFlag("bio.verilen",0);
  2648. SetQuestFlag("bio.ruhtasi",0);
  2649. SetQuestFlag("bio.kalan",get_global_time());
  2650. int bioverilen = GetQuestFlag("bio.verilen");
  2651. int biokalan = GetQuestFlag("bio.kalan");
  2652. biodurum = GetQuestFlag("bio.durum");
  2653. ChatPacket(CHAT_TYPE_COMMAND, "biyolog %d %d %d %d ", BiyologSistemi[biodurum][0], bioverilen, BiyologSistemi[biodurum][1], biokalan);
  2654. }
  2655. else if (biodurum == 91 && GetLevel() >= 92)
  2656. {
  2657. SetQuestFlag("bio.durum",9);
  2658. SetQuestFlag("bio.verilen",0);
  2659. SetQuestFlag("bio.ruhtasi",0);
  2660. SetQuestFlag("bio.kalan",get_global_time());
  2661. int bioverilen = GetQuestFlag("bio.verilen");
  2662. int biokalan = GetQuestFlag("bio.kalan");
  2663. biodurum = GetQuestFlag("bio.durum");
  2664. ChatPacket(CHAT_TYPE_COMMAND, "biyolog %d %d %d %d ", BiyologSistemi[biodurum][0], bioverilen, BiyologSistemi[biodurum][1], biokalan);
  2665. }
  2666. else if (biodurum == 93 && GetLevel() >= 94)
  2667. {
  2668. SetQuestFlag("bio.durum",10);
  2669. SetQuestFlag("bio.verilen",0);
  2670. SetQuestFlag("bio.ruhtasi",0);
  2671. SetQuestFlag("bio.kalan",get_global_time());
  2672. int bioverilen = GetQuestFlag("bio.verilen");
  2673. int biokalan = GetQuestFlag("bio.kalan");
  2674. biodurum = GetQuestFlag("bio.durum");
  2675. ChatPacket(CHAT_TYPE_COMMAND, "biyolog %d %d %d %d ", BiyologSistemi[biodurum][0], bioverilen, BiyologSistemi[biodurum][1], biokalan);
  2676. }
  2677. LogManager::instance().LevelLog(this, val, GetRealPoint(POINT_PLAYTIME) + (get_dword_time() - m_dwPlayStartTime) / 60000);
  2678. if (GetGuild())
  2679. {
  2680. GetGuild()->LevelChange(GetPlayerID(), GetLevel());
  2681. }
  2682. if (GetParty())
  2683. {
  2684. GetParty()->RequestSetMemberLevel(GetPlayerID(), GetLevel());
  2685. }
  2686. }
  2687. break;
  2688. #ifdef ENABLE_WOLFMAN_CHARACTER
  2689. if (GetJob() == JOB_WOLFMAN)
  2690. {
  2691. if ((5 <= val) && (GetSkillGroup()!=1))
  2692. {
  2693. ClearSkill();
  2694. // set skill group
  2695. SetSkillGroup(1);
  2696. // set skill points
  2697. SetRealPoint(POINT_SKILL, GetLevel()-1);
  2698. SetPoint(POINT_SKILL, GetRealPoint(POINT_SKILL));
  2699. PointChange(POINT_SKILL, 0);
  2700. // update points (not required)
  2701. // ComputePoints();
  2702. // PointsPacket();
  2703. }
  2704. }
  2705. #endif
  2706. PointChange(POINT_NEXT_EXP, GetNextExp(), false);
  2707. case POINT_NEXT_EXP:
  2708. val = GetNextExp();
  2709. bAmount = false;
  2710. break;
  2711. case POINT_EXP:
  2712. {
  2713. DWORD exp = GetExp();
  2714. DWORD next_exp = GetNextExp();
  2715. if (g_bChinaIntoxicationCheck)
  2716. {
  2717. if (IsOverTime(OT_NONE))
  2718. {
  2719. dev_log(LOG_DEB0, "<EXP_LOG> %s = NONE", GetName());
  2720. }
  2721. else if (IsOverTime(OT_3HOUR))
  2722. {
  2723. amount = (amount / 2);
  2724. dev_log(LOG_DEB0, "<EXP_LOG> %s = 3HOUR", GetName());
  2725. }
  2726. else if (IsOverTime(OT_5HOUR))
  2727. {
  2728. amount = 0;
  2729. dev_log(LOG_DEB0, "<EXP_LOG> %s = 5HOUR", GetName());
  2730. }
  2731. }
  2732. if ((amount < 0) && (exp < (DWORD)(-amount)))
  2733. {
  2734. sys_log(1, "%s AMOUNT < 0 %d, CUR EXP: %d", GetName(), -amount, exp);
  2735. amount = -exp;
  2736. SetExp(exp + amount);
  2737. val = GetExp();
  2738. }
  2739. else
  2740. {
  2741. if (gPlayerMaxLevel <= GetLevel())
  2742. return;
  2743. if (test_server)
  2744. ChatPacket(CHAT_TYPE_INFO, "You have gained %d exp.", amount);
  2745. DWORD iExpBalance = 0;
  2746. // ·¹º§ ¾÷!
  2747. if (exp + amount >= next_exp)
  2748. {
  2749. iExpBalance = (exp + amount) - next_exp;
  2750. amount = next_exp - exp;
  2751. SetExp(0);
  2752. exp = next_exp;
  2753. }
  2754. else
  2755. {
  2756. SetExp(exp + amount);
  2757. exp = GetExp();
  2758. }
  2759. DWORD q = DWORD(next_exp / 4.0f);
  2760. int iLevStep = GetRealPoint(POINT_LEVEL_STEP);
  2761. if (iLevStep >= 4)
  2762. {
  2763. sys_err("%s LEVEL_STEP bigger than 4! (%d)", GetName(), iLevStep);
  2764. iLevStep = 4;
  2765. }
  2766. if (exp >= next_exp && iLevStep < 4)
  2767. {
  2768. for (int i = 0; i < 4 - iLevStep; ++i)
  2769. PointChange(POINT_LEVEL_STEP, 1, false, true);
  2770. }
  2771. else if (exp >= q * 3 && iLevStep < 3)
  2772. {
  2773. for (int i = 0; i < 3 - iLevStep; ++i)
  2774. PointChange(POINT_LEVEL_STEP, 1, false, true);
  2775. }
  2776. else if (exp >= q * 2 && iLevStep < 2)
  2777. {
  2778. for (int i = 0; i < 2 - iLevStep; ++i)
  2779. PointChange(POINT_LEVEL_STEP, 1, false, true);
  2780. }
  2781. else if (exp >= q && iLevStep < 1)
  2782. PointChange(POINT_LEVEL_STEP, 1);
  2783. if (iExpBalance)
  2784. {
  2785. PointChange(POINT_EXP, iExpBalance);
  2786. }
  2787. val = GetExp();
  2788. }
  2789. }
  2790. break;
  2791. case POINT_LEVEL_STEP:
  2792. if (amount > 0)
  2793. {
  2794. val = GetPoint(POINT_LEVEL_STEP) + amount;
  2795. switch (val)
  2796. {
  2797. case 1:
  2798. case 2:
  2799. case 3:
  2800. if ((GetLevel() <= g_iStatusPointGetLevelLimit) &&
  2801. (GetLevel() <= gPlayerMaxLevel) )
  2802. PointChange(POINT_STAT, 1);
  2803. break;
  2804. case 4:
  2805. {
  2806. int iHP = number(JobInitialPoints[GetJob()].hp_per_lv_begin, JobInitialPoints[GetJob()].hp_per_lv_end);
  2807. int iSP = number(JobInitialPoints[GetJob()].sp_per_lv_begin, JobInitialPoints[GetJob()].sp_per_lv_end);
  2808. m_points.iRandomHP += iHP;
  2809. m_points.iRandomSP += iSP;
  2810. if (GetSkillGroup())
  2811. {
  2812. if (GetLevel() >= 5)
  2813. PointChange(POINT_SKILL, 1);
  2814. if (GetLevel() >= 9)
  2815. PointChange(POINT_SUB_SKILL, 1);
  2816. }
  2817. PointChange(POINT_MAX_HP, iHP);
  2818. PointChange(POINT_MAX_SP, iSP);
  2819. PointChange(POINT_LEVEL, 1, false, true);
  2820. val = 0;
  2821. }
  2822. break;
  2823. }
  2824. if (GetLevel() <= 10)
  2825. AutoGiveItem(27001, 2);
  2826. else if (GetLevel() <= 30)
  2827. AutoGiveItem(27002, 2);
  2828. else
  2829. {
  2830. AutoGiveItem(27002, 2);
  2831. // AutoGiveItem(27003, 2);
  2832. }
  2833. PointChange(POINT_HP, GetMaxHP() - GetHP());
  2834. PointChange(POINT_SP, GetMaxSP() - GetSP());
  2835. PointChange(POINT_STAMINA, GetMaxStamina() - GetStamina());
  2836. SetPoint(POINT_LEVEL_STEP, val);
  2837. SetRealPoint(POINT_LEVEL_STEP, val);
  2838. Save();
  2839. }
  2840. else
  2841. val = GetPoint(POINT_LEVEL_STEP);
  2842. break;
  2843. case POINT_HP:
  2844. {
  2845. if (IsDead() || IsStun())
  2846. return;
  2847. int prev_hp = GetHP();
  2848. amount = MIN(GetMaxHP() - GetHP(), amount);
  2849. SetHP(GetHP() + amount);
  2850. val = GetHP();
  2851. BroadcastTargetPacket();
  2852. if (GetParty() && IsPC() && val != prev_hp)
  2853. GetParty()->SendPartyInfoOneToAll(this);
  2854. }
  2855. break;
  2856. case POINT_SP:
  2857. {
  2858. if (IsDead() || IsStun())
  2859. return;
  2860. amount = MIN(GetMaxSP() - GetSP(), amount);
  2861. SetSP(GetSP() + amount);
  2862. val = GetSP();
  2863. }
  2864. break;
  2865. case POINT_STAMINA:
  2866. {
  2867. if (IsDead() || IsStun())
  2868. return;
  2869. int prev_val = GetStamina();
  2870. amount = MIN(GetMaxStamina() - GetStamina(), amount);
  2871. SetStamina(GetStamina() + amount);
  2872. val = GetStamina();
  2873. if (val == 0)
  2874. {
  2875. SetNowWalking(true);
  2876. }
  2877. else if (prev_val == 0)
  2878. {
  2879. ResetWalking();
  2880. }
  2881. if (amount < 0 && val != 0)
  2882. return;
  2883. }
  2884. break;
  2885. case POINT_MAX_HP:
  2886. {
  2887. SetPoint(type, GetPoint(type) + amount);
  2888. int hp = GetRealPoint(POINT_MAX_HP);
  2889. int add_hp = MIN(3500, hp * GetPoint(POINT_MAX_HP_PCT) / 100);
  2890. add_hp += GetPoint(POINT_MAX_HP);
  2891. add_hp += GetPoint(POINT_PARTY_TANKER_BONUS);
  2892. SetMaxHP(hp + add_hp);
  2893. val = GetMaxHP();
  2894. }
  2895. break;
  2896. case POINT_MAX_SP:
  2897. {
  2898. SetPoint(type, GetPoint(type) + amount);
  2899. int sp = GetRealPoint(POINT_MAX_SP);
  2900. int add_sp = MIN(800, sp * GetPoint(POINT_MAX_SP_PCT) / 100);
  2901. add_sp += GetPoint(POINT_MAX_SP);
  2902. add_sp += GetPoint(POINT_PARTY_SKILL_MASTER_BONUS);
  2903. SetMaxSP(sp + add_sp);
  2904. val = GetMaxSP();
  2905. }
  2906. break;
  2907. case POINT_MAX_HP_PCT:
  2908. SetPoint(type, GetPoint(type) + amount);
  2909. val = GetPoint(type);
  2910. PointChange(POINT_MAX_HP, 0);
  2911. break;
  2912. case POINT_MAX_SP_PCT:
  2913. SetPoint(type, GetPoint(type) + amount);
  2914. val = GetPoint(type);
  2915. PointChange(POINT_MAX_SP, 0);
  2916. break;
  2917. case POINT_MAX_STAMINA:
  2918. SetMaxStamina(GetMaxStamina() + amount);
  2919. val = GetMaxStamina();
  2920. break;
  2921. case POINT_GOLD:
  2922. {
  2923. const int64_t nTotalMoney = static_cast<int64_t>(GetGold()) + static_cast<int64_t>(amount);
  2924. if (GOLD_MAX <= nTotalMoney)
  2925. {
  2926. sys_err("[OVERFLOW_GOLD] OriGold %d AddedGold %d id %u Name %s ", GetGold(), amount, GetPlayerID(), GetName());
  2927. LogManager::instance().CharLog(this, GetGold() + amount, "OVERFLOW_GOLD", "");
  2928. return;
  2929. }
  2930. if (g_bChinaIntoxicationCheck && amount > 0)
  2931. {
  2932. if (IsOverTime(OT_NONE))
  2933. {
  2934. dev_log(LOG_DEB0, "<GOLD_LOG> %s = NONE", GetName());
  2935. }
  2936. else if (IsOverTime(OT_3HOUR))
  2937. {
  2938. amount = (amount / 2);
  2939. dev_log(LOG_DEB0, "<GOLD_LOG> %s = 3HOUR", GetName());
  2940. }
  2941. else if (IsOverTime(OT_5HOUR))
  2942. {
  2943. amount = 0;
  2944. dev_log(LOG_DEB0, "<GOLD_LOG> %s = 5HOUR", GetName());
  2945. }
  2946. }
  2947. SetGold(GetGold() + amount);
  2948. val = GetGold();
  2949. }
  2950. break;
  2951. #ifdef __COINS_SYSTEM__
  2952. case POINT_COINS:
  2953. {
  2954. SetCoins(GetCoins() + amount);
  2955. val = GetCoins();
  2956. }
  2957. break;
  2958. #endif
  2959. case POINT_SKILL:
  2960. case POINT_STAT:
  2961. case POINT_SUB_SKILL:
  2962. case POINT_STAT_RESET_COUNT:
  2963. case POINT_HORSE_SKILL:
  2964. SetPoint(type, GetPoint(type) + amount);
  2965. val = GetPoint(type);
  2966. SetRealPoint(type, val);
  2967. break;
  2968. case POINT_DEF_GRADE:
  2969. SetPoint(type, GetPoint(type) + amount);
  2970. val = GetPoint(type);
  2971. PointChange(POINT_CLIENT_DEF_GRADE, amount);
  2972. break;
  2973. case POINT_CLIENT_DEF_GRADE:
  2974. SetPoint(type, GetPoint(type) + amount);
  2975. val = GetPoint(type);
  2976. break;
  2977. case POINT_ST:
  2978. case POINT_HT:
  2979. case POINT_DX:
  2980. case POINT_IQ:
  2981. case POINT_HP_REGEN:
  2982. case POINT_SP_REGEN:
  2983. case POINT_ATT_SPEED:
  2984. case POINT_ATT_GRADE:
  2985. case POINT_MOV_SPEED:
  2986. case POINT_CASTING_SPEED:
  2987. case POINT_MAGIC_ATT_GRADE:
  2988. case POINT_MAGIC_DEF_GRADE:
  2989. case POINT_BOW_DISTANCE:
  2990. case POINT_HP_RECOVERY:
  2991. case POINT_SP_RECOVERY:
  2992. case POINT_ATTBONUS_HUMAN:
  2993. case POINT_ATTBONUS_ANIMAL:
  2994. case POINT_ATTBONUS_ORC:
  2995. case POINT_ATTBONUS_MILGYO:
  2996. case POINT_ATTBONUS_UNDEAD:
  2997. case POINT_ATTBONUS_DEVIL:
  2998. case POINT_ATTBONUS_MONSTER:
  2999. case POINT_ATTBONUS_SURA:
  3000. case POINT_ATTBONUS_ASSASSIN:
  3001. case POINT_ATTBONUS_WARRIOR:
  3002. case POINT_ATTBONUS_SHAMAN:
  3003. #ifdef ENABLE_WOLFMAN_CHARACTER
  3004. case POINT_ATTBONUS_WOLFMAN:
  3005. #endif
  3006. case POINT_POISON_PCT:
  3007. #ifdef ENABLE_WOLFMAN_CHARACTER
  3008. case POINT_BLEEDING_PCT:
  3009. #endif
  3010. case POINT_STUN_PCT:
  3011. case POINT_SLOW_PCT:
  3012. case POINT_BLOCK:
  3013. case POINT_DODGE:
  3014. case POINT_CRITICAL_PCT:
  3015. case POINT_RESIST_CRITICAL:
  3016. case POINT_PENETRATE_PCT:
  3017. case POINT_RESIST_PENETRATE:
  3018. case POINT_CURSE_PCT:
  3019. case POINT_STEAL_HP:
  3020. case POINT_STEAL_SP:
  3021. case POINT_MANA_BURN_PCT:
  3022. case POINT_DAMAGE_SP_RECOVER:
  3023. case POINT_RESIST_NORMAL_DAMAGE:
  3024. case POINT_RESIST_SWORD:
  3025. case POINT_RESIST_TWOHAND:
  3026. case POINT_RESIST_DAGGER:
  3027. case POINT_RESIST_BELL:
  3028. case POINT_RESIST_FAN:
  3029. case POINT_RESIST_BOW:
  3030. #ifdef ENABLE_WOLFMAN_CHARACTER
  3031. case POINT_RESIST_CLAW:
  3032. #endif
  3033. case POINT_RESIST_FIRE:
  3034. case POINT_RESIST_ELEC:
  3035. case POINT_RESIST_MAGIC:
  3036. case POINT_RESIST_WIND:
  3037. case POINT_RESIST_ICE:
  3038. case POINT_RESIST_EARTH:
  3039. case POINT_RESIST_DARK:
  3040. case POINT_REFLECT_MELEE:
  3041. case POINT_REFLECT_CURSE:
  3042. case POINT_POISON_REDUCE:
  3043. #ifdef ENABLE_WOLFMAN_CHARACTER
  3044. case POINT_BLEEDING_REDUCE:
  3045. #endif
  3046. case POINT_KILL_SP_RECOVER:
  3047. case POINT_KILL_HP_RECOVERY:
  3048. case POINT_HIT_HP_RECOVERY:
  3049. case POINT_HIT_SP_RECOVERY:
  3050. case POINT_MANASHIELD:
  3051. case POINT_ATT_BONUS:
  3052. case POINT_DEF_BONUS:
  3053. case POINT_SKILL_DAMAGE_BONUS:
  3054. case POINT_NORMAL_HIT_DAMAGE_BONUS:
  3055. // DEPEND_BONUS_ATTRIBUTES
  3056. case POINT_SKILL_DEFEND_BONUS:
  3057. case POINT_NORMAL_HIT_DEFEND_BONUS:
  3058. SetPoint(type, GetPoint(type) + amount);
  3059. val = GetPoint(type);
  3060. break;
  3061. // END_OF_DEPEND_BONUS_ATTRIBUTES
  3062. case POINT_PARTY_ATTACKER_BONUS:
  3063. case POINT_PARTY_TANKER_BONUS:
  3064. case POINT_PARTY_BUFFER_BONUS:
  3065. case POINT_PARTY_SKILL_MASTER_BONUS:
  3066. case POINT_PARTY_HASTE_BONUS:
  3067. case POINT_PARTY_DEFENDER_BONUS:
  3068. case POINT_RESIST_WARRIOR :
  3069. case POINT_RESIST_ASSASSIN :
  3070. case POINT_RESIST_SURA :
  3071. case POINT_RESIST_SHAMAN :
  3072. #ifdef ENABLE_WOLFMAN_CHARACTER
  3073. case POINT_RESIST_WOLFMAN :
  3074. #endif
  3075. SetPoint(type, GetPoint(type) + amount);
  3076. val = GetPoint(type);
  3077. break;
  3078. case POINT_MALL_ATTBONUS:
  3079. case POINT_MALL_DEFBONUS:
  3080. case POINT_MALL_EXPBONUS:
  3081. case POINT_MALL_ITEMBONUS:
  3082. case POINT_MALL_GOLDBONUS:
  3083. case POINT_MELEE_MAGIC_ATT_BONUS_PER:
  3084. if (GetPoint(type) + amount > 100)
  3085. {
  3086. sys_err("MALL_BONUS exceeded over 100!! point type: %d name: %s amount %d", type, GetName(), amount);
  3087. amount = 100 - GetPoint(type);
  3088. }
  3089. SetPoint(type, GetPoint(type) + amount);
  3090. val = GetPoint(type);
  3091. break;
  3092. // PC_BANG_ITEM_ADD
  3093. case POINT_PC_BANG_EXP_BONUS :
  3094. case POINT_PC_BANG_DROP_BONUS :
  3095. case POINT_RAMADAN_CANDY_BONUS_EXP:
  3096. SetPoint(type, amount);
  3097. val = GetPoint(type);
  3098. break;
  3099. // END_PC_BANG_ITEM_ADD
  3100. case POINT_EXP_DOUBLE_BONUS: // 71
  3101. case POINT_GOLD_DOUBLE_BONUS: // 72
  3102. case POINT_ITEM_DROP_BONUS: // 73
  3103. case POINT_POTION_BONUS: // 74
  3104. if (GetPoint(type) + amount > 100)
  3105. {
  3106. sys_err("BONUS exceeded over 100!! point type: %d name: %s amount %d", type, GetName(), amount);
  3107. amount = 100 - GetPoint(type);
  3108. }
  3109. SetPoint(type, GetPoint(type) + amount);
  3110. val = GetPoint(type);
  3111. break;
  3112. case POINT_IMMUNE_STUN: // 76
  3113. SetPoint(type, GetPoint(type) + amount);
  3114. val = GetPoint(type);
  3115. if (val)
  3116. {
  3117. // ChatPacket(CHAT_TYPE_INFO, "IMMUNE_STUN SET_BIT type(%u) amount(%d)", type, amount);
  3118. SET_BIT(m_pointsInstant.dwImmuneFlag, IMMUNE_STUN);
  3119. }
  3120. else
  3121. {
  3122. // ChatPacket(CHAT_TYPE_INFO, "IMMUNE_STUN REMOVE_BIT type(%u) amount(%d)", type, amount);
  3123. REMOVE_BIT(m_pointsInstant.dwImmuneFlag, IMMUNE_STUN);
  3124. }
  3125. break;
  3126. case POINT_IMMUNE_SLOW:
  3127. SetPoint(type, GetPoint(type) + amount);
  3128. val = GetPoint(type);
  3129. if (val)
  3130. {
  3131. SET_BIT(m_pointsInstant.dwImmuneFlag, IMMUNE_SLOW);
  3132. }
  3133. else
  3134. {
  3135. REMOVE_BIT(m_pointsInstant.dwImmuneFlag, IMMUNE_SLOW);
  3136. }
  3137. break;
  3138. case POINT_IMMUNE_FALL:
  3139. SetPoint(type, GetPoint(type) + amount);
  3140. val = GetPoint(type);
  3141. if (val)
  3142. {
  3143. SET_BIT(m_pointsInstant.dwImmuneFlag, IMMUNE_FALL);
  3144. }
  3145. else
  3146. {
  3147. REMOVE_BIT(m_pointsInstant.dwImmuneFlag, IMMUNE_FALL);
  3148. }
  3149. break;
  3150. case POINT_ATT_GRADE_BONUS:
  3151. SetPoint(type, GetPoint(type) + amount);
  3152. PointChange(POINT_ATT_GRADE, amount);
  3153. val = GetPoint(type);
  3154. break;
  3155. case POINT_DEF_GRADE_BONUS:
  3156. SetPoint(type, GetPoint(type) + amount);
  3157. PointChange(POINT_DEF_GRADE, amount);
  3158. val = GetPoint(type);
  3159. break;
  3160. case POINT_MAGIC_ATT_GRADE_BONUS:
  3161. SetPoint(type, GetPoint(type) + amount);
  3162. PointChange(POINT_MAGIC_ATT_GRADE, amount);
  3163. val = GetPoint(type);
  3164. break;
  3165. case POINT_MAGIC_DEF_GRADE_BONUS:
  3166. SetPoint(type, GetPoint(type) + amount);
  3167. PointChange(POINT_MAGIC_DEF_GRADE, amount);
  3168. val = GetPoint(type);
  3169. break;
  3170. case POINT_VOICE:
  3171. case POINT_EMPIRE_POINT:
  3172. //sys_err("CHARACTER::PointChange: %s: point cannot be changed. use SetPoint instead (type: %d)", GetName(), type);
  3173. val = GetRealPoint(type);
  3174. break;
  3175. case POINT_POLYMORPH:
  3176. SetPoint(type, GetPoint(type) + amount);
  3177. val = GetPoint(type);
  3178. SetPolymorph(val);
  3179. break;
  3180. case POINT_MOUNT:
  3181. SetPoint(type, GetPoint(type) + amount);
  3182. val = GetPoint(type);
  3183. MountVnum(val);
  3184. break;
  3185. case POINT_ENERGY:
  3186. case POINT_COSTUME_ATTR_BONUS:
  3187. {
  3188. int old_val = GetPoint(type);
  3189. SetPoint(type, old_val + amount);
  3190. val = GetPoint(type);
  3191. BuffOnAttr_ValueChange(type, old_val, val);
  3192. }
  3193. break;
  3194. default:
  3195. sys_err("CHARACTER::PointChange: %s: unknown point change type %d", GetName(), type);
  3196. return;
  3197. }
  3198. switch (type)
  3199. {
  3200. case POINT_LEVEL:
  3201. case POINT_ST:
  3202. case POINT_DX:
  3203. case POINT_IQ:
  3204. case POINT_HT:
  3205. ComputeBattlePoints();
  3206. break;
  3207. case POINT_MAX_HP:
  3208. case POINT_MAX_SP:
  3209. case POINT_MAX_STAMINA:
  3210. break;
  3211. }
  3212. if (type == POINT_HP && amount == 0)
  3213. return;
  3214. if (GetDesc())
  3215. {
  3216. struct packet_point_change pack;
  3217. pack.header = HEADER_GC_CHARACTER_POINT_CHANGE;
  3218. pack.dwVID = m_vid;
  3219. pack.type = type;
  3220. pack.value = val;
  3221. if (bAmount)
  3222. pack.amount = amount;
  3223. else
  3224. pack.amount = 0;
  3225. if (!bBroadcast)
  3226. GetDesc()->Packet(&pack, sizeof(struct packet_point_change));
  3227. else
  3228. PacketAround(&pack, sizeof(pack));
  3229. }
  3230. }
  3231. void CHARACTER::ApplyPoint(BYTE bApplyType, int iVal)
  3232. {
  3233. switch (bApplyType)
  3234. {
  3235. case APPLY_NONE:
  3236. break;;
  3237. case APPLY_CON:
  3238. PointChange(POINT_HT, iVal);
  3239. PointChange(POINT_MAX_HP, (iVal * JobInitialPoints[GetJob()].hp_per_ht));
  3240. PointChange(POINT_MAX_STAMINA, (iVal * JobInitialPoints[GetJob()].stamina_per_con));
  3241. break;
  3242. case APPLY_INT:
  3243. PointChange(POINT_IQ, iVal);
  3244. PointChange(POINT_MAX_SP, (iVal * JobInitialPoints[GetJob()].sp_per_iq));
  3245. break;
  3246. case APPLY_SKILL:
  3247. {
  3248. BYTE bSkillVnum = (BYTE) (((DWORD)iVal) >> 24);
  3249. int iAdd = iVal & 0x00800000;
  3250. int iChange = iVal & 0x007fffff;
  3251. sys_log(1, "APPLY_SKILL skill %d add? %d change %d", bSkillVnum, iAdd ? 1 : 0, iChange);
  3252. if (0 == iAdd)
  3253. iChange = -iChange;
  3254. boost::unordered_map<BYTE, int>::iterator iter = m_SkillDamageBonus.find(bSkillVnum);
  3255. if (iter == m_SkillDamageBonus.end())
  3256. m_SkillDamageBonus.insert(std::make_pair(bSkillVnum, iChange));
  3257. else
  3258. iter->second += iChange;
  3259. }
  3260. // END_OF_SKILL_DAMAGE_BONUS
  3261. break;
  3262. case APPLY_MAX_HP:
  3263. case APPLY_MAX_HP_PCT:
  3264. {
  3265. int i = GetMaxHP(); if(i == 0) break;
  3266. PointChange(aApplyInfo[bApplyType].bPointType, iVal);
  3267. float fRatio = (float)GetMaxHP() / (float)i;
  3268. PointChange(POINT_HP, GetHP() * fRatio - GetHP());
  3269. }
  3270. break;
  3271. case APPLY_MAX_SP:
  3272. case APPLY_MAX_SP_PCT:
  3273. {
  3274. int i = GetMaxSP(); if(i == 0) break;
  3275. PointChange(aApplyInfo[bApplyType].bPointType, iVal);
  3276. float fRatio = (float)GetMaxSP() / (float)i;
  3277. PointChange(POINT_SP, GetSP() * fRatio - GetSP());
  3278. }
  3279. break;
  3280. case APPLY_STR:
  3281. case APPLY_DEX:
  3282. case APPLY_ATT_SPEED:
  3283. case APPLY_MOV_SPEED:
  3284. case APPLY_CAST_SPEED:
  3285. case APPLY_HP_REGEN:
  3286. case APPLY_SP_REGEN:
  3287. case APPLY_POISON_PCT:
  3288. #ifdef ENABLE_WOLFMAN_CHARACTER
  3289. case APPLY_BLEEDING_PCT:
  3290. #endif
  3291. case APPLY_STUN_PCT:
  3292. case APPLY_SLOW_PCT:
  3293. case APPLY_CRITICAL_PCT:
  3294. case APPLY_PENETRATE_PCT:
  3295. case APPLY_ATTBONUS_HUMAN:
  3296. case APPLY_ATTBONUS_ANIMAL:
  3297. case APPLY_ATTBONUS_ORC:
  3298. case APPLY_ATTBONUS_MILGYO:
  3299. case APPLY_ATTBONUS_UNDEAD:
  3300. case APPLY_ATTBONUS_DEVIL:
  3301. case APPLY_ATTBONUS_WARRIOR:
  3302. case APPLY_ATTBONUS_ASSASSIN:
  3303. case APPLY_ATTBONUS_SURA:
  3304. case APPLY_ATTBONUS_SHAMAN:
  3305. #ifdef ENABLE_WOLFMAN_CHARACTER
  3306. case APPLY_ATTBONUS_WOLFMAN:
  3307. #endif
  3308. case APPLY_ATTBONUS_MONSTER:
  3309. case APPLY_STEAL_HP:
  3310. case APPLY_STEAL_SP:
  3311. case APPLY_MANA_BURN_PCT:
  3312. case APPLY_DAMAGE_SP_RECOVER:
  3313. case APPLY_BLOCK:
  3314. case APPLY_DODGE:
  3315. case APPLY_RESIST_SWORD:
  3316. case APPLY_RESIST_TWOHAND:
  3317. case APPLY_RESIST_DAGGER:
  3318. case APPLY_RESIST_BELL:
  3319. case APPLY_RESIST_FAN:
  3320. case APPLY_RESIST_BOW:
  3321. #ifdef ENABLE_WOLFMAN_CHARACTER
  3322. case APPLY_RESIST_CLAW:
  3323. #endif
  3324. case APPLY_RESIST_FIRE:
  3325. case APPLY_RESIST_ELEC:
  3326. case APPLY_RESIST_MAGIC:
  3327. case APPLY_RESIST_WIND:
  3328. case APPLY_RESIST_ICE:
  3329. case APPLY_RESIST_EARTH:
  3330. case APPLY_RESIST_DARK:
  3331. case APPLY_REFLECT_MELEE:
  3332. case APPLY_REFLECT_CURSE:
  3333. case APPLY_ANTI_CRITICAL_PCT:
  3334. case APPLY_ANTI_PENETRATE_PCT:
  3335. case APPLY_POISON_REDUCE:
  3336. #ifdef ENABLE_WOLFMAN_CHARACTER
  3337. case APPLY_BLEEDING_REDUCE:
  3338. #endif
  3339. case APPLY_KILL_SP_RECOVER:
  3340. case APPLY_EXP_DOUBLE_BONUS:
  3341. case APPLY_GOLD_DOUBLE_BONUS:
  3342. case APPLY_ITEM_DROP_BONUS:
  3343. case APPLY_POTION_BONUS:
  3344. case APPLY_KILL_HP_RECOVER:
  3345. case APPLY_IMMUNE_STUN:
  3346. case APPLY_IMMUNE_SLOW:
  3347. case APPLY_IMMUNE_FALL:
  3348. case APPLY_BOW_DISTANCE:
  3349. case APPLY_ATT_GRADE_BONUS:
  3350. case APPLY_DEF_GRADE_BONUS:
  3351. case APPLY_MAGIC_ATT_GRADE:
  3352. case APPLY_MAGIC_DEF_GRADE:
  3353. case APPLY_CURSE_PCT:
  3354. case APPLY_MAX_STAMINA:
  3355. case APPLY_MALL_ATTBONUS:
  3356. case APPLY_MALL_DEFBONUS:
  3357. case APPLY_MALL_EXPBONUS:
  3358. case APPLY_MALL_ITEMBONUS:
  3359. case APPLY_MALL_GOLDBONUS:
  3360. case APPLY_SKILL_DAMAGE_BONUS:
  3361. case APPLY_NORMAL_HIT_DAMAGE_BONUS:
  3362. // DEPEND_BONUS_ATTRIBUTES
  3363. case APPLY_SKILL_DEFEND_BONUS:
  3364. case APPLY_NORMAL_HIT_DEFEND_BONUS:
  3365. // END_OF_DEPEND_BONUS_ATTRIBUTES
  3366. case APPLY_PC_BANG_EXP_BONUS :
  3367. case APPLY_PC_BANG_DROP_BONUS :
  3368. case APPLY_RESIST_WARRIOR :
  3369. case APPLY_RESIST_ASSASSIN :
  3370. case APPLY_RESIST_SURA :
  3371. case APPLY_RESIST_SHAMAN :
  3372. #ifdef ENABLE_WOLFMAN_CHARACTER
  3373. case APPLY_RESIST_WOLFMAN :
  3374. #endif
  3375. case APPLY_ENERGY:
  3376. case APPLY_DEF_GRADE:
  3377. case APPLY_COSTUME_ATTR_BONUS:
  3378. case APPLY_MAGIC_ATTBONUS_PER:
  3379. case APPLY_MELEE_MAGIC_ATTBONUS_PER:
  3380. PointChange(aApplyInfo[bApplyType].bPointType, iVal);
  3381. break;
  3382. default:
  3383. sys_err("Unknown apply type %d name %s", bApplyType, GetName());
  3384. break;
  3385. }
  3386. }
  3387. void CHARACTER::MotionPacketEncode(BYTE motion, LPCHARACTER victim, struct packet_motion * packet)
  3388. {
  3389. packet->header = HEADER_GC_MOTION;
  3390. packet->vid = m_vid;
  3391. packet->motion = motion;
  3392. if (victim)
  3393. packet->victim_vid = victim->GetVID();
  3394. else
  3395. packet->victim_vid = 0;
  3396. }
  3397. void CHARACTER::Motion(BYTE motion, LPCHARACTER victim)
  3398. {
  3399. struct packet_motion pack_motion;
  3400. MotionPacketEncode(motion, victim, &pack_motion);
  3401. PacketAround(&pack_motion, sizeof(struct packet_motion));
  3402. }
  3403. EVENTFUNC(save_event)
  3404. {
  3405. char_event_info* info = dynamic_cast<char_event_info*>( event->info );
  3406. if ( info == NULL )
  3407. {
  3408. sys_err( "save_event> <Factor> Null pointer" );
  3409. return 0;
  3410. }
  3411. LPCHARACTER ch = info->ch;
  3412. if (ch == NULL) {
  3413. return 0;
  3414. }
  3415. sys_log(1, "SAVE_EVENT: %s", ch->GetName());
  3416. ch->Save();
  3417. ch->FlushDelayedSaveItem();
  3418. return (save_event_second_cycle);
  3419. }
  3420. void CHARACTER::StartSaveEvent()
  3421. {
  3422. if (m_pkSaveEvent)
  3423. return;
  3424. char_event_info* info = AllocEventInfo<char_event_info>();
  3425. info->ch = this;
  3426. m_pkSaveEvent = event_create(save_event, info, save_event_second_cycle);
  3427. }
  3428. void CHARACTER::MonsterLog(const char* format, ...)
  3429. {
  3430. if (!test_server)
  3431. return;
  3432. if (IsPC())
  3433. return;
  3434. char chatbuf[CHAT_MAX_LEN + 1];
  3435. int len = snprintf(chatbuf, sizeof(chatbuf), "%u)", (DWORD)GetVID());
  3436. if (len < 0 || len >= (int) sizeof(chatbuf))
  3437. len = sizeof(chatbuf) - 1;
  3438. va_list args;
  3439. va_start(args, format);
  3440. int len2 = vsnprintf(chatbuf + len, sizeof(chatbuf) - len, format, args);
  3441. if (len2 < 0 || len2 >= (int) sizeof(chatbuf) - len)
  3442. len += (sizeof(chatbuf) - len) - 1;
  3443. else
  3444. len += len2;
  3445. ++len;
  3446. va_end(args);
  3447. TPacketGCChat pack_chat;
  3448. pack_chat.header = HEADER_GC_CHAT;
  3449. pack_chat.size = sizeof(TPacketGCChat) + len;
  3450. pack_chat.type = CHAT_TYPE_TALKING;
  3451. pack_chat.id = (DWORD)GetVID();
  3452. pack_chat.bEmpire = 0;
  3453. TEMP_BUFFER buf;
  3454. buf.write(&pack_chat, sizeof(TPacketGCChat));
  3455. buf.write(chatbuf, len);
  3456. CHARACTER_MANAGER::instance().PacketMonsterLog(this, buf.read_peek(), buf.size());
  3457. }
  3458. void CHARACTER::ChatPacket(BYTE type, const char * format, ...)
  3459. {
  3460. LPDESC d = GetDesc();
  3461. if (!d || !format)
  3462. return;
  3463. char chatbuf[CHAT_MAX_LEN + 1];
  3464. va_list args;
  3465. va_start(args, format);
  3466. int len = vsnprintf(chatbuf, sizeof(chatbuf), format, args);
  3467. va_end(args);
  3468. struct packet_chat pack_chat;
  3469. pack_chat.header = HEADER_GC_CHAT;
  3470. pack_chat.size = sizeof(struct packet_chat) + len;
  3471. pack_chat.type = type;
  3472. pack_chat.id = 0;
  3473. pack_chat.bEmpire = d->GetEmpire();
  3474. TEMP_BUFFER buf;
  3475. buf.write(&pack_chat, sizeof(struct packet_chat));
  3476. buf.write(chatbuf, len);
  3477. d->Packet(buf.read_peek(), buf.size());
  3478. if (type == CHAT_TYPE_COMMAND && test_server)
  3479. sys_log(0, "SEND_COMMAND %s %s", GetName(), chatbuf);
  3480. }
  3481. // MINING
  3482. void CHARACTER::mining_take()
  3483. {
  3484. m_pkMiningEvent = NULL;
  3485. }
  3486. void CHARACTER::mining_cancel()
  3487. {
  3488. if (m_pkMiningEvent)
  3489. {
  3490. sys_log(0, "XXX MINING CANCEL");
  3491. event_cancel(&m_pkMiningEvent);
  3492. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("䱤À» Áß´ÜÇÏ¿´½À´Ï´Ù."));
  3493. }
  3494. }
  3495. void CHARACTER::mining(LPCHARACTER chLoad)
  3496. {
  3497. if (m_pkMiningEvent)
  3498. {
  3499. mining_cancel();
  3500. return;
  3501. }
  3502. if (!chLoad)
  3503. return;
  3504. if (GetMapIndex() != chLoad->GetMapIndex() || DISTANCE_APPROX(GetX() - chLoad->GetX(), GetY() - chLoad->GetY()) > 1000)
  3505. return;
  3506. if (mining::GetRawOreFromLoad(chLoad->GetRaceNum()) == 0)
  3507. return;
  3508. LPITEM pick = GetWear(WEAR_WEAPON);
  3509. if (!pick || pick->GetType() != ITEM_PICK)
  3510. {
  3511. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("°î±ªÀ̸¦ ÀåÂøÇϼ¼¿ä."));
  3512. return;
  3513. }
  3514. int count = number(5, 15);
  3515. TPacketGCDigMotion p;
  3516. p.header = HEADER_GC_DIG_MOTION;
  3517. p.vid = GetVID();
  3518. p.target_vid = chLoad->GetVID();
  3519. p.count = count;
  3520. PacketAround(&p, sizeof(p));
  3521. m_pkMiningEvent = mining::CreateMiningEvent(this, chLoad, count);
  3522. }
  3523. // END_OF_MINING
  3524. void CHARACTER::fishing()
  3525. {
  3526. if (m_pkFishingEvent)
  3527. {
  3528. fishing_take();
  3529. return;
  3530. }
  3531. {
  3532. LPSECTREE_MAP pkSectreeMap = SECTREE_MANAGER::instance().GetMap(GetMapIndex());
  3533. int x = GetX();
  3534. int y = GetY();
  3535. LPSECTREE tree = pkSectreeMap->Find(x, y);
  3536. DWORD dwAttr = tree->GetAttribute(x, y);
  3537. if (IS_SET(dwAttr, ATTR_BLOCK))
  3538. {
  3539. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("³¬½Ã¸¦ ÇÒ ¼ö ÀÖ´Â °÷ÀÌ ¾Æ´Õ´Ï´Ù"));
  3540. return;
  3541. }
  3542. }
  3543. LPITEM rod = GetWear(WEAR_WEAPON);
  3544. if (!rod || rod->GetType() != ITEM_ROD)
  3545. {
  3546. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("³¬½Ã´ë¸¦ ÀåÂø Çϼ¼¿ä."));
  3547. return;
  3548. }
  3549. if (0 == rod->GetSocket(2))
  3550. {
  3551. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("¹Ì³¢¸¦ ³¢°í ´øÁ® ÁÖ¼¼¿ä."));
  3552. return;
  3553. }
  3554. float fx, fy;
  3555. GetDeltaByDegree(GetRotation(), 400.0f, &fx, &fy);
  3556. m_pkFishingEvent = fishing::CreateFishingEvent(this);
  3557. }
  3558. void CHARACTER::fishing_take()
  3559. {
  3560. LPITEM rod = GetWear(WEAR_WEAPON);
  3561. if (rod && rod->GetType() == ITEM_ROD)
  3562. {
  3563. using fishing::fishing_event_info;
  3564. if (m_pkFishingEvent)
  3565. {
  3566. struct fishing_event_info* info = dynamic_cast<struct fishing_event_info*>(m_pkFishingEvent->info);
  3567. if (info)
  3568. fishing::Take(info, this);
  3569. }
  3570. }
  3571. else
  3572. {
  3573. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("³¬½Ã´ë°¡ ¾Æ´Ñ ¹°°ÇÀ¸·Î ³¬½Ã¸¦ ÇÒ ¼ö ¾ø½À´Ï´Ù!"));
  3574. }
  3575. event_cancel(&m_pkFishingEvent);
  3576. }
  3577. bool CHARACTER::StartStateMachine(int iNextPulse)
  3578. {
  3579. if (CHARACTER_MANAGER::instance().AddToStateList(this))
  3580. {
  3581. m_dwNextStatePulse = thecore_heart->pulse + iNextPulse;
  3582. return true;
  3583. }
  3584. return false;
  3585. }
  3586. void CHARACTER::StopStateMachine()
  3587. {
  3588. CHARACTER_MANAGER::instance().RemoveFromStateList(this);
  3589. }
  3590. void CHARACTER::UpdateStateMachine(DWORD dwPulse)
  3591. {
  3592. if (dwPulse < m_dwNextStatePulse)
  3593. return;
  3594. if (IsDead())
  3595. return;
  3596. Update();
  3597. m_dwNextStatePulse = dwPulse + m_dwStateDuration;
  3598. }
  3599. void CHARACTER::SetNextStatePulse(int iNextPulse)
  3600. {
  3601. CHARACTER_MANAGER::instance().AddToStateList(this);
  3602. m_dwNextStatePulse = iNextPulse;
  3603. if (iNextPulse < 10)
  3604. MonsterLog("´ÙÀ½»óÅ·ξ°¡ÀÚ");
  3605. }
  3606. void CHARACTER::UpdateCharacter(DWORD dwPulse)
  3607. {
  3608. CFSM::Update();
  3609. }
  3610. void CHARACTER::SetShop(LPSHOP pkShop)
  3611. {
  3612. if ((m_pkShop = pkShop))
  3613. SET_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_SHOP);
  3614. else
  3615. {
  3616. REMOVE_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_SHOP);
  3617. SetShopOwner(NULL);
  3618. }
  3619. }
  3620. void CHARACTER::SetOfflineShop(LPOFFLINESHOP pkOfflineShop)
  3621. {
  3622. if ((m_pkOfflineShop = pkOfflineShop))
  3623. SET_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_OFFLINE_SHOP);
  3624. else
  3625. {
  3626. REMOVE_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_OFFLINE_SHOP);
  3627. SetOfflineShopOwner(NULL);
  3628. }
  3629. }
  3630. #ifdef ENABLE_MAXIMUM_YANG_FOR_OFFLINE_SHOP
  3631. void CHARACTER::OpenMyOfflineShop(const char * c_pszSign, TOfflineShopItemTable * pTable, BYTE bItemCount, BYTE bTime)
  3632. #else
  3633. void CHARACTER::OpenMyOfflineShop(const char * c_pszSign, TShopItemTable * pTable, BYTE bItemCount, BYTE bTime)
  3634. #endif
  3635. {
  3636. quest::PC * pPC = quest::CQuestManager::instance().GetPC(GetPlayerID());
  3637. if (pPC && pPC->IsRunning())
  3638. return;
  3639. if (bItemCount == 0)
  3640. return;
  3641. if (GetShop() || GetOfflineShop())
  3642. return;
  3643. if (g_bEnableEmpireLimit)
  3644. {
  3645. if (GetEmpire() == 1 && (GetMapIndex() == 41 || GetMapIndex() == 21))
  3646. {
  3647. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("kendi koyuna gider misin"));
  3648. return;
  3649. }
  3650. else if (GetEmpire() == 2 && (GetMapIndex() == 1 || GetMapIndex() == 41))
  3651. {
  3652. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("kendi koyuna gider misin"));
  3653. return;
  3654. }
  3655. else if (GetEmpire() == 3 && (GetMapIndex() == 1 || GetMapIndex() == 21))
  3656. {
  3657. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("kendi koyuna gider misin"));
  3658. return;
  3659. }
  3660. }
  3661. if (IsSashCombinationOpen() || IsSashAbsorptionOpen())
  3662. {
  3663. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Bu Pencerede Offline Shop Acilamaz"));
  3664. return;
  3665. }
  3666. {
  3667. std::auto_ptr<SQLMsg> pMsg(DBManager::instance().DirectQuery("SELECT COUNT(*) FROM %soffline_shop_item WHERE owner_id = %u and status = 1", get_table_postfix(), GetPlayerID()));
  3668. MYSQL_ROW row = mysql_fetch_row(pMsg->Get()->pSQLResult);
  3669. BYTE bResult = 0;
  3670. str_to_number(bResult, row[0]);
  3671. if (bResult)
  3672. {
  3673. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("At first, you have to get your unsold items at admin panel."));
  3674. return;
  3675. }
  3676. }
  3677. {
  3678. std::auto_ptr<SQLMsg> pMsg(DBManager::instance().DirectQuery("SELECT COUNT(*) FROM %soffline_shop_npc WHERE owner_id = %u", get_table_postfix(), GetPlayerID()));
  3679. MYSQL_ROW row = mysql_fetch_row(pMsg->Get()->pSQLResult);
  3680. BYTE bResult = 0;
  3681. str_to_number(bResult, row[0]);
  3682. if (bResult)
  3683. {
  3684. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You already have an offline-shop."));
  3685. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot open a new offline-shop before close old one."));
  3686. return;
  3687. }
  3688. }
  3689. if (g_bOfflineShopMapAllowLimit)
  3690. {
  3691. if (!offlineshop_map_allow_find(GetMapIndex()))
  3692. {
  3693. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot open an offline-shop here!"));
  3694. return;
  3695. }
  3696. }
  3697. if (g_bNeededItem)
  3698. {
  3699. BYTE bCount = quest::CQuestManager::instance().GetCurrentCharacterPtr()->CountSpecifyItem(g_iItemVnum);
  3700. if (bCount < g_iItemVnum)
  3701. {
  3702. LPITEM pItem = ITEM_MANAGER::instance().CreateItem(g_iItemVnum);
  3703. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot open an offline-shop at the moment. You need to x%d %s"), g_bItemCount, pItem->GetName());
  3704. return;
  3705. }
  3706. }
  3707. if (g_bNeededMoney)
  3708. {
  3709. #ifdef ENABLE_MAXIMUM_YANG_FOR_OFFLINE_SHOP
  3710. if (GetGold() < static_cast<long long>(g_dwNeedMoney))
  3711. #else
  3712. if (GetGold() < static_cast<int>(g_dwNeedMoney))
  3713. #endif
  3714. {
  3715. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You do not have enough money to open an offline-shop at the moment."));
  3716. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Required money : %u"), g_dwNeedMoney);
  3717. return;
  3718. }
  3719. }
  3720. if (g_bNeedMinLevel && GetLevel() < g_bMinLevel)
  3721. {
  3722. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Your level is not enough to open an offline shop!"));
  3723. return;
  3724. }
  3725. {
  3726. if (g_wCoinsForUnlimited > 0 && bTime == 4)
  3727. {
  3728. std::auto_ptr<SQLMsg> pMsg(DBManager::instance().DirectQuery("SELECT coins FROM account.account WHERE id = %u", GetAID()));
  3729. if (pMsg->Get()->uiNumRows == 0) return;
  3730. MYSQL_ROW row = mysql_fetch_row(pMsg->Get()->pSQLResult);
  3731. long lCoins = 0;
  3732. str_to_number(lCoins, row[0]);
  3733. if (lCoins < static_cast<long>(g_wCoinsForUnlimited))
  3734. {
  3735. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You can't open an offline shop. You need to %d coins to open an offline shop!"), g_wCoinsForUnlimited);
  3736. return;
  3737. }
  3738. DBManager::instance().DirectQuery("UPDATE account.account SET coins = coins - %d where id = %u", g_wCoinsForUnlimited, GetAID());
  3739. }
  3740. }
  3741. #ifdef DISABLE_ALPHA_CHARACTER
  3742. if (!check_name(c_pszSign))
  3743. {
  3744. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You can't use this offline shop title!"));
  3745. return;
  3746. }
  3747. #endif
  3748. m_stOfflineShopSign = c_pszSign;
  3749. if (CBanwordManager::instance().CheckString(m_stOfflineShopSign.c_str(), m_stOfflineShopSign.length()))
  3750. {
  3751. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("¨¬n¨ùO¨úi©ø¨£ A¨¬¨úi¡Æ¢® ¨¡¡ÀCO¥ìE ¡íoA¢® AI¢¬¡×A¢¬¡¤I ¡íoA¢®A¡í ¢¯¡© ¨ùo ¨ú©ª¨öA¢¥I¢¥U."));
  3752. return;
  3753. }
  3754. LPCHARACTER npc = CHARACTER_MANAGER::instance().SpawnMob(30000, GetMapIndex(), GetX(), GetY(), GetZ(), false, -1, false, true, GetPlayerID());
  3755. if (!npc)
  3756. {
  3757. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Offline shop npc can not create! Please try again."));
  3758. return;
  3759. }
  3760. bool bIsWrong = false;
  3761. for (BYTE i = 0; i < bItemCount; ++i)
  3762. {
  3763. LPITEM pItem = GetItem((pTable + i)->pos);
  3764. if (!pItem)
  3765. continue;
  3766. if (pItem->IsEquipped())
  3767. {
  3768. bIsWrong = true;
  3769. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You can't put the equipped items."));
  3770. return;
  3771. }
  3772. if (pItem->isLocked())
  3773. {
  3774. bIsWrong = true;
  3775. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You can't sell the locked items!"));
  3776. return;
  3777. }
  3778. #ifdef __SOULBINDING_SYSTEM__
  3779. if (pItem->IsBind() || pItem->IsUntilBind())
  3780. {
  3781. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You can't sell this item because is binded!"));
  3782. return;
  3783. }
  3784. #endif
  3785. #ifdef ENABLE_MAXIMUM_YANG_FOR_OFFLINE_SHOP
  3786. if ((pTable + i)->price >= GOLD_MAX)
  3787. {
  3788. bIsWrong = true;
  3789. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You can't build this offline shop because of the overflow yang!"));
  3790. return;
  3791. }
  3792. #else
  3793. if ((pTable + i)->price >= GOLD_MAX - 1)
  3794. {
  3795. bIsWrong = true;
  3796. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You can't build this offline shop because of the overflow yang!"));
  3797. return;
  3798. }
  3799. #endif
  3800. }
  3801. if (!bIsWrong)
  3802. {
  3803. for (BYTE i = 0; i < bItemCount; ++i)
  3804. {
  3805. LPITEM pkItem = GetItem((pTable + i)->pos);
  3806. if (!pkItem)
  3807. continue;
  3808. char szColumns[QUERY_MAX_LEN], szValues[QUERY_MAX_LEN];
  3809. int iLen = snprintf(szColumns, sizeof(szColumns),
  3810. "id, "
  3811. "owner_id, "
  3812. "pos, "
  3813. "count, "
  3814. "price, "
  3815. "vnum "
  3816. #ifdef __CHANGELOOK_SYSTEM__
  3817. ", transmutation"
  3818. #endif
  3819. );
  3820. #ifdef ENABLE_MAXIMUM_YANG_FOR_OFFLINE_SHOP
  3821. int iUpdateLen = snprintf(szValues, sizeof(szValues),
  3822. "%u, "
  3823. "%u, "
  3824. "%d, "
  3825. "%u, "
  3826. "%lld, "
  3827. "%u "
  3828. #ifdef __CHANGELOOK_SYSTEM__
  3829. ", %d "
  3830. #endif
  3831. ,
  3832. pkItem->GetID(),
  3833. GetPlayerID(),
  3834. (pTable + i)->display_pos,
  3835. pkItem->GetCount(),
  3836. (pTable + i)->price,
  3837. pkItem->GetVnum()
  3838. #ifdef __CHANGELOOK_SYSTEM__
  3839. ,pkItem->GetTransmutation()
  3840. #endif
  3841. );
  3842. #else
  3843. int iUpdateLen = snprintf(szValues, sizeof(szValues),
  3844. "%u, "
  3845. "%u, "
  3846. "%d, "
  3847. "%u, "
  3848. "%u, "
  3849. "%u "
  3850. #ifdef __CHANGELOOK_SYSTEM__
  3851. ", %d "
  3852. #endif
  3853. ,
  3854. pkItem->GetID(),
  3855. GetPlayerID(),
  3856. (pTable + i)->display_pos,
  3857. pkItem->GetCount(),
  3858. (pTable + i)->price,
  3859. pkItem->GetVnum()
  3860. #ifdef __CHANGELOOK_SYSTEM__
  3861. ,pkItem->GetTransmutation()
  3862. #endif
  3863. );
  3864. #endif
  3865. iLen += snprintf(szColumns + iLen, sizeof(szColumns) - iLen, ",socket0,socket1,socket2");
  3866. iUpdateLen += snprintf(szValues + iUpdateLen, sizeof(szValues) - iUpdateLen, ",%ld,%ld,%ld", pkItem->GetSocket(0), pkItem->GetSocket(1), pkItem->GetSocket(2));
  3867. #ifdef USE_LENTS_SHOULDER_SASH
  3868. iLen += snprintf(szColumns + iLen, sizeof(szColumns) - iLen, ", attrtype0, attrvalue0, attrtype1, attrvalue1, attrtype2, attrvalue2, attrtype3, attrvalue3, attrtype4, attrvalue4, attrtype5, attrvalue5, attrtype6, attrvalue6, applytype0, applyvalue0, applytype1, applyvalue1, applytype2, applyvalue2, applytype3, applyvalue3, applytype4, applyvalue4, applytype5, applyvalue5, applytype6, applyvalue6, applytype7, applyvalue7");
  3869. iUpdateLen += snprintf(szValues + iUpdateLen, sizeof(szValues) - iUpdateLen, ", %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",
  3870. pkItem->GetAttributeType(0), pkItem->GetAttributeValue(0),
  3871. pkItem->GetAttributeType(1), pkItem->GetAttributeValue(1),
  3872. pkItem->GetAttributeType(2), pkItem->GetAttributeValue(2),
  3873. pkItem->GetAttributeType(3), pkItem->GetAttributeValue(3),
  3874. pkItem->GetAttributeType(4), pkItem->GetAttributeValue(4),
  3875. pkItem->GetAttributeType(5), pkItem->GetAttributeValue(5),
  3876. pkItem->GetAttributeType(6), pkItem->GetAttributeValue(6),
  3877. pkItem->GetAttributeType(7), pkItem->GetAttributeValue(7),
  3878. pkItem->GetAttributeType(8), pkItem->GetAttributeValue(8),
  3879. pkItem->GetAttributeType(9), pkItem->GetAttributeValue(9),
  3880. pkItem->GetAttributeType(10), pkItem->GetAttributeValue(10),
  3881. pkItem->GetAttributeType(11), pkItem->GetAttributeValue(11),
  3882. pkItem->GetAttributeType(12), pkItem->GetAttributeValue(12),
  3883. pkItem->GetAttributeType(13), pkItem->GetAttributeValue(13),
  3884. pkItem->GetAttributeType(14), pkItem->GetAttributeValue(14));
  3885. #else
  3886. iLen += snprintf(szColumns + iLen, sizeof(szColumns) - iLen, ",attrtype0,attrvalue0,attrtype1,attrvalue1,attrtype2,attrvalue2,attrtype3,attrvalue3,attrtype4,attrvalue4,attrtype5,attrvalue5,attrtype6,attrvalue6");
  3887. iUpdateLen += snprintf(szValues + iUpdateLen, sizeof(szValues) - iUpdateLen, ",%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
  3888. pkItem->GetAttributeType(0), pkItem->GetAttributeValue(0),
  3889. pkItem->GetAttributeType(1), pkItem->GetAttributeValue(1),
  3890. pkItem->GetAttributeType(2), pkItem->GetAttributeValue(2),
  3891. pkItem->GetAttributeType(3), pkItem->GetAttributeValue(3),
  3892. pkItem->GetAttributeType(4), pkItem->GetAttributeValue(4),
  3893. pkItem->GetAttributeType(5), pkItem->GetAttributeValue(5),
  3894. pkItem->GetAttributeType(6), pkItem->GetAttributeValue(6));
  3895. #endif
  3896. char szInsertQuery[QUERY_MAX_LEN];
  3897. snprintf(szInsertQuery, sizeof(szInsertQuery), "INSERT INTO %soffline_shop_item (%s) VALUES (%s)", get_table_postfix(), szColumns, szValues);
  3898. std::auto_ptr<SQLMsg> pMsg(DBManager::instance().DirectQuery(szInsertQuery));
  3899. pkItem->RemoveFromCharacter();
  3900. }
  3901. }
  3902. int iTime = 0;
  3903. switch (bTime)
  3904. {
  3905. case 1:
  3906. iTime = 1 * 60 * 60;
  3907. break;
  3908. case 2:
  3909. iTime = 2 * 60 * 60;
  3910. break;
  3911. case 3:
  3912. iTime = 4 * 60 * 60;
  3913. break;
  3914. }
  3915. // If bTime is not equal to unlimited time, start the time!
  3916. if (bTime != 4)
  3917. {
  3918. npc->SetOfflineShopTimer(iTime);
  3919. npc->StartOfflineShopUpdateEvent();
  3920. }
  3921. // Insert
  3922. char szSign2[SHOP_SIGN_MAX_LEN+1];
  3923. DBManager::instance().EscapeString(szSign2,sizeof( szSign2), c_pszSign, strlen(c_pszSign));
  3924. char szQuery2[512];
  3925. snprintf(szQuery2,sizeof(szQuery2),"INSERT INTO %soffline_shop_npc(owner_id, sign, name, time, x, y, z, mapIndex, channel) VALUES(%u, '%s', '%s', %d, %ld, %ld, %ld, %ld, %d)", get_table_postfix(),GetPlayerID(), szSign2,GetName(), iTime,GetX(),GetY(),GetZ(),GetMapIndex(), g_bChannel);
  3926. DBManager::Instance().DirectQuery(szQuery2);
  3927. // Create Offline Shop
  3928. LPOFFLINESHOP pkOfflineShop = COfflineShopManager::instance().CreateOfflineShop(npc, GetPlayerID());
  3929. if (!pkOfflineShop)
  3930. {
  3931. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Offline shop npc can not create! Please try again."));
  3932. return;
  3933. }
  3934. npc->SetOfflineShop(pkOfflineShop);
  3935. npc->SetOfflineShopChannel(g_bChannel);
  3936. // End Of Create Offline Shop
  3937. // Set Name
  3938. char szName[CHARACTER_NAME_MAX_LEN + 1];
  3939. #ifdef DISABLE_OFFLINESHOP_NAME
  3940. snprintf(szName, sizeof(szName), "%s", GetName());
  3941. #else
  3942. snprintf(szName, sizeof(szName), "%s's offline shop", GetName());
  3943. #endif
  3944. npc->SetName(szName);
  3945. // End Of Set Name
  3946. SetOfflineShopVID(npc->GetVID());
  3947. npc->Show(GetMapIndex(), GetX(), GetY(), GetZ(), true);
  3948. // Send Offline Shop Sign to Everyone
  3949. TPacketGCShopSign p;
  3950. p.bHeader = HEADER_GC_OFFLINE_SHOP_SIGN;
  3951. p.dwVID = npc->GetVID();
  3952. strlcpy(p.szSign, c_pszSign, sizeof(p.szSign));
  3953. PacketAround(&p, sizeof(TPacketGCShopSign));
  3954. // End Of Send Offline Shop Sign to Everyone
  3955. if (bTime != 4)
  3956. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Your offline shop's time is expired after %d hour(s)"), iTime / 60 / 60);
  3957. else
  3958. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Your offline shop's time is configured as unlimited!"));
  3959. if (g_bNeededItem)
  3960. {
  3961. LPITEM item = FindSpecifyItem(g_iItemVnum);
  3962. if (!item)
  3963. {
  3964. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Ups! Something went wrong!"));
  3965. return;
  3966. }
  3967. if (item->IsStackable())
  3968. if (item->GetCount() == g_bItemCount)
  3969. ITEM_MANAGER::instance().RemoveItem(item);
  3970. else
  3971. item->SetCount(item->GetCount() - g_bItemCount);
  3972. else
  3973. ITEM_MANAGER::instance().RemoveItem(item);
  3974. }
  3975. if (g_bNeededMoney)
  3976. PointChange(POINT_GOLD, -g_dwNeedMoney, false);
  3977. SetOfflineShopStatus(2);
  3978. }
  3979. EVENTFUNC(offline_shop_update_event)
  3980. {
  3981. char_event_info* pInfo = dynamic_cast<char_event_info*>(event->info);
  3982. if (pInfo == NULL)
  3983. {
  3984. sys_err("offline_shop_update_event> <Factor> Null pointer");
  3985. return 0;
  3986. }
  3987. LPCHARACTER npc = pInfo->ch;
  3988. if (npc == NULL)
  3989. return 0;
  3990. int remain_time = npc->GetOfflineShopTimer() - processing_time / passes_per_sec;
  3991. if (remain_time <= 0)
  3992. {
  3993. sys_log(0, "OFFLINE SHOP EXPIRED : expired %s", npc->GetName());
  3994. LPCHARACTER pChar = CHARACTER_MANAGER::Instance().FindByPID(npc->GetOfflineShopRealOwner());
  3995. if (pChar)
  3996. {
  3997. pChar->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Your offline shop timer is over. You can check your unsold items at get back window."));
  3998. COfflineShopManager::Instance().DestroyOfflineShop(pChar, npc->GetVID());
  3999. }
  4000. else
  4001. COfflineShopManager::Instance().DestroyOfflineShop(NULL, npc->GetVID());
  4002. DBManager::instance().DirectQuery("UPDATE %soffline_shop_item SET status = 1 WHERE owner_id = %u and status = 0", get_table_postfix(), npc->GetOfflineShopRealOwner());
  4003. DBManager::instance().DirectQuery("DELETE FROM %soffline_shop_npc WHERE owner_id = %u", get_table_postfix(), npc->GetOfflineShopRealOwner());
  4004. M2_DESTROY_CHARACTER(npc);
  4005. return 0;
  4006. }
  4007. if (npc->GetOfflineShopSaveTime() >= g_bOfflineShopSaveTime)
  4008. {
  4009. DBManager::instance().DirectQuery("UPDATE %soffline_shop_npc SET time = %d WHERE owner_id = %u", get_table_postfix(), npc->GetOfflineShopTimer(), npc->GetOfflineShopRealOwner());
  4010. npc->SetOfflineShopTimer(1);
  4011. }
  4012. npc->SetOfflineShopTimer(remain_time);
  4013. npc->SetOfflineShopSaveTime(npc->GetOfflineShopSaveTime() + 1);
  4014. return PASSES_PER_SEC(MIN(60, remain_time));
  4015. }
  4016. void CHARACTER::StartOfflineShopUpdateEvent()
  4017. {
  4018. if (m_pkOfflineShopUpdateEvent)
  4019. return;
  4020. if (IsPC() || IsMonster())
  4021. return;
  4022. char_event_info * pInfo = AllocEventInfo<char_event_info>();
  4023. pInfo->ch = this;
  4024. m_pkOfflineShopUpdateEvent = event_create(offline_shop_update_event, pInfo, PASSES_PER_SEC(60));
  4025. }
  4026. void CHARACTER::StopOfflineShopUpdateEvent()
  4027. {
  4028. m_pointsInstant.bSaveTime = 0;
  4029. m_pointsInstant.leftTime = 0;
  4030. event_cancel(&m_pkOfflineShopUpdateEvent);
  4031. }
  4032. void CHARACTER::SetExchange(CExchange * pkExchange)
  4033. {
  4034. m_pkExchange = pkExchange;
  4035. }
  4036. void CHARACTER::SetPart(BYTE bPartPos, WORD wVal)
  4037. {
  4038. assert(bPartPos < PART_MAX_NUM);
  4039. m_pointsInstant.parts[bPartPos] = wVal;
  4040. }
  4041. WORD CHARACTER::GetPart(BYTE bPartPos) const
  4042. {
  4043. assert(bPartPos < PART_MAX_NUM);
  4044. return m_pointsInstant.parts[bPartPos];
  4045. }
  4046. WORD CHARACTER::GetOriginalPart(BYTE bPartPos) const
  4047. {
  4048. switch (bPartPos)
  4049. {
  4050. case PART_MAIN:
  4051. if (!IsPC())
  4052. return GetPart(PART_MAIN);
  4053. else
  4054. return m_pointsInstant.bBasePart;
  4055. case PART_HAIR:
  4056. return GetPart(PART_HAIR);
  4057. #ifdef __SASH_SYSTEM__
  4058. case PART_SASH:
  4059. return GetPart(PART_SASH);
  4060. #endif
  4061. default:
  4062. return 0;
  4063. }
  4064. }
  4065. BYTE CHARACTER::GetCharType() const
  4066. {
  4067. return m_bCharType;
  4068. }
  4069. bool CHARACTER::SetSyncOwner(LPCHARACTER ch, bool bRemoveFromList)
  4070. {
  4071. // TRENT_MONSTER
  4072. if (IS_SET(m_pointsInstant.dwAIFlag, AIFLAG_NOMOVE))
  4073. return false;
  4074. // END_OF_TRENT_MONSTER
  4075. if (ch)
  4076. {
  4077. if (!battle_is_attackable(ch, this))
  4078. {
  4079. SendDamagePacket(ch, 0, DAMAGE_BLOCK);
  4080. return false;
  4081. }
  4082. }
  4083. if (ch == this)
  4084. {
  4085. sys_err("SetSyncOwner owner == this (%p)", this);
  4086. return false;
  4087. }
  4088. if (!ch)
  4089. {
  4090. if (bRemoveFromList && m_pkChrSyncOwner)
  4091. {
  4092. m_pkChrSyncOwner->m_kLst_pkChrSyncOwned.remove(this);
  4093. }
  4094. if (m_pkChrSyncOwner)
  4095. sys_log(1, "SyncRelease %s %p from %s", GetName(), this, m_pkChrSyncOwner->GetName());
  4096. m_pkChrSyncOwner = NULL;
  4097. }
  4098. else
  4099. {
  4100. if (!IsSyncOwner(ch))
  4101. return false;
  4102. if (DISTANCE_APPROX(GetX() - ch->GetX(), GetY() - ch->GetY()) > 250)
  4103. {
  4104. sys_log(1, "SetSyncOwner distance over than 250 %s %s", GetName(), ch->GetName());
  4105. if (m_pkChrSyncOwner == ch)
  4106. return true;
  4107. return false;
  4108. }
  4109. if (m_pkChrSyncOwner != ch)
  4110. {
  4111. if (m_pkChrSyncOwner)
  4112. {
  4113. sys_log(1, "SyncRelease %s %p from %s", GetName(), this, m_pkChrSyncOwner->GetName());
  4114. m_pkChrSyncOwner->m_kLst_pkChrSyncOwned.remove(this);
  4115. }
  4116. m_pkChrSyncOwner = ch;
  4117. m_pkChrSyncOwner->m_kLst_pkChrSyncOwned.push_back(this);
  4118. static const timeval zero_tv = {0, 0};
  4119. SetLastSyncTime(zero_tv);
  4120. sys_log(1, "SetSyncOwner set %s %p to %s", GetName(), this, ch->GetName());
  4121. }
  4122. m_fSyncTime = get_float_time();
  4123. }
  4124. TPacketGCOwnership pack;
  4125. pack.bHeader = HEADER_GC_OWNERSHIP;
  4126. pack.dwOwnerVID = ch ? ch->GetVID() : 0;
  4127. pack.dwVictimVID = GetVID();
  4128. PacketAround(&pack, sizeof(TPacketGCOwnership));
  4129. return true;
  4130. }
  4131. struct FuncClearSync
  4132. {
  4133. void operator () (LPCHARACTER ch)
  4134. {
  4135. assert(ch != NULL);
  4136. ch->SetSyncOwner(NULL, false);
  4137. }
  4138. };
  4139. void CHARACTER::ClearSync()
  4140. {
  4141. SetSyncOwner(NULL);
  4142. std::for_each(m_kLst_pkChrSyncOwned.begin(), m_kLst_pkChrSyncOwned.end(), FuncClearSync());
  4143. m_kLst_pkChrSyncOwned.clear();
  4144. }
  4145. bool CHARACTER::IsSyncOwner(LPCHARACTER ch) const
  4146. {
  4147. if (m_pkChrSyncOwner == ch)
  4148. return true;
  4149. if (get_float_time() - m_fSyncTime >= 3.0f)
  4150. return true;
  4151. return false;
  4152. }
  4153. void CHARACTER::SetParty(LPPARTY pkParty)
  4154. {
  4155. if (pkParty == m_pkParty)
  4156. return;
  4157. if (pkParty && m_pkParty)
  4158. sys_err("%s is trying to reassigning party (current %p, new party %p)", GetName(), get_pointer(m_pkParty), get_pointer(pkParty));
  4159. sys_log(1, "PARTY set to %p", get_pointer(pkParty));
  4160. if (m_pkDungeon && IsPC() && !pkParty)
  4161. SetDungeon(NULL);
  4162. m_pkParty = pkParty;
  4163. if (IsPC())
  4164. {
  4165. if (m_pkParty)
  4166. SET_BIT(m_bAddChrState, ADD_CHARACTER_STATE_PARTY);
  4167. else
  4168. REMOVE_BIT(m_bAddChrState, ADD_CHARACTER_STATE_PARTY);
  4169. UpdatePacket();
  4170. }
  4171. }
  4172. EVENTINFO(TPartyJoinEventInfo)
  4173. {
  4174. DWORD dwGuestPID;
  4175. DWORD dwLeaderPID;
  4176. TPartyJoinEventInfo()
  4177. : dwGuestPID( 0 )
  4178. , dwLeaderPID( 0 )
  4179. {
  4180. }
  4181. } ;
  4182. EVENTFUNC(party_request_event)
  4183. {
  4184. TPartyJoinEventInfo * info = dynamic_cast<TPartyJoinEventInfo *>( event->info );
  4185. if ( info == NULL )
  4186. {
  4187. sys_err( "party_request_event> <Factor> Null pointer" );
  4188. return 0;
  4189. }
  4190. LPCHARACTER ch = CHARACTER_MANAGER::instance().FindByPID(info->dwGuestPID);
  4191. if (ch)
  4192. {
  4193. sys_log(0, "PartyRequestEvent %s", ch->GetName());
  4194. ch->ChatPacket(CHAT_TYPE_COMMAND, "PartyRequestDenied");
  4195. ch->SetPartyRequestEvent(NULL);
  4196. }
  4197. return 0;
  4198. }
  4199. bool CHARACTER::RequestToParty(LPCHARACTER leader)
  4200. {
  4201. if (leader->GetParty())
  4202. leader = leader->GetParty()->GetLeaderCharacter();
  4203. if (!leader)
  4204. {
  4205. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("ÆÄƼÀåÀÌ Á¢¼Ó »óŰ¡ ¾Æ´Ï¶ó¼­ ¿äûÀ» ÇÒ ¼ö ¾ø½À´Ï´Ù."));
  4206. return false;
  4207. }
  4208. if (m_pkPartyRequestEvent)
  4209. return false;
  4210. if (!IsPC() || !leader->IsPC())
  4211. return false;
  4212. if (leader->IsBlockMode(BLOCK_PARTY_REQUEST))
  4213. return false;
  4214. PartyJoinErrCode errcode = IsPartyJoinableCondition(leader, this);
  4215. switch (errcode)
  4216. {
  4217. case PERR_NONE:
  4218. break;
  4219. case PERR_SERVER:
  4220. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ¼­¹ö ¹®Á¦·Î ÆÄƼ °ü·Ã 󸮸¦ ÇÒ ¼ö ¾ø½À´Ï´Ù."));
  4221. return false;
  4222. case PERR_DIFFEMPIRE:
  4223. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ´Ù¸¥ Á¦±¹°ú ÆÄƼ¸¦ ÀÌ·ê ¼ö ¾ø½À´Ï´Ù."));
  4224. return false;
  4225. case PERR_DUNGEON:
  4226. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ´øÀü ¾È¿¡¼­´Â ÆÄƼ Ãʴ븦 ÇÒ ¼ö ¾ø½À´Ï´Ù."));
  4227. return false;
  4228. case PERR_OBSERVER:
  4229. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> °üÀü ¸ğµå¿¡¼± ÆÄƼ Ãʴ븦 ÇÒ ¼ö ¾ø½À´Ï´Ù."));
  4230. return false;
  4231. case PERR_LVBOUNDARY:
  4232. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> -30 ~ +30 ·¹º§ À̳»ÀÇ »ó´ë¹æ¸¸ ÃÊ´ëÇÒ ¼ö ÀÖ½À´Ï´Ù."));
  4233. return false;
  4234. case PERR_LOWLEVEL:
  4235. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ÆÄƼ³» ÃÖ°í ·¹º§ º¸´Ù 30·¹º§ÀÌ ³·¾Æ ÃÊ´ëÇÒ ¼ö ¾ø½À´Ï´Ù."));
  4236. return false;
  4237. case PERR_HILEVEL:
  4238. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ÆÄƼ³» ÃÖÀú ·¹º§ º¸´Ù 30·¹º§ÀÌ ³ô¾Æ ÃÊ´ëÇÒ ¼ö ¾ø½À´Ï´Ù."));
  4239. return false;
  4240. case PERR_ALREADYJOIN:
  4241. return false;
  4242. case PERR_PARTYISFULL:
  4243. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ´õ ÀÌ»ó ÆÄƼ¿øÀ» ÃÊ´ëÇÒ ¼ö ¾ø½À´Ï´Ù."));
  4244. return false;
  4245. default:
  4246. sys_err("Do not process party join error(%d)", errcode);
  4247. return false;
  4248. }
  4249. TPartyJoinEventInfo* info = AllocEventInfo<TPartyJoinEventInfo>();
  4250. info->dwGuestPID = GetPlayerID();
  4251. info->dwLeaderPID = leader->GetPlayerID();
  4252. SetPartyRequestEvent(event_create(party_request_event, info, PASSES_PER_SEC(10)));
  4253. leader->ChatPacket(CHAT_TYPE_COMMAND, "PartyRequest %u", (DWORD) GetVID());
  4254. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s ´Ô¿¡°Ô ÆÄƼ°¡ÀÔ ½ÅûÀ» Çß½À´Ï´Ù."), leader->GetName());
  4255. return true;
  4256. }
  4257. void CHARACTER::DenyToParty(LPCHARACTER member)
  4258. {
  4259. sys_log(1, "DenyToParty %s member %s %p", GetName(), member->GetName(), get_pointer(member->m_pkPartyRequestEvent));
  4260. if (!member->m_pkPartyRequestEvent)
  4261. return;
  4262. TPartyJoinEventInfo * info = dynamic_cast<TPartyJoinEventInfo *>(member->m_pkPartyRequestEvent->info);
  4263. if (!info)
  4264. {
  4265. sys_err( "CHARACTER::DenyToParty> <Factor> Null pointer" );
  4266. return;
  4267. }
  4268. if (info->dwGuestPID != member->GetPlayerID())
  4269. return;
  4270. if (info->dwLeaderPID != GetPlayerID())
  4271. return;
  4272. event_cancel(&member->m_pkPartyRequestEvent);
  4273. member->ChatPacket(CHAT_TYPE_COMMAND, "PartyRequestDenied");
  4274. }
  4275. void CHARACTER::AcceptToParty(LPCHARACTER member)
  4276. {
  4277. sys_log(1, "AcceptToParty %s member %s %p", GetName(), member->GetName(), get_pointer(member->m_pkPartyRequestEvent));
  4278. if (!member->m_pkPartyRequestEvent)
  4279. return;
  4280. TPartyJoinEventInfo * info = dynamic_cast<TPartyJoinEventInfo *>(member->m_pkPartyRequestEvent->info);
  4281. if (!info)
  4282. {
  4283. sys_err( "CHARACTER::AcceptToParty> <Factor> Null pointer" );
  4284. return;
  4285. }
  4286. if (info->dwGuestPID != member->GetPlayerID())
  4287. return;
  4288. if (info->dwLeaderPID != GetPlayerID())
  4289. return;
  4290. event_cancel(&member->m_pkPartyRequestEvent);
  4291. if (!GetParty())
  4292. member->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("»ó´ë¹æÀÌ ÆÄƼ¿¡ ¼ÓÇØÀÖÁö ¾Ê½À´Ï´Ù."));
  4293. else
  4294. {
  4295. if (GetPlayerID() != GetParty()->GetLeaderPID())
  4296. return;
  4297. PartyJoinErrCode errcode = IsPartyJoinableCondition(this, member);
  4298. switch (errcode)
  4299. {
  4300. case PERR_NONE: member->PartyJoin(this); return;
  4301. case PERR_SERVER: member->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ¼­¹ö ¹®Á¦·Î ÆÄƼ °ü·Ã 󸮸¦ ÇÒ ¼ö ¾ø½À´Ï´Ù.")); break;
  4302. case PERR_DUNGEON: member->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ´øÀü ¾È¿¡¼­´Â ÆÄƼ Ãʴ븦 ÇÒ ¼ö ¾ø½À´Ï´Ù.")); break;
  4303. case PERR_OBSERVER: member->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> °üÀü ¸ğµå¿¡¼± ÆÄƼ Ãʴ븦 ÇÒ ¼ö ¾ø½À´Ï´Ù.")); break;
  4304. case PERR_LVBOUNDARY: member->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> -30 ~ +30 ·¹º§ À̳»ÀÇ »ó´ë¹æ¸¸ ÃÊ´ëÇÒ ¼ö ÀÖ½À´Ï´Ù.")); break;
  4305. case PERR_LOWLEVEL: member->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ÆÄƼ³» ÃÖ°í ·¹º§ º¸´Ù 30·¹º§ÀÌ ³·¾Æ ÃÊ´ëÇÒ ¼ö ¾ø½À´Ï´Ù.")); break;
  4306. case PERR_HILEVEL: member->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ÆÄƼ³» ÃÖÀú ·¹º§ º¸´Ù 30·¹º§ÀÌ ³ô¾Æ ÃÊ´ëÇÒ ¼ö ¾ø½À´Ï´Ù.")); break;
  4307. case PERR_ALREADYJOIN: break;
  4308. case PERR_PARTYISFULL: {
  4309. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ´õ ÀÌ»ó ÆÄƼ¿øÀ» ÃÊ´ëÇÒ ¼ö ¾ø½À´Ï´Ù."));
  4310. member->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ÆÄƼÀÇ ÀοøÁ¦ÇÑÀÌ ÃʰúÇÏ¿© ÆÄƼ¿¡ Âü°¡ÇÒ ¼ö ¾ø½À´Ï´Ù."));
  4311. break;
  4312. }
  4313. default: sys_err("Do not process party join error(%d)", errcode);
  4314. }
  4315. }
  4316. member->ChatPacket(CHAT_TYPE_COMMAND, "PartyRequestDenied");
  4317. }
  4318. EVENTFUNC(party_invite_event)
  4319. {
  4320. TPartyJoinEventInfo * pInfo = dynamic_cast<TPartyJoinEventInfo *>( event->info );
  4321. if ( pInfo == NULL )
  4322. {
  4323. sys_err( "party_invite_event> <Factor> Null pointer" );
  4324. return 0;
  4325. }
  4326. LPCHARACTER pchInviter = CHARACTER_MANAGER::instance().FindByPID(pInfo->dwLeaderPID);
  4327. if (pchInviter)
  4328. {
  4329. sys_log(1, "PartyInviteEvent %s", pchInviter->GetName());
  4330. pchInviter->PartyInviteDeny(pInfo->dwGuestPID);
  4331. }
  4332. return 0;
  4333. }
  4334. void CHARACTER::PartyInvite(LPCHARACTER pchInvitee)
  4335. {
  4336. if (GetParty() && GetParty()->GetLeaderPID() != GetPlayerID())
  4337. {
  4338. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ÆÄƼ¿øÀ» ÃÊ´ëÇÒ ¼ö ÀÖ´Â ±ÇÇÑÀÌ ¾ø½À´Ï´Ù."));
  4339. return;
  4340. }
  4341. else if (pchInvitee->IsBlockMode(BLOCK_PARTY_INVITE))
  4342. {
  4343. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> %s ´ÔÀÌ ÆÄƼ °ÅºÎ »óÅÂÀÔ´Ï´Ù."), pchInvitee->GetName());
  4344. return;
  4345. }
  4346. PartyJoinErrCode errcode = IsPartyJoinableCondition(this, pchInvitee);
  4347. switch (errcode)
  4348. {
  4349. case PERR_NONE:
  4350. break;
  4351. case PERR_SERVER:
  4352. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ¼­¹ö ¹®Á¦·Î ÆÄƼ °ü·Ã 󸮸¦ ÇÒ ¼ö ¾ø½À´Ï´Ù."));
  4353. return;
  4354. case PERR_DIFFEMPIRE:
  4355. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ´Ù¸¥ Á¦±¹°ú ÆÄƼ¸¦ ÀÌ·ê ¼ö ¾ø½À´Ï´Ù."));
  4356. return;
  4357. case PERR_DUNGEON:
  4358. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ´øÀü ¾È¿¡¼­´Â ÆÄƼ Ãʴ븦 ÇÒ ¼ö ¾ø½À´Ï´Ù."));
  4359. return;
  4360. case PERR_OBSERVER:
  4361. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> °üÀü ¸ğµå¿¡¼± ÆÄƼ Ãʴ븦 ÇÒ ¼ö ¾ø½À´Ï´Ù."));
  4362. return;
  4363. case PERR_LVBOUNDARY:
  4364. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> -30 ~ +30 ·¹º§ À̳»ÀÇ »ó´ë¹æ¸¸ ÃÊ´ëÇÒ ¼ö ÀÖ½À´Ï´Ù."));
  4365. return;
  4366. case PERR_LOWLEVEL:
  4367. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ÆÄƼ³» ÃÖ°í ·¹º§ º¸´Ù 30·¹º§ÀÌ ³·¾Æ ÃÊ´ëÇÒ ¼ö ¾ø½À´Ï´Ù."));
  4368. return;
  4369. case PERR_HILEVEL:
  4370. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ÆÄƼ³» ÃÖÀú ·¹º§ º¸´Ù 30·¹º§ÀÌ ³ô¾Æ ÃÊ´ëÇÒ ¼ö ¾ø½À´Ï´Ù."));
  4371. return;
  4372. case PERR_ALREADYJOIN:
  4373. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ÀÌ¹Ì %s´ÔÀº ÆÄƼ¿¡ ¼ÓÇØ ÀÖ½À´Ï´Ù."), pchInvitee->GetName());
  4374. return;
  4375. case PERR_PARTYISFULL:
  4376. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ´õ ÀÌ»ó ÆÄƼ¿øÀ» ÃÊ´ëÇÒ ¼ö ¾ø½À´Ï´Ù."));
  4377. return;
  4378. default:
  4379. sys_err("Do not process party join error(%d)", errcode);
  4380. return;
  4381. }
  4382. if (m_PartyInviteEventMap.end() != m_PartyInviteEventMap.find(pchInvitee->GetPlayerID()))
  4383. return;
  4384. TPartyJoinEventInfo* info = AllocEventInfo<TPartyJoinEventInfo>();
  4385. info->dwGuestPID = pchInvitee->GetPlayerID();
  4386. info->dwLeaderPID = GetPlayerID();
  4387. m_PartyInviteEventMap.insert(EventMap::value_type(pchInvitee->GetPlayerID(), event_create(party_invite_event, info, PASSES_PER_SEC(10))));
  4388. TPacketGCPartyInvite p;
  4389. p.header = HEADER_GC_PARTY_INVITE;
  4390. p.leader_vid = GetVID();
  4391. pchInvitee->GetDesc()->Packet(&p, sizeof(p));
  4392. }
  4393. void CHARACTER::PartyInviteAccept(LPCHARACTER pchInvitee)
  4394. {
  4395. EventMap::iterator itFind = m_PartyInviteEventMap.find(pchInvitee->GetPlayerID());
  4396. if (itFind == m_PartyInviteEventMap.end())
  4397. {
  4398. sys_log(1, "PartyInviteAccept from not invited character(%s)", pchInvitee->GetName());
  4399. return;
  4400. }
  4401. event_cancel(&itFind->second);
  4402. m_PartyInviteEventMap.erase(itFind);
  4403. if (GetParty() && GetParty()->GetLeaderPID() != GetPlayerID())
  4404. {
  4405. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ÆÄƼ¿øÀ» ÃÊ´ëÇÒ ¼ö ÀÖ´Â ±ÇÇÑÀÌ ¾ø½À´Ï´Ù."));
  4406. return;
  4407. }
  4408. PartyJoinErrCode errcode = IsPartyJoinableMutableCondition(this, pchInvitee);
  4409. switch (errcode)
  4410. {
  4411. case PERR_NONE:
  4412. break;
  4413. case PERR_SERVER:
  4414. pchInvitee->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ¼­¹ö ¹®Á¦·Î ÆÄƼ °ü·Ã 󸮸¦ ÇÒ ¼ö ¾ø½À´Ï´Ù."));
  4415. return;
  4416. case PERR_DUNGEON:
  4417. pchInvitee->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ´øÀü ¾È¿¡¼­´Â ÆÄƼ ÃÊ´ë¿¡ ÀÀÇÒ ¼ö ¾ø½À´Ï´Ù."));
  4418. return;
  4419. case PERR_OBSERVER:
  4420. pchInvitee->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> °üÀü ¸ğµå¿¡¼± ÆÄƼ Ãʴ븦 ÇÒ ¼ö ¾ø½À´Ï´Ù."));
  4421. return;
  4422. case PERR_LVBOUNDARY:
  4423. pchInvitee->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> -30 ~ +30 ·¹º§ À̳»ÀÇ »ó´ë¹æ¸¸ ÃÊ´ëÇÒ ¼ö ÀÖ½À´Ï´Ù."));
  4424. return;
  4425. case PERR_LOWLEVEL:
  4426. pchInvitee->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ÆÄƼ³» ÃÖ°í ·¹º§ º¸´Ù 30·¹º§ÀÌ ³·¾Æ ÃÊ´ëÇÒ ¼ö ¾ø½À´Ï´Ù."));
  4427. return;
  4428. case PERR_HILEVEL:
  4429. pchInvitee->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ÆÄƼ³» ÃÖÀú ·¹º§ º¸´Ù 30·¹º§ÀÌ ³ô¾Æ ÃÊ´ëÇÒ ¼ö ¾ø½À´Ï´Ù."));
  4430. return;
  4431. case PERR_ALREADYJOIN:
  4432. pchInvitee->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ÆÄƼ ÃÊ´ë¿¡ ÀÀÇÒ ¼ö ¾ø½À´Ï´Ù."));
  4433. return;
  4434. case PERR_PARTYISFULL:
  4435. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ´õ ÀÌ»ó ÆÄƼ¿øÀ» ÃÊ´ëÇÒ ¼ö ¾ø½À´Ï´Ù."));
  4436. pchInvitee->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> ÆÄƼÀÇ ÀοøÁ¦ÇÑÀÌ ÃʰúÇÏ¿© ÆÄƼ¿¡ Âü°¡ÇÒ ¼ö ¾ø½À´Ï´Ù."));
  4437. return;
  4438. default:
  4439. sys_err("ignore party join error(%d)", errcode);
  4440. return;
  4441. }
  4442. if (GetParty())
  4443. pchInvitee->PartyJoin(this);
  4444. else
  4445. {
  4446. LPPARTY pParty = CPartyManager::instance().CreateParty(this);
  4447. pParty->Join(pchInvitee->GetPlayerID());
  4448. pParty->Link(pchInvitee);
  4449. pParty->SendPartyInfoAllToOne(this);
  4450. }
  4451. }
  4452. void CHARACTER::PartyInviteDeny(DWORD dwPID)
  4453. {
  4454. EventMap::iterator itFind = m_PartyInviteEventMap.find(dwPID);
  4455. if (itFind == m_PartyInviteEventMap.end())
  4456. {
  4457. sys_log(1, "PartyInviteDeny to not exist event(inviter PID: %d, invitee PID: %d)", GetPlayerID(), dwPID);
  4458. return;
  4459. }
  4460. event_cancel(&itFind->second);
  4461. m_PartyInviteEventMap.erase(itFind);
  4462. LPCHARACTER pchInvitee = CHARACTER_MANAGER::instance().FindByPID(dwPID);
  4463. if (pchInvitee)
  4464. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> %s´ÔÀÌ ÆÄƼ Ãʴ븦 °ÅÀıÇϼ̽À´Ï´Ù."), pchInvitee->GetName());
  4465. }
  4466. void CHARACTER::PartyJoin(LPCHARACTER pLeader)
  4467. {
  4468. pLeader->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> %s´ÔÀÌ ÆÄƼ¿¡ Âü°¡Çϼ̽À´Ï´Ù."), GetName());
  4469. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<ÆÄƼ> %s´ÔÀÇ ÆÄƼ¿¡ Âü°¡Çϼ̽À´Ï´Ù."), pLeader->GetName());
  4470. pLeader->GetParty()->Join(GetPlayerID());
  4471. pLeader->GetParty()->Link(this);
  4472. }
  4473. CHARACTER::PartyJoinErrCode CHARACTER::IsPartyJoinableCondition(const LPCHARACTER pchLeader, const LPCHARACTER pchGuest)
  4474. {
  4475. if (pchLeader->GetEmpire() != pchGuest->GetEmpire())
  4476. return PERR_DIFFEMPIRE;
  4477. return IsPartyJoinableMutableCondition(pchLeader, pchGuest);
  4478. }
  4479. static bool __party_can_join_by_level(LPCHARACTER leader, LPCHARACTER quest)
  4480. {
  4481. int level_limit = 30;
  4482. return (abs(leader->GetLevel() - quest->GetLevel()) <= level_limit);
  4483. }
  4484. CHARACTER::PartyJoinErrCode CHARACTER::IsPartyJoinableMutableCondition(const LPCHARACTER pchLeader, const LPCHARACTER pchGuest)
  4485. {
  4486. if (!CPartyManager::instance().IsEnablePCParty())
  4487. return PERR_SERVER;
  4488. else if (pchLeader->GetDungeon())
  4489. return PERR_DUNGEON;
  4490. else if (pchGuest->IsObserverMode())
  4491. return PERR_OBSERVER;
  4492. else if (false == __party_can_join_by_level(pchLeader, pchGuest))
  4493. return PERR_LVBOUNDARY;
  4494. else if (pchGuest->GetParty())
  4495. return PERR_ALREADYJOIN;
  4496. else if (pchLeader->GetParty())
  4497. {
  4498. if (pchLeader->GetParty()->GetMemberCount() == PARTY_MAX_MEMBER)
  4499. return PERR_PARTYISFULL;
  4500. }
  4501. return PERR_NONE;
  4502. }
  4503. // END_OF_PARTY_JOIN_BUG_FIX
  4504. void CHARACTER::SetDungeon(LPDUNGEON pkDungeon)
  4505. {
  4506. if (pkDungeon && m_pkDungeon)
  4507. sys_err("%s is trying to reassigning dungeon (current %p, new party %p)", GetName(), get_pointer(m_pkDungeon), get_pointer(pkDungeon));
  4508. if (m_pkDungeon == pkDungeon) {
  4509. return;
  4510. }
  4511. if (m_pkDungeon)
  4512. {
  4513. if (IsPC())
  4514. {
  4515. if (GetParty())
  4516. m_pkDungeon->DecPartyMember(GetParty(), this);
  4517. else
  4518. m_pkDungeon->DecMember(this);
  4519. }
  4520. else if (IsMonster() || IsStone())
  4521. {
  4522. m_pkDungeon->DecMonster();
  4523. }
  4524. }
  4525. m_pkDungeon = pkDungeon;
  4526. if (pkDungeon)
  4527. {
  4528. sys_log(0, "%s DUNGEON set to %p, PARTY is %p", GetName(), get_pointer(pkDungeon), get_pointer(m_pkParty));
  4529. if (IsPC())
  4530. {
  4531. if (GetParty())
  4532. m_pkDungeon->IncPartyMember(GetParty(), this);
  4533. else
  4534. m_pkDungeon->IncMember(this);
  4535. }
  4536. else if (IsMonster() || IsStone())
  4537. {
  4538. m_pkDungeon->IncMonster();
  4539. }
  4540. }
  4541. }
  4542. void CHARACTER::SetWarMap(CWarMap * pWarMap)
  4543. {
  4544. if (m_pWarMap)
  4545. m_pWarMap->DecMember(this);
  4546. m_pWarMap = pWarMap;
  4547. if (m_pWarMap)
  4548. m_pWarMap->IncMember(this);
  4549. }
  4550. void CHARACTER::SetWeddingMap(marriage::WeddingMap* pMap)
  4551. {
  4552. if (m_pWeddingMap)
  4553. m_pWeddingMap->DecMember(this);
  4554. m_pWeddingMap = pMap;
  4555. if (m_pWeddingMap)
  4556. m_pWeddingMap->IncMember(this);
  4557. }
  4558. void CHARACTER::SetRegen(LPREGEN pkRegen)
  4559. {
  4560. m_pkRegen = pkRegen;
  4561. if (pkRegen != NULL) {
  4562. regen_id_ = pkRegen->id;
  4563. }
  4564. m_fRegenAngle = GetRotation();
  4565. m_posRegen = GetXYZ();
  4566. }
  4567. bool CHARACTER::OnIdle()
  4568. {
  4569. return false;
  4570. }
  4571. void CHARACTER::OnMove(bool bIsAttack)
  4572. {
  4573. m_dwLastMoveTime = get_dword_time();
  4574. if (bIsAttack)
  4575. {
  4576. m_dwLastAttackTime = m_dwLastMoveTime;
  4577. if (IsAffectFlag(AFF_REVIVE_INVISIBLE))
  4578. RemoveAffect(AFFECT_REVIVE_INVISIBLE);
  4579. if (IsAffectFlag(AFF_EUNHYUNG))
  4580. {
  4581. RemoveAffect(SKILL_EUNHYUNG);
  4582. SetAffectedEunhyung();
  4583. }
  4584. else
  4585. {
  4586. ClearAffectedEunhyung();
  4587. }
  4588. /*if (IsAffectFlag(AFF_JEONSIN))
  4589. RemoveAffect(SKILL_JEONSINBANGEO);*/
  4590. }
  4591. /*if (IsAffectFlag(AFF_GUNGON))
  4592. RemoveAffect(SKILL_GUNGON);*/
  4593. // MINING
  4594. mining_cancel();
  4595. // END_OF_MINING
  4596. }
  4597. void CHARACTER::OnClick(LPCHARACTER pkChrCauser)
  4598. {
  4599. if (!pkChrCauser)
  4600. {
  4601. sys_err("OnClick %s by NULL", GetName());
  4602. return;
  4603. }
  4604. DWORD vid = GetVID();
  4605. sys_log(0, "OnClick %s[vnum %d ServerUniqueID %d, pid %d] by %s", GetName(), GetRaceNum(), vid, GetPlayerID(), pkChrCauser->GetName());
  4606. {
  4607. if (pkChrCauser->GetMyShop() && pkChrCauser != this)
  4608. {
  4609. sys_err("OnClick Fail (%s->%s) - pc has shop", pkChrCauser->GetName(), GetName());
  4610. return;
  4611. }
  4612. }
  4613. {
  4614. if (pkChrCauser->GetExchange())
  4615. {
  4616. sys_err("OnClick Fail (%s->%s) - pc is exchanging", pkChrCauser->GetName(), GetName());
  4617. return;
  4618. }
  4619. }
  4620. if (IsPC())
  4621. {
  4622. if (!CTargetManager::instance().GetTargetInfo(pkChrCauser->GetPlayerID(), TARGET_TYPE_VID, GetVID()))
  4623. {
  4624. if (GetMyShop())
  4625. {
  4626. if (pkChrCauser->IsDead() == true) return;
  4627. //PREVENT_TRADE_WINDOW
  4628. if (pkChrCauser == this)
  4629. {
  4630. if ((GetExchange() || IsOpenSafebox() || GetShopOwner()) || IsCubeOpen() || GetOfflineShopOwner())
  4631. {
  4632. pkChrCauser->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("´Ù¸¥ °Å·¡Áß(â°í,±³È¯,»óÁ¡)¿¡´Â °³ÀλóÁ¡À» »ç¿ëÇÒ ¼ö ¾ø½À´Ï´Ù."));
  4633. return;
  4634. }
  4635. }
  4636. else
  4637. {
  4638. if ((pkChrCauser->GetExchange() || pkChrCauser->IsOpenSafebox() || pkChrCauser->GetMyShop() || pkChrCauser->GetShopOwner()) || pkChrCauser->IsCubeOpen() )
  4639. {
  4640. pkChrCauser->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("´Ù¸¥ °Å·¡Áß(â°í,±³È¯,»óÁ¡)¿¡´Â °³ÀλóÁ¡À» »ç¿ëÇÒ ¼ö ¾ø½À´Ï´Ù."));
  4641. return;
  4642. }
  4643. //if ((GetExchange() || IsOpenSafebox() || GetShopOwner()))
  4644. if ((GetExchange() || IsOpenSafebox() || IsCubeOpen()))
  4645. {
  4646. pkChrCauser->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("»ó´ë¹æÀÌ ´Ù¸¥ °Å·¡¸¦ Çϰí ÀÖ´Â ÁßÀÔ´Ï´Ù."));
  4647. return;
  4648. }
  4649. }
  4650. //END_PREVENT_TRADE_WINDOW
  4651. if (pkChrCauser->GetShop())
  4652. {
  4653. pkChrCauser->GetShop()->RemoveGuest(pkChrCauser);
  4654. pkChrCauser->SetShop(NULL);
  4655. }
  4656. GetMyShop()->AddGuest(pkChrCauser, GetVID(), false);
  4657. pkChrCauser->SetShopOwner(this);
  4658. return;
  4659. }
  4660. if (test_server)
  4661. sys_err("%s.OnClickFailure(%s) - target is PC", pkChrCauser->GetName(), GetName());
  4662. return;
  4663. }
  4664. }
  4665. // Offline Shop
  4666. if (IsOfflineShopNPC() && GetOfflineShop())
  4667. {
  4668. pkChrCauser->SetOfflineShopOwner(this);
  4669. GetOfflineShop()->AddGuest(pkChrCauser, this);
  4670. return;
  4671. }
  4672. if (g_bChinaIntoxicationCheck)
  4673. {
  4674. if (pkChrCauser->IsOverTime(OT_3HOUR))
  4675. {
  4676. sys_log(0, "Teen OverTime : name = %s, hour = %d)", pkChrCauser->GetName(), 3);
  4677. return;
  4678. }
  4679. else if (pkChrCauser->IsOverTime(OT_5HOUR))
  4680. {
  4681. sys_log(0, "Teen OverTime : name = %s, hour = %d)", pkChrCauser->GetName(), 5);
  4682. return;
  4683. }
  4684. }
  4685. pkChrCauser->SetQuestNPCID(GetVID());
  4686. if (quest::CQuestManager::instance().Click(pkChrCauser->GetPlayerID(), this))
  4687. {
  4688. return;
  4689. }
  4690. if (!IsPC())
  4691. {
  4692. if (!m_triggerOnClick.pFunc)
  4693. {
  4694. //sys_err("%s.OnClickFailure(%s) : triggerOnClick.pFunc is EMPTY(pid=%d)",
  4695. // pkChrCauser->GetName(),
  4696. // GetName(),
  4697. // pkChrCauser->GetPlayerID());
  4698. return;
  4699. }
  4700. m_triggerOnClick.pFunc(this, pkChrCauser);
  4701. }
  4702. }
  4703. BYTE CHARACTER::GetGMLevel() const
  4704. {
  4705. if (test_server)
  4706. return GM_IMPLEMENTOR;
  4707. return m_pointsInstant.gm_level;
  4708. }
  4709. void CHARACTER::SetGMLevel()
  4710. {
  4711. if (GetDesc())
  4712. {
  4713. m_pointsInstant.gm_level = gm_get_level(GetName(), GetDesc()->GetHostName(), GetDesc()->GetAccountTable().login);
  4714. }
  4715. else
  4716. {
  4717. m_pointsInstant.gm_level = GM_PLAYER;
  4718. }
  4719. }
  4720. BOOL CHARACTER::IsGM() const
  4721. {
  4722. if (m_pointsInstant.gm_level != GM_PLAYER)
  4723. return true;
  4724. if (test_server)
  4725. return true;
  4726. return false;
  4727. }
  4728. void CHARACTER::SetStone(LPCHARACTER pkChrStone)
  4729. {
  4730. m_pkChrStone = pkChrStone;
  4731. if (m_pkChrStone)
  4732. {
  4733. if (pkChrStone->m_set_pkChrSpawnedBy.find(this) == pkChrStone->m_set_pkChrSpawnedBy.end())
  4734. pkChrStone->m_set_pkChrSpawnedBy.insert(this);
  4735. }
  4736. }
  4737. struct FuncDeadSpawnedByStone
  4738. {
  4739. void operator () (LPCHARACTER ch)
  4740. {
  4741. ch->Dead(NULL);
  4742. ch->SetStone(NULL);
  4743. }
  4744. };
  4745. void CHARACTER::ClearStone()
  4746. {
  4747. if (!m_set_pkChrSpawnedBy.empty())
  4748. {
  4749. FuncDeadSpawnedByStone f;
  4750. std::for_each(m_set_pkChrSpawnedBy.begin(), m_set_pkChrSpawnedBy.end(), f);
  4751. m_set_pkChrSpawnedBy.clear();
  4752. }
  4753. if (!m_pkChrStone)
  4754. return;
  4755. m_pkChrStone->m_set_pkChrSpawnedBy.erase(this);
  4756. m_pkChrStone = NULL;
  4757. }
  4758. void CHARACTER::ClearTarget()
  4759. {
  4760. if (m_pkChrTarget)
  4761. {
  4762. m_pkChrTarget->m_set_pkChrTargetedBy.erase(this);
  4763. m_pkChrTarget = NULL;
  4764. }
  4765. TPacketGCTarget p;
  4766. p.header = HEADER_GC_TARGET;
  4767. p.dwVID = 0;
  4768. p.bHPPercent = 0;
  4769. CHARACTER_SET::iterator it = m_set_pkChrTargetedBy.begin();
  4770. while (it != m_set_pkChrTargetedBy.end())
  4771. {
  4772. LPCHARACTER pkChr = *(it++);
  4773. pkChr->m_pkChrTarget = NULL;
  4774. if (!pkChr->GetDesc())
  4775. {
  4776. sys_err("%s %p does not have desc", pkChr->GetName(), get_pointer(pkChr));
  4777. abort();
  4778. }
  4779. pkChr->GetDesc()->Packet(&p, sizeof(TPacketGCTarget));
  4780. }
  4781. m_set_pkChrTargetedBy.clear();
  4782. }
  4783. void CHARACTER::SetTarget(LPCHARACTER pkChrTarget)
  4784. {
  4785. if (m_pkChrTarget == pkChrTarget)
  4786. return;
  4787. // CASTLE
  4788. if (IS_CASTLE_MAP(GetMapIndex()) && !IsGM())
  4789. return;
  4790. // CASTLE
  4791. if (m_pkChrTarget)
  4792. m_pkChrTarget->m_set_pkChrTargetedBy.erase(this);
  4793. m_pkChrTarget = pkChrTarget;
  4794. TPacketGCTarget p;
  4795. p.header = HEADER_GC_TARGET;
  4796. if (m_pkChrTarget)
  4797. {
  4798. m_pkChrTarget->m_set_pkChrTargetedBy.insert(this);
  4799. p.dwVID = m_pkChrTarget->GetVID();
  4800. if ((m_pkChrTarget->IsPC() && !m_pkChrTarget->IsPolymorphed()) || (m_pkChrTarget->GetMaxHP() <= 0))
  4801. p.bHPPercent = 0;
  4802. else
  4803. {
  4804. if (m_pkChrTarget->GetRaceNum() == 20101 ||
  4805. m_pkChrTarget->GetRaceNum() == 20102 ||
  4806. m_pkChrTarget->GetRaceNum() == 20103 ||
  4807. m_pkChrTarget->GetRaceNum() == 20104 ||
  4808. m_pkChrTarget->GetRaceNum() == 20105 ||
  4809. m_pkChrTarget->GetRaceNum() == 20106 ||
  4810. m_pkChrTarget->GetRaceNum() == 20107 ||
  4811. m_pkChrTarget->GetRaceNum() == 20108 ||
  4812. m_pkChrTarget->GetRaceNum() == 20109)
  4813. {
  4814. LPCHARACTER owner = m_pkChrTarget->GetVictim();
  4815. if (owner)
  4816. {
  4817. int iHorseHealth = owner->GetHorseHealth();
  4818. int iHorseMaxHealth = owner->GetHorseMaxHealth();
  4819. if (iHorseMaxHealth)
  4820. p.bHPPercent = MINMAX(0, iHorseHealth * 100 / iHorseMaxHealth, 100);
  4821. else
  4822. p.bHPPercent = 100;
  4823. }
  4824. else
  4825. p.bHPPercent = 100;
  4826. }
  4827. else
  4828. {
  4829. if (m_pkChrTarget->GetMaxHP() <= 0)
  4830. p.bHPPercent = 0;
  4831. else
  4832. p.bHPPercent = MINMAX(0, (m_pkChrTarget->GetHP() * 100) / m_pkChrTarget->GetMaxHP(), 100);
  4833. }
  4834. }
  4835. }
  4836. else
  4837. {
  4838. p.dwVID = 0;
  4839. p.bHPPercent = 0;
  4840. }
  4841. GetDesc()->Packet(&p, sizeof(TPacketGCTarget));
  4842. }
  4843. void CHARACTER::BroadcastTargetPacket()
  4844. {
  4845. if (m_set_pkChrTargetedBy.empty())
  4846. return;
  4847. TPacketGCTarget p;
  4848. p.header = HEADER_GC_TARGET;
  4849. p.dwVID = GetVID();
  4850. if (IsPC())
  4851. p.bHPPercent = 0;
  4852. else if (GetMaxHP() <= 0)
  4853. p.bHPPercent = 0;
  4854. else
  4855. p.bHPPercent = MINMAX(0, (GetHP() * 100) / GetMaxHP(), 100);
  4856. CHARACTER_SET::iterator it = m_set_pkChrTargetedBy.begin();
  4857. while (it != m_set_pkChrTargetedBy.end())
  4858. {
  4859. LPCHARACTER pkChr = *it++;
  4860. if (!pkChr->GetDesc())
  4861. {
  4862. sys_err("%s %p does not have desc", pkChr->GetName(), get_pointer(pkChr));
  4863. abort();
  4864. }
  4865. pkChr->GetDesc()->Packet(&p, sizeof(TPacketGCTarget));
  4866. }
  4867. }
  4868. void CHARACTER::CheckTarget()
  4869. {
  4870. if (!m_pkChrTarget)
  4871. return;
  4872. if (DISTANCE_APPROX(GetX() - m_pkChrTarget->GetX(), GetY() - m_pkChrTarget->GetY()) >= 4800)
  4873. SetTarget(NULL);
  4874. }
  4875. void CHARACTER::SetWarpLocation(long lMapIndex, long x, long y)
  4876. {
  4877. m_posWarp.x = x * 100;
  4878. m_posWarp.y = y * 100;
  4879. m_lWarpMapIndex = lMapIndex;
  4880. }
  4881. void CHARACTER::SaveExitLocation()
  4882. {
  4883. m_posExit = GetXYZ();
  4884. m_lExitMapIndex = GetMapIndex();
  4885. }
  4886. void CHARACTER::ExitToSavedLocation()
  4887. {
  4888. sys_log (0, "ExitToSavedLocation");
  4889. WarpSet(m_posWarp.x, m_posWarp.y, m_lWarpMapIndex);
  4890. m_posExit.x = m_posExit.y = m_posExit.z = 0;
  4891. m_lExitMapIndex = 0;
  4892. }
  4893. bool CHARACTER::WarpSet(long x, long y, long lPrivateMapIndex)
  4894. {
  4895. if (!IsPC())
  4896. return false;
  4897. long lAddr;
  4898. long lMapIndex;
  4899. WORD wPort;
  4900. if (!CMapLocation::instance().Get(x, y, lMapIndex, lAddr, wPort))
  4901. {
  4902. sys_err("cannot find map location index %d x %d y %d name %s", lMapIndex, x, y, GetName());
  4903. return false;
  4904. }
  4905. {
  4906. long lCurAddr;
  4907. long lCurMapIndex = 0;
  4908. WORD wCurPort;
  4909. CMapLocation::instance().Get(GetX(), GetY(), lCurMapIndex, lCurAddr, wCurPort);
  4910. if( lCurMapIndex != lMapIndex )
  4911. {
  4912. const TMapRegion * rMapRgn = SECTREE_MANAGER::instance().GetMapRegion(lMapIndex);
  4913. {
  4914. DESC_MANAGER::instance().SendClientPackageSDBToLoadMap( GetDesc(), rMapRgn->strMapName.c_str() );
  4915. }
  4916. }
  4917. }
  4918. if (lPrivateMapIndex >= 10000)
  4919. {
  4920. if (lPrivateMapIndex / 10000 != lMapIndex)
  4921. {
  4922. sys_err("Invalid map inedx %d, must be child of %d", lPrivateMapIndex, lMapIndex);
  4923. return false;
  4924. }
  4925. lMapIndex = lPrivateMapIndex;
  4926. }
  4927. Stop();
  4928. Save();
  4929. if (GetSectree())
  4930. {
  4931. GetSectree()->RemoveEntity(this);
  4932. ViewCleanup();
  4933. EncodeRemovePacket(this);
  4934. }
  4935. m_lWarpMapIndex = lMapIndex;
  4936. m_posWarp.x = x;
  4937. m_posWarp.y = y;
  4938. sys_log(0, "WarpSet %s %d %d current map %d target map %d", GetName(), x, y, GetMapIndex(), lMapIndex);
  4939. TPacketGCWarp p;
  4940. p.bHeader = HEADER_GC_WARP;
  4941. p.lX = x;
  4942. p.lY = y;
  4943. p.lAddr = lAddr;
  4944. p.wPort = wPort;
  4945. GetDesc()->Packet(&p, sizeof(TPacketGCWarp));
  4946. char buf[256];
  4947. snprintf(buf, sizeof(buf), "%s MapIdx %ld DestMapIdx%ld DestX%ld DestY%ld Empire%d", GetName(), GetMapIndex(), lPrivateMapIndex, x, y, GetEmpire());
  4948. LogManager::instance().CharLog(this, 0, "WARP", buf);
  4949. return true;
  4950. }
  4951. #define ENABLE_GOHOME_IFNOMAP
  4952. void CHARACTER::WarpEnd()
  4953. {
  4954. if (test_server)
  4955. sys_log(0, "WarpEnd %s", GetName());
  4956. if (m_posWarp.x == 0 && m_posWarp.y == 0)
  4957. return;
  4958. int index = m_lWarpMapIndex;
  4959. if (index > 10000)
  4960. index /= 10000;
  4961. if (!map_allow_find(index))
  4962. {
  4963. sys_err("location %d %d not allowed to login this server", m_posWarp.x, m_posWarp.y);
  4964. #ifdef ENABLE_GOHOME_IFNOMAP
  4965. GoHome();
  4966. #else
  4967. GetDesc()->SetPhase(PHASE_CLOSE);
  4968. #endif
  4969. return;
  4970. }
  4971. sys_log(0, "WarpEnd %s %d %u %u", GetName(), m_lWarpMapIndex, m_posWarp.x, m_posWarp.y);
  4972. Show(m_lWarpMapIndex, m_posWarp.x, m_posWarp.y, 0);
  4973. Stop();
  4974. m_lWarpMapIndex = 0;
  4975. m_posWarp.x = m_posWarp.y = m_posWarp.z = 0;
  4976. {
  4977. // P2P Login
  4978. TPacketGGLogin p;
  4979. p.bHeader = HEADER_GG_LOGIN;
  4980. strlcpy(p.szName, GetName(), sizeof(p.szName));
  4981. p.dwPID = GetPlayerID();
  4982. p.bEmpire = GetEmpire();
  4983. p.lMapIndex = SECTREE_MANAGER::instance().GetMapIndex(GetX(), GetY());
  4984. p.bChannel = g_bChannel;
  4985. P2P_MANAGER::instance().Send(&p, sizeof(TPacketGGLogin));
  4986. }
  4987. }
  4988. bool CHARACTER::Return()
  4989. {
  4990. if (!IsNPC())
  4991. return false;
  4992. int x, y;
  4993. /*
  4994. float fDist = DISTANCE_SQRT(m_pkMobData->m_posLastAttacked.x - GetX(), m_pkMobData->m_posLastAttacked.y - GetY());
  4995. float fx, fy;
  4996. GetDeltaByDegree(GetRotation(), fDist, &fx, &fy);
  4997. x = GetX() + (int) fx;
  4998. y = GetY() + (int) fy;
  4999. */
  5000. SetVictim(NULL);
  5001. x = m_pkMobInst->m_posLastAttacked.x;
  5002. y = m_pkMobInst->m_posLastAttacked.y;
  5003. SetRotationToXY(x, y);
  5004. if (!Goto(x, y))
  5005. return false;
  5006. SendMovePacket(FUNC_WAIT, 0, 0, 0, 0);
  5007. if (test_server)
  5008. sys_log(0, "%s %p Æ÷±âÇÏ°í µ¹¾Æ°¡ÀÚ! %d %d", GetName(), this, x, y);
  5009. if (GetParty())
  5010. GetParty()->SendMessage(this, PM_RETURN, x, y);
  5011. return true;
  5012. }
  5013. bool CHARACTER::Follow(LPCHARACTER pkChr, float fMinDistance)
  5014. {
  5015. if (IsPC())
  5016. {
  5017. sys_err("CHARACTER::Follow : PC cannot use this method", GetName());
  5018. return false;
  5019. }
  5020. // TRENT_MONSTER
  5021. if (IS_SET(m_pointsInstant.dwAIFlag, AIFLAG_NOMOVE))
  5022. {
  5023. if (pkChr->IsPC())
  5024. {
  5025. if (!GetParty() || !GetParty()->GetLeader() || GetParty()->GetLeader() == this)
  5026. {
  5027. if (get_dword_time() - m_pkMobInst->m_dwLastAttackedTime >= 15000)
  5028. {
  5029. if (m_pkMobData->m_table.wAttackRange < DISTANCE_APPROX(pkChr->GetX() - GetX(), pkChr->GetY() - GetY()))
  5030. if (Return())
  5031. return true;
  5032. }
  5033. }
  5034. }
  5035. return false;
  5036. }
  5037. // END_OF_TRENT_MONSTER
  5038. long x = pkChr->GetX();
  5039. long y = pkChr->GetY();
  5040. if (pkChr->IsPC())
  5041. {
  5042. if (!GetParty() || !GetParty()->GetLeader() || GetParty()->GetLeader() == this)
  5043. {
  5044. if (get_dword_time() - m_pkMobInst->m_dwLastAttackedTime >= 15000)
  5045. {
  5046. if (5000 < DISTANCE_APPROX(m_pkMobInst->m_posLastAttacked.x - GetX(), m_pkMobInst->m_posLastAttacked.y - GetY()))
  5047. if (Return())
  5048. return true;
  5049. }
  5050. }
  5051. }
  5052. if (IsGuardNPC())
  5053. {
  5054. if (5000 < DISTANCE_APPROX(m_pkMobInst->m_posLastAttacked.x - GetX(), m_pkMobInst->m_posLastAttacked.y - GetY()))
  5055. if (Return())
  5056. return true;
  5057. }
  5058. if (pkChr->IsState(pkChr->m_stateMove) &&
  5059. GetMobBattleType() != BATTLE_TYPE_RANGE &&
  5060. GetMobBattleType() != BATTLE_TYPE_MAGIC &&
  5061. false == IsPet())
  5062. {
  5063. float rot = pkChr->GetRotation();
  5064. float rot_delta = GetDegreeDelta(rot, GetDegreeFromPositionXY(GetX(), GetY(), pkChr->GetX(), pkChr->GetY()));
  5065. float yourSpeed = pkChr->GetMoveSpeed();
  5066. float mySpeed = GetMoveSpeed();
  5067. float fDist = DISTANCE_SQRT(x - GetX(), y - GetY());
  5068. float fFollowSpeed = mySpeed - yourSpeed * cos(rot_delta * M_PI / 180);
  5069. if (fFollowSpeed >= 0.1f)
  5070. {
  5071. float fMeetTime = fDist / fFollowSpeed;
  5072. float fYourMoveEstimateX, fYourMoveEstimateY;
  5073. if( fMeetTime * yourSpeed <= 100000.0f )
  5074. {
  5075. GetDeltaByDegree(pkChr->GetRotation(), fMeetTime * yourSpeed, &fYourMoveEstimateX, &fYourMoveEstimateY);
  5076. x += (long) fYourMoveEstimateX;
  5077. y += (long) fYourMoveEstimateY;
  5078. float fDistNew = sqrt(((double)x - GetX())*(x-GetX())+((double)y - GetY())*(y-GetY()));
  5079. if (fDist < fDistNew)
  5080. {
  5081. x = (long)(GetX() + (x - GetX()) * fDist / fDistNew);
  5082. y = (long)(GetY() + (y - GetY()) * fDist / fDistNew);
  5083. }
  5084. }
  5085. }
  5086. }
  5087. SetRotationToXY(x, y);
  5088. float fDist = DISTANCE_SQRT(x - GetX(), y - GetY());
  5089. if (fDist <= fMinDistance)
  5090. return false;
  5091. float fx, fy;
  5092. if (IsChangeAttackPosition(pkChr) && GetMobRank() < MOB_RANK_BOSS)
  5093. {
  5094. SetChangeAttackPositionTime();
  5095. int retry = 16;
  5096. int dx, dy;
  5097. int rot = (int) GetDegreeFromPositionXY(x, y, GetX(), GetY());
  5098. while (--retry)
  5099. {
  5100. if (fDist < 500.0f)
  5101. GetDeltaByDegree((rot + number(-90, 90) + number(-90, 90)) % 360, fMinDistance, &fx, &fy);
  5102. else
  5103. GetDeltaByDegree(number(0, 359), fMinDistance, &fx, &fy);
  5104. dx = x + (int) fx;
  5105. dy = y + (int) fy;
  5106. LPSECTREE tree = SECTREE_MANAGER::instance().Get(GetMapIndex(), dx, dy);
  5107. if (NULL == tree)
  5108. break;
  5109. if (0 == (tree->GetAttribute(dx, dy) & (ATTR_BLOCK | ATTR_OBJECT)))
  5110. break;
  5111. }
  5112. //sys_log(0, "±Ùó ¾îµò°¡·Î À̵¿ %s retry %d", GetName(), retry);
  5113. if (!Goto(dx, dy))
  5114. return false;
  5115. }
  5116. else
  5117. {
  5118. // Á÷¼± µû¶ó°¡±â
  5119. float fDistToGo = fDist - fMinDistance;
  5120. GetDeltaByDegree(GetRotation(), fDistToGo, &fx, &fy);
  5121. //sys_log(0, "Á÷¼±À¸·Î À̵¿ %s", GetName());
  5122. if (!Goto(GetX() + (int) fx, GetY() + (int) fy))
  5123. return false;
  5124. }
  5125. SendMovePacket(FUNC_WAIT, 0, 0, 0, 0);
  5126. //MonsterLog("ÂѾư¡±â; %s", pkChr->GetName());
  5127. return true;
  5128. }
  5129. float CHARACTER::GetDistanceFromSafeboxOpen() const
  5130. {
  5131. return DISTANCE_APPROX(GetX() - m_posSafeboxOpen.x, GetY() - m_posSafeboxOpen.y);
  5132. }
  5133. void CHARACTER::SetSafeboxOpenPosition()
  5134. {
  5135. m_posSafeboxOpen = GetXYZ();
  5136. }
  5137. CSafebox * CHARACTER::GetSafebox() const
  5138. {
  5139. return m_pkSafebox;
  5140. }
  5141. void CHARACTER::ReqSafeboxLoad(const char* pszPassword)
  5142. {
  5143. if (!*pszPassword || strlen(pszPassword) > SAFEBOX_PASSWORD_MAX_LEN)
  5144. {
  5145. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<â°í> À߸øµÈ ¾ÏÈ£¸¦ ÀÔ·ÂÇϼ̽À´Ï´Ù."));
  5146. return;
  5147. }
  5148. else if (m_pkSafebox)
  5149. {
  5150. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<â°í> â°í°¡ ÀÌ¹Ì ¿­·ÁÀÖ½À´Ï´Ù."));
  5151. return;
  5152. }
  5153. int iPulse = thecore_pulse();
  5154. if (iPulse - GetSafeboxLoadTime() < PASSES_PER_SEC(10))
  5155. {
  5156. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<â°í> â°í¸¦ ´İÀºÁö 10ÃÊ ¾È¿¡´Â ¿­ ¼ö ¾ø½À´Ï´Ù."));
  5157. return;
  5158. }
  5159. else if (GetDistanceFromSafeboxOpen() > 1000)
  5160. {
  5161. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<â°í> °Å¸®°¡ ¸Ö¾î¼­ â°í¸¦ ¿­ ¼ö ¾ø½À´Ï´Ù."));
  5162. return;
  5163. }
  5164. else if (m_bOpeningSafebox)
  5165. {
  5166. sys_log(0, "Overlapped safebox load request from %s", GetName());
  5167. return;
  5168. }
  5169. SetSafeboxLoadTime();
  5170. m_bOpeningSafebox = true;
  5171. TSafeboxLoadPacket p;
  5172. p.dwID = GetDesc()->GetAccountTable().id;
  5173. strlcpy(p.szLogin, GetDesc()->GetAccountTable().login, sizeof(p.szLogin));
  5174. strlcpy(p.szPassword, pszPassword, sizeof(p.szPassword));
  5175. db_clientdesc->DBPacket(HEADER_GD_SAFEBOX_LOAD, GetDesc()->GetHandle(), &p, sizeof(p));
  5176. }
  5177. void CHARACTER::LoadSafebox(int iSize, DWORD dwGold, int iItemCount, TPlayerItem * pItems)
  5178. {
  5179. bool bLoaded = false;
  5180. //PREVENT_TRADE_WINDOW
  5181. SetOpenSafebox(true);
  5182. //END_PREVENT_TRADE_WINDOW
  5183. if (m_pkSafebox)
  5184. bLoaded = true;
  5185. if (!m_pkSafebox)
  5186. m_pkSafebox = M2_NEW CSafebox(this, iSize, dwGold);
  5187. else
  5188. m_pkSafebox->ChangeSize(iSize);
  5189. m_iSafeboxSize = iSize;
  5190. TPacketCGSafeboxSize p;
  5191. p.bHeader = HEADER_GC_SAFEBOX_SIZE;
  5192. p.bSize = iSize;
  5193. GetDesc()->Packet(&p, sizeof(TPacketCGSafeboxSize));
  5194. if (!bLoaded)
  5195. {
  5196. for (int i = 0; i < iItemCount; ++i, ++pItems)
  5197. {
  5198. if (!m_pkSafebox->IsValidPosition(pItems->pos))
  5199. continue;
  5200. #ifdef __SOULBINDING_SYSTEM__
  5201. LPITEM item = ITEM_MANAGER::instance().CreateItem(pItems->vnum, pItems->count, pItems->id, false, -1, false, pItems->bind);
  5202. #else
  5203. LPITEM item = ITEM_MANAGER::instance().CreateItem(pItems->vnum, pItems->count, pItems->id);
  5204. #endif
  5205. if (!item)
  5206. {
  5207. sys_err("cannot create item vnum %d id %u (name: %s)", pItems->vnum, pItems->id, GetName());
  5208. continue;
  5209. }
  5210. item->SetSkipSave(true);
  5211. item->SetSockets(pItems->alSockets);
  5212. item->SetAttributes(pItems->aAttr);
  5213. #ifdef __CHANGELOOK_SYSTEM__
  5214. item->SetTransmutation(pItems->transmutation);
  5215. #endif
  5216. if (!m_pkSafebox->Add(pItems->pos, item))
  5217. {
  5218. M2_DESTROY_ITEM(item);
  5219. }
  5220. else
  5221. item->SetSkipSave(false);
  5222. }
  5223. }
  5224. }
  5225. void CHARACTER::ChangeSafeboxSize(BYTE bSize)
  5226. {
  5227. //if (!m_pkSafebox)
  5228. //return;
  5229. TPacketCGSafeboxSize p;
  5230. p.bHeader = HEADER_GC_SAFEBOX_SIZE;
  5231. p.bSize = bSize;
  5232. GetDesc()->Packet(&p, sizeof(TPacketCGSafeboxSize));
  5233. if (m_pkSafebox)
  5234. m_pkSafebox->ChangeSize(bSize);
  5235. m_iSafeboxSize = bSize;
  5236. }
  5237. void CHARACTER::CloseSafebox()
  5238. {
  5239. if (!m_pkSafebox)
  5240. return;
  5241. //PREVENT_TRADE_WINDOW
  5242. SetOpenSafebox(false);
  5243. //END_PREVENT_TRADE_WINDOW
  5244. m_pkSafebox->Save();
  5245. M2_DELETE(m_pkSafebox);
  5246. m_pkSafebox = NULL;
  5247. ChatPacket(CHAT_TYPE_COMMAND, "CloseSafebox");
  5248. SetSafeboxLoadTime();
  5249. m_bOpeningSafebox = false;
  5250. Save();
  5251. }
  5252. CSafebox * CHARACTER::GetMall() const
  5253. {
  5254. return m_pkMall;
  5255. }
  5256. void CHARACTER::LoadMall(int iItemCount, TPlayerItem * pItems)
  5257. {
  5258. bool bLoaded = false;
  5259. if (m_pkMall)
  5260. bLoaded = true;
  5261. if (!m_pkMall)
  5262. m_pkMall = M2_NEW CSafebox(this, 3 * SAFEBOX_PAGE_SIZE, 0);
  5263. else
  5264. m_pkMall->ChangeSize(3 * SAFEBOX_PAGE_SIZE);
  5265. m_pkMall->SetWindowMode(MALL);
  5266. TPacketCGSafeboxSize p;
  5267. p.bHeader = HEADER_GC_MALL_OPEN;
  5268. p.bSize = 3 * SAFEBOX_PAGE_SIZE;
  5269. GetDesc()->Packet(&p, sizeof(TPacketCGSafeboxSize));
  5270. if (!bLoaded)
  5271. {
  5272. for (int i = 0; i < iItemCount; ++i, ++pItems)
  5273. {
  5274. if (!m_pkMall->IsValidPosition(pItems->pos))
  5275. continue;
  5276. #ifdef __SOULBINDING_SYSTEM__
  5277. LPITEM item = ITEM_MANAGER::instance().CreateItem(pItems->vnum, pItems->count, pItems->id, false, -1, false, pItems->bind);
  5278. #else
  5279. LPITEM item = ITEM_MANAGER::instance().CreateItem(pItems->vnum, pItems->count, pItems->id);
  5280. #endif
  5281. if (!item)
  5282. {
  5283. sys_err("cannot create item vnum %d id %u (name: %s)", pItems->vnum, pItems->id, GetName());
  5284. continue;
  5285. }
  5286. item->SetSkipSave(true);
  5287. item->SetSockets(pItems->alSockets);
  5288. item->SetAttributes(pItems->aAttr);
  5289. #ifdef __CHANGELOOK_SYSTEM__
  5290. item->SetTransmutation(pItems->transmutation);
  5291. #endif
  5292. if (!m_pkMall->Add(pItems->pos, item))
  5293. M2_DESTROY_ITEM(item);
  5294. else
  5295. item->SetSkipSave(false);
  5296. }
  5297. }
  5298. }
  5299. void CHARACTER::CloseMall()
  5300. {
  5301. if (!m_pkMall)
  5302. return;
  5303. m_pkMall->Save();
  5304. M2_DELETE(m_pkMall);
  5305. m_pkMall = NULL;
  5306. ChatPacket(CHAT_TYPE_COMMAND, "CloseMall");
  5307. }
  5308. bool CHARACTER::BuildUpdatePartyPacket(TPacketGCPartyUpdate & out)
  5309. {
  5310. if (!GetParty())
  5311. return false;
  5312. memset(&out, 0, sizeof(out));
  5313. out.header = HEADER_GC_PARTY_UPDATE;
  5314. out.pid = GetPlayerID();
  5315. if (GetMaxHP() <= 0)
  5316. out.percent_hp = 0;
  5317. else
  5318. out.percent_hp = MINMAX(0, GetHP() * 100 / GetMaxHP(), 100);
  5319. out.role = GetParty()->GetRole(GetPlayerID());
  5320. sys_log(1, "PARTY %s role is %d", GetName(), out.role);
  5321. LPCHARACTER l = GetParty()->GetLeaderCharacter();
  5322. if (l && DISTANCE_APPROX(GetX() - l->GetX(), GetY() - l->GetY()) < PARTY_DEFAULT_RANGE)
  5323. {
  5324. out.affects[0] = GetParty()->GetPartyBonusExpPercent();
  5325. out.affects[1] = GetPoint(POINT_PARTY_ATTACKER_BONUS);
  5326. out.affects[2] = GetPoint(POINT_PARTY_TANKER_BONUS);
  5327. out.affects[3] = GetPoint(POINT_PARTY_BUFFER_BONUS);
  5328. out.affects[4] = GetPoint(POINT_PARTY_SKILL_MASTER_BONUS);
  5329. out.affects[5] = GetPoint(POINT_PARTY_HASTE_BONUS);
  5330. out.affects[6] = GetPoint(POINT_PARTY_DEFENDER_BONUS);
  5331. }
  5332. return true;
  5333. }
  5334. int CHARACTER::GetLeadershipSkillLevel() const
  5335. {
  5336. return GetSkillLevel(SKILL_LEADERSHIP);
  5337. }
  5338. void CHARACTER::QuerySafeboxSize()
  5339. {
  5340. if (m_iSafeboxSize == -1)
  5341. {
  5342. DBManager::instance().ReturnQuery(QID_SAFEBOX_SIZE,
  5343. GetPlayerID(),
  5344. NULL,
  5345. "SELECT size FROM safebox%s WHERE account_id = %u",
  5346. get_table_postfix(),
  5347. GetDesc()->GetAccountTable().id);
  5348. }
  5349. }
  5350. void CHARACTER::SetSafeboxSize(int iSize)
  5351. {
  5352. sys_log(1, "SetSafeboxSize: %s %d", GetName(), iSize);
  5353. m_iSafeboxSize = iSize;
  5354. DBManager::instance().Query("UPDATE safebox%s SET size = %d WHERE account_id = %u", get_table_postfix(), iSize / SAFEBOX_PAGE_SIZE, GetDesc()->GetAccountTable().id);
  5355. }
  5356. int CHARACTER::GetSafeboxSize() const
  5357. {
  5358. return m_iSafeboxSize;
  5359. }
  5360. void CHARACTER::SetNowWalking(bool bWalkFlag)
  5361. {
  5362. //if (m_bNowWalking != bWalkFlag || IsNPC())
  5363. if (m_bNowWalking != bWalkFlag)
  5364. {
  5365. if (bWalkFlag)
  5366. {
  5367. m_bNowWalking = true;
  5368. m_dwWalkStartTime = get_dword_time();
  5369. }
  5370. else
  5371. {
  5372. m_bNowWalking = false;
  5373. }
  5374. //if (m_bNowWalking)
  5375. {
  5376. TPacketGCWalkMode p;
  5377. p.vid = GetVID();
  5378. p.header = HEADER_GC_WALK_MODE;
  5379. p.mode = m_bNowWalking ? WALKMODE_WALK : WALKMODE_RUN;
  5380. PacketView(&p, sizeof(p));
  5381. }
  5382. if (IsNPC())
  5383. {
  5384. if (m_bNowWalking)
  5385. MonsterLog("°È´Â´Ù");
  5386. else
  5387. MonsterLog("¶Ú´Ù");
  5388. }
  5389. //sys_log(0, "%s is now %s", GetName(), m_bNowWalking?"walking.":"running.");
  5390. }
  5391. }
  5392. void CHARACTER::StartStaminaConsume()
  5393. {
  5394. if (m_bStaminaConsume)
  5395. return;
  5396. PointChange(POINT_STAMINA, 0);
  5397. m_bStaminaConsume = true;
  5398. //ChatPacket(CHAT_TYPE_COMMAND, "StartStaminaConsume %d %d", STAMINA_PER_STEP * passes_per_sec, GetStamina());
  5399. if (IsStaminaHalfConsume())
  5400. ChatPacket(CHAT_TYPE_COMMAND, "StartStaminaConsume %d %d", STAMINA_PER_STEP * passes_per_sec / 2, GetStamina());
  5401. else
  5402. ChatPacket(CHAT_TYPE_COMMAND, "StartStaminaConsume %d %d", STAMINA_PER_STEP * passes_per_sec, GetStamina());
  5403. }
  5404. void CHARACTER::StopStaminaConsume()
  5405. {
  5406. if (!m_bStaminaConsume)
  5407. return;
  5408. PointChange(POINT_STAMINA, 0);
  5409. m_bStaminaConsume = false;
  5410. ChatPacket(CHAT_TYPE_COMMAND, "StopStaminaConsume %d", GetStamina());
  5411. }
  5412. bool CHARACTER::IsStaminaConsume() const
  5413. {
  5414. return m_bStaminaConsume;
  5415. }
  5416. bool CHARACTER::IsStaminaHalfConsume() const
  5417. {
  5418. return IsEquipUniqueItem(UNIQUE_ITEM_HALF_STAMINA);
  5419. }
  5420. void CHARACTER::ResetStopTime()
  5421. {
  5422. m_dwStopTime = get_dword_time();
  5423. }
  5424. DWORD CHARACTER::GetStopTime() const
  5425. {
  5426. return m_dwStopTime;
  5427. }
  5428. void CHARACTER::ResetPoint(int iLv)
  5429. {
  5430. BYTE bJob = GetJob();
  5431. PointChange(POINT_LEVEL, iLv - GetLevel());
  5432. SetRealPoint(POINT_ST, JobInitialPoints[bJob].st);
  5433. SetPoint(POINT_ST, GetRealPoint(POINT_ST));
  5434. SetRealPoint(POINT_HT, JobInitialPoints[bJob].ht);
  5435. SetPoint(POINT_HT, GetRealPoint(POINT_HT));
  5436. SetRealPoint(POINT_DX, JobInitialPoints[bJob].dx);
  5437. SetPoint(POINT_DX, GetRealPoint(POINT_DX));
  5438. SetRealPoint(POINT_IQ, JobInitialPoints[bJob].iq);
  5439. SetPoint(POINT_IQ, GetRealPoint(POINT_IQ));
  5440. SetRandomHP((iLv - 1) * number(JobInitialPoints[GetJob()].hp_per_lv_begin, JobInitialPoints[GetJob()].hp_per_lv_end));
  5441. SetRandomSP((iLv - 1) * number(JobInitialPoints[GetJob()].sp_per_lv_begin, JobInitialPoints[GetJob()].sp_per_lv_end));
  5442. PointChange(POINT_STAT, (MINMAX(1, iLv, g_iStatusPointGetLevelLimit) * 3) + GetPoint(POINT_LEVEL_STEP) - GetPoint(POINT_STAT));
  5443. ComputePoints();
  5444. PointChange(POINT_HP, GetMaxHP() - GetHP());
  5445. PointChange(POINT_SP, GetMaxSP() - GetSP());
  5446. PointsPacket();
  5447. LogManager::instance().CharLog(this, 0, "RESET_POINT", "");
  5448. }
  5449. bool CHARACTER::IsChangeAttackPosition(LPCHARACTER target) const
  5450. {
  5451. if (!IsNPC())
  5452. return true;
  5453. DWORD dwChangeTime = AI_CHANGE_ATTACK_POISITION_TIME_NEAR;
  5454. if (DISTANCE_APPROX(GetX() - target->GetX(), GetY() - target->GetY()) >
  5455. AI_CHANGE_ATTACK_POISITION_DISTANCE + GetMobAttackRange())
  5456. dwChangeTime = AI_CHANGE_ATTACK_POISITION_TIME_FAR;
  5457. return get_dword_time() - m_dwLastChangeAttackPositionTime > dwChangeTime;
  5458. }
  5459. void CHARACTER::GiveRandomSkillBook()
  5460. {
  5461. LPITEM item = AutoGiveItem(50300);
  5462. if (NULL != item)
  5463. {
  5464. extern const DWORD GetRandomSkillVnum(BYTE bJob = JOB_MAX_NUM);
  5465. DWORD dwSkillVnum = 0;
  5466. if (!number(0, 1))
  5467. dwSkillVnum = GetRandomSkillVnum(GetJob());
  5468. else
  5469. dwSkillVnum = GetRandomSkillVnum();
  5470. item->SetSocket(0, dwSkillVnum);
  5471. }
  5472. }
  5473. void CHARACTER::ReviveInvisible(int iDur)
  5474. {
  5475. AddAffect(AFFECT_REVIVE_INVISIBLE, POINT_NONE, 0, AFF_REVIVE_INVISIBLE, iDur, 0, true);
  5476. }
  5477. void CHARACTER::ToggleMonsterLog()
  5478. {
  5479. m_bMonsterLog = !m_bMonsterLog;
  5480. if (m_bMonsterLog)
  5481. {
  5482. CHARACTER_MANAGER::instance().RegisterForMonsterLog(this);
  5483. }
  5484. else
  5485. {
  5486. CHARACTER_MANAGER::instance().UnregisterForMonsterLog(this);
  5487. }
  5488. }
  5489. void CHARACTER::SetGuild(CGuild* pGuild)
  5490. {
  5491. if (m_pGuild != pGuild)
  5492. {
  5493. m_pGuild = pGuild;
  5494. UpdatePacket();
  5495. }
  5496. }
  5497. void CHARACTER::SendGreetMessage()
  5498. {
  5499. typeof(DBManager::instance().GetGreetMessage()) v = DBManager::instance().GetGreetMessage();
  5500. for (itertype(v) it = v.begin(); it != v.end(); ++it)
  5501. {
  5502. ChatPacket(CHAT_TYPE_NOTICE, it->c_str());
  5503. }
  5504. }
  5505. void CHARACTER::BeginStateEmpty()
  5506. {
  5507. MonsterLog("!");
  5508. }
  5509. void CHARACTER::EffectPacket(int enumEffectType)
  5510. {
  5511. TPacketGCSpecialEffect p;
  5512. p.header = HEADER_GC_SEPCIAL_EFFECT;
  5513. p.type = enumEffectType;
  5514. p.vid = GetVID();
  5515. PacketAround(&p, sizeof(TPacketGCSpecialEffect));
  5516. }
  5517. void CHARACTER::SpecificEffectPacket(const char filename[MAX_EFFECT_FILE_NAME])
  5518. {
  5519. TPacketGCSpecificEffect p;
  5520. p.header = HEADER_GC_SPECIFIC_EFFECT;
  5521. p.vid = GetVID();
  5522. memcpy (p.effect_file, filename, MAX_EFFECT_FILE_NAME);
  5523. PacketAround(&p, sizeof(TPacketGCSpecificEffect));
  5524. }
  5525. void CHARACTER::MonsterChat(BYTE bMonsterChatType)
  5526. {
  5527. if (IsPC())
  5528. return;
  5529. char sbuf[256+1];
  5530. if (IsMonster())
  5531. {
  5532. if (number(0, 60))
  5533. return;
  5534. snprintf(sbuf, sizeof(sbuf),
  5535. "(locale.monster_chat[%i] and locale.monster_chat[%i][%d] or '')",
  5536. GetRaceNum(), GetRaceNum(), bMonsterChatType*3 + number(1, 3));
  5537. }
  5538. else
  5539. {
  5540. if (bMonsterChatType != MONSTER_CHAT_WAIT)
  5541. return;
  5542. if (IsGuardNPC())
  5543. {
  5544. if (number(0, 6))
  5545. return;
  5546. }
  5547. else
  5548. {
  5549. if (number(0, 30))
  5550. return;
  5551. }
  5552. 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());
  5553. }
  5554. std::string text = quest::ScriptToString(sbuf);
  5555. if (text.empty())
  5556. return;
  5557. struct packet_chat pack_chat;
  5558. pack_chat.header = HEADER_GC_CHAT;
  5559. pack_chat.size = sizeof(struct packet_chat) + text.size() + 1;
  5560. pack_chat.type = CHAT_TYPE_TALKING;
  5561. pack_chat.id = GetVID();
  5562. pack_chat.bEmpire = 0;
  5563. TEMP_BUFFER buf;
  5564. buf.write(&pack_chat, sizeof(struct packet_chat));
  5565. buf.write(text.c_str(), text.size() + 1);
  5566. PacketAround(buf.read_peek(), buf.size());
  5567. }
  5568. void CHARACTER::SetQuestNPCID(DWORD vid)
  5569. {
  5570. m_dwQuestNPCVID = vid;
  5571. }
  5572. LPCHARACTER CHARACTER::GetQuestNPC() const
  5573. {
  5574. return CHARACTER_MANAGER::instance().Find(m_dwQuestNPCVID);
  5575. }
  5576. void CHARACTER::SetQuestItemPtr(LPITEM item)
  5577. {
  5578. m_pQuestItem = item;
  5579. }
  5580. void CHARACTER::ClearQuestItemPtr()
  5581. {
  5582. m_pQuestItem = NULL;
  5583. }
  5584. LPITEM CHARACTER::GetQuestItemPtr() const
  5585. {
  5586. return m_pQuestItem;
  5587. }
  5588. LPDUNGEON CHARACTER::GetDungeonForce() const
  5589. {
  5590. if (m_lWarpMapIndex > 10000)
  5591. return CDungeonManager::instance().FindByMapIndex(m_lWarpMapIndex);
  5592. return m_pkDungeon;
  5593. }
  5594. void CHARACTER::SetBlockMode(BYTE bFlag)
  5595. {
  5596. m_pointsInstant.bBlockMode = bFlag;
  5597. ChatPacket(CHAT_TYPE_COMMAND, "setblockmode %d", m_pointsInstant.bBlockMode);
  5598. SetQuestFlag("game_option.block_exchange", bFlag & BLOCK_EXCHANGE ? 1 : 0);
  5599. SetQuestFlag("game_option.block_party_invite", bFlag & BLOCK_PARTY_INVITE ? 1 : 0);
  5600. SetQuestFlag("game_option.block_guild_invite", bFlag & BLOCK_GUILD_INVITE ? 1 : 0);
  5601. SetQuestFlag("game_option.block_whisper", bFlag & BLOCK_WHISPER ? 1 : 0);
  5602. SetQuestFlag("game_option.block_messenger_invite", bFlag & BLOCK_MESSENGER_INVITE ? 1 : 0);
  5603. SetQuestFlag("game_option.block_party_request", bFlag & BLOCK_PARTY_REQUEST ? 1 : 0);
  5604. }
  5605. void CHARACTER::SetBlockModeForce(BYTE bFlag)
  5606. {
  5607. m_pointsInstant.bBlockMode = bFlag;
  5608. ChatPacket(CHAT_TYPE_COMMAND, "setblockmode %d", m_pointsInstant.bBlockMode);
  5609. }
  5610. bool CHARACTER::IsGuardNPC() const
  5611. {
  5612. return IsNPC() && (GetRaceNum() == 11000 || GetRaceNum() == 11002 || GetRaceNum() == 11004);
  5613. }
  5614. int CHARACTER::GetPolymorphPower() const
  5615. {
  5616. if (test_server)
  5617. {
  5618. int value = quest::CQuestManager::instance().GetEventFlag("poly");
  5619. if (value)
  5620. return value;
  5621. }
  5622. return aiPolymorphPowerByLevel[MINMAX(0, GetSkillLevel(SKILL_POLYMORPH), 40)];
  5623. }
  5624. void CHARACTER::SetPolymorph(DWORD dwRaceNum, bool bMaintainStat)
  5625. {
  5626. #ifdef ENABLE_WOLFMAN_CHARACTER
  5627. if (dwRaceNum < MAIN_RACE_MAX_NUM)
  5628. #else
  5629. if (dwRaceNum < JOB_MAX_NUM)
  5630. #endif
  5631. {
  5632. dwRaceNum = 0;
  5633. bMaintainStat = false;
  5634. }
  5635. if (m_dwPolymorphRace == dwRaceNum)
  5636. return;
  5637. m_bPolyMaintainStat = bMaintainStat;
  5638. m_dwPolymorphRace = dwRaceNum;
  5639. sys_log(0, "POLYMORPH: %s race %u ", GetName(), dwRaceNum);
  5640. if (dwRaceNum != 0)
  5641. StopRiding();
  5642. SET_BIT(m_bAddChrState, ADD_CHARACTER_STATE_SPAWN);
  5643. m_afAffectFlag.Set(AFF_SPAWN);
  5644. ViewReencode();
  5645. REMOVE_BIT(m_bAddChrState, ADD_CHARACTER_STATE_SPAWN);
  5646. if (!bMaintainStat)
  5647. {
  5648. PointChange(POINT_ST, 0);
  5649. PointChange(POINT_DX, 0);
  5650. PointChange(POINT_IQ, 0);
  5651. PointChange(POINT_HT, 0);
  5652. }
  5653. SetValidComboInterval(0);
  5654. SetComboSequence(0);
  5655. ComputeBattlePoints();
  5656. }
  5657. int CHARACTER::GetQuestFlag(const std::string& flag) const
  5658. {
  5659. quest::CQuestManager& q = quest::CQuestManager::instance();
  5660. quest::PC* pPC = q.GetPC(GetPlayerID());
  5661. return pPC->GetFlag(flag);
  5662. }
  5663. void CHARACTER::SetQuestFlag(const std::string& flag, int value)
  5664. {
  5665. quest::CQuestManager& q = quest::CQuestManager::instance();
  5666. quest::PC* pPC = q.GetPC(GetPlayerID());
  5667. pPC->SetFlag(flag, value);
  5668. }
  5669. void CHARACTER::DetermineDropMetinStone()
  5670. {
  5671. #ifdef ENABLE_NEWSTUFF
  5672. if (g_NoDropMetinStone)
  5673. {
  5674. m_dwDropMetinStone = 0;
  5675. return;
  5676. }
  5677. #endif
  5678. const int METIN_STONE_NUM = 14;
  5679. static DWORD c_adwMetin[METIN_STONE_NUM] =
  5680. {
  5681. 28030,
  5682. 28031,
  5683. 28032,
  5684. 28033,
  5685. 28034,
  5686. 28035,
  5687. 28036,
  5688. 28037,
  5689. 28038,
  5690. 28039,
  5691. 28040,
  5692. 28041,
  5693. 28042,
  5694. 28043,
  5695. };
  5696. DWORD stone_num = GetRaceNum();
  5697. int idx = std::lower_bound(aStoneDrop, aStoneDrop+STONE_INFO_MAX_NUM, stone_num) - aStoneDrop;
  5698. if (idx >= STONE_INFO_MAX_NUM || aStoneDrop[idx].dwMobVnum != stone_num)
  5699. {
  5700. m_dwDropMetinStone = 0;
  5701. }
  5702. else
  5703. {
  5704. const SStoneDropInfo & info = aStoneDrop[idx];
  5705. m_bDropMetinStonePct = info.iDropPct;
  5706. {
  5707. m_dwDropMetinStone = c_adwMetin[number(0, METIN_STONE_NUM - 1)];
  5708. int iGradePct = number(1, 100);
  5709. for (int iStoneLevel = 0; iStoneLevel < STONE_LEVEL_MAX_NUM; iStoneLevel ++)
  5710. {
  5711. int iLevelGradePortion = info.iLevelPct[iStoneLevel];
  5712. if (iGradePct <= iLevelGradePortion)
  5713. {
  5714. break;
  5715. }
  5716. else
  5717. {
  5718. iGradePct -= iLevelGradePortion;
  5719. m_dwDropMetinStone += 100;
  5720. }
  5721. }
  5722. }
  5723. }
  5724. }
  5725. void CHARACTER::SendEquipment(LPCHARACTER ch)
  5726. {
  5727. TPacketViewEquip p;
  5728. p.header = HEADER_GC_VIEW_EQUIP;
  5729. p.vid = GetVID();
  5730. for (int i = 0; i<WEAR_MAX_NUM; i++)
  5731. {
  5732. LPITEM item = GetWear(i);
  5733. if (item)
  5734. {
  5735. p.equips[i].vnum = item->GetVnum();
  5736. p.equips[i].count = item->GetCount();
  5737. thecore_memcpy(p.equips[i].alSockets, item->GetSockets(), sizeof(p.equips[i].alSockets));
  5738. thecore_memcpy(p.equips[i].aAttr, item->GetAttributes(), sizeof(p.equips[i].aAttr));
  5739. }
  5740. else
  5741. {
  5742. p.equips[i].vnum = 0;
  5743. }
  5744. }
  5745. ch->GetDesc()->Packet(&p, sizeof(p));
  5746. }
  5747. bool CHARACTER::CanSummon(int iLeaderShip)
  5748. {
  5749. return ((iLeaderShip >= 20) || ((iLeaderShip >= 12) && ((m_dwLastDeadTime + 180) > get_dword_time())));
  5750. }
  5751. void CHARACTER::MountVnum(DWORD vnum)
  5752. {
  5753. if (m_dwMountVnum == vnum)
  5754. return;
  5755. if ((m_dwMountVnum != 0)&&(vnum!=0))
  5756. MountVnum(0);
  5757. m_dwMountVnum = vnum;
  5758. m_dwMountTime = get_dword_time();
  5759. if (m_bIsObserver)
  5760. return;
  5761. m_posDest.x = m_posStart.x = GetX();
  5762. m_posDest.y = m_posStart.y = GetY();
  5763. //EncodeRemovePacket(this);
  5764. EncodeInsertPacket(this);
  5765. ENTITY_MAP::iterator it = m_map_view.begin();
  5766. while (it != m_map_view.end())
  5767. {
  5768. LPENTITY entity = (it++)->first;
  5769. //EncodeRemovePacket(entity);
  5770. //if (!m_bIsObserver)
  5771. EncodeInsertPacket(entity);
  5772. //if (!entity->IsObserverMode())
  5773. // entity->EncodeInsertPacket(this);
  5774. }
  5775. SetValidComboInterval(0);
  5776. SetComboSequence(0);
  5777. ComputePoints();
  5778. }
  5779. namespace {
  5780. class FuncCheckWarp
  5781. {
  5782. public:
  5783. FuncCheckWarp(LPCHARACTER pkWarp)
  5784. {
  5785. m_lTargetY = 0;
  5786. m_lTargetX = 0;
  5787. m_lX = pkWarp->GetX();
  5788. m_lY = pkWarp->GetY();
  5789. m_bInvalid = false;
  5790. m_bEmpire = pkWarp->GetEmpire();
  5791. char szTmp[64];
  5792. if (3 != sscanf(pkWarp->GetName(), " %s %ld %ld ", szTmp, &m_lTargetX, &m_lTargetY))
  5793. {
  5794. if (number(1, 100) < 5)
  5795. sys_err("Warp NPC name wrong : vnum(%d) name(%s)", pkWarp->GetRaceNum(), pkWarp->GetName());
  5796. m_bInvalid = true;
  5797. return;
  5798. }
  5799. m_lTargetX *= 100;
  5800. m_lTargetY *= 100;
  5801. m_bUseWarp = true;
  5802. if (pkWarp->IsGoto())
  5803. {
  5804. LPSECTREE_MAP pkSectreeMap = SECTREE_MANAGER::instance().GetMap(pkWarp->GetMapIndex());
  5805. m_lTargetX += pkSectreeMap->m_setting.iBaseX;
  5806. m_lTargetY += pkSectreeMap->m_setting.iBaseY;
  5807. m_bUseWarp = false;
  5808. }
  5809. }
  5810. bool Valid()
  5811. {
  5812. return !m_bInvalid;
  5813. }
  5814. void operator () (LPENTITY ent)
  5815. {
  5816. if (!Valid())
  5817. return;
  5818. if (!ent->IsType(ENTITY_CHARACTER))
  5819. return;
  5820. LPCHARACTER pkChr = (LPCHARACTER) ent;
  5821. if (!pkChr->IsPC())
  5822. return;
  5823. int iDist = DISTANCE_APPROX(pkChr->GetX() - m_lX, pkChr->GetY() - m_lY);
  5824. if (iDist > 300)
  5825. return;
  5826. if (m_bEmpire && pkChr->GetEmpire() && m_bEmpire != pkChr->GetEmpire())
  5827. return;
  5828. if (pkChr->IsHack())
  5829. return;
  5830. if (!pkChr->CanHandleItem(false, true))
  5831. return;
  5832. if (m_bUseWarp)
  5833. pkChr->WarpSet(m_lTargetX, m_lTargetY);
  5834. else
  5835. {
  5836. pkChr->Show(pkChr->GetMapIndex(), m_lTargetX, m_lTargetY);
  5837. pkChr->Stop();
  5838. }
  5839. }
  5840. bool m_bInvalid;
  5841. bool m_bUseWarp;
  5842. long m_lX;
  5843. long m_lY;
  5844. long m_lTargetX;
  5845. long m_lTargetY;
  5846. BYTE m_bEmpire;
  5847. };
  5848. }
  5849. EVENTFUNC(warp_npc_event)
  5850. {
  5851. char_event_info* info = dynamic_cast<char_event_info*>( event->info );
  5852. if ( info == NULL )
  5853. {
  5854. sys_err( "warp_npc_event> <Factor> Null pointer" );
  5855. return 0;
  5856. }
  5857. LPCHARACTER ch = info->ch;
  5858. if (ch == NULL) {
  5859. return 0;
  5860. }
  5861. if (!ch->GetSectree())
  5862. {
  5863. ch->m_pkWarpNPCEvent = NULL;
  5864. return 0;
  5865. }
  5866. FuncCheckWarp f(ch);
  5867. if (f.Valid())
  5868. ch->GetSectree()->ForEachAround(f);
  5869. return passes_per_sec / 2;
  5870. }
  5871. void CHARACTER::StartWarpNPCEvent()
  5872. {
  5873. if (m_pkWarpNPCEvent)
  5874. return;
  5875. if (!IsWarp() && !IsGoto())
  5876. return;
  5877. char_event_info* info = AllocEventInfo<char_event_info>();
  5878. info->ch = this;
  5879. m_pkWarpNPCEvent = event_create(warp_npc_event, info, passes_per_sec / 2);
  5880. }
  5881. void CHARACTER::SyncPacket()
  5882. {
  5883. TEMP_BUFFER buf;
  5884. TPacketCGSyncPositionElement elem;
  5885. elem.dwVID = GetVID();
  5886. elem.lX = GetX();
  5887. elem.lY = GetY();
  5888. TPacketGCSyncPosition pack;
  5889. pack.bHeader = HEADER_GC_SYNC_POSITION;
  5890. pack.wSize = sizeof(TPacketGCSyncPosition) + sizeof(elem);
  5891. buf.write(&pack, sizeof(pack));
  5892. buf.write(&elem, sizeof(elem));
  5893. PacketAround(buf.read_peek(), buf.size());
  5894. }
  5895. LPCHARACTER CHARACTER::GetMarryPartner() const
  5896. {
  5897. return m_pkChrMarried;
  5898. }
  5899. void CHARACTER::SetMarryPartner(LPCHARACTER ch)
  5900. {
  5901. m_pkChrMarried = ch;
  5902. }
  5903. int CHARACTER::GetMarriageBonus(DWORD dwItemVnum, bool bSum)
  5904. {
  5905. if (IsNPC())
  5906. return 0;
  5907. marriage::TMarriage* pMarriage = marriage::CManager::instance().Get(GetPlayerID());
  5908. if (!pMarriage)
  5909. return 0;
  5910. return pMarriage->GetBonus(dwItemVnum, bSum, this);
  5911. }
  5912. void CHARACTER::ConfirmWithMsg(const char* szMsg, int iTimeout, DWORD dwRequestPID)
  5913. {
  5914. if (!IsPC())
  5915. return;
  5916. TPacketGCQuestConfirm p;
  5917. p.header = HEADER_GC_QUEST_CONFIRM;
  5918. p.requestPID = dwRequestPID;
  5919. p.timeout = iTimeout;
  5920. strlcpy(p.msg, szMsg, sizeof(p.msg));
  5921. GetDesc()->Packet(&p, sizeof(p));
  5922. }
  5923. int CHARACTER::GetPremiumRemainSeconds(BYTE bType) const
  5924. {
  5925. if (bType >= PREMIUM_MAX_NUM)
  5926. return 0;
  5927. return m_aiPremiumTimes[bType] - get_global_time();
  5928. }
  5929. bool CHARACTER::WarpToPID(DWORD dwPID)
  5930. {
  5931. LPCHARACTER victim;
  5932. if ((victim = (CHARACTER_MANAGER::instance().FindByPID(dwPID))))
  5933. {
  5934. int mapIdx = victim->GetMapIndex();
  5935. if (IS_SUMMONABLE_ZONE(mapIdx))
  5936. {
  5937. if (CAN_ENTER_ZONE(this, mapIdx))
  5938. {
  5939. WarpSet(victim->GetX(), victim->GetY());
  5940. }
  5941. else
  5942. {
  5943. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("»ó´ë¹æÀÌ ÀÖ´Â °÷À¸·Î ¿öÇÁÇÒ ¼ö ¾ø½À´Ï´Ù."));
  5944. return false;
  5945. }
  5946. }
  5947. else
  5948. {
  5949. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("»ó´ë¹æÀÌ ÀÖ´Â °÷À¸·Î ¿öÇÁÇÒ ¼ö ¾ø½À´Ï´Ù."));
  5950. return false;
  5951. }
  5952. }
  5953. else
  5954. {
  5955. CCI * pcci = P2P_MANAGER::instance().FindByPID(dwPID);
  5956. if (!pcci)
  5957. {
  5958. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("»ó´ë¹æÀÌ ¿Â¶óÀÎ »óŰ¡ ¾Æ´Õ´Ï´Ù."));
  5959. return false;
  5960. }
  5961. if (pcci->bChannel != g_bChannel)
  5962. {
  5963. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("»ó´ë¹æÀÌ %d ä³Î¿¡ ÀÖ½À´Ï´Ù. (ÇöÀç ä³Î %d)"), pcci->bChannel, g_bChannel);
  5964. return false;
  5965. }
  5966. else if (false == IS_SUMMONABLE_ZONE(pcci->lMapIndex))
  5967. {
  5968. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("»ó´ë¹æÀÌ ÀÖ´Â °÷À¸·Î ¿öÇÁÇÒ ¼ö ¾ø½À´Ï´Ù."));
  5969. return false;
  5970. }
  5971. else
  5972. {
  5973. if (!CAN_ENTER_ZONE(this, pcci->lMapIndex))
  5974. {
  5975. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("»ó´ë¹æÀÌ ÀÖ´Â °÷À¸·Î ¿öÇÁÇÒ ¼ö ¾ø½À´Ï´Ù."));
  5976. return false;
  5977. }
  5978. TPacketGGFindPosition p;
  5979. p.header = HEADER_GG_FIND_POSITION;
  5980. p.dwFromPID = GetPlayerID();
  5981. p.dwTargetPID = dwPID;
  5982. pcci->pkDesc->Packet(&p, sizeof(TPacketGGFindPosition));
  5983. if (test_server)
  5984. ChatPacket(CHAT_TYPE_PARTY, "sent find position packet for teleport");
  5985. }
  5986. }
  5987. return true;
  5988. }
  5989. // ADD_REFINE_BUILDING
  5990. CGuild* CHARACTER::GetRefineGuild() const
  5991. {
  5992. LPCHARACTER chRefineNPC = CHARACTER_MANAGER::instance().Find(m_dwRefineNPCVID);
  5993. return (chRefineNPC ? chRefineNPC->GetGuild() : NULL);
  5994. }
  5995. bool CHARACTER::IsRefineThroughGuild() const
  5996. {
  5997. return GetRefineGuild() != NULL;
  5998. }
  5999. int CHARACTER::ComputeRefineFee(int iCost, int iMultiply) const
  6000. {
  6001. CGuild* pGuild = GetRefineGuild();
  6002. if (pGuild)
  6003. {
  6004. if (pGuild == GetGuild())
  6005. return iCost * iMultiply * 9 / 10;
  6006. LPCHARACTER chRefineNPC = CHARACTER_MANAGER::instance().Find(m_dwRefineNPCVID);
  6007. if (chRefineNPC && chRefineNPC->GetEmpire() != GetEmpire())
  6008. return iCost * iMultiply * 3;
  6009. return iCost * iMultiply;
  6010. }
  6011. else
  6012. return iCost;
  6013. }
  6014. void CHARACTER::PayRefineFee(int iTotalMoney)
  6015. {
  6016. int iFee = iTotalMoney / 10;
  6017. CGuild* pGuild = GetRefineGuild();
  6018. int iRemain = iTotalMoney;
  6019. if (pGuild)
  6020. {
  6021. if (pGuild != GetGuild())
  6022. {
  6023. pGuild->RequestDepositMoney(this, iFee);
  6024. iRemain -= iFee;
  6025. }
  6026. }
  6027. PointChange(POINT_GOLD, -iRemain);
  6028. }
  6029. // END_OF_ADD_REFINE_BUILDING
  6030. bool CHARACTER::IsHack(bool bSendMsg, bool bCheckShopOwner, int limittime)
  6031. {
  6032. const int iPulse = thecore_pulse();
  6033. if (test_server)
  6034. bSendMsg = true;
  6035. if (iPulse - GetSafeboxLoadTime() < PASSES_PER_SEC(limittime))
  6036. {
  6037. if (bSendMsg)
  6038. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("â°í¸¦ ¿¬ÈÄ %dÃÊ À̳»¿¡´Â ´Ù¸¥°÷À¸·Î À̵¿ÇÒ¼ö ¾ø½À´Ï´Ù."), limittime);
  6039. if (test_server)
  6040. ChatPacket(CHAT_TYPE_INFO, "[TestOnly]Pulse %d LoadTime %d PASS %d", iPulse, GetSafeboxLoadTime(), PASSES_PER_SEC(limittime));
  6041. return true;
  6042. }
  6043. if (bCheckShopOwner)
  6044. {
  6045. if (GetExchange() || GetMyShop() || GetShopOwner() || IsOpenSafebox() || IsCubeOpen() || GetOfflineShopOwner())
  6046. {
  6047. if (bSendMsg)
  6048. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("°Å·¡Ã¢,â°í µîÀ» ¿¬ »óÅ¿¡¼­´Â ´Ù¸¥°÷À¸·Î À̵¿,Á¾·á ÇÒ¼ö ¾ø½À´Ï´Ù"));
  6049. return true;
  6050. }
  6051. }
  6052. else
  6053. {
  6054. if (GetExchange() || GetMyShop() || GetShopOwner() || IsOpenSafebox() || IsCubeOpen() || GetOfflineShopOwner())
  6055. {
  6056. if (bSendMsg)
  6057. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("°Å·¡Ã¢,â°í µîÀ» ¿¬ »óÅ¿¡¼­´Â ´Ù¸¥°÷À¸·Î À̵¿,Á¾·á ÇÒ¼ö ¾ø½À´Ï´Ù"));
  6058. return true;
  6059. }
  6060. }
  6061. //PREVENT_PORTAL_AFTER_EXCHANGE
  6062. if (iPulse - GetExchangeTime() < PASSES_PER_SEC(limittime))
  6063. {
  6064. if (bSendMsg)
  6065. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("°Å·¡ ÈÄ %dÃÊ À̳»¿¡´Â ´Ù¸¥Áö¿ªÀ¸·Î À̵¿ ÇÒ ¼ö ¾ø½À´Ï´Ù."), limittime );
  6066. return true;
  6067. }
  6068. //END_PREVENT_PORTAL_AFTER_EXCHANGE
  6069. //PREVENT_ITEM_COPY
  6070. if (iPulse - GetMyShopTime() < PASSES_PER_SEC(limittime))
  6071. {
  6072. if (bSendMsg)
  6073. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("°Å·¡ ÈÄ %dÃÊ À̳»¿¡´Â ´Ù¸¥Áö¿ªÀ¸·Î À̵¿ ÇÒ ¼ö ¾ø½À´Ï´Ù."), limittime);
  6074. return true;
  6075. }
  6076. if (iPulse - GetRefineTime() < PASSES_PER_SEC(limittime))
  6077. {
  6078. if (bSendMsg)
  6079. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("¾ÆÀÌÅÛ °³·®ÈÄ %dÃÊ À̳»¿¡´Â ±ÍȯºÎ,±Íȯ±â¾ïºÎ¸¦ »ç¿ëÇÒ ¼ö ¾ø½À´Ï´Ù."), limittime);
  6080. return true;
  6081. }
  6082. //END_PREVENT_ITEM_COPY
  6083. return false;
  6084. }
  6085. BOOL CHARACTER::IsMonarch() const
  6086. {
  6087. //MONARCH_LIMIT
  6088. if (CMonarch::instance().IsMonarch(GetPlayerID(), GetEmpire()))
  6089. return true;
  6090. return false;
  6091. //END_MONARCH_LIMIT
  6092. }
  6093. void CHARACTER::Say(const std::string & s)
  6094. {
  6095. struct ::packet_script packet_script;
  6096. packet_script.header = HEADER_GC_SCRIPT;
  6097. packet_script.skin = 1;
  6098. packet_script.src_size = s.size();
  6099. packet_script.size = packet_script.src_size + sizeof(struct packet_script);
  6100. TEMP_BUFFER buf;
  6101. buf.write(&packet_script, sizeof(struct packet_script));
  6102. buf.write(&s[0], s.size());
  6103. if (IsPC())
  6104. {
  6105. GetDesc()->Packet(buf.read_peek(), buf.size());
  6106. }
  6107. }
  6108. void CHARACTER::InitMC()
  6109. {
  6110. for (int n = 0; n < MI_MAX; ++n)
  6111. {
  6112. m_dwMonarchCooltime[n] = thecore_pulse();
  6113. }
  6114. m_dwMonarchCooltimelimit[MI_HEAL] = PASSES_PER_SEC(MC_HEAL);
  6115. m_dwMonarchCooltimelimit[MI_WARP] = PASSES_PER_SEC(MC_WARP);
  6116. m_dwMonarchCooltimelimit[MI_TRANSFER] = PASSES_PER_SEC(MC_TRANSFER);
  6117. m_dwMonarchCooltimelimit[MI_TAX] = PASSES_PER_SEC(MC_TAX);
  6118. m_dwMonarchCooltimelimit[MI_SUMMON] = PASSES_PER_SEC(MC_SUMMON);
  6119. m_dwMonarchCooltime[MI_HEAL] -= PASSES_PER_SEC(GetMCL(MI_HEAL));
  6120. m_dwMonarchCooltime[MI_WARP] -= PASSES_PER_SEC(GetMCL(MI_WARP));
  6121. m_dwMonarchCooltime[MI_TRANSFER] -= PASSES_PER_SEC(GetMCL(MI_TRANSFER));
  6122. m_dwMonarchCooltime[MI_TAX] -= PASSES_PER_SEC(GetMCL(MI_TAX));
  6123. m_dwMonarchCooltime[MI_SUMMON] -= PASSES_PER_SEC(GetMCL(MI_SUMMON));
  6124. }
  6125. DWORD CHARACTER::GetMC(enum MONARCH_INDEX e) const
  6126. {
  6127. return m_dwMonarchCooltime[e];
  6128. }
  6129. void CHARACTER::SetMC(enum MONARCH_INDEX e)
  6130. {
  6131. m_dwMonarchCooltime[e] = thecore_pulse();
  6132. }
  6133. bool CHARACTER::IsMCOK(enum MONARCH_INDEX e) const
  6134. {
  6135. int iPulse = thecore_pulse();
  6136. if ((iPulse - GetMC(e)) < GetMCL(e))
  6137. {
  6138. if (test_server)
  6139. sys_log(0, " Pulse %d cooltime %d, limit %d", iPulse, GetMC(e), GetMCL(e));
  6140. return false;
  6141. }
  6142. if (test_server)
  6143. sys_log(0, " Pulse %d cooltime %d, limit %d", iPulse, GetMC(e), GetMCL(e));
  6144. return true;
  6145. }
  6146. DWORD CHARACTER::GetMCL(enum MONARCH_INDEX e) const
  6147. {
  6148. return m_dwMonarchCooltimelimit[e];
  6149. }
  6150. DWORD CHARACTER::GetMCLTime(enum MONARCH_INDEX e) const
  6151. {
  6152. int iPulse = thecore_pulse();
  6153. if (test_server)
  6154. sys_log(0, " Pulse %d cooltime %d, limit %d", iPulse, GetMC(e), GetMCL(e));
  6155. return (GetMCL(e)) / passes_per_sec - (iPulse - GetMC(e)) / passes_per_sec;
  6156. }
  6157. bool CHARACTER::IsSiegeNPC() const
  6158. {
  6159. return IsNPC() && (GetRaceNum() == 11000 || GetRaceNum() == 11002 || GetRaceNum() == 11004);
  6160. }
  6161. void CHARACTER::UpdateDepositPulse()
  6162. {
  6163. m_deposit_pulse = thecore_pulse() + PASSES_PER_SEC(60*5);
  6164. }
  6165. bool CHARACTER::CanDeposit() const
  6166. {
  6167. return (m_deposit_pulse == 0 || (m_deposit_pulse < thecore_pulse()));
  6168. }
  6169. ESex GET_SEX(LPCHARACTER ch)
  6170. {
  6171. switch (ch->GetRaceNum())
  6172. {
  6173. case MAIN_RACE_WARRIOR_M:
  6174. case MAIN_RACE_SURA_M:
  6175. case MAIN_RACE_ASSASSIN_M:
  6176. case MAIN_RACE_SHAMAN_M:
  6177. #ifdef ENABLE_WOLFMAN_CHARACTER
  6178. case MAIN_RACE_WOLFMAN_M:
  6179. #endif
  6180. return SEX_MALE;
  6181. case MAIN_RACE_ASSASSIN_W:
  6182. case MAIN_RACE_SHAMAN_W:
  6183. case MAIN_RACE_WARRIOR_W:
  6184. case MAIN_RACE_SURA_W:
  6185. return SEX_FEMALE;
  6186. }
  6187. return SEX_MALE;
  6188. }
  6189. int CHARACTER::GetHPPct() const
  6190. {
  6191. if (GetMaxHP() <= 0)
  6192. return 0;
  6193. return (GetHP() * 100) / GetMaxHP();
  6194. }
  6195. bool CHARACTER::IsBerserk() const
  6196. {
  6197. if (m_pkMobInst != NULL)
  6198. return m_pkMobInst->m_IsBerserk;
  6199. else
  6200. return false;
  6201. }
  6202. void CHARACTER::SetBerserk(bool mode)
  6203. {
  6204. if (m_pkMobInst != NULL)
  6205. m_pkMobInst->m_IsBerserk = mode;
  6206. }
  6207. bool CHARACTER::IsGodSpeed() const
  6208. {
  6209. if (m_pkMobInst != NULL)
  6210. {
  6211. return m_pkMobInst->m_IsGodSpeed;
  6212. }
  6213. else
  6214. {
  6215. return false;
  6216. }
  6217. }
  6218. void CHARACTER::SetGodSpeed(bool mode)
  6219. {
  6220. if (m_pkMobInst != NULL)
  6221. {
  6222. m_pkMobInst->m_IsGodSpeed = mode;
  6223. if (mode == true)
  6224. {
  6225. SetPoint(POINT_ATT_SPEED, 250);
  6226. }
  6227. else
  6228. {
  6229. SetPoint(POINT_ATT_SPEED, m_pkMobData->m_table.sAttackSpeed);
  6230. }
  6231. }
  6232. }
  6233. bool CHARACTER::IsDeathBlow() const
  6234. {
  6235. if (number(1, 100) <= m_pkMobData->m_table.bDeathBlowPoint)
  6236. {
  6237. return true;
  6238. }
  6239. else
  6240. {
  6241. return false;
  6242. }
  6243. }
  6244. struct FFindReviver
  6245. {
  6246. FFindReviver()
  6247. {
  6248. pChar = NULL;
  6249. HasReviver = false;
  6250. }
  6251. void operator() (LPCHARACTER ch)
  6252. {
  6253. if (ch->IsMonster() != true)
  6254. {
  6255. return;
  6256. }
  6257. if (ch->IsReviver() == true && pChar != ch && ch->IsDead() != true)
  6258. {
  6259. if (number(1, 100) <= ch->GetMobTable().bRevivePoint)
  6260. {
  6261. HasReviver = true;
  6262. pChar = ch;
  6263. }
  6264. }
  6265. }
  6266. LPCHARACTER pChar;
  6267. bool HasReviver;
  6268. };
  6269. bool CHARACTER::HasReviverInParty() const
  6270. {
  6271. LPPARTY party = GetParty();
  6272. if (party != NULL)
  6273. {
  6274. if (party->GetMemberCount() == 1) return false;
  6275. FFindReviver f;
  6276. party->ForEachMemberPtr(f);
  6277. return f.HasReviver;
  6278. }
  6279. return false;
  6280. }
  6281. bool CHARACTER::IsRevive() const
  6282. {
  6283. if (m_pkMobInst != NULL)
  6284. {
  6285. return m_pkMobInst->m_IsRevive;
  6286. }
  6287. return false;
  6288. }
  6289. void CHARACTER::SetRevive(bool mode)
  6290. {
  6291. if (m_pkMobInst != NULL)
  6292. {
  6293. m_pkMobInst->m_IsRevive = mode;
  6294. }
  6295. }
  6296. #define IS_SPEED_HACK_PLAYER(ch) (ch->m_speed_hack_count > SPEEDHACK_LIMIT_COUNT)
  6297. EVENTFUNC(check_speedhack_event)
  6298. {
  6299. char_event_info* info = dynamic_cast<char_event_info*>( event->info );
  6300. if ( info == NULL )
  6301. {
  6302. sys_err( "check_speedhack_event> <Factor> Null pointer" );
  6303. return 0;
  6304. }
  6305. LPCHARACTER ch = info->ch;
  6306. if (NULL == ch || ch->IsNPC())
  6307. return 0;
  6308. if (IS_SPEED_HACK_PLAYER(ch))
  6309. {
  6310. LogManager::instance().SpeedHackLog(ch->GetPlayerID(), ch->GetX(), ch->GetY(), ch->m_speed_hack_count);
  6311. if (g_bEnableSpeedHackCrash)
  6312. {
  6313. LPDESC desc = ch->GetDesc();
  6314. if (desc)
  6315. {
  6316. DESC_MANAGER::instance().DestroyDesc(desc);
  6317. return 0;
  6318. }
  6319. }
  6320. }
  6321. ch->m_speed_hack_count = 0;
  6322. ch->ResetComboHackCount();
  6323. return PASSES_PER_SEC(60);
  6324. }
  6325. void CHARACTER::StartCheckSpeedHackEvent()
  6326. {
  6327. if (m_pkCheckSpeedHackEvent)
  6328. return;
  6329. char_event_info* info = AllocEventInfo<char_event_info>();
  6330. info->ch = this;
  6331. m_pkCheckSpeedHackEvent = event_create(check_speedhack_event, info, PASSES_PER_SEC(60));
  6332. }
  6333. void CHARACTER::GoHome()
  6334. {
  6335. WarpSet(EMPIRE_START_X(GetEmpire()), EMPIRE_START_Y(GetEmpire()));
  6336. }
  6337. void CHARACTER::SendGuildName(CGuild* pGuild)
  6338. {
  6339. if (NULL == pGuild) return;
  6340. DESC *desc = GetDesc();
  6341. if (NULL == desc) return;
  6342. if (m_known_guild.find(pGuild->GetID()) != m_known_guild.end()) return;
  6343. m_known_guild.insert(pGuild->GetID());
  6344. TPacketGCGuildName pack;
  6345. memset(&pack, 0x00, sizeof(pack));
  6346. pack.header = HEADER_GC_GUILD;
  6347. pack.subheader = GUILD_SUBHEADER_GC_GUILD_NAME;
  6348. pack.size = sizeof(TPacketGCGuildName);
  6349. pack.guildID = pGuild->GetID();
  6350. memcpy(pack.guildName, pGuild->GetName(), GUILD_NAME_MAX_LEN);
  6351. desc->Packet(&pack, sizeof(pack));
  6352. }
  6353. void CHARACTER::SendGuildName(DWORD dwGuildID)
  6354. {
  6355. SendGuildName(CGuildManager::instance().FindGuild(dwGuildID));
  6356. }
  6357. EVENTFUNC(destroy_when_idle_event)
  6358. {
  6359. char_event_info* info = dynamic_cast<char_event_info*>( event->info );
  6360. if ( info == NULL )
  6361. {
  6362. sys_err( "destroy_when_idle_event> <Factor> Null pointer" );
  6363. return 0;
  6364. }
  6365. LPCHARACTER ch = info->ch;
  6366. if (ch == NULL) {
  6367. return 0;
  6368. }
  6369. if (ch->GetVictim())
  6370. {
  6371. return PASSES_PER_SEC(300);
  6372. }
  6373. sys_log(1, "DESTROY_WHEN_IDLE: %s", ch->GetName());
  6374. ch->m_pkDestroyWhenIdleEvent = NULL;
  6375. M2_DESTROY_CHARACTER(ch);
  6376. return 0;
  6377. }
  6378. void CHARACTER::StartDestroyWhenIdleEvent()
  6379. {
  6380. if (m_pkDestroyWhenIdleEvent)
  6381. return;
  6382. char_event_info* info = AllocEventInfo<char_event_info>();
  6383. info->ch = this;
  6384. m_pkDestroyWhenIdleEvent = event_create(destroy_when_idle_event, info, PASSES_PER_SEC(300));
  6385. }
  6386. void CHARACTER::SetComboSequence(BYTE seq)
  6387. {
  6388. m_bComboSequence = seq;
  6389. }
  6390. BYTE CHARACTER::GetComboSequence() const
  6391. {
  6392. return m_bComboSequence;
  6393. }
  6394. void CHARACTER::SetLastComboTime(DWORD time)
  6395. {
  6396. m_dwLastComboTime = time;
  6397. }
  6398. DWORD CHARACTER::GetLastComboTime() const
  6399. {
  6400. return m_dwLastComboTime;
  6401. }
  6402. void CHARACTER::SetValidComboInterval(int interval)
  6403. {
  6404. m_iValidComboInterval = interval;
  6405. }
  6406. int CHARACTER::GetValidComboInterval() const
  6407. {
  6408. return m_iValidComboInterval;
  6409. }
  6410. BYTE CHARACTER::GetComboIndex() const
  6411. {
  6412. return m_bComboIndex;
  6413. }
  6414. void CHARACTER::IncreaseComboHackCount(int k)
  6415. {
  6416. m_iComboHackCount += k;
  6417. if (m_iComboHackCount >= 10)
  6418. {
  6419. if (GetDesc())
  6420. if (GetDesc()->DelayedDisconnect(number(2, 7)))
  6421. {
  6422. sys_log(0, "COMBO_HACK_DISCONNECT: %s count: %d", GetName(), m_iComboHackCount);
  6423. LogManager::instance().HackLog("Combo", this);
  6424. }
  6425. }
  6426. }
  6427. void CHARACTER::ResetComboHackCount()
  6428. {
  6429. m_iComboHackCount = 0;
  6430. }
  6431. void CHARACTER::SkipComboAttackByTime(int interval)
  6432. {
  6433. m_dwSkipComboAttackByTime = get_dword_time() + interval;
  6434. }
  6435. DWORD CHARACTER::GetSkipComboAttackByTime() const
  6436. {
  6437. return m_dwSkipComboAttackByTime;
  6438. }
  6439. void CHARACTER::ResetChatCounter()
  6440. {
  6441. m_bChatCounter = 0;
  6442. }
  6443. BYTE CHARACTER::IncreaseChatCounter()
  6444. {
  6445. return ++m_bChatCounter;
  6446. }
  6447. BYTE CHARACTER::GetChatCounter() const
  6448. {
  6449. return m_bChatCounter;
  6450. }
  6451. bool CHARACTER::IsRiding() const
  6452. {
  6453. return IsHorseRiding() || GetMountVnum();
  6454. }
  6455. bool CHARACTER::CanWarp() const
  6456. {
  6457. const int iPulse = thecore_pulse();
  6458. const int limit_time = PASSES_PER_SEC(g_nPortalLimitTime);
  6459. if ((iPulse - GetSafeboxLoadTime()) < limit_time)
  6460. return false;
  6461. if ((iPulse - GetExchangeTime()) < limit_time)
  6462. return false;
  6463. if ((iPulse - GetMyShopTime()) < limit_time)
  6464. return false;
  6465. if ((iPulse - GetRefineTime()) < limit_time)
  6466. return false;
  6467. if (GetExchange() || GetMyShop() || GetShopOwner() || IsOpenSafebox() || IsCubeOpen() || GetOfflineShopOwner())
  6468. return false;
  6469. return true;
  6470. }
  6471. DWORD CHARACTER::GetNextExp() const
  6472. {
  6473. if (PLAYER_MAX_LEVEL_CONST < GetLevel())
  6474. return 2500000000u;
  6475. else
  6476. return exp_table[GetLevel()];
  6477. }
  6478. int CHARACTER::GetSkillPowerByLevel(int level, bool bMob) const
  6479. {
  6480. return CTableBySkill::instance().GetSkillPowerByLevelFromType(GetJob(), GetSkillGroup(), MINMAX(0, level, SKILL_MAX_LEVEL), bMob);
  6481. }
  6482. void CHARACTER::SetOfflineShopSign(const char * c_szSign)
  6483. {
  6484. char szSign[SHOP_SIGN_MAX_LEN + 1];
  6485. strlcpy(szSign, c_szSign, sizeof(szSign));
  6486. m_stOfflineShopSign = szSign;
  6487. }
  6488. void CHARACTER::DestroyOfflineShop()
  6489. {
  6490. DBManager::instance().DirectQuery("DELETE FROM %soffline_shop_npc WHERE owner_id = %u", get_table_postfix(), GetOfflineShopRealOwner());
  6491. LPOFFLINESHOP pkOfflineShop = GetOfflineShop();
  6492. if (pkOfflineShop)
  6493. pkOfflineShop->RemoveAllGuest();
  6494. M2_DESTROY_CHARACTER(this);
  6495. }
  6496. #ifdef __SASH_SYSTEM__
  6497. void CHARACTER::OpenSash(bool bCombination)
  6498. {
  6499. if (isSashOpened(bCombination))
  6500. {
  6501. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("The sash window it's already opened."));
  6502. return;
  6503. }
  6504. if (bCombination)
  6505. {
  6506. if (m_bSashAbsorption)
  6507. {
  6508. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Before you may close the sash absorption window."));
  6509. return;
  6510. }
  6511. m_bSashCombination = true;
  6512. }
  6513. else
  6514. {
  6515. if (m_bSashCombination)
  6516. {
  6517. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Before you may close the sash combine window."));
  6518. return;
  6519. }
  6520. m_bSashAbsorption = true;
  6521. }
  6522. TItemPos tPos;
  6523. tPos.window_type = INVENTORY;
  6524. tPos.cell = 0;
  6525. TPacketSash sPacket;
  6526. sPacket.header = HEADER_GC_SASH;
  6527. sPacket.subheader = SASH_SUBHEADER_GC_OPEN;
  6528. sPacket.bWindow = bCombination;
  6529. sPacket.dwPrice = 0;
  6530. sPacket.bPos = 0;
  6531. sPacket.tPos = tPos;
  6532. sPacket.dwItemVnum = 0;
  6533. sPacket.dwMinAbs = 0;
  6534. sPacket.dwMaxAbs = 0;
  6535. GetDesc()->Packet(&sPacket, sizeof(TPacketSash));
  6536. ClearSashMaterials();
  6537. }
  6538. void CHARACTER::CloseSash()
  6539. {
  6540. if ((!m_bSashCombination) && (!m_bSashAbsorption))
  6541. return;
  6542. bool bWindow = (m_bSashCombination == true ? true : false);
  6543. TItemPos tPos;
  6544. tPos.window_type = INVENTORY;
  6545. tPos.cell = 0;
  6546. TPacketSash sPacket;
  6547. sPacket.header = HEADER_GC_SASH;
  6548. sPacket.subheader = SASH_SUBHEADER_GC_CLOSE;
  6549. sPacket.bWindow = bWindow;
  6550. sPacket.dwPrice = 0;
  6551. sPacket.bPos = 0;
  6552. sPacket.tPos = tPos;
  6553. sPacket.dwItemVnum = 0;
  6554. sPacket.dwMinAbs = 0;
  6555. sPacket.dwMaxAbs = 0;
  6556. GetDesc()->Packet(&sPacket, sizeof(TPacketSash));
  6557. if (bWindow)
  6558. m_bSashCombination = false;
  6559. else
  6560. m_bSashAbsorption = false;
  6561. ClearSashMaterials();
  6562. }
  6563. void CHARACTER::ClearSashMaterials()
  6564. {
  6565. LPITEM * pkItemMaterial;
  6566. pkItemMaterial = GetSashMaterials();
  6567. for (int i = 0; i < SASH_WINDOW_MAX_MATERIALS; ++i)
  6568. {
  6569. if (!pkItemMaterial[i])
  6570. continue;
  6571. pkItemMaterial[i]->Lock(false);
  6572. pkItemMaterial[i] = NULL;
  6573. }
  6574. }
  6575. bool CHARACTER::SashIsSameGrade(long lGrade)
  6576. {
  6577. LPITEM * pkItemMaterial;
  6578. pkItemMaterial = GetSashMaterials();
  6579. if (!pkItemMaterial[0])
  6580. return false;
  6581. bool bReturn = (pkItemMaterial[0]->GetValue(SASH_GRADE_VALUE_FIELD) == lGrade ? true : false);
  6582. return bReturn;
  6583. }
  6584. DWORD CHARACTER::GetSashCombinePrice(long lGrade)
  6585. {
  6586. DWORD dwPrice = 0;
  6587. switch (lGrade)
  6588. {
  6589. case 2:
  6590. {
  6591. dwPrice = SASH_GRADE_2_PRICE;
  6592. }
  6593. break;
  6594. case 3:
  6595. {
  6596. dwPrice = SASH_GRADE_3_PRICE;
  6597. }
  6598. break;
  6599. case 4:
  6600. {
  6601. dwPrice = SASH_GRADE_4_PRICE;
  6602. }
  6603. break;
  6604. default:
  6605. {
  6606. dwPrice = SASH_GRADE_1_PRICE;
  6607. }
  6608. break;
  6609. }
  6610. return dwPrice;
  6611. }
  6612. BYTE CHARACTER::CheckEmptyMaterialSlot()
  6613. {
  6614. LPITEM * pkItemMaterial;
  6615. pkItemMaterial = GetSashMaterials();
  6616. for (int i = 0; i < SASH_WINDOW_MAX_MATERIALS; ++i)
  6617. {
  6618. if (!pkItemMaterial[i])
  6619. return i;
  6620. }
  6621. return 255;
  6622. }
  6623. void CHARACTER::GetSashCombineResult(DWORD & dwItemVnum, DWORD & dwMinAbs, DWORD & dwMaxAbs)
  6624. {
  6625. LPITEM * pkItemMaterial;
  6626. pkItemMaterial = GetSashMaterials();
  6627. if (m_bSashCombination)
  6628. {
  6629. if ((pkItemMaterial[0]) && (pkItemMaterial[1]))
  6630. {
  6631. long lVal = pkItemMaterial[0]->GetValue(SASH_GRADE_VALUE_FIELD);
  6632. if (lVal == 4)
  6633. {
  6634. dwItemVnum = pkItemMaterial[0]->GetOriginalVnum();
  6635. dwMinAbs = pkItemMaterial[0]->GetSocket(SASH_ABSORPTION_SOCKET);
  6636. DWORD dwMaxAbsCalc = (dwMinAbs + SASH_GRADE_4_ABS_RANGE > SASH_GRADE_4_ABS_MAX ? SASH_GRADE_4_ABS_MAX : (dwMinAbs + SASH_GRADE_4_ABS_RANGE));
  6637. dwMaxAbs = dwMaxAbsCalc;
  6638. }
  6639. else
  6640. {
  6641. DWORD dwMaskVnum = pkItemMaterial[0]->GetOriginalVnum();
  6642. TItemTable * pTable = ITEM_MANAGER::instance().GetTable(dwMaskVnum + 1);
  6643. if (pTable)
  6644. dwMaskVnum += 1;
  6645. dwItemVnum = dwMaskVnum;
  6646. switch (lVal)
  6647. {
  6648. case 2:
  6649. {
  6650. dwMinAbs = SASH_GRADE_3_ABS;
  6651. dwMaxAbs = SASH_GRADE_3_ABS;
  6652. }
  6653. break;
  6654. case 3:
  6655. {
  6656. dwMinAbs = SASH_GRADE_4_ABS_MIN;
  6657. dwMaxAbs = SASH_GRADE_4_ABS_MAX_COMB;
  6658. }
  6659. break;
  6660. default:
  6661. {
  6662. dwMinAbs = SASH_GRADE_2_ABS;
  6663. dwMaxAbs = SASH_GRADE_2_ABS;
  6664. }
  6665. break;
  6666. }
  6667. }
  6668. }
  6669. else
  6670. {
  6671. dwItemVnum = 0;
  6672. dwMinAbs = 0;
  6673. dwMaxAbs = 0;
  6674. }
  6675. }
  6676. else
  6677. {
  6678. if ((pkItemMaterial[0]) && (pkItemMaterial[1]))
  6679. {
  6680. dwItemVnum = pkItemMaterial[0]->GetOriginalVnum();
  6681. dwMinAbs = pkItemMaterial[0]->GetSocket(SASH_ABSORPTION_SOCKET);
  6682. dwMaxAbs = dwMinAbs;
  6683. }
  6684. else
  6685. {
  6686. dwItemVnum = 0;
  6687. dwMinAbs = 0;
  6688. dwMaxAbs = 0;
  6689. }
  6690. }
  6691. }
  6692. void CHARACTER::AddSashMaterial(TItemPos tPos, BYTE bPos)
  6693. {
  6694. if (bPos >= SASH_WINDOW_MAX_MATERIALS)
  6695. {
  6696. if (bPos == 255)
  6697. {
  6698. bPos = CheckEmptyMaterialSlot();
  6699. if (bPos >= SASH_WINDOW_MAX_MATERIALS)
  6700. return;
  6701. }
  6702. else
  6703. return;
  6704. }
  6705. LPITEM pkItem = GetItem(tPos);
  6706. if (!pkItem)
  6707. return;
  6708. else if ((pkItem->GetCell() >= INVENTORY_MAX_NUM) || (pkItem->IsEquipped()) || (tPos.IsBeltInventoryPosition()) || (pkItem->IsDragonSoul()))
  6709. return;
  6710. else if ((pkItem->GetType() != ITEM_COSTUME) && (m_bSashCombination))
  6711. return;
  6712. else if ((pkItem->GetType() != ITEM_COSTUME) && (bPos == 0) && (m_bSashAbsorption))
  6713. return;
  6714. else if (pkItem->isLocked())
  6715. {
  6716. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You can't add locked items."));
  6717. return;
  6718. }
  6719. #ifdef __SOULBINDING_SYSTEM__
  6720. else if ((pkItem->IsBind()) || (pkItem->IsUntilBind()))
  6721. {
  6722. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You can't add binded items."));
  6723. return;
  6724. }
  6725. #endif
  6726. else if ((m_bSashCombination) && (bPos == 1) && (!SashIsSameGrade(pkItem->GetValue(SASH_GRADE_VALUE_FIELD))))
  6727. {
  6728. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You can combine just sashes of same grade."));
  6729. return;
  6730. }
  6731. else if ((m_bSashCombination) && (pkItem->GetSocket(SASH_ABSORPTION_SOCKET) >= SASH_GRADE_4_ABS_MAX))
  6732. {
  6733. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("This sash got already maximum absorption chance."));
  6734. return;
  6735. }
  6736. else if ((bPos == 1) && (m_bSashAbsorption))
  6737. {
  6738. if ((pkItem->GetType() != ITEM_WEAPON) && (pkItem->GetType() != ITEM_ARMOR))
  6739. {
  6740. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You can absorb just the bonuses from armors and weapons."));
  6741. return;
  6742. }
  6743. else if ((pkItem->GetType() == ITEM_ARMOR) && (pkItem->GetSubType() != ARMOR_BODY))
  6744. {
  6745. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You can absorb just the bonuses from armors and weapons."));
  6746. return;
  6747. }
  6748. }
  6749. else if ((pkItem->GetSubType() != COSTUME_SASH) && (m_bSashCombination))
  6750. return;
  6751. else if ((pkItem->GetSubType() != COSTUME_SASH) && (bPos == 0) && (m_bSashAbsorption))
  6752. return;
  6753. else if ((pkItem->GetSocket(SASH_ABSORBED_SOCKET) > 0) && (bPos == 0) && (m_bSashAbsorption))
  6754. return;
  6755. LPITEM * pkItemMaterial;
  6756. pkItemMaterial = GetSashMaterials();
  6757. if ((bPos == 1) && (!pkItemMaterial[0]))
  6758. return;
  6759. if (pkItemMaterial[bPos])
  6760. return;
  6761. pkItemMaterial[bPos] = pkItem;
  6762. pkItemMaterial[bPos]->Lock(true);
  6763. DWORD dwItemVnum, dwMinAbs, dwMaxAbs;
  6764. GetSashCombineResult(dwItemVnum, dwMinAbs, dwMaxAbs);
  6765. TPacketSash sPacket;
  6766. sPacket.header = HEADER_GC_SASH;
  6767. sPacket.subheader = SASH_SUBHEADER_GC_ADDED;
  6768. sPacket.bWindow = m_bSashCombination == true ? true : false;
  6769. sPacket.dwPrice = GetSashCombinePrice(pkItem->GetValue(SASH_GRADE_VALUE_FIELD));
  6770. sPacket.bPos = bPos;
  6771. sPacket.tPos = tPos;
  6772. sPacket.dwItemVnum = dwItemVnum;
  6773. sPacket.dwMinAbs = dwMinAbs;
  6774. sPacket.dwMaxAbs = dwMaxAbs;
  6775. GetDesc()->Packet(&sPacket, sizeof(TPacketSash));
  6776. }
  6777. void CHARACTER::RemoveSashMaterial(BYTE bPos)
  6778. {
  6779. if (bPos >= SASH_WINDOW_MAX_MATERIALS)
  6780. return;
  6781. LPITEM * pkItemMaterial;
  6782. pkItemMaterial = GetSashMaterials();
  6783. DWORD dwPrice = 0;
  6784. if (bPos == 1)
  6785. {
  6786. if (pkItemMaterial[bPos])
  6787. {
  6788. pkItemMaterial[bPos]->Lock(false);
  6789. pkItemMaterial[bPos] = NULL;
  6790. }
  6791. if (pkItemMaterial[0])
  6792. dwPrice = GetSashCombinePrice(pkItemMaterial[0]->GetValue(SASH_GRADE_VALUE_FIELD));
  6793. }
  6794. else
  6795. ClearSashMaterials();
  6796. TItemPos tPos;
  6797. tPos.window_type = INVENTORY;
  6798. tPos.cell = 0;
  6799. TPacketSash sPacket;
  6800. sPacket.header = HEADER_GC_SASH;
  6801. sPacket.subheader = SASH_SUBHEADER_GC_REMOVED;
  6802. sPacket.bWindow = m_bSashCombination == true ? true : false;
  6803. sPacket.dwPrice = dwPrice;
  6804. sPacket.bPos = bPos;
  6805. sPacket.tPos = tPos;
  6806. sPacket.dwItemVnum = 0;
  6807. sPacket.dwMinAbs = 0;
  6808. sPacket.dwMaxAbs = 0;
  6809. GetDesc()->Packet(&sPacket, sizeof(TPacketSash));
  6810. }
  6811. BYTE CHARACTER::CanRefineSashMaterials()
  6812. {
  6813. BYTE bReturn = 0;
  6814. LPITEM * pkItemMaterial;
  6815. pkItemMaterial = GetSashMaterials();
  6816. if (m_bSashCombination)
  6817. {
  6818. for (int i = 0; i < SASH_WINDOW_MAX_MATERIALS; ++i)
  6819. {
  6820. if (pkItemMaterial[i])
  6821. {
  6822. if ((pkItemMaterial[i]->GetType() == ITEM_COSTUME) && (pkItemMaterial[i]->GetSubType() == COSTUME_SASH))
  6823. bReturn = 1;
  6824. else
  6825. {
  6826. bReturn = 0;
  6827. break;
  6828. }
  6829. }
  6830. else
  6831. {
  6832. bReturn = 0;
  6833. break;
  6834. }
  6835. }
  6836. }
  6837. else if (m_bSashAbsorption)
  6838. {
  6839. if ((pkItemMaterial[0]) && (pkItemMaterial[1]))
  6840. {
  6841. if ((pkItemMaterial[0]->GetType() == ITEM_COSTUME) && (pkItemMaterial[0]->GetSubType() == COSTUME_SASH))
  6842. bReturn = 2;
  6843. else
  6844. bReturn = 0;
  6845. if ((pkItemMaterial[1]->GetType() == ITEM_WEAPON) || ((pkItemMaterial[1]->GetType() == ITEM_ARMOR) && (pkItemMaterial[1]->GetSubType() == ARMOR_BODY)))
  6846. bReturn = 2;
  6847. else
  6848. bReturn = 0;
  6849. if (pkItemMaterial[0]->GetSocket(SASH_ABSORBED_SOCKET) > 0)
  6850. bReturn = 0;
  6851. }
  6852. else
  6853. bReturn = 0;
  6854. }
  6855. return bReturn;
  6856. }
  6857. void CHARACTER::RefineSashMaterials()
  6858. {
  6859. BYTE bCan = CanRefineSashMaterials();
  6860. if (bCan == 0)
  6861. return;
  6862. LPITEM * pkItemMaterial;
  6863. pkItemMaterial = GetSashMaterials();
  6864. DWORD dwItemVnum, dwMinAbs, dwMaxAbs;
  6865. GetSashCombineResult(dwItemVnum, dwMinAbs, dwMaxAbs);
  6866. int dwPrice = GetSashCombinePrice(pkItemMaterial[0]->GetValue(SASH_GRADE_VALUE_FIELD));
  6867. if (bCan == 1)
  6868. {
  6869. int iSuccessChance = 0;
  6870. long lVal = pkItemMaterial[0]->GetValue(SASH_GRADE_VALUE_FIELD);
  6871. switch (lVal)
  6872. {
  6873. case 2:
  6874. {
  6875. iSuccessChance = SASH_COMBINE_GRADE_2;
  6876. }
  6877. break;
  6878. case 3:
  6879. {
  6880. iSuccessChance = SASH_COMBINE_GRADE_3;
  6881. }
  6882. break;
  6883. case 4:
  6884. {
  6885. iSuccessChance = SASH_COMBINE_GRADE_4;
  6886. }
  6887. break;
  6888. default:
  6889. {
  6890. iSuccessChance = SASH_COMBINE_GRADE_1;
  6891. }
  6892. break;
  6893. }
  6894. if (GetGold() < dwPrice)
  6895. {
  6896. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You don't have enough Yang."));
  6897. return;
  6898. }
  6899. int iChance = number(1, 100);
  6900. bool bSucces = (iChance <= iSuccessChance ? true : false);
  6901. if (bSucces)
  6902. {
  6903. LPITEM pkItem = ITEM_MANAGER::instance().CreateItem(dwItemVnum, 1, 0, false);
  6904. if (!pkItem)
  6905. {
  6906. sys_err("%d can't be created.", dwItemVnum);
  6907. return;
  6908. }
  6909. ITEM_MANAGER::CopyAllAttrTo(pkItemMaterial[0], pkItem);
  6910. LogManager::instance().ItemLog(this, pkItem, "COMBINE SUCCESS", pkItem->GetName());
  6911. DWORD dwAbs = (dwMinAbs == dwMaxAbs ? dwMinAbs : number(dwMinAbs + 1, dwMaxAbs));
  6912. pkItem->SetSocket(SASH_ABSORPTION_SOCKET, dwAbs);
  6913. pkItem->SetSocket(SASH_ABSORBED_SOCKET, pkItemMaterial[0]->GetSocket(SASH_ABSORBED_SOCKET));
  6914. PointChange(POINT_GOLD, -dwPrice);
  6915. DBManager::instance().SendMoneyLog(MONEY_LOG_REFINE, pkItemMaterial[0]->GetVnum(), -dwPrice);
  6916. WORD wCell = pkItemMaterial[0]->GetCell();
  6917. ITEM_MANAGER::instance().RemoveItem(pkItemMaterial[0], "COMBINE (REFINE SUCCESS)");
  6918. ITEM_MANAGER::instance().RemoveItem(pkItemMaterial[1], "COMBINE (REFINE SUCCESS)");
  6919. pkItem->AddToCharacter(this, TItemPos(INVENTORY, wCell));
  6920. ITEM_MANAGER::instance().FlushDelayedSave(pkItem);
  6921. pkItem->AttrLog();
  6922. if (lVal == 4)
  6923. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("New absorption rate: %d%"), dwAbs);
  6924. else
  6925. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Success."));
  6926. EffectPacket(SE_EFFECT_SASH_SUCCEDED);
  6927. LogManager::instance().SashLog(GetPlayerID(), GetX(), GetY(), dwItemVnum, pkItem->GetID(), 1, dwAbs, 1);
  6928. ClearSashMaterials();
  6929. }
  6930. else
  6931. {
  6932. PointChange(POINT_GOLD, -dwPrice);
  6933. DBManager::instance().SendMoneyLog(MONEY_LOG_REFINE, pkItemMaterial[0]->GetVnum(), -dwPrice);
  6934. ITEM_MANAGER::instance().RemoveItem(pkItemMaterial[1], "COMBINE (REFINE FAIL)");
  6935. if (lVal == 4)
  6936. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("New absorption rate: %d%"), pkItemMaterial[0]->GetSocket(SASH_ABSORPTION_SOCKET));
  6937. else
  6938. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Failed."));
  6939. LogManager::instance().SashLog(GetPlayerID(), GetX(), GetY(), dwItemVnum, 0, 0, 0, 0);
  6940. pkItemMaterial[1] = NULL;
  6941. }
  6942. TItemPos tPos;
  6943. tPos.window_type = INVENTORY;
  6944. tPos.cell = 0;
  6945. TPacketSash sPacket;
  6946. sPacket.header = HEADER_GC_SASH;
  6947. sPacket.subheader = SASH_SUBHEADER_CG_REFINED;
  6948. sPacket.bWindow = m_bSashCombination == true ? true : false;
  6949. sPacket.dwPrice = dwPrice;
  6950. sPacket.bPos = 0;
  6951. sPacket.tPos = tPos;
  6952. sPacket.dwItemVnum = 0;
  6953. sPacket.dwMinAbs = 0;
  6954. if (bSucces)
  6955. sPacket.dwMaxAbs = 100;
  6956. else
  6957. sPacket.dwMaxAbs = 0;
  6958. GetDesc()->Packet(&sPacket, sizeof(TPacketSash));
  6959. }
  6960. else
  6961. {
  6962. pkItemMaterial[1]->CopyAttributeTo(pkItemMaterial[0]);
  6963. LogManager::instance().ItemLog(this, pkItemMaterial[0], "ABSORB (REFINE SUCCESS)", pkItemMaterial[0]->GetName());
  6964. pkItemMaterial[0]->SetSocket(SASH_ABSORBED_SOCKET, pkItemMaterial[1]->GetOriginalVnum());
  6965. for (int i = 0; i < ITEM_ATTRIBUTE_MAX_NUM; ++i)
  6966. {
  6967. if (pkItemMaterial[0]->GetAttributeValue(i) < 0)
  6968. pkItemMaterial[0]->SetForceAttribute(i, pkItemMaterial[0]->GetAttributeType(i), 0);
  6969. }
  6970. ITEM_MANAGER::instance().RemoveItem(pkItemMaterial[1], "ABSORBED (REFINE SUCCESS)");
  6971. ITEM_MANAGER::instance().FlushDelayedSave(pkItemMaterial[0]);
  6972. pkItemMaterial[0]->AttrLog();
  6973. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Success."));
  6974. #define ENABLE_SASH_EFFECT
  6975. #ifdef ENABLE_SASH_EFFECT
  6976. EffectPacket(SE_EFFECT_SASH_SUCCEDED);
  6977. #endif
  6978. ClearSashMaterials();
  6979. TItemPos tPos;
  6980. tPos.window_type = INVENTORY;
  6981. tPos.cell = 0;
  6982. TPacketSash sPacket;
  6983. sPacket.header = HEADER_GC_SASH;
  6984. sPacket.subheader = SASH_SUBHEADER_CG_REFINED;
  6985. sPacket.bWindow = m_bSashCombination == true ? true : false;
  6986. sPacket.dwPrice = dwPrice;
  6987. sPacket.bPos = 255;
  6988. sPacket.tPos = tPos;
  6989. sPacket.dwItemVnum = 0;
  6990. sPacket.dwMinAbs = 0;
  6991. sPacket.dwMaxAbs = 1;
  6992. GetDesc()->Packet(&sPacket, sizeof(TPacketSash));
  6993. }
  6994. }
  6995. bool CHARACTER::CleanSashAttr(LPITEM pkItem, LPITEM pkTarget)
  6996. {
  6997. if (!CanHandleItem())
  6998. return false;
  6999. else if ((!pkItem) || (!pkTarget))
  7000. return false;
  7001. else if ((pkTarget->GetType() != ITEM_COSTUME) && (pkTarget->GetSubType() != COSTUME_SASH))
  7002. return false;
  7003. if (pkTarget->GetSocket(SASH_ABSORBED_SOCKET) <= 0)
  7004. return false;
  7005. pkTarget->SetSocket(SASH_ABSORBED_SOCKET, 0);
  7006. for (int i = 0; i < ITEM_ATTRIBUTE_MAX_NUM; ++i)
  7007. pkTarget->SetForceAttribute(i, 0, 0);
  7008. pkItem->SetCount(pkItem->GetCount() - 1);
  7009. LogManager::instance().ItemLog(this, pkTarget, "USE_DETACHMENT (CLEAN ATTR)", pkTarget->GetName());
  7010. return true;
  7011. }
  7012. #endif
  7013. #ifdef __CHANGELOOK_SYSTEM__
  7014. void CHARACTER::ChangeLookWindow(bool bOpen, bool bRequest)
  7015. {
  7016. if ((bOpen) && (isChangeLookOpened()))
  7017. {
  7018. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[Transmutation] The window is already opened."));
  7019. return;
  7020. }
  7021. if ((!bOpen) && (!isChangeLookOpened()))
  7022. {
  7023. if (!bRequest)
  7024. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[Transmutation] The window is not opened."));
  7025. return;
  7026. }
  7027. TItemPos tPos;
  7028. tPos.window_type = INVENTORY;
  7029. tPos.cell = 0;
  7030. TPacketChangeLook sPacket;
  7031. sPacket.header = HEADER_GC_CL;
  7032. sPacket.subheader = CL_SUBHEADER_OPEN;
  7033. sPacket.subheader = bOpen == true ? CL_SUBHEADER_OPEN : CL_SUBHEADER_CLOSE;
  7034. sPacket.dwCost = bOpen == true ? CL_TRANSMUTATION_PRICE : 0;
  7035. sPacket.bPos = 0;
  7036. sPacket.tPos = tPos;
  7037. GetDesc()->Packet(&sPacket, sizeof(TPacketChangeLook));
  7038. m_bChangeLook = bOpen;
  7039. ClearClWindowMaterials();
  7040. }
  7041. void CHARACTER::ClearClWindowMaterials()
  7042. {
  7043. LPITEM * pkItemMaterial;
  7044. pkItemMaterial = GetClWindowMaterials();
  7045. for (int i = 0; i < CL_WINDOW_MAX_MATERIALS; ++i)
  7046. {
  7047. if (!pkItemMaterial[i])
  7048. continue;
  7049. pkItemMaterial[i]->Lock(false);
  7050. pkItemMaterial[i] = NULL;
  7051. }
  7052. }
  7053. BYTE CHARACTER::CheckClEmptyMaterialSlot()
  7054. {
  7055. LPITEM * pkItemMaterial;
  7056. pkItemMaterial = GetClWindowMaterials();
  7057. for (int i = 0; i < CL_WINDOW_MAX_MATERIALS; ++i)
  7058. {
  7059. if (!pkItemMaterial[i])
  7060. return i;
  7061. }
  7062. return 255;
  7063. }
  7064. void CHARACTER::AddClMaterial(TItemPos tPos, BYTE bPos)
  7065. {
  7066. if (!isChangeLookOpened())
  7067. return;
  7068. else if (bPos >= CL_WINDOW_MAX_MATERIALS)
  7069. {
  7070. if (bPos != 255)
  7071. return;
  7072. bPos = CheckClEmptyMaterialSlot();
  7073. if (bPos >= CL_WINDOW_MAX_MATERIALS)
  7074. return;
  7075. }
  7076. LPITEM pkItem = GetItem(tPos);
  7077. if (!pkItem)
  7078. return;
  7079. else if ((pkItem->GetCell() >= INVENTORY_MAX_NUM) || (tPos.IsBeltInventoryPosition()))
  7080. return;
  7081. else if (pkItem->IsEquipped())
  7082. {
  7083. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[Transmutation] You cannot transmute an item while it is equipped."));
  7084. return;
  7085. }
  7086. else if ((pkItem->GetType() != ITEM_WEAPON) && (pkItem->GetType() != ITEM_ARMOR) && (pkItem->GetType() != ITEM_COSTUME))
  7087. {
  7088. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[Transmutation] This item cannot be transmuted."));
  7089. return;
  7090. }
  7091. #ifdef __NEW_ARROW_SYSTEM__
  7092. else if ((pkItem->GetType() == ITEM_WEAPON) && ((pkItem->GetSubType() == WEAPON_ARROW) || (pkItem->GetSubType() == WEAPON_MOUNT_SPEAR) || (pkItem->GetSubType() == WEAPON_UNLIMITED_ARROW)))
  7093. #else
  7094. else if ((pkItem->GetType() == ITEM_WEAPON) && ((pkItem->GetSubType() == WEAPON_ARROW) || (pkItem->GetSubType() == WEAPON_MOUNT_SPEAR)))
  7095. #endif
  7096. {
  7097. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[Transmutation] This item cannot be transmuted."));
  7098. return;
  7099. }
  7100. else if ((pkItem->GetType() == ITEM_ARMOR) && (pkItem->GetSubType() != ARMOR_BODY))
  7101. {
  7102. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[Transmutation] This item cannot be transmuted."));
  7103. return;
  7104. }
  7105. #ifdef __WEAPON_COSTUME_SYSTEM__
  7106. else if ((pkItem->GetType() == ITEM_COSTUME) && (pkItem->GetSubType() != COSTUME_BODY) && (pkItem->GetSubType() != COSTUME_HAIR) && (pkItem->GetSubType() != COSTUME_WEAPON))
  7107. #else
  7108. else if ((pkItem->GetType() == ITEM_COSTUME) && (pkItem->GetSubType() != COSTUME_BODY) && (pkItem->GetSubType() != COSTUME_HAIR))
  7109. #endif
  7110. {
  7111. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[Transmutation] This item cannot be transmuted."));
  7112. return;
  7113. }
  7114. #ifdef __SOULBINDING_SYSTEM__
  7115. else if ((pkItem->IsBind()) || (pkItem->IsUntilBind()))
  7116. {
  7117. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[Transmutation] You can't add binded items."));
  7118. return;
  7119. }
  7120. #endif
  7121. else if (pkItem->isLocked())
  7122. {
  7123. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[Transmutation] You can't add locked items."));
  7124. return;
  7125. }
  7126. else if (pkItem->GetTransmutation() != 0)
  7127. {
  7128. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[Transmutation] You can't add items which are transmuted yet."));
  7129. return;
  7130. }
  7131. LPITEM * pkItemMaterial;
  7132. pkItemMaterial = GetClWindowMaterials();
  7133. if ((bPos == 1) && (!pkItemMaterial[0]))
  7134. return;
  7135. if (pkItemMaterial[bPos])
  7136. return;
  7137. if (bPos == 1)
  7138. {
  7139. bool bStop = false;
  7140. if (pkItemMaterial[0]->GetType() != pkItem->GetType())
  7141. bStop = true;
  7142. else if (pkItemMaterial[0]->GetSubType() != pkItem->GetSubType())
  7143. bStop = true;
  7144. else if (pkItemMaterial[0]->GetOriginalVnum() == pkItem->GetOriginalVnum())
  7145. bStop = true;
  7146. else if (((IS_SET(pkItemMaterial[0]->GetAntiFlag(), ITEM_ANTIFLAG_FEMALE)) && (!IS_SET(pkItem->GetAntiFlag(), ITEM_ANTIFLAG_FEMALE))) || ((IS_SET(pkItemMaterial[0]->GetAntiFlag(), ITEM_ANTIFLAG_MALE)) && (!IS_SET(pkItem->GetAntiFlag(), ITEM_ANTIFLAG_MALE))))
  7147. bStop = true;
  7148. else if ((pkItem->GetAntiFlag() & ITEM_ANTIFLAG_WARRIOR) && (!IS_SET(pkItemMaterial[0]->GetAntiFlag(), ITEM_ANTIFLAG_WARRIOR)))
  7149. bStop = true;
  7150. else if ((pkItem->GetAntiFlag() & ITEM_ANTIFLAG_ASSASSIN) && (!IS_SET(pkItemMaterial[0]->GetAntiFlag(), ITEM_ANTIFLAG_ASSASSIN)))
  7151. bStop = true;
  7152. else if ((pkItem->GetAntiFlag() & ITEM_ANTIFLAG_SHAMAN) && (!IS_SET(pkItemMaterial[0]->GetAntiFlag(), ITEM_ANTIFLAG_SHAMAN)))
  7153. bStop = true;
  7154. else if ((pkItem->GetAntiFlag() & ITEM_ANTIFLAG_SURA) && (!IS_SET(pkItemMaterial[0]->GetAntiFlag(), ITEM_ANTIFLAG_SURA)))
  7155. bStop = true;
  7156. #ifdef __WOLFMAN_CHARACTER__
  7157. else if ((pkItem->GetAntiFlag() & ITEM_ANTIFLAG_WOLFMAN) && (!IS_SET(pkItemMaterial[0]->GetAntiFlag(), ITEM_ANTIFLAG_WOLFMAN)))
  7158. bStop = true;
  7159. #endif
  7160. if (bStop)
  7161. {
  7162. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[Transmutation] You cannot submit this item."));
  7163. return;
  7164. }
  7165. }
  7166. pkItemMaterial[bPos] = pkItem;
  7167. pkItemMaterial[bPos]->Lock(true);
  7168. TPacketChangeLook sPacket;
  7169. sPacket.header = HEADER_GC_CL;
  7170. sPacket.subheader = CL_SUBHEADER_ADD;
  7171. sPacket.dwCost = 0;
  7172. sPacket.bPos = bPos;
  7173. sPacket.tPos = tPos;
  7174. GetDesc()->Packet(&sPacket, sizeof(TPacketChangeLook));
  7175. }
  7176. void CHARACTER::RemoveClMaterial(BYTE bPos)
  7177. {
  7178. if (bPos >= CL_WINDOW_MAX_MATERIALS)
  7179. return;
  7180. LPITEM * pkItemMaterial;
  7181. pkItemMaterial = GetClWindowMaterials();
  7182. if (!pkItemMaterial[bPos])
  7183. return;
  7184. if (bPos == 1)
  7185. {
  7186. pkItemMaterial[bPos]->Lock(false);
  7187. pkItemMaterial[bPos] = NULL;
  7188. }
  7189. else
  7190. ClearClWindowMaterials();
  7191. TItemPos tPos;
  7192. tPos.window_type = INVENTORY;
  7193. tPos.cell = 0;
  7194. TPacketChangeLook sPacket;
  7195. sPacket.header = HEADER_GC_CL;
  7196. sPacket.subheader = CL_SUBHEADER_REMOVE;
  7197. sPacket.dwCost = 0;
  7198. sPacket.bPos = bPos;
  7199. sPacket.tPos = tPos;
  7200. GetDesc()->Packet(&sPacket, sizeof(TPacketChangeLook));
  7201. }
  7202. void CHARACTER::RefineClMaterials()
  7203. {
  7204. LPITEM * pkItemMaterial;
  7205. pkItemMaterial = GetClWindowMaterials();
  7206. if (!pkItemMaterial[0])
  7207. return;
  7208. else if (!pkItemMaterial[1])
  7209. {
  7210. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[Transmutation] Please submit the item you want to transmute."));
  7211. return;
  7212. }
  7213. int dwPrice = CL_TRANSMUTATION_PRICE;
  7214. if (GetGold() < dwPrice)
  7215. {
  7216. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[Transmutation] You don't have enough Yang."));
  7217. return;
  7218. }
  7219. DWORD dwVnum = pkItemMaterial[1]->GetVnum();
  7220. PointChange(POINT_GOLD, -dwPrice);
  7221. DBManager::instance().SendMoneyLog(MONEY_LOG_REFINE, pkItemMaterial[0]->GetVnum(), -dwPrice);
  7222. ITEM_MANAGER::instance().RemoveItem(pkItemMaterial[1], "TRANSMUTED (SUCCESSFULLY)");
  7223. pkItemMaterial[0]->SetTransmutation(dwVnum, true);
  7224. ClearClWindowMaterials();
  7225. TItemPos tPos;
  7226. tPos.window_type = INVENTORY;
  7227. tPos.cell = 0;
  7228. TPacketChangeLook sPacket;
  7229. sPacket.header = HEADER_GC_CL;
  7230. sPacket.subheader = CL_SUBHEADER_REFINE;
  7231. sPacket.dwCost = 0;
  7232. sPacket.bPos = 0;
  7233. sPacket.tPos = tPos;
  7234. GetDesc()->Packet(&sPacket, sizeof(TPacketChangeLook));
  7235. }
  7236. bool CHARACTER::CleanTransmutation(LPITEM pkItem, LPITEM pkTarget)
  7237. {
  7238. if (!CanHandleItem())
  7239. return false;
  7240. else if ((!pkItem) || (!pkTarget))
  7241. return false;
  7242. else if ((pkTarget->GetType() != ITEM_WEAPON) && (pkTarget->GetType() != ITEM_ARMOR) && (pkTarget->GetType() != ITEM_COSTUME))
  7243. return false;
  7244. #ifdef __SOULBINDING_SYSTEM__
  7245. else if ((pkTarget->IsBind()) || (pkTarget->IsUntilBind()))
  7246. {
  7247. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You can't remove the transmute because item is binded."));
  7248. return false;
  7249. }
  7250. #endif
  7251. else if (pkTarget->isLocked())
  7252. {
  7253. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You can't remove the transmute because item is locked."));
  7254. return false;
  7255. }
  7256. if (pkTarget->GetTransmutation() == 0)
  7257. return false;
  7258. pkTarget->SetTransmutation(0);
  7259. pkItem->SetCount(pkItem->GetCount() - 1);
  7260. LogManager::instance().ItemLog(this, pkTarget, "USE_DETACHMENT (CLEAN TRANSMUTED)", pkTarget->GetName());
  7261. return true;
  7262. }
  7263. #endif

adad