From 0f79d890ba4860f2a29a0d006b9f96e931d06edc Mon Sep 17 00:00:00 2001 From: Mind Rapist Date: Sun, 14 Dec 2025 05:17:16 +0200 Subject: [PATCH] MRMJ-1: Messenger & Skills fixes --- .gitignore | 62 +++++ README.md | 33 +++ src/common/item_length.h | 3 +- src/common/length.h | 4 +- src/common/service.h | 11 + src/db/Cache.cpp | 4 +- src/db/ClientManager.cpp | 10 +- src/db/ClientManagerBoot.cpp | 12 +- src/db/ClientManagerEventFlag.cpp | 2 +- src/db/ClientManagerPlayer.cpp | 50 ++-- src/db/CsvReader.cpp | 2 +- src/db/DBManager.cpp | 13 +- src/db/GuildManager.cpp | 2 +- src/db/Monarch.cpp | 14 +- src/game/DragonSoul.cpp | 103 ++++++- src/game/MarkManager.cpp | 6 +- src/game/SpeedServer.cpp | 11 +- src/game/arena.cpp | 9 +- src/game/char.cpp | 31 +++ src/game/char.h | 14 + src/game/char_battle.cpp | 8 + src/game/char_item.cpp | 224 ++++++++------- src/game/char_manager.cpp | 2 +- src/game/char_skill.cpp | 117 +++++++- src/game/char_state.cpp | 53 ++++ src/game/cmd_general.cpp | 15 ++ src/game/cmd_gm.cpp | 98 ++++++- src/game/db.cpp | 13 +- src/game/input.h | 4 + src/game/input_login.cpp | 5 + src/game/input_main.cpp | 33 ++- src/game/input_p2p.cpp | 79 ++++++ src/game/item.cpp | 15 +- src/game/item_manager.cpp | 2 +- src/game/item_manager_read_tables.cpp | 11 +- src/game/messenger_manager.cpp | 374 +++++++++++++++++++++++++- src/game/messenger_manager.h | 39 ++- src/game/packet.h | 57 +++- src/game/packet_info.cpp | 5 + src/game/questlua_dungeon.cpp | 2 +- src/game/questlua_global.cpp | 6 +- src/game/shop_manager.cpp | 2 +- src/game/trigger.cpp | 5 +- src/game/utils.cpp | 6 +- src/liblua/src/llex.c | 2 +- src/liblua/src/llimits.h | 3 +- src/liblua/src/ltable.c | 2 +- src/liblua/src/ltable.h | 2 +- src/libthecore/main.cpp | 12 +- src/libthecore/main.h | 6 +- src/libthecore/signal.cpp | 8 +- src/qc/CMakeLists.txt | 4 +- src/qc/qc.cpp | 8 +- 53 files changed, 1387 insertions(+), 231 deletions(-) diff --git a/.gitignore b/.gitignore index 80a1eda..6b1448a 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,63 @@ ๏ปฟ/build/ + +# ======================================================= +# FULLY CASE-INSENSITIVE BACKUP EXCLUSIONS +# Matches all files and folders ending in: +# _BK, _BAK, .BK, .BAK (and all case permutations) +# ======================================================= + +# ------------------------------------------------------- +# 1. EXCLUSIONS ENDING IN .BK / _BK +# ------------------------------------------------------- + +# Files/Folders ending in _BK (e.g., File_Bk, Folder_bK) +*_BK +*_Bk +*_bK +*_bk + +# Files ending in .BK (e.g., File.BK, File.bK) +*.BK +*.Bk +*.bK +*.bk + +# Files ending in "double extension" .X.BK (e.g., File.txt.Bk) +*.*.BK +*.*.Bk +*.*.bK +*.*.bk + +# ------------------------------------------------------- +# 2. EXCLUSIONS ENDING IN .BAK / _BAK +# ------------------------------------------------------- + +# Files/Folders ending in _BAK (e.g., File_BAK, Folder_bak) +*_BAK +*_BAk +*_BaK +*_Bak +*_bAK +*_bAk +*_baK +*_bak + +# Files ending in .BAK (e.g., File.BAK, File.bak) +*.BAK +*.BAk +*.BaK +*.Bak +*.bAK +*.bAk +*.baK +*.bak + +# Files ending in "double extension" .X.BAK (e.g., File.txt.Bak) +*.*.BAK +*.*.BAk +*.*.BaK +*.*.Bak +*.*.bAK +*.*.bAk +*.*.baK +*.*.bak diff --git a/README.md b/README.md index 514d131..331b2e6 100644 --- a/README.md +++ b/README.md @@ -18,4 +18,37 @@ It builds as it is, without external dependencies. > > cmake --build . +--- + +## ๐Ÿ“‹ Changelog + +### ๐Ÿ› Bug Fixes +* **Login:** Fixed an issue where the login phase did not support the updated packet header `100` (`GC_MARK_LOGIN`). +* **Core Stability:** Implemented safeguards to prevent server cores from crashing (`core downer`) when a negative value is used in commands, such as `/m `. +* **Book reading in max level:** Reading skill books does not consume experience points anymore if the character has reached the maximum level (gets max level from game configuration, not a static number). +* **Character Selection:** Corrected the display of character stats and ensured gauge bars accurately reflect the character's stats during the selection phase. +* **Negative HP:** Ensured that a character's HP does not drop below 0 upon death. +* **CMakeLists for QC:** Target libraries link to `qc` (was `db`). + +### โฌ†๏ธ Feature Improvements +* **All compiler warnings for building in FreeBSD environments have been fixed** + * Types are synced in comparisons, dynamic string building and other functions and some definitions. + * Minor performance improvements noticed in start time after changing `libthecore`'s `virtuals` into `atomic`. + * More modern practices introduced in some parts of the codebase. +* **Messenger System:** + * **Cross-Channel/Core Friend Requests:** Implemented support for sending and processing friend requests across different channels and server cores. `ChatPacket` notification is functional if the recipient is not found after searching all channels/cores. + * **Live Status Updates:** Live updates for adding/removing friend for both parties. + * **Request Guarding:** Added extensive validation checks to prevent: + * Resending a request while a previous one is unanswered. + * Sending a request to a person who has already sent an active, unanswered request to the sender. + * Sending a friend request to an existing friend or to yourself. + * All guard mechanisms provide translated `ChatPacket` notification messages and function correctly across channels and cores. + * All pending friend requests are cleared on character disconnect (teleport, logout, kick, etc...). + * A new friend request cancels all previous unanswered ones for that target. +* **Skill Cooldowns and States:** + * **Level Reset Handling:** Skill cooldowns are now cleared upon a skill level reset or a skill-group reset. Works with `/setsk` setting horse skills levels to 0 as well. + * **Togglable Skills:** If a togglable skill is reset, it is automatically deactivated, and its active effect is immediately removed from the character. + * **Combo Skills:** Combo skill is automatically deactivate if its level is changed to 0 (`/setsk`). +* **.gitignore file:** Ignoring all files and directories ending in `_BAK` or `.BAK` (case-insensitive) + diff --git a/src/common/item_length.h b/src/common/item_length.h index 2de324f..d8d81a7 100644 --- a/src/common/item_length.h +++ b/src/common/item_length.h @@ -147,11 +147,12 @@ enum EDragonSoulStepTypes DRAGON_SOUL_STEP_HIGHEST, DRAGON_SOUL_STEP_MAX, }; + #define DRAGON_SOUL_STRENGTH_MAX 7 enum EDSInventoryMaxNum { - DRAGON_SOUL_INVENTORY_MAX_NUM = DS_SLOT_MAX * DRAGON_SOUL_GRADE_MAX * DRAGON_SOUL_BOX_SIZE, + DRAGON_SOUL_INVENTORY_MAX_NUM = static_cast(DS_SLOT_MAX) * static_cast(DRAGON_SOUL_GRADE_MAX) * DRAGON_SOUL_BOX_SIZE, }; enum EFishSubTypes diff --git a/src/common/length.h b/src/common/length.h index 126a84d..b83bf45 100644 --- a/src/common/length.h +++ b/src/common/length.h @@ -672,8 +672,8 @@ enum EDragonSoulRefineWindowSize enum EMisc2 { DRAGON_SOUL_EQUIP_SLOT_START = INVENTORY_MAX_NUM + WEAR_MAX_NUM, - DRAGON_SOUL_EQUIP_SLOT_END = DRAGON_SOUL_EQUIP_SLOT_START + (DS_SLOT_MAX * DRAGON_SOUL_DECK_MAX_NUM), - DRAGON_SOUL_EQUIP_RESERVED_SLOT_END = DRAGON_SOUL_EQUIP_SLOT_END + (DS_SLOT_MAX * DRAGON_SOUL_DECK_RESERVED_MAX_NUM), + DRAGON_SOUL_EQUIP_SLOT_END = DRAGON_SOUL_EQUIP_SLOT_START + (static_cast(DS_SLOT_MAX) * static_cast(DRAGON_SOUL_DECK_MAX_NUM)), + DRAGON_SOUL_EQUIP_RESERVED_SLOT_END = DRAGON_SOUL_EQUIP_SLOT_END + (static_cast(DS_SLOT_MAX) * static_cast(DRAGON_SOUL_DECK_RESERVED_MAX_NUM)), BELT_INVENTORY_SLOT_START = DRAGON_SOUL_EQUIP_RESERVED_SLOT_END, BELT_INVENTORY_SLOT_END = BELT_INVENTORY_SLOT_START + BELT_INVENTORY_SLOT_COUNT, diff --git a/src/common/service.h b/src/common/service.h index 2d85760..37df8a0 100644 --- a/src/common/service.h +++ b/src/common/service.h @@ -6,4 +6,15 @@ #define _IMPROVED_PACKET_ENCRYPTION_ // ํŒจํ‚ท ์•”ํ˜ธํ™” ๊ฐœ์„  #define __PET_SYSTEM__ #define __UDP_BLOCK__ + +#define FIX_HEADER_CG_MARK_LOGIN // Fix for syserr error header 100 (login phase does not handle this packet! header 100); +#define FIX_NEG_CMD_CORE_DOWNER // Fix core downer after negative command value (mobs, items, etc...) +#define FIX_NEG_HP // Fix negative HP value when dead +#define FIX_MESSENGER_ACTION_SYNC // Fix companion messenger updates when being deleted by a friend +#define CHAR_SELECT_STATS_IMPROVEMENT // Improve stats values in character select screen +#define CROSS_CHANNEL_FRIEND_REQUEST // Allow friend requests across different channels +#define FIX_REFRESH_SKILL_COOLDOWN // Fix cooldown display time on skill slots +#define FIX_BOOK_READING_FOR_MAX_LEVEL // Disable experience point deduction for reading a book when in max level +//#define FIX_POS_SYNC // Fix position synching between clients + #endif diff --git a/src/db/Cache.cpp b/src/db/Cache.cpp index da4d3be..f944b09 100644 --- a/src/db/Cache.cpp +++ b/src/db/Cache.cpp @@ -96,9 +96,9 @@ void CItemCache::OnFlush() { iLen += snprintf(szColumns + iLen, sizeof(szColumns) - iLen, ", socket0, socket1, socket2"); iValueLen += snprintf(szValues + iValueLen, sizeof(szValues) - iValueLen, - ", %lu, %lu, %lu", p->alSockets[0], p->alSockets[1], p->alSockets[2]); + ", %lu, %lu, %lu", static_cast(p->alSockets[0]), static_cast(p->alSockets[1]), static_cast(p->alSockets[2])); iUpdateLen += snprintf(szUpdate + iUpdateLen, sizeof(szUpdate) - iUpdateLen, - ", socket0=%lu, socket1=%lu, socket2=%lu", p->alSockets[0], p->alSockets[1], p->alSockets[2]); + ", socket0=%lu, socket1=%lu, socket2=%lu", static_cast(p->alSockets[0]), static_cast(p->alSockets[1]), static_cast(p->alSockets[2])); } if (isAttr) diff --git a/src/db/ClientManager.cpp b/src/db/ClientManager.cpp index 341a178..cc4e269 100644 --- a/src/db/ClientManager.cpp +++ b/src/db/ClientManager.cpp @@ -458,7 +458,7 @@ void CClientManager::QUERY_QUEST_SAVE(CPeer * pkPeer, TQuestTable * pTable, DWOR { snprintf(szQuery, sizeof(szQuery), "REPLACE INTO quest%s (dwPID, szName, szState, lValue) VALUES(%d, '%s', '%s', %ld)", - GetTablePostfix(), pTable->dwPID, pTable->szName, pTable->szState, pTable->lValue); + GetTablePostfix(), pTable->dwPID, pTable->szName, pTable->szState, static_cast(pTable->lValue)); } CDBManager::instance().ReturnQuery(szQuery, QID_QUEST_SAVE, pkPeer->GetHandle(), NULL); @@ -683,7 +683,7 @@ void CClientManager::RESULT_SAFEBOX_LOAD(CPeer * pkPeer, SQLMsg * msg) dwSkillVnum = m_vec_skillTable[dwSkillIdx].dwVnum; - if (!dwSkillVnum > 120) + if (dwSkillVnum > 120) continue; break; @@ -1297,9 +1297,9 @@ void CClientManager::QUERY_ITEM_SAVE(CPeer * pkPeer, const char * c_pData) p->pos, p->count, p->vnum, - p->alSockets[0], - p->alSockets[1], - p->alSockets[2], + static_cast(p->alSockets[0]), + static_cast(p->alSockets[1]), + static_cast(p->alSockets[2]), p->aAttr[0].bType, p->aAttr[0].sValue, p->aAttr[1].bType, p->aAttr[1].sValue, p->aAttr[2].bType, p->aAttr[2].sValue, diff --git a/src/db/ClientManagerBoot.cpp b/src/db/ClientManagerBoot.cpp index 8de79c5..2b9deae 100644 --- a/src/db/ClientManagerBoot.cpp +++ b/src/db/ClientManagerBoot.cpp @@ -347,6 +347,7 @@ bool CClientManager::InitializeMobTable() mob_table->dwDropItemVnum = tempTable->dwDropItemVnum; mob_table->dwResurrectionVnum = tempTable->dwResurrectionVnum; + for (int i = 0; i < MOB_ENCHANTS_MAX_NUM; ++i) mob_table->cEnchants[i] = tempTable->cEnchants[i]; @@ -357,7 +358,6 @@ bool CClientManager::InitializeMobTable() mob_table->dwSummonVnum = tempTable->dwSummonVnum; mob_table->dwDrainSP = tempTable->dwDrainSP; mob_table->dwPolymorphItemVnum = tempTable->dwPolymorphItemVnum; - mob_table->Skills[0].bLevel = tempTable->Skills[0].bLevel; mob_table->Skills[0].dwVnum = tempTable->Skills[0].dwVnum; @@ -400,20 +400,22 @@ bool CClientManager::InitializeMobTable() //ํŒŒ์ผ ๋‹ค์‹œ ์ฝ์–ด์˜ค๊ธฐ. test_data.Destroy(); isTestFile = true; - test_data; - if(!test_data.Load("mob_proto_test.txt",'\t')) + + if (!test_data.Load("mob_proto_test.txt",'\t')) { fprintf(stderr, "ํ…Œ์ŠคํŠธ ํŒŒ์ผ์ด ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋Œ€๋กœ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค.\n"); isTestFile = false; } - if(isTestFile) { + + if (isTestFile) { test_data.Next(); //์„ค๋ช… ๋กœ์šฐ ๋„˜์–ด๊ฐ€๊ธฐ. while (test_data.Next()) //ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ ๊ฐ๊ฐ์„ ํ›‘์–ด๋‚˜๊ฐ€๋ฉฐ,์ƒˆ๋กœ์šด ๊ฒƒ์„ ์ถ”๊ฐ€ํ•œ๋‹ค. { //์ค‘๋ณต๋˜๋Š” ๋ถ€๋ถ„์ด๋ฉด ๋„˜์–ด๊ฐ„๋‹ค. set::iterator itVnum; - itVnum=vnumSet.find(atoi(test_data.AsStringByIndex(0))); + itVnum = vnumSet.find(atoi(test_data.AsStringByIndex(0))); + if (itVnum != vnumSet.end()) { continue; } diff --git a/src/db/ClientManagerEventFlag.cpp b/src/db/ClientManagerEventFlag.cpp index e92578c..8d9e54b 100644 --- a/src/db/ClientManagerEventFlag.cpp +++ b/src/db/ClientManagerEventFlag.cpp @@ -51,7 +51,7 @@ void CClientManager::SetEventFlag(TPacketSetEventFlag* p) char szQuery[1024]; snprintf(szQuery, sizeof(szQuery), "REPLACE INTO quest%s (dwPID, szName, szState, lValue) VALUES(0, '%s', '', %ld)", - GetTablePostfix(), p->szFlagName, p->lValue); + GetTablePostfix(), p->szFlagName, static_cast(p->lValue)); szQuery[1023] = '\0'; //CDBManager::instance().ReturnQuery(szQuery, QID_QUEST_SAVE, 0, NULL); diff --git a/src/db/ClientManagerPlayer.cpp b/src/db/ClientManagerPlayer.cpp index 7728cda..cdb6017 100644 --- a/src/db/ClientManagerPlayer.cpp +++ b/src/db/ClientManagerPlayer.cpp @@ -1,4 +1,4 @@ - +๏ปฟ #include "stdafx.h" #include "ClientManager.h" @@ -126,9 +126,9 @@ size_t CreatePlayerSaveQuery(char * pszQuery, size_t querySize, TPlayerTable * p pkTab->y, pkTab->z, pkTab->lMapIndex, - pkTab->lExitX, - pkTab->lExitY, - pkTab->lExitMapIndex, + static_cast(pkTab->lExitX), + static_cast(pkTab->lExitY), + static_cast(pkTab->lExitMapIndex), pkTab->hp, pkTab->sp, pkTab->stamina, @@ -151,7 +151,7 @@ size_t CreatePlayerSaveQuery(char * pszQuery, size_t querySize, TPlayerTable * p pkTab->parts[PART_MAIN], pkTab->parts[PART_HAIR], pkTab->skill_group, - pkTab->lAlignment, + static_cast(pkTab->lAlignment), pkTab->horse.bLevel, pkTab->horse.bRiding, pkTab->horse.sHealth, @@ -414,28 +414,34 @@ void CClientManager::ItemAward(CPeer * peer,char* login) TItemAward * pItemAward = *(it++); char* whyStr = pItemAward->szWhy; //why ์ฝœ๋ฃธ ์ฝ๊ธฐ char cmdStr[100] = ""; //why์ฝœ๋ฃธ์—์„œ ์ฝ์€ ๊ฐ’์„ ์ž„์‹œ ๋ฌธ์ž์—ด์— ๋ณต์‚ฌํ•ด๋‘  - strcpy(cmdStr,whyStr); //๋ช…๋ น์–ด ์–ป๋Š” ๊ณผ์ •์—์„œ ํ† ํฐ์“ฐ๋ฉด ์›๋ณธ๋„ ํ† ํฐํ™” ๋˜๊ธฐ ๋•Œ๋ฌธ + strcpy(cmdStr, whyStr); //๋ช…๋ น์–ด ์–ป๋Š” ๊ณผ์ •์—์„œ ํ† ํฐ์“ฐ๋ฉด ์›๋ณธ๋„ ํ† ํฐํ™” ๋˜๊ธฐ ๋•Œ๋ฌธ + char command[20] = ""; - strcpy(command,GetCommand(cmdStr)); // command ์–ป๊ธฐ - if( !(strcmp(command,"GIFT") )) // command ๊ฐ€ GIFT์ด๋ฉด + strcpy(command,GetCommand(cmdStr)); // command ์–ป๊ธฐ + + if (!(strcmp(command,"GIFT"))) // command ๊ฐ€ GIFT์ด๋ฉด { TPacketItemAwardInfromer giftData; strcpy(giftData.login, pItemAward->szLogin); //๋กœ๊ทธ์ธ ์•„์ด๋”” ๋ณต์‚ฌ strcpy(giftData.command, command); //๋ช…๋ น์–ด ๋ณต์‚ฌ giftData.vnum = pItemAward->dwVnum; //์•„์ดํ…œ vnum๋„ ๋ณต์‚ฌ - ForwardPacket(HEADER_DG_ITEMAWARD_INFORMER,&giftData,sizeof(TPacketItemAwardInfromer)); + ForwardPacket(HEADER_DG_ITEMAWARD_INFORMER, &giftData, sizeof(TPacketItemAwardInfromer)); } } } char* CClientManager::GetCommand(char* str) { - char command[20] = ""; + static char command[20] = ""; char* tok; - if( str[0] == '[' ) + if (str[0] == '[') { - tok = strtok(str,"]"); - strcat(command,&tok[1]); + tok = strtok(str, "]"); + strlcpy(command, &tok[1], sizeof(command)); + } + else + { + command[0] = '\0'; } return command; @@ -579,12 +585,15 @@ void CClientManager::RESULT_COMPOSITE_PLAYER(CPeer * peer, SQLMsg * pMsg, DWORD if (temp1 == NULL) break; - CLoginData* pLoginData1 = GetLoginDataByAID(temp1->account_id); // + CLoginData* pLoginData1 = GetLoginDataByAID(temp1->account_id); + + if (pLoginData1 == NULL) + break; + //๋…์ผ ์„ ๋ฌผ ๊ธฐ๋Šฅ - if( pLoginData1->GetAccountRef().login == NULL) - break; - if( pLoginData1 == NULL ) + if (pLoginData1->GetAccountRef().login[0] == '\0') break; + sys_log(0,"info of pLoginData1 before call ItemAwardfunction %d",pLoginData1); ItemAward(peer,pLoginData1->GetAccountRef().login); } @@ -893,7 +902,6 @@ void CClientManager::__QUERY_PLAYER_CREATE(CPeer *peer, DWORD dwHandle, TPlayerC packet->player_table.ht, packet->player_table.job); - //tw1x1: Buffer overflow (14.11.2025 / 21:08 GMT) static char text[8192 + 1]; CDBManager::instance().EscapeString(text, packet->player_table.skills, sizeof(packet->player_table.skills)); @@ -1191,10 +1199,10 @@ void CClientManager::QUERY_ADD_AFFECT(CPeer * peer, TPacketGDAddAffect * p) p->dwPID, p->elem.dwType, p->elem.bApplyOn, - p->elem.lApplyValue, + static_cast(p->elem.lApplyValue), p->elem.dwFlag, - p->elem.lDuration, - p->elem.lSPCost); + static_cast(p->elem.lDuration), + static_cast(p->elem.lSPCost)); CDBManager::instance().AsyncQuery(queryStr); } diff --git a/src/db/CsvReader.cpp b/src/db/CsvReader.cpp index c63d523..a019f21 100644 --- a/src/db/CsvReader.cpp +++ b/src/db/CsvReader.cpp @@ -6,7 +6,7 @@ #ifndef Assert #include #define Assert assert - #define LogToFile (void)(0); + #define LogToFile(...) ((void)0) #endif namespace diff --git a/src/db/DBManager.cpp b/src/db/DBManager.cpp index 33ff638..ad43076 100644 --- a/src/db/DBManager.cpp +++ b/src/db/DBManager.cpp @@ -128,7 +128,18 @@ int CDBManager::Connect(int iSlot, const char * db_address, const int db_port, c SQLMsg * CDBManager::DirectQuery(const char * c_pszQuery, int iSlot) { - return m_directSQL[iSlot]->DirectQuery(c_pszQuery); + //return m_directSQL[iSlot]->DirectQuery(c_pszQuery); + + // DirectQuery LPHeart debuging trace 15/11/2015 06:38AM GMT + DWORD t = get_dword_time(); + SQLMsg* p = m_directSQL[iSlot]->DirectQuery(c_pszQuery); + DWORD dt = get_dword_time() - t; + + if (dt > 200) { + sys_err("[SLOW-DB] DirectQuery(%d) took %u ms: %s", iSlot, dt, c_pszQuery); + } + + return p; } extern CPacketInfo g_query_info; diff --git a/src/db/GuildManager.cpp b/src/db/GuildManager.cpp index 6c91545..d8c6a7f 100644 --- a/src/db/GuildManager.cpp +++ b/src/db/GuildManager.cpp @@ -1063,7 +1063,7 @@ bool CGuildManager::ReserveWar(TPacketGuildWar * p) snprintf(szQuery, sizeof(szQuery), "INSERT INTO guild_war_reservation (guild1, guild2, time, type, warprice, initscore, power1, power2, handicap) " "VALUES(%u, %u, DATE_ADD(NOW(), INTERVAL 180 SECOND), %u, %ld, %ld, %ld, %ld, %ld)", - GID1, GID2, p->bType, p->lWarPrice, p->lInitialScore, t.lPowerFrom, t.lPowerTo, t.lHandicap); + GID1, GID2, p->bType, static_cast(p->lWarPrice), static_cast(p->lInitialScore), static_cast(t.lPowerFrom), static_cast(t.lPowerTo), static_cast(t.lHandicap)); std::unique_ptr pmsg(CDBManager::instance().DirectQuery(szQuery)); diff --git a/src/db/Monarch.cpp b/src/db/Monarch.cpp index 5112e75..8147e26 100644 --- a/src/db/Monarch.cpp +++ b/src/db/Monarch.cpp @@ -129,7 +129,7 @@ bool CMonarch::AddMoney(int Empire, int64_t Money) int64_t Money64 = m_MonarchInfo.money[Empire]; char szQuery[1024]; - snprintf(szQuery, sizeof(szQuery), "UPDATE monarch set money=%lld where empire=%d", Money64, Empire); + snprintf(szQuery, sizeof(szQuery), "UPDATE monarch set money=%lld where empire=%d", static_cast(Money64), Empire); CDBManager::instance().AsyncQuery(szQuery); @@ -145,7 +145,7 @@ bool CMonarch::DecMoney(int Empire, int64_t Money) int64_t Money64 = m_MonarchInfo.money[Empire]; char szQuery[1024]; - snprintf(szQuery, sizeof(szQuery), "UPDATE monarch set money=%lld where empire=%d", Money64, Empire); + snprintf(szQuery, sizeof(szQuery), "UPDATE monarch set money=%lld where empire=%d", static_cast(Money64), Empire); CDBManager::instance().AsyncQuery(szQuery); return true; @@ -163,12 +163,12 @@ bool CMonarch::TakeMoney(int Empire, DWORD pid, int64_t Money) char szQuery[1024]; snprintf(szQuery, sizeof(szQuery), - "UPDATE monarch set money=%lld; where empire=%d", m_MonarchInfo.money[Empire], Empire); + "UPDATE monarch set money=%lld where empire=%d", static_cast(m_MonarchInfo.money[Empire]), Empire); CDBManager::instance().AsyncQuery(szQuery); if (g_test_server) - sys_log(0, "[MONARCH] Take money empire(%d) money(%lld)", Empire, m_MonarchInfo.money[Empire]); + sys_log(0, "[MONARCH] Take money empire(%d) money(%lld)", Empire, static_cast(m_MonarchInfo.money[Empire])); return true; } @@ -198,7 +198,7 @@ bool CMonarch::LoadMonarch() strlcpy(p->date[Empire], row[idx++], sizeof(p->date[Empire])); if (g_test_server) - sys_log(0, "[LOAD_MONARCH] Empire %d pid %d money %lld windate %s", Empire, p->pid[Empire], p->money[Empire], p->date[Empire]); + sys_log(0, "[LOAD_MONARCH] Empire %d pid %d money %lld windate %s", Empire, p->pid[Empire], static_cast(p->money[Empire]), p->date[Empire]); } delete pMsg; @@ -231,13 +231,13 @@ bool CMonarch::SetMonarch(const char * name) p->money[Empire] = atoll(row[idx++]); if (g_test_server) - sys_log(0, "[Set_MONARCH] Empire %d pid %d money %lld windate %s", Empire, p->pid[Empire], p->money[Empire], p->date[Empire]); + sys_log(0, "[Set_MONARCH] Empire %d pid %d money %lld windate %s", Empire, p->pid[Empire], static_cast(p->money[Empire]), p->date[Empire]); } delete pMsg; //dbยฟยก ร€ร”ยทร‚ snprintf(szQuery, sizeof(szQuery), - "REPLACE INTO monarch (empire, name, windate, money) VALUES(%d, %d, now(), %lld)", Empire, p->pid[Empire], p->money[Empire]); + "REPLACE INTO monarch (empire, name, windate, money) VALUES(%d, %d, now(), %lld)", Empire, p->pid[Empire], static_cast(p->money[Empire])); CDBManager::instance().AsyncQuery(szQuery, SQL_PLAYER); return true; diff --git a/src/game/DragonSoul.cpp b/src/game/DragonSoul.cpp index f326132..272472f 100644 --- a/src/game/DragonSoul.cpp +++ b/src/game/DragonSoul.cpp @@ -48,27 +48,33 @@ bool MakeDistinctRandomNumberSet(std::list prob_lst, OUT std::vector::iterator it = prob_lst.begin(); it != prob_lst.end(); it++) { range += *it; } + float r = fnumber (0.f, range); float sum = 0.f; int idx = 0; + for (std::list ::iterator it = prob_lst.begin(); it != prob_lst.end(); it++) { while (select_bit[idx++]); sum += *it; + if (sum >= r) { select_bit[idx - 1] = 1; random_set[i] = idx - 1; prob_lst.erase(it); + break; } } } + return true; } @@ -119,6 +125,7 @@ bool DSManager::IsValidCellForThisItem(const LPITEM pItem, const TItemPos& Cell) return false; WORD wBaseCell = GetBasePosition(pItem); + if (WORD_MAX == wBaseCell) return false; @@ -142,6 +149,7 @@ WORD DSManager::GetBasePosition(const LPITEM pItem) const BYTE col_type = pItem->GetSubType(); BYTE row_type = grade_idx; + if (row_type > DRAGON_SOUL_GRADE_MAX) return WORD_MAX; @@ -176,6 +184,7 @@ bool DSManager::RefreshItemAttributes(LPITEM pDS) // add_min๊ณผ add_max๋Š” ๋”๋ฏธ๋กœ ์ฝ์Œ. int basic_apply_num, add_min, add_max; + if (!m_pTable->GetApplyNumSettings(ds_type, grade_idx, basic_apply_num, add_min, add_max)) { sys_err ("In ApplyNumSettings, INVALID VALUES Group type(%d), GRADE idx(%d)", ds_type, grade_idx); @@ -183,13 +192,16 @@ bool DSManager::RefreshItemAttributes(LPITEM pDS) } float fWeight = 0.f; + if (!m_pTable->GetWeight(ds_type, grade_idx, step_idx, strength_idx, fWeight)) { return false; } + fWeight /= 100.f; int n = MIN(basic_apply_num, vec_basic_applys.size()); + for (int i = 0; i < n; i++) { const SApply& basic_apply = vec_basic_applys[i]; @@ -203,8 +215,10 @@ bool DSManager::RefreshItemAttributes(LPITEM pDS) { BYTE bType = pDS->GetAttributeType(i); short sValue = 0; + if (APPLY_NONE == bType) continue; + for (int j = 0; j < vec_addtional_applys.size(); j++) { if (vec_addtional_applys[j].apply_type == bType) @@ -213,6 +227,7 @@ bool DSManager::RefreshItemAttributes(LPITEM pDS) break; } } + pDS->SetForceAttribute(i, bType, (short)(ceil((float)sValue * fWeight - 0.01f))); } return true; @@ -237,6 +252,7 @@ bool DSManager::PutAttributes(LPITEM pDS) sys_err ("There is no BasicApply about %d type dragon soul.", ds_type); return false; } + if (!m_pTable->GetAdditionalApplys(ds_type, vec_addtional_applys)) { sys_err ("There is no AdditionalApply about %d type dragon soul.", ds_type); @@ -245,6 +261,7 @@ bool DSManager::PutAttributes(LPITEM pDS) int basic_apply_num, add_min, add_max; + if (!m_pTable->GetApplyNumSettings(ds_type, grade_idx, basic_apply_num, add_min, add_max)) { sys_err ("In ApplyNumSettings, INVALID VALUES Group type(%d), GRADE idx(%d)", ds_type, grade_idx); @@ -252,13 +269,16 @@ bool DSManager::PutAttributes(LPITEM pDS) } float fWeight = 0.f; + if (!m_pTable->GetWeight(ds_type, grade_idx, step_idx, strength_idx, fWeight)) { return false; } + fWeight /= 100.f; int n = MIN(basic_apply_num, vec_basic_applys.size()); + for (int i = 0; i < n; i++) { const SApply& basic_apply = vec_basic_applys[i]; @@ -275,10 +295,12 @@ bool DSManager::PutAttributes(LPITEM pDS) { random_set.resize(additional_attr_num); std::list list_probs; + for (int i = 0; i < vec_addtional_applys.size(); i++) { list_probs.push_back(vec_addtional_applys[i].prob); } + if (!MakeDistinctRandomNumberSet(list_probs, random_set)) { sys_err ("MakeDistinctRandomNumberSet error."); @@ -303,10 +325,13 @@ bool DSManager::DragonSoulItemInitialize(LPITEM pItem) { if (NULL == pItem || !pItem->IsDragonSoul()) return false; + PutAttributes(pItem); int time = DSManager::instance().GetDuration(pItem); + if (time > 0) pItem->SetSocket(ITEM_SOCKET_REMAIN_SEC, time); + return true; } @@ -325,6 +350,7 @@ bool DSManager::ExtractDragonHeart(LPCHARACTER ch, LPITEM pItem, LPITEM pExtract { if (NULL == ch || NULL == pItem) return false; + if (pItem->IsEquipped()) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("์ฐฉ์šฉ ์ค‘์ธ ์šฉํ˜ผ์„์€ ์ถ”์ถœํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")); @@ -353,6 +379,7 @@ bool DSManager::ExtractDragonHeart(LPCHARACTER ch, LPITEM pItem, LPITEM pExtract int idx = Gamble(vec_probs); float sum = 0.f; + if (-1 == idx) { sys_err ("Gamble is failed. ds_type(%d), grade_idx(%d)", ds_type, grade_idx); @@ -365,13 +392,16 @@ bool DSManager::ExtractDragonHeart(LPCHARACTER ch, LPITEM pItem, LPITEM pExtract if (fCharge < FLT_EPSILON) { pItem->SetCount(pItem->GetCount() - 1); + if (NULL != pExtractor) { pExtractor->SetCount(pExtractor->GetCount() - 1); } + LogManager::instance().ItemLog(ch, pItem, "DS_HEART_EXTRACT_FAIL", ""); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("์šฉ์‹ฌ ์ถ”์ถœ์— ์‹คํŒจํ•˜์˜€์Šต๋‹ˆ๋‹ค.")); + return false; } else @@ -386,6 +416,7 @@ bool DSManager::ExtractDragonHeart(LPCHARACTER ch, LPITEM pItem, LPITEM pExtract } pItem->SetCount(pItem->GetCount() - 1); + if (NULL != pExtractor) { pExtractor->SetCount(pExtractor->GetCount() - 1); @@ -397,8 +428,10 @@ bool DSManager::ExtractDragonHeart(LPCHARACTER ch, LPITEM pItem, LPITEM pExtract std::string s = std::to_string(iCharge); s += "%s"; + LogManager::instance().ItemLog(ch, pItem, "DS_HEART_EXTRACT_SUCCESS", s.c_str()); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("์šฉ์‹ฌ ์ถ”์ถœ์— ์„ฑ๊ณตํ•˜์˜€์Šต๋‹ˆ๋‹ค.")); + return true; } } @@ -416,6 +449,7 @@ bool DSManager::PullOut(LPCHARACTER ch, TItemPos DestCell, LPITEM& pItem, LPITEM if (!IsValidCellForThisItem(pItem, DestCell)) { int iEmptyCell = ch->GetEmptyDragonSoulInventory(pItem); + if (iEmptyCell < 0) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("์†Œ์ง€ํ’ˆ์— ๋นˆ ๊ณต๊ฐ„์ด ์—†์Šต๋‹ˆ๋‹ค.")); @@ -456,6 +490,7 @@ bool DSManager::PullOut(LPCHARACTER ch, TItemPos DestCell, LPITEM& pItem, LPITEM iBonus = pExtractor->GetValue(ITEM_VALUE_DRAGON_SOUL_POLL_OUT_BONUS_IDX); pExtractor->SetCount(pExtractor->GetCount() - 1); } + fDice = fnumber(0.f, 100.f); bSuccess = fDice <= (fProb * (100 + iBonus) / 100.f); } @@ -472,11 +507,13 @@ bool DSManager::PullOut(LPCHARACTER ch, TItemPos DestCell, LPITEM& pItem, LPITEM } else { - sprintf(buf, "dice(%d) prob(%d)", fDice, fProb); + sprintf(buf, "dice(%d) prob(%d)", (int)fDice, (int)fProb); } + LogManager::instance().ItemLog(ch, pItem, "DS_PULL_OUT_SUCCESS", buf); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("์šฉํ˜ผ์„ ์ถ”์ถœ์— ์„ฑ๊ณตํ•˜์˜€์Šต๋‹ˆ๋‹ค.")); pItem->AddToCharacter(ch, DestCell); + return true; } else @@ -489,9 +526,11 @@ bool DSManager::PullOut(LPCHARACTER ch, TItemPos DestCell, LPITEM& pItem, LPITEM { sprintf(buf, "dice(%d) prob(%d) ByProd(VNUM:%d)", (int)fDice, (int)fProb, dwByProduct); } + LogManager::instance().ItemLog(ch, pItem, "DS_PULL_OUT_FAILED", buf); M2_DESTROY_ITEM(pItem); pItem = NULL; + if (dwByProduct) { LPITEM pByProduct = ch->AutoGiveItem(dwByProduct, true); @@ -521,18 +560,22 @@ bool DSManager::DoRefineGrade(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL if (!ch->DragonSoul_RefineWindow_CanRefine()) { sys_err ("%s do not activate DragonSoulRefineWindow. But how can he come here?", ch->GetName()); - ch->ChatPacket(CHAT_TYPE_INFO, "[SYSTEM ERROR]You cannot upgrade dragon soul without refine window."); + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[SYSTEM ERROR]You cannot upgrade dragon soul grade without refine window.")); + return false; } // ํ˜น์‹œ๋‚˜ ๋ชจ๋ฅผ ์ค‘๋ณต๋˜๋Š” item pointer ์—†์• ๊ธฐ ์œ„ํ•ด์„œ set ์‚ฌ์šฉ // ์ด์ƒํ•œ ํŒจํ‚ท์„ ๋ณด๋‚ผ ๊ฒฝ์šฐ, ์ค‘๋ณต๋œ TItemPos๊ฐ€ ์žˆ์„ ์ˆ˜๋„ ์žˆ๊ณ , ์ž˜๋ชป๋œ TItemPos๊ฐ€ ์žˆ์„ ์ˆ˜๋„ ์žˆ๋‹ค. std::set set_items; + for (int i = 0; i < DRAGON_SOUL_REFINE_GRID_SIZE; i++) { if (aItemPoses[i].IsEquipPosition()) return false; + LPITEM pItem = ch->GetItem(aItemPoses[i]); + if (NULL != pItem) { // ์šฉํ˜ผ์„์ด ์•„๋‹Œ ์•„์ดํ…œ์ด ๊ฐœ๋Ÿ‰์ฐฝ์— ์žˆ์„ ์ˆ˜ ์—†๋‹ค. @@ -604,6 +647,7 @@ bool DSManager::DoRefineGrade(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL sys_err ("Possiblity of invalid client. Name %s", ch->GetName()); BYTE bSubHeader = count < need_count? DS_SUB_HEADER_REFINE_FAIL_NOT_ENOUGH_MATERIAL : DS_SUB_HEADER_REFINE_FAIL_TOO_MUCH_MATERIAL; SendRefineResultPacket(ch, bSubHeader, NPOS); + return false; } @@ -611,6 +655,7 @@ bool DSManager::DoRefineGrade(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("๊ฐœ๋Ÿ‰์„ ํ•˜๊ธฐ ์œ„ํ•œ ๋ˆ์ด ๋ถ€์กฑํ•ฉ๋‹ˆ๋‹ค.")); SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_NOT_ENOUGH_MONEY, NPOS); + return false; } @@ -635,6 +680,7 @@ bool DSManager::DoRefineGrade(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL { LPITEM pItem = *it; int n = pItem->GetCount(); + if (left_count > n) { pItem->RemoveFromCharacter(); @@ -656,6 +702,7 @@ bool DSManager::DoRefineGrade(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL LogManager::instance().ItemLog(ch, pResultItem, "DS_GRADE_REFINE_SUCCESS", buf); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("๋“ฑ๊ธ‰ ๊ฐœ๋Ÿ‰์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค.")); SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_SUCCEED, TItemPos (pResultItem->GetWindow(), pResultItem->GetCell())); + return true; } else @@ -665,6 +712,7 @@ bool DSManager::DoRefineGrade(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL LogManager::instance().ItemLog(ch, pResultItem, "DS_GRADE_REFINE_FAIL", buf); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("๋“ฑ๊ธ‰ ๊ฐœ๋Ÿ‰์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค.")); SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL, TItemPos (pResultItem->GetWindow(), pResultItem->GetCell())); + return false; } } @@ -673,6 +721,7 @@ bool DSManager::DoRefineStep(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_ { if (NULL == ch) return false; + if (NULL == aItemPoses) { return false; @@ -681,16 +730,19 @@ bool DSManager::DoRefineStep(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_ if (!ch->DragonSoul_RefineWindow_CanRefine()) { sys_err ("%s do not activate DragonSoulRefineWindow. But how can he come here?", ch->GetName()); - ch->ChatPacket(CHAT_TYPE_INFO, "[SYSTEM ERROR]You cannot use dragon soul refine window."); + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[SYSTEM ERROR]You cannot upgrade dragon soul clarity without refine window.")); + return false; } // ํ˜น์‹œ๋‚˜ ๋ชจ๋ฅผ ์ค‘๋ณต๋˜๋Š” item pointer ์—†์• ๊ธฐ ์œ„ํ•ด์„œ set ์‚ฌ์šฉ // ์ด์ƒํ•œ ํŒจํ‚ท์„ ๋ณด๋‚ผ ๊ฒฝ์šฐ, ์ค‘๋ณต๋œ TItemPos๊ฐ€ ์žˆ์„ ์ˆ˜๋„ ์žˆ๊ณ , ์ž˜๋ชป๋œ TItemPos๊ฐ€ ์žˆ์„ ์ˆ˜๋„ ์žˆ๋‹ค. std::set set_items; + for (int i = 0; i < DRAGON_SOUL_REFINE_GRID_SIZE; i++) { LPITEM pItem = ch->GetItem(aItemPoses[i]); + if (NULL != pItem) { // ์šฉํ˜ผ์„์ด ์•„๋‹Œ ์•„์ดํ…œ์ด ๊ฐœ๋Ÿ‰์ฐฝ์— ์žˆ์„ ์ˆ˜ ์—†๋‹ค. @@ -698,8 +750,10 @@ bool DSManager::DoRefineStep(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_ { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("๋‹จ๊ณ„ ๊ฐœ๋Ÿ‰์— ํ•„์š”ํ•œ ์žฌ๋ฃŒ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.")); SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_INVALID_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell())); + return false; } + set_items.insert(pItem); } } @@ -707,6 +761,7 @@ bool DSManager::DoRefineStep(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_ if (set_items.size() == 0) { SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_NOT_ENOUGH_MATERIAL, NPOS); + return false; } @@ -729,6 +784,7 @@ bool DSManager::DoRefineStep(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_ { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("๋‹จ๊ณ„ ๊ฐœ๋Ÿ‰ํ•  ์ˆ˜ ์—†๋Š” ์šฉํ˜ผ์„์ž…๋‹ˆ๋‹ค.")); SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_INVALID_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell())); + return false; } } @@ -736,6 +792,7 @@ bool DSManager::DoRefineStep(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_ while(++it != set_items.end()) { LPITEM pItem = *it; + // ํด๋ผ ui์—์„œ ์žฅ์ฐฉํ•œ ์•„์ดํ…œ์€ ๊ฐœ๋Ÿ‰์ฐฝ์— ์˜ฌ๋ฆด ์ˆ˜ ์—†๋„๋ก ๋ง‰์•˜๊ธฐ ๋•Œ๋ฌธ์—, // ๋ณ„๋„์˜ ์•Œ๋ฆผ ์ฒ˜๋ฆฌ๋Š” ์•ˆํ•จ. if (pItem->IsEquipped()) @@ -746,6 +803,7 @@ bool DSManager::DoRefineStep(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_ { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("๋‹จ๊ณ„ ๊ฐœ๋Ÿ‰์— ํ•„์š”ํ•œ ์žฌ๋ฃŒ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.")); SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_INVALID_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell())); + return false; } } @@ -756,6 +814,7 @@ bool DSManager::DoRefineStep(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_ sys_err ("Possiblity of invalid client. Name %s", ch->GetName()); BYTE bSubHeader = count < need_count? DS_SUB_HEADER_REFINE_FAIL_NOT_ENOUGH_MATERIAL : DS_SUB_HEADER_REFINE_FAIL_TOO_MUCH_MATERIAL; SendRefineResultPacket(ch, bSubHeader, NPOS); + return false; } @@ -763,6 +822,7 @@ bool DSManager::DoRefineStep(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_ { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("๊ฐœ๋Ÿ‰์„ ํ•˜๊ธฐ ์œ„ํ•œ ๋ˆ์ด ๋ถ€์กฑํ•ฉ๋‹ˆ๋‹ค.")); SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_NOT_ENOUGH_MONEY, NPOS); + return false; } @@ -784,10 +844,12 @@ bool DSManager::DoRefineStep(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_ ch->PointChange(POINT_GOLD, -fee); int left_count = need_count; + for (std::set ::iterator it = set_items.begin(); it != set_items.end(); it++) { LPITEM pItem = *it; int n = pItem->GetCount(); + if (left_count > n) { pItem->RemoveFromCharacter(); @@ -801,6 +863,7 @@ bool DSManager::DoRefineStep(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_ } ch->AutoGiveItem(pResultItem, true); + if (result_step > step_idx) { char buf[128]; @@ -808,6 +871,7 @@ bool DSManager::DoRefineStep(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_ LogManager::instance().ItemLog(ch, pResultItem, "DS_STEP_REFINE_SUCCESS", buf); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("๋‹จ๊ณ„ ๊ฐœ๋Ÿ‰์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค.")); SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_SUCCEED, TItemPos (pResultItem->GetWindow(), pResultItem->GetCell())); + return true; } else @@ -817,6 +881,7 @@ bool DSManager::DoRefineStep(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_ LogManager::instance().ItemLog(ch, pResultItem, "DS_STEP_REFINE_FAIL", buf); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("๋‹จ๊ณ„ ๊ฐœ๋Ÿ‰์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค.")); SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL, TItemPos (pResultItem->GetWindow(), pResultItem->GetCell())); + return false; } } @@ -825,6 +890,7 @@ bool IsDragonSoulRefineMaterial(LPITEM pItem) { if (pItem->GetType() != ITEM_MATERIAL) return false; + return (pItem->GetSubType() == MATERIAL_DS_REFINE_NORMAL || pItem->GetSubType() == MATERIAL_DS_REFINE_BLESSED || pItem->GetSubType() == MATERIAL_DS_REFINE_HOLLY); @@ -834,6 +900,7 @@ bool DSManager::DoRefineStrength(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_S { if (NULL == ch) return false; + if (NULL == aItemPoses) { return false; @@ -842,13 +909,15 @@ bool DSManager::DoRefineStrength(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_S if (!ch->DragonSoul_RefineWindow_CanRefine()) { sys_err ("%s do not activate DragonSoulRefineWindow. But how can he come here?", ch->GetName()); - ch->ChatPacket(CHAT_TYPE_INFO, "[SYSTEM ERROR]You cannot use dragon soul refine window."); + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[SYSTEM ERROR]You cannot upgrade dragon soul level without refine window.")); + return false; } // ํ˜น์‹œ๋‚˜ ๋ชจ๋ฅผ ์ค‘๋ณต๋˜๋Š” item pointer ์—†์• ๊ธฐ ์œ„ํ•ด์„œ set ์‚ฌ์šฉ // ์ด์ƒํ•œ ํŒจํ‚ท์„ ๋ณด๋‚ผ ๊ฒฝ์šฐ, ์ค‘๋ณต๋œ TItemPos๊ฐ€ ์žˆ์„ ์ˆ˜๋„ ์žˆ๊ณ , ์ž˜๋ชป๋œ TItemPos๊ฐ€ ์žˆ์„ ์ˆ˜๋„ ์žˆ๋‹ค. std::set set_items; + for (int i = 0; i < DRAGON_SOUL_REFINE_GRID_SIZE; i++) { LPITEM pItem = ch->GetItem(aItemPoses[i]); @@ -866,6 +935,7 @@ bool DSManager::DoRefineStrength(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_S LPITEM pRefineStone = NULL; LPITEM pDragonSoul = NULL; + for (std::set ::iterator it = set_items.begin(); it != set_items.end(); it++) { LPITEM pItem = *it; @@ -885,6 +955,7 @@ bool DSManager::DoRefineStrength(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_S SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_TOO_MUCH_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell())); return false; } + pDragonSoul = pItem; } else if(IsDragonSoulRefineMaterial(pItem)) @@ -894,12 +965,14 @@ bool DSManager::DoRefineStrength(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_S SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_TOO_MUCH_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell())); return false; } + pRefineStone = pItem; } else { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("๊ฐ•ํ™”์— ํ•„์š”ํ•œ ์žฌ๋ฃŒ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.")); SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_INVALID_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell())); + return false; } } @@ -918,6 +991,7 @@ bool DSManager::DoRefineStrength(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_S GetDragonSoulInfo(pDragonSoul->GetVnum(), bType, bGrade, bStep, bStrength); float fWeight = 0.f; + // ๊ฐ€์ค‘์น˜ ๊ฐ’์ด ์—†๋‹ค๋ฉด ๊ฐ•ํ™”ํ•  ์ˆ˜ ์—†๋Š” ์šฉํ˜ผ์„ if (!m_pTable->GetWeight(bType, bGrade, bStep, bStrength + 1, fWeight)) { @@ -925,6 +999,7 @@ bool DSManager::DoRefineStrength(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_S SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_MAX_REFINE, TItemPos(pDragonSoul->GetWindow(), pDragonSoul->GetCell())); return false; } + // ๊ฐ•ํ™”ํ–ˆ์„ ๋•Œ ๊ฐ€์ค‘์น˜๊ฐ€ 0์ด๋ผ๋ฉด ๋” ์ด์ƒ ๊ฐ•ํ™”๋˜์„œ๋Š” ์•ˆ๋œ๋‹ค. if (fWeight < FLT_EPSILON) { @@ -935,6 +1010,7 @@ bool DSManager::DoRefineStrength(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_S } float fProb; + if (!m_pTable->GetRefineStrengthValues(bType, pRefineStone->GetSubType(), bStrength, fee, fProb)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("๊ฐ•ํ™”ํ•  ์ˆ˜ ์—†๋Š” ์šฉํ˜ผ์„์ž…๋‹ˆ๋‹ค.")); @@ -947,21 +1023,25 @@ bool DSManager::DoRefineStrength(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_S { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("๊ฐœ๋Ÿ‰์„ ํ•˜๊ธฐ ์œ„ํ•œ ๋ˆ์ด ๋ถ€์กฑํ•ฉ๋‹ˆ๋‹ค.")); SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_NOT_ENOUGH_MONEY, NPOS); + return false; } ch->PointChange(POINT_GOLD, -fee); + LPITEM pResult = NULL; BYTE bSubHeader; if (fnumber(0.f, 100.f) <= fProb) { pResult = ITEM_MANAGER::instance().CreateItem(MakeDragonSoulVnum(bType, bGrade, bStep, bStrength + 1)); + if (NULL == pResult) { sys_err ("INVALID DRAGON SOUL(%d)", MakeDragonSoulVnum(bType, bGrade, bStep, bStrength + 1)); return false; } + pDragonSoul->RemoveFromCharacter(); pDragonSoul->CopyAttributeTo(pResult); @@ -982,11 +1062,13 @@ bool DSManager::DoRefineStrength(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_S if (bStrength != 0) { pResult = ITEM_MANAGER::instance().CreateItem(MakeDragonSoulVnum(bType, bGrade, bStep, bStrength - 1)); + if (NULL == pResult) { sys_err ("INVALID DRAGON SOUL(%d)", MakeDragonSoulVnum(bType, bGrade, bStep, bStrength - 1)); return false; } + pDragonSoul->CopyAttributeTo(pResult); RefreshItemAttributes(pResult); } @@ -1000,6 +1082,7 @@ bool DSManager::DoRefineStrength(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_S ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("๊ฐ•ํ™”์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค.")); pDragonSoul->SetCount(pDragonSoul->GetCount() - 1); pRefineStone->SetCount(pRefineStone->GetCount() - 1); + if (NULL != pResult) ch->AutoGiveItem(pResult, true); @@ -1019,7 +1102,9 @@ void DSManager::SendRefineResultPacket(LPCHARACTER ch, BYTE bSubHeader, const TI { pack.Pos = pos; } + LPDESC d = ch->GetDesc(); + if (NULL == d) { return ; @@ -1073,7 +1158,9 @@ bool DSManager::ActivateDragonSoul(LPITEM pItem) { if (NULL == pItem) return false; + LPCHARACTER pOwner = pItem->GetOwner(); + if (NULL == pOwner) return false; @@ -1107,6 +1194,7 @@ bool DSManager::DeactivateDragonSoul(LPITEM pItem, bool bSkipRefreshOwnerActiveS return false; LPCHARACTER pOwner = pItem->GetOwner(); + if (NULL == pOwner) return false; @@ -1131,17 +1219,20 @@ void DSManager::RefreshDragonSoulState(LPCHARACTER ch) { if (NULL == ch) return ; - for (int i = WEAR_MAX_NUM; i < WEAR_MAX_NUM + DS_SLOT_MAX * DRAGON_SOUL_DECK_MAX_NUM; i++) + + for (int i = WEAR_MAX_NUM; i < WEAR_MAX_NUM + (int)DS_SLOT_MAX * (int)DRAGON_SOUL_DECK_MAX_NUM; i++) { LPITEM pItem = ch->GetWear(i); + if (pItem != NULL) { - if(IsActiveDragonSoul(pItem)) + if (IsActiveDragonSoul(pItem)) { return; } } } + ch->DragonSoul_DeactivateAll(); } diff --git a/src/game/MarkManager.cpp b/src/game/MarkManager.cpp index 7edebf0..7420f9d 100644 --- a/src/game/MarkManager.cpp +++ b/src/game/MarkManager.cpp @@ -18,7 +18,7 @@ void CGuildMarkManager::__DeleteImage(CGuildMarkImage * pkImgDel) CGuildMarkManager::CGuildMarkManager() { // ๋‚จ์€ mark id ์…‹์„ ๋งŒ๋“ ๋‹ค. (์„œ๋ฒ„์šฉ) - for (DWORD i = 0; i < MAX_IMAGE_COUNT * CGuildMarkImage::MARK_TOTAL_COUNT; ++i) + for (DWORD i = 0; i < (DWORD)MAX_IMAGE_COUNT * (DWORD)CGuildMarkImage::MARK_TOTAL_COUNT; ++i) m_setFreeMarkID.insert(i); } @@ -103,7 +103,7 @@ void CGuildMarkManager::LoadMarkImages() { DWORD markID = it->second; - if (markID < MAX_IMAGE_COUNT * CGuildMarkImage::MARK_TOTAL_COUNT) + if (markID < (DWORD)MAX_IMAGE_COUNT * (DWORD)CGuildMarkImage::MARK_TOTAL_COUNT) isMarkExists[markID / CGuildMarkImage::MARK_TOTAL_COUNT] = true; } @@ -151,7 +151,7 @@ CGuildMarkImage * CGuildMarkManager::__GetImage(DWORD imgIdx) bool CGuildMarkManager::AddMarkIDByGuildID(DWORD guildID, DWORD markID) { - if (markID >= MAX_IMAGE_COUNT * CGuildMarkImage::MARK_TOTAL_COUNT) + if (markID >= (DWORD)MAX_IMAGE_COUNT * (DWORD)CGuildMarkImage::MARK_TOTAL_COUNT) return false; //sys_log(0, "MarkManager: guild_id=%d mark_id=%d", guildID, markID); diff --git a/src/game/SpeedServer.cpp b/src/game/SpeedServer.cpp index 0909b8d..557a9df 100644 --- a/src/game/SpeedServer.cpp +++ b/src/game/SpeedServer.cpp @@ -101,15 +101,18 @@ bool CSpeedServerEmpireExp::WriteExpTable() FILE *fp; sys_log (0, "write"); - if (0==file_name || 0==file_name[0]) + + // if (0 == file_name || 0 == file_name[0]) + if (0 == file_name[0]) return false; - if ((fp = fopen(file_name, "w"))==0) + if ((fp = fopen(file_name, "w")) == 0) { return false; } char wday_name[7][4] = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"}; + for (int i = 0; i < 7; i++) { fprintf (fp, "%s", wday_name[i]); @@ -141,7 +144,9 @@ bool CSpeedServerEmpireExp::LoadExpTable() const char *delim = " \t\r\n"; sys_log (0, "load"); - if (0==file_name || 0==file_name[0]) + + // if (0 == file_name || 0 == file_name[0]) + if (file_name[0] == '\0') return false; if ((fp = fopen(file_name, "r"))==0) diff --git a/src/game/arena.cpp b/src/game/arena.cpp index b335657..d914bb7 100644 --- a/src/game/arena.cpp +++ b/src/game/arena.cpp @@ -150,9 +150,14 @@ void CArenaMap::SendArenaMapListTo(LPCHARACTER pChar, DWORD mapIdx) for (; iter != m_listArena.end(); iter++) { + // The iterator (*iter) is already a pointer to the container's element. + // We assume the element is a pointer type that needs to be treated as CArena*. + + CArena* pArena = (CArena*)(*iter); // Cast and assign the pointer once + pChar->ChatPacket(CHAT_TYPE_INFO, "ArenaMapInfo Map: %d stA(%d, %d) stB(%d, %d)", mapIdx, - (CArena*)(*iter)->GetStartPointA().x, (CArena*)(*iter)->GetStartPointA().y, - (CArena*)(*iter)->GetStartPointB().x, (CArena*)(*iter)->GetStartPointB().y); + pArena->GetStartPointA().x, pArena->GetStartPointA().y, + pArena->GetStartPointB().x, pArena->GetStartPointB().y); } } diff --git a/src/game/char.cpp b/src/game/char.cpp index 1b3dbfa..b5f954d 100644 --- a/src/game/char.cpp +++ b/src/game/char.cpp @@ -1003,6 +1003,11 @@ void CHARACTER::UpdatePacket() { if (GetSectree() == NULL) return; +#ifdef CHAR_SELECT_STATS_IMPROVEMENT + if (IsPC() && (!GetDesc() || !GetDesc()->GetCharacter())) + return; +#endif + TPacketGCCharacterUpdate pack; TPacketGCCharacterUpdate pack2; @@ -1389,6 +1394,18 @@ void CHARACTER::Disconnect(const char * c_pszReason) if (GetDesc()) { +#ifdef CHAR_SELECT_STATS_IMPROVEMENT + PointsPacket(); + + packet_point_change pack; + pack.header = HEADER_GC_CHARACTER_POINT_CHANGE; + pack.dwVID = m_vid; + pack.type = POINT_PLAYTIME; + pack.value = GetRealPoint(POINT_PLAYTIME) + (get_dword_time() - m_dwPlayStartTime) / 60000; + pack.amount = 0; + + GetDesc()->Packet(&pack, sizeof(struct packet_point_change)); +#endif GetDesc()->BindCharacter(NULL); // BindDesc(NULL); } @@ -1603,8 +1620,16 @@ void CHARACTER::PointsPacket() pack.points[POINT_STAMINA] = GetStamina(); pack.points[POINT_MAX_STAMINA] = GetMaxStamina(); +#ifdef CHAR_SELECT_STATS_IMPROVEMENT + for (int i = POINT_ST; i < POINT_IQ + 1; ++i) + pack.points[i] = GetRealPoint(i); + + for (int i = POINT_IQ + 1; i < POINT_MAX_NUM; ++i) + pack.points[i] = GetPoint(i); +#else for (int i = POINT_ST; i < POINT_MAX_NUM; ++i) pack.points[i] = GetPoint(i); +#endif GetDesc()->Packet(&pack, sizeof(TPacketGCPoints)); } @@ -1782,9 +1807,15 @@ void CHARACTER::SetPlayerProto(const TPlayerTable * t) ComputePoints(); +#ifdef FIX_NEG_HP + SetHP(GetMaxHP()); + SetSP(GetMaxSP()); + SetStamina(GetMaxStamina()); +#else SetHP(t->hp); SetSP(t->sp); SetStamina(t->stamina); +#endif //GM์ผ๋•Œ ๋ณดํ˜ธ๋ชจ๋“œ if (!test_server) diff --git a/src/game/char.h b/src/game/char.h index 6779b3a..3417bbe 100644 --- a/src/game/char.h +++ b/src/game/char.h @@ -522,10 +522,17 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider CStateTemplate m_stateMove; CStateTemplate m_stateBattle; CStateTemplate m_stateIdle; +#ifdef FIX_POS_SYNC + CStateTemplate m_stateSyncing; +#endif public: virtual void StateMove(); virtual void StateBattle(); +#ifdef FIX_POS_SYNC + virtual void StateSyncing(); + virtual bool BlendSync(long x, long y, unsigned int unDuration); +#endif virtual void StateIdle(); virtual void StateFlag(); virtual void StateFlagBase(); @@ -1364,6 +1371,9 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider // ADD_GRANDMASTER_SKILL bool UseSkill(DWORD dwVnum, LPCHARACTER pkVictim, bool bUseGrandMaster = true); void ResetSkill(); +#ifdef FIX_REFRESH_SKILL_COOLDOWN + void ResetSkillCoolTimes(); +#endif void SetSkillLevel(DWORD dwVnum, BYTE bLev); int GetUsedSkillMasterType(DWORD dwVnum); @@ -1759,6 +1769,10 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider bool ResetOneSkill(DWORD dwVnum); // END_RESET_ONE_SKILL +#ifdef FIX_REFRESH_SKILL_COOLDOWN + void ResetOneSkillCoolTime(DWORD dwVnum); +#endif + private : void SendDamagePacket(LPCHARACTER pAttacker, int Damage, BYTE DamageFlag); diff --git a/src/game/char_battle.cpp b/src/game/char_battle.cpp index d962cff..f991fb0 100644 --- a/src/game/char_battle.cpp +++ b/src/game/char_battle.cpp @@ -774,6 +774,7 @@ void CHARACTER::Reward(bool bItemDrop) if (pkAttacker->IsPC()) { if (GetLevel() - pkAttacker->GetLevel() >= -10) + { if (pkAttacker->GetRealAlignment() < 0) { if (pkAttacker->IsEquipUniqueItem(UNIQUE_ITEM_FASTER_ALIGNMENT_UP_BY_KILL)) @@ -782,7 +783,10 @@ void CHARACTER::Reward(bool bItemDrop) pkAttacker->UpdateAlignment(7); } else + { pkAttacker->UpdateAlignment(2); + } + } pkAttacker->SetQuestNPCID(GetVID()); quest::CQuestManager::instance().Kill(pkAttacker->GetPlayerID(), GetRaceNum()); @@ -2287,6 +2291,10 @@ bool CHARACTER::Damage(LPCHARACTER pAttacker, int dam, EDamageType type) // retu // if (!cannot_dead) { +#ifdef FIX_NEG_HP + if (GetHP() - dam <= 0) + dam = GetHP(); +#endif PointChange(POINT_HP, -dam, false); } diff --git a/src/game/char_item.cpp b/src/game/char_item.cpp index 8d50b81..bcc9139 100644 --- a/src/game/char_item.cpp +++ b/src/game/char_item.cpp @@ -444,7 +444,7 @@ void CHARACTER::SetItem(TItemPos Cell, LPITEM pItem) LPITEM CHARACTER::GetWear(BYTE bCell) const { // > WEAR_MAX_NUM : ์šฉํ˜ผ์„ ์Šฌ๋กฏ๋“ค. - if (bCell >= WEAR_MAX_NUM + DRAGON_SOUL_DECK_MAX_NUM * DS_SLOT_MAX) + if (bCell >= WEAR_MAX_NUM + (DWORD)DRAGON_SOUL_DECK_MAX_NUM * (DWORD)DS_SLOT_MAX) { sys_err("CHARACTER::GetWear: invalid wear cell %d", bCell); return NULL; @@ -456,7 +456,7 @@ LPITEM CHARACTER::GetWear(BYTE bCell) const void CHARACTER::SetWear(BYTE bCell, LPITEM item) { // > WEAR_MAX_NUM : ์šฉํ˜ผ์„ ์Šฌ๋กฏ๋“ค. - if (bCell >= WEAR_MAX_NUM + DRAGON_SOUL_DECK_MAX_NUM * DS_SLOT_MAX) + if (bCell >= WEAR_MAX_NUM + (DWORD)DRAGON_SOUL_DECK_MAX_NUM * (DWORD)DS_SLOT_MAX) { sys_err("CHARACTER::SetItem: invalid item cell %d", bCell); return; @@ -479,6 +479,19 @@ void CHARACTER::ClearItem() { int i; LPITEM item; + + // Clear equipment slots first + for (i = 0; i < WEAR_MAX_NUM + (DWORD)DRAGON_SOUL_DECK_MAX_NUM * (DWORD)DS_SLOT_MAX; ++i) + { + if ((item = GetWear(i))) + { + item->SetSkipSave(true); + ITEM_MANAGER::instance().FlushDelayedSave(item); + + item->RemoveFromCharacter(); + M2_DESTROY_ITEM(item); + } + } for (i = 0; i < INVENTORY_AND_EQUIP_SLOT_MAX; ++i) { @@ -510,46 +523,76 @@ bool CHARACTER::IsEmptyItemGrid(TItemPos Cell, BYTE bSize, int iExceptionCell) c { switch (Cell.window_type) { - case INVENTORY: - { - BYTE bCell = Cell.cell; - - // bItemCell์€ 0์ด false์ž„์„ ๋‚˜ํƒ€๋‚ด๊ธฐ ์œ„ํ•ด + 1 ํ•ด์„œ ์ฒ˜๋ฆฌํ•œ๋‹ค. - // ๋”ฐ๋ผ์„œ iExceptionCell์— 1์„ ๋”ํ•ด ๋น„๊ตํ•œ๋‹ค. - ++iExceptionCell; - - if (Cell.IsBeltInventoryPosition()) + case INVENTORY: { - LPITEM beltItem = GetWear(WEAR_BELT); + BYTE bCell = Cell.cell; - if (NULL == beltItem) - return false; + // bItemCell์€ 0์ด false์ž„์„ ๋‚˜ํƒ€๋‚ด๊ธฐ ์œ„ํ•ด + 1 ํ•ด์„œ ์ฒ˜๋ฆฌํ•œ๋‹ค. + // ๋”ฐ๋ผ์„œ iExceptionCell์— 1์„ ๋”ํ•ด ๋น„๊ตํ•œ๋‹ค. + ++iExceptionCell; - if (false == CBeltInventoryHelper::IsAvailableCell(bCell - BELT_INVENTORY_SLOT_START, beltItem->GetValue(0))) + if (Cell.IsBeltInventoryPosition()) + { + LPITEM beltItem = GetWear(WEAR_BELT); + + if (NULL == beltItem) + return false; + + if (false == CBeltInventoryHelper::IsAvailableCell(bCell - BELT_INVENTORY_SLOT_START, beltItem->GetValue(0))) + return false; + + if (m_pointsInstant.bItemGrid[bCell]) + { + if (m_pointsInstant.bItemGrid[bCell] == iExceptionCell) + return true; + + return false; + } + + if (bSize == 1) + return true; + + } + else if (bCell >= INVENTORY_MAX_NUM) return false; if (m_pointsInstant.bItemGrid[bCell]) { if (m_pointsInstant.bItemGrid[bCell] == iExceptionCell) - return true; + { + if (bSize == 1) + return true; - return false; + int j = 1; + BYTE bPage = bCell / (INVENTORY_MAX_NUM / 2); + + do + { + BYTE p = bCell + (5 * j); + + if (p >= INVENTORY_MAX_NUM) + return false; + + if (p / (INVENTORY_MAX_NUM / 2) != bPage) + return false; + + if (m_pointsInstant.bItemGrid[p]) + if (m_pointsInstant.bItemGrid[p] != iExceptionCell) + return false; + } + while (++j < bSize); + + return true; + } + else + return false; } - if (bSize == 1) + // ํฌ๊ธฐ๊ฐ€ 1์ด๋ฉด ํ•œ์นธ์„ ์ฐจ์ง€ํ•˜๋Š” ๊ฒƒ์ด๋ฏ€๋กœ ๊ทธ๋ƒฅ ๋ฆฌํ„ด + if (1 == bSize) return true; - - } - else if (bCell >= INVENTORY_MAX_NUM) - return false; - - if (m_pointsInstant.bItemGrid[bCell]) - { - if (m_pointsInstant.bItemGrid[bCell] == iExceptionCell) + else { - if (bSize == 1) - return true; - int j = 1; BYTE bPage = bCell / (INVENTORY_MAX_NUM / 2); @@ -571,65 +614,61 @@ bool CHARACTER::IsEmptyItemGrid(TItemPos Cell, BYTE bSize, int iExceptionCell) c return true; } - else + } + break; + case DRAGON_SOUL_INVENTORY: + { + WORD wCell = Cell.cell; + if (wCell >= DRAGON_SOUL_INVENTORY_MAX_NUM) return false; - } - // ํฌ๊ธฐ๊ฐ€ 1์ด๋ฉด ํ•œ์นธ์„ ์ฐจ์ง€ํ•˜๋Š” ๊ฒƒ์ด๋ฏ€๋กœ ๊ทธ๋ƒฅ ๋ฆฌํ„ด - if (1 == bSize) - return true; - else - { - int j = 1; - BYTE bPage = bCell / (INVENTORY_MAX_NUM / 2); + // bItemCell์€ 0์ด false์ž„์„ ๋‚˜ํƒ€๋‚ด๊ธฐ ์œ„ํ•ด + 1 ํ•ด์„œ ์ฒ˜๋ฆฌํ•œ๋‹ค. + // ๋”ฐ๋ผ์„œ iExceptionCell์— 1์„ ๋”ํ•ด ๋น„๊ตํ•œ๋‹ค. + iExceptionCell++; - do + if (m_pointsInstant.wDSItemGrid[wCell]) { - BYTE p = bCell + (5 * j); + if (m_pointsInstant.wDSItemGrid[wCell] == iExceptionCell) + { + if (bSize == 1) + return true; - if (p >= INVENTORY_MAX_NUM) - return false; + int j = 1; - if (p / (INVENTORY_MAX_NUM / 2) != bPage) - return false; + do + { + WORD p = wCell + (DRAGON_SOUL_BOX_COLUMN_NUM * j); - if (m_pointsInstant.bItemGrid[p]) - if (m_pointsInstant.bItemGrid[p] != iExceptionCell) - return false; - } - while (++j < bSize); + if (p >= DRAGON_SOUL_INVENTORY_MAX_NUM) + return false; - return true; - } - } - break; - case DRAGON_SOUL_INVENTORY: - { - WORD wCell = Cell.cell; - if (wCell >= DRAGON_SOUL_INVENTORY_MAX_NUM) - return false; + if (m_pointsInstant.wDSItemGrid[p]) + if (m_pointsInstant.wDSItemGrid[p] != iExceptionCell) + return false; + } + while (++j < bSize); - // bItemCell์€ 0์ด false์ž„์„ ๋‚˜ํƒ€๋‚ด๊ธฐ ์œ„ํ•ด + 1 ํ•ด์„œ ์ฒ˜๋ฆฌํ•œ๋‹ค. - // ๋”ฐ๋ผ์„œ iExceptionCell์— 1์„ ๋”ํ•ด ๋น„๊ตํ•œ๋‹ค. - iExceptionCell++; - - if (m_pointsInstant.wDSItemGrid[wCell]) - { - if (m_pointsInstant.wDSItemGrid[wCell] == iExceptionCell) - { - if (bSize == 1) return true; + } + else + return false; + } + // ํฌ๊ธฐ๊ฐ€ 1์ด๋ฉด ํ•œ์นธ์„ ์ฐจ์ง€ํ•˜๋Š” ๊ฒƒ์ด๋ฏ€๋กœ ๊ทธ๋ƒฅ ๋ฆฌํ„ด + if (1 == bSize) + return true; + else + { int j = 1; do { - BYTE p = wCell + (DRAGON_SOUL_BOX_COLUMN_NUM * j); + WORD p = wCell + (DRAGON_SOUL_BOX_COLUMN_NUM * j); if (p >= DRAGON_SOUL_INVENTORY_MAX_NUM) return false; - if (m_pointsInstant.wDSItemGrid[p]) + if (m_pointsInstant.bItemGrid[p]) if (m_pointsInstant.wDSItemGrid[p] != iExceptionCell) return false; } @@ -637,33 +676,10 @@ bool CHARACTER::IsEmptyItemGrid(TItemPos Cell, BYTE bSize, int iExceptionCell) c return true; } - else - return false; } - - // ํฌ๊ธฐ๊ฐ€ 1์ด๋ฉด ํ•œ์นธ์„ ์ฐจ์ง€ํ•˜๋Š” ๊ฒƒ์ด๋ฏ€๋กœ ๊ทธ๋ƒฅ ๋ฆฌํ„ด - if (1 == bSize) - return true; - else - { - int j = 1; - - do - { - BYTE p = wCell + (DRAGON_SOUL_BOX_COLUMN_NUM * j); - - if (p >= DRAGON_SOUL_INVENTORY_MAX_NUM) - return false; - - if (m_pointsInstant.bItemGrid[p]) - if (m_pointsInstant.wDSItemGrid[p] != iExceptionCell) - return false; - } - while (++j < bSize); - - return true; - } - } + break; + default: + return false; } } @@ -2022,7 +2038,7 @@ bool CHARACTER::UseItemEx(LPITEM item, TItemPos DestCell) { if (GetLevel() < 15) { - ChatPacket(CHAT_TYPE_INFO, "15๋ ˆ๋ฒจ ์ดํ•˜์—์„œ๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + ChatPacket(CHAT_TYPE_INFO, LC_TEXT("15๋ ˆ๋ฒจ ์ดํ•˜์—์„œ๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")); return false; } } @@ -2364,7 +2380,7 @@ bool CHARACTER::UseItemEx(LPITEM item, TItemPos DestCell) } else { - sprintf(buf, "Inc %ds by item{VN:%d VAL%d:%d}", ret, item->GetVnum(), ITEM_VALUE_CHARGING_AMOUNT_IDX, item->GetValue(ITEM_VALUE_CHARGING_AMOUNT_IDX)); + sprintf(buf, "Inc %ds by item{VN:%d VAL%d:%ld}", ret, item->GetVnum(), ITEM_VALUE_CHARGING_AMOUNT_IDX, item->GetValue(ITEM_VALUE_CHARGING_AMOUNT_IDX)); } ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%d์ดˆ ๋งŒํผ ์ถฉ์ „๋˜์—ˆ์Šต๋‹ˆ๋‹ค."), ret); @@ -2380,7 +2396,7 @@ bool CHARACTER::UseItemEx(LPITEM item, TItemPos DestCell) } else { - sprintf(buf, "No change by item{VN:%d VAL%d:%d}", item->GetVnum(), ITEM_VALUE_CHARGING_AMOUNT_IDX, item->GetValue(ITEM_VALUE_CHARGING_AMOUNT_IDX)); + sprintf(buf, "No change by item{VN:%d VAL%d:%ld}", item->GetVnum(), ITEM_VALUE_CHARGING_AMOUNT_IDX, item->GetValue(ITEM_VALUE_CHARGING_AMOUNT_IDX)); } ChatPacket(CHAT_TYPE_INFO, LC_TEXT("์ถฉ์ „ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")); @@ -2407,7 +2423,7 @@ bool CHARACTER::UseItemEx(LPITEM item, TItemPos DestCell) if (ret) { ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%d์ดˆ ๋งŒํผ ์ถฉ์ „๋˜์—ˆ์Šต๋‹ˆ๋‹ค."), ret); - sprintf(buf, "Increase %ds by item{VN:%d VAL%d:%d}", ret, item->GetVnum(), ITEM_VALUE_CHARGING_AMOUNT_IDX, item->GetValue(ITEM_VALUE_CHARGING_AMOUNT_IDX)); + sprintf(buf, "Increase %ds by item{VN:%d VAL%d:%ld}", ret, item->GetVnum(), ITEM_VALUE_CHARGING_AMOUNT_IDX, item->GetValue(ITEM_VALUE_CHARGING_AMOUNT_IDX)); LogManager::instance().ItemLog(this, item, "DS_CHARGING_SUCCESS", buf); item->SetCount(item->GetCount() - 1); return true; @@ -2415,7 +2431,7 @@ bool CHARACTER::UseItemEx(LPITEM item, TItemPos DestCell) else { ChatPacket(CHAT_TYPE_INFO, LC_TEXT("์ถฉ์ „ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")); - sprintf(buf, "No change by item{VN:%d VAL%d:%d}", item->GetVnum(), ITEM_VALUE_CHARGING_AMOUNT_IDX, item->GetValue(ITEM_VALUE_CHARGING_AMOUNT_IDX)); + sprintf(buf, "No change by item{VN:%d VAL%d:%ld}", item->GetVnum(), ITEM_VALUE_CHARGING_AMOUNT_IDX, item->GetValue(ITEM_VALUE_CHARGING_AMOUNT_IDX)); LogManager::instance().ItemLog(this, item, "DS_CHARGING_FAILED", buf); return false; } @@ -5262,9 +5278,11 @@ bool CHARACTER::UseItem(TItemPos Cell, TItemPos DestCell) if (nDistant > nDist) { - ChatPacket(CHAT_TYPE_INFO, LC_TEXT("์ด๋™ ๋˜์–ด์งˆ ์œ„์น˜์™€ ๋„ˆ๋ฌด ๊ฐ€๊นŒ์›Œ ๊ท€ํ™˜๋ถ€๋ฅผ ์‚ฌ์šฉํ• ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")); + ChatPacket(CHAT_TYPE_INFO, LC_TEXT("์ด๋™ ๋˜์–ด์งˆ ์œ„์น˜์™€ ๋„ˆ๋ฌด ๊ฐ€๊นŒ์›Œ ๊ท€ํ™˜๋ถ€๋ฅผ ์‚ฌ์šฉํ• ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")); + if (test_server) - ChatPacket(CHAT_TYPE_INFO, "PossibleDistant %f nNowDist %f", nDistant,nDist); + ChatPacket(CHAT_TYPE_INFO, "PossibleDistant %f nNowDist %f", nDistant,nDist); + return false; } } @@ -6114,7 +6132,7 @@ bool CHARACTER::EquipItem(LPITEM item, int iCandidateCell) // ์šฉํ˜ผ์„์€ swap์„ ์ง€์›ํ•˜๋ฉด ์•ˆ๋จ. if(GetInventoryItem(INVENTORY_MAX_NUM + iWearCell)) { - ChatPacket(CHAT_TYPE_INFO, "์ด๋ฏธ ๊ฐ™์€ ์ข…๋ฅ˜์˜ ์šฉํ˜ผ์„์„ ์ฐฉ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค."); + ChatPacket(CHAT_TYPE_INFO, LC_TEXT("์ด๋ฏธ ๊ฐ™์€ ์ข…๋ฅ˜์˜ ์šฉํ˜ผ์„์„ ์ฐฉ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.")); return false; } diff --git a/src/game/char_manager.cpp b/src/game/char_manager.cpp index 10f2401..56fe881 100644 --- a/src/game/char_manager.cpp +++ b/src/game/char_manager.cpp @@ -336,7 +336,7 @@ LPCHARACTER CHARACTER_MANAGER::SpawnMobRandomPosition(DWORD dwVnum, long lMapInd char buf[512+1]; long local_x = x - pkSectreeMap->m_setting.iBaseX; long local_y = y - pkSectreeMap->m_setting.iBaseY; - snprintf(buf, sizeof(buf), "spawn %s[%d] random position at %ld %ld %ld %ld (time: %d)", ch->GetName(), dwVnum, x, y, local_x, local_y, get_global_time()); + snprintf(buf, sizeof(buf), "spawn %s[%d] random position at %ld %ld %ld %ld (time: %ld)", ch->GetName(), dwVnum, x, y, local_x, local_y, get_global_time()); if (test_server) SendNotice(buf); diff --git a/src/game/char_skill.cpp b/src/game/char_skill.cpp index b68edbc..430fac6 100644 --- a/src/game/char_skill.cpp +++ b/src/game/char_skill.cpp @@ -148,6 +148,10 @@ void CHARACTER::SetSkillGroup(BYTE bSkillGroup) p.skill_group = m_points.skill_group; GetDesc()->Packet(&p, sizeof(TPacketGCChangeSkillGroup)); +#ifdef FIX_REFRESH_SKILL_COOLDOWN + SkillLevelPacket(); + PointsPacket(); +#endif } int CHARACTER::ComputeCooltime(int time) @@ -178,6 +182,14 @@ void CHARACTER::SetSkillLevel(DWORD dwVnum, BYTE bLev) return; } +#ifdef FIX_REFRESH_SKILL_COOLDOWN + if (dwVnum == SKILL_COMBO && (bLev == 0 || m_pSkillLevels[dwVnum].bLevel == 0) && m_bComboIndex > 0) + { + m_bComboIndex = 0; + ChatPacket(CHAT_TYPE_COMMAND, "combo %d", 0); + } +#endif + m_pSkillLevels[dwVnum].bLevel = MIN(40, bLev); if (bLev >= 40) @@ -187,7 +199,14 @@ void CHARACTER::SetSkillLevel(DWORD dwVnum, BYTE bLev) else if (bLev >= 20) m_pSkillLevels[dwVnum].bMasterType = SKILL_MASTER; else + { +#ifdef FIX_REFRESH_SKILL_COOLDOWN + if (bLev == 0) + ResetOneSkillCoolTime(dwVnum); +#endif + m_pSkillLevels[dwVnum].bMasterType = SKILL_NORMAL; + } } bool CHARACTER::IsLearnableSkill(DWORD dwSkillVnum) const @@ -432,7 +451,11 @@ bool CHARACTER::LearnSkillByBook(DWORD dwSkillVnum, BYTE bProb) { need_exp = 20000; - if ( GetExp() < need_exp ) +#ifdef FIX_BOOK_READING_FOR_MAX_LEVEL + if (GetExp() < need_exp && GetLevel() < gPlayerMaxLevel) +#else + if (GetExp() < need_exp) +#endif { ChatPacket(CHAT_TYPE_INFO, LC_TEXT("๊ฒฝํ—˜์น˜๊ฐ€ ๋ถ€์กฑํ•˜์—ฌ ์ฑ…์„ ์ฝ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")); return false; @@ -888,10 +911,23 @@ void CHARACTER::ResetSkill() m_pSkillLevels[pair.first] = pair.second; } +#ifdef FIX_REFRESH_SKILL_COOLDOWN + ResetSkillCoolTimes(); +#endif + ComputePoints(); SkillLevelPacket(); } + +#ifdef FIX_REFRESH_SKILL_COOLDOWN +void CHARACTER::ResetSkillCoolTimes() +{ + for (std::map::iterator it = m_SkillUseInfo.begin(); it != m_SkillUseInfo.end(); ++it) + ResetOneSkillCoolTime(it->first); +} +#endif + void CHARACTER::ComputePassiveSkill(DWORD dwVnum) { if (g_bSkillDisable) @@ -1960,11 +1996,23 @@ int CHARACTER::ComputeSkillAtPosition(DWORD dwVnum, const PIXEL_POSITION& posTar // bSkillLevel๋กœ ๊ณ„์‚ฐํ•œ๋‹ค. int CHARACTER::ComputeSkill(DWORD dwVnum, LPCHARACTER pkVictim, BYTE bSkillLevel) { + CSkillProto* pkSk = CSkillManager::instance().Get(dwVnum); const bool bCanUseHorseSkill = CanUseHorseSkill(); // ๋ง์„ ํƒ€๊ณ ์žˆ์ง€๋งŒ ์Šคํ‚ฌ์€ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” ์ƒํƒœ๋ผ๋ฉด return if (false == bCanUseHorseSkill && true == IsRiding()) +#ifdef FIX_REFRESH_SKILL_COOLDOWN + { + const bool bToggleSkill = pkSk && IS_SET(pkSk->dwFlag, SKILL_FLAG_TOGGLE); + const bool bToggleActive = bToggleSkill ? (dwVnum == SKILL_COMBO ? m_bComboIndex != 0 : FindAffect(dwVnum) != nullptr) : false; + + // Allow only deactivation of already-active toggles (combo or other) while riding + if (!bToggleActive) + return BATTLE_NONE; + } +#else return BATTLE_NONE; +#endif if (IsPolymorphed()) return BATTLE_NONE; @@ -1972,12 +2020,17 @@ int CHARACTER::ComputeSkill(DWORD dwVnum, LPCHARACTER pkVictim, BYTE bSkillLevel if (g_bSkillDisable) return BATTLE_NONE; - CSkillProto* pkSk = CSkillManager::instance().Get(dwVnum); - if (!pkSk) return BATTLE_NONE; +#ifdef FIX_REFRESH_SKILL_COOLDOWN + const bool bIsToggleSkill = IS_SET(pkSk->dwFlag, SKILL_FLAG_TOGGLE); + const bool bToggleActive = bIsToggleSkill ? (dwVnum == SKILL_COMBO ? m_bComboIndex != 0 : FindAffect(dwVnum) != nullptr) : false; + + if (bCanUseHorseSkill && pkSk->dwType != SKILL_TYPE_HORSE && !(bIsToggleSkill && bToggleActive)) +#else if (bCanUseHorseSkill && pkSk->dwType != SKILL_TYPE_HORSE) +#endif return BATTLE_NONE; if (!bCanUseHorseSkill && pkSk->dwType == SKILL_TYPE_HORSE) @@ -2452,17 +2505,37 @@ bool CHARACTER::UseSkill(DWORD dwVnum, LPCHARACTER pkVictim, bool bUseGrandMaste return true; } + CSkillProto* pkSk = CSkillManager::instance().Get(dwVnum); + // ๋ง์„ ํƒ€๊ณ ์žˆ์ง€๋งŒ ์Šคํ‚ฌ์€ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” ์ƒํƒœ๋ผ๋ฉด return false if (false == bCanUseHorseSkill && true == IsRiding()) - return false; +#ifdef FIX_REFRESH_SKILL_COOLDOWN + { + const bool bToggleSkill = pkSk && IS_SET(pkSk->dwFlag, SKILL_FLAG_TOGGLE); + const bool bToggleActive = bToggleSkill ? (dwVnum == SKILL_COMBO ? m_bComboIndex != 0 : FindAffect(dwVnum) != nullptr) : false; - CSkillProto * pkSk = CSkillManager::instance().Get(dwVnum); + // Allow only deactivation of already-active toggles (combo or other) while riding + if (!bToggleActive) + return false; + } +#else + return false; +#endif + + // CSkillProto * pkSk = CSkillManager::instance().Get(dwVnum); sys_log(0, "%s: USE_SKILL: %d pkVictim %p", GetName(), dwVnum, get_pointer(pkVictim)); if (!pkSk) return false; +#ifdef FIX_REFRESH_SKILL_COOLDOWN + const bool bIsToggleSkill = IS_SET(pkSk->dwFlag, SKILL_FLAG_TOGGLE); + const bool bToggleActive = bIsToggleSkill ? (dwVnum == SKILL_COMBO ? m_bComboIndex != 0 : FindAffect(dwVnum) != nullptr) : false; + + if (bCanUseHorseSkill && pkSk->dwType != SKILL_TYPE_HORSE && !(bIsToggleSkill && bToggleActive)) +#else if (bCanUseHorseSkill && pkSk->dwType != SKILL_TYPE_HORSE) +#endif return BATTLE_NONE; if (!bCanUseHorseSkill && pkSk->dwType == SKILL_TYPE_HORSE) @@ -3459,6 +3532,10 @@ bool CHARACTER::ResetOneSkill(DWORD dwVnum) m_pSkillLevels[dwVnum].bMasterType = 0; m_pSkillLevels[dwVnum].tNextRead = 0; +#ifdef FIX_REFRESH_SKILL_COOLDOWN + ResetOneSkillCoolTime(dwVnum); +#endif + if (level > 17) level = 17; @@ -3472,6 +3549,36 @@ bool CHARACTER::ResetOneSkill(DWORD dwVnum) return true; } +#ifdef FIX_REFRESH_SKILL_COOLDOWN +void CHARACTER::ResetOneSkillCoolTime(DWORD dwVnum) +{ + if (dwVnum >= SKILL_MAX_NUM) + return; + + if (!GetSkillGroup() || m_SkillUseInfo.empty()) + { + // still try to disable toggle state even when no cooldown info exists + CSkillProto* pkSkNoInfo = CSkillManager::instance().Get(dwVnum); + + if (pkSkNoInfo && IS_SET(pkSkNoInfo->dwFlag, SKILL_FLAG_TOGGLE)) + RemoveAffect(pkSkNoInfo->dwVnum); + + return; + } + + std::map::iterator it = m_SkillUseInfo.find(dwVnum); + + if (it != m_SkillUseInfo.end()) + it->second.dwNextSkillUsableTime = 0; + + // If the skill is togglable, ensure it is turned off. + CSkillProto* pkSk = CSkillManager::instance().Get(dwVnum); + + if (pkSk && IS_SET(pkSk->dwFlag, SKILL_FLAG_TOGGLE)) + RemoveAffect(pkSk->dwVnum); +} +#endif + bool CHARACTER::CanUseSkill(DWORD dwSkillVnum) const { if (0 == dwSkillVnum) return false; diff --git a/src/game/char_state.cpp b/src/game/char_state.cpp index 080815a..e41fd1e 100644 --- a/src/game/char_state.cpp +++ b/src/game/char_state.cpp @@ -801,6 +801,7 @@ void CHARACTER::StateMove() // ์ „ํˆฌ ์ค‘์ด๋ฉด์„œ ๋›ฐ๋Š” ์ค‘์ด๋ฉด if (!IsWalking() && !IsRiding()) + { if ((get_dword_time() - GetLastAttackTime()) < 20000) { StartAffectEvent(); @@ -827,6 +828,7 @@ void CHARACTER::StateMove() { StopStaminaConsume(); } + } } else { @@ -1124,6 +1126,57 @@ void CHARACTER::StateBattle() } } +#ifdef FIX_POS_SYNC +void CHARACTER::StateSyncing() +{ + if (IsStone() || IsDoor()) { + StopConcurrentState(); + + return; + } + + DWORD dwElapsedTime = get_dword_time() - m_dwSyncStartTime; + float fRate = (float)dwElapsedTime / (float)m_dwSyncDuration; + + if (fRate > 1.0f) + fRate = 1.0f; + + int x = (int)((float)(m_posDest.x - m_posStart.x) * fRate + m_posStart.x); + int y = (int)((float)(m_posDest.y - m_posStart.y) * fRate + m_posStart.y); + + + Sync(x, y); + + if (1.0f == fRate) + { + StopConcurrentState(); + } +} + +/////////////////// +////// To use to gradually "move" the entity on the desired position while it can do whatever it wants (to use when receiving HEADER_CG_ATTACK) +bool CHARACTER::BlendSync(long x, long y, unsigned int unDuration) +{ + // TODO distance check required + // No need to go the same side as the position (automatic success) + if (GetX() == x && GetY() == y) + return false; + + m_posDest.x = m_posStart.x = GetX(); + m_posDest.y = m_posStart.y = GetY(); + + m_posDest.x = x; + m_posDest.y = y; + + m_dwSyncStartTime = get_dword_time(); + m_dwSyncDuration = unDuration; + m_dwStateDuration = 1; + + ConcurrentState(m_stateSyncing); + return true; +} +#endif + void CHARACTER::StateFlag() { m_dwStateDuration = (DWORD) PASSES_PER_SEC(0.5); diff --git a/src/game/cmd_general.cpp b/src/game/cmd_general.cpp index fbb9c8f..876b4fe 100644 --- a/src/game/cmd_general.cpp +++ b/src/game/cmd_general.cpp @@ -1291,6 +1291,21 @@ ACMD(do_messenger_auth) if (tch) tch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s ๋‹˜์œผ๋กœ ๋ถ€ํ„ฐ ์นœ๊ตฌ ๋“ฑ๋ก์„ ๊ฑฐ๋ถ€ ๋‹นํ–ˆ์Šต๋‹ˆ๋‹ค."), ch->GetName()); +#ifdef CROSS_CHANNEL_FRIEND_REQUEST + else + { + CCI* pkCCI = P2P_MANAGER::Instance().Find(arg2); + + if (pkCCI) + { + LPDESC pkDesc = pkCCI->pkDesc; + + pkDesc->SetRelay(arg2); + pkDesc->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s ๋‹˜์œผ๋กœ ๋ถ€ํ„ฐ ์นœ๊ตฌ ๋“ฑ๋ก์„ ๊ฑฐ๋ถ€ ๋‹นํ–ˆ์Šต๋‹ˆ๋‹ค."), ch->GetName()); + pkDesc->SetRelay(""); + } + } +#endif } //MessengerManager::instance().AuthToAdd(ch->GetName(), arg2, answer == 'y' ? false : true); // DENY diff --git a/src/game/cmd_gm.cpp b/src/game/cmd_gm.cpp index 1efb680..eea2cf1 100644 --- a/src/game/cmd_gm.cpp +++ b/src/game/cmd_gm.cpp @@ -457,7 +457,7 @@ ACMD(do_item) if (!*arg1) { - ch->ChatPacket(CHAT_TYPE_INFO, "Usage: item "); + ch->ChatPacket(CHAT_TYPE_INFO, "Usage: /item "); return; } @@ -500,7 +500,7 @@ ACMD(do_item) M2_DESTROY_ITEM(item); if (!ch->DragonSoul_IsQualified()) { - ch->ChatPacket(CHAT_TYPE_INFO, "์ธ๋ฒค์ด ํ™œ์„ฑํ™” ๋˜์ง€ ์•Š์Œ."); + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("์ธ๋ฒค์ด ํ™œ์„ฑํ™” ๋˜์ง€ ์•Š์Œ.")); } else ch->ChatPacket(CHAT_TYPE_INFO, "Not enough inventory space."); @@ -574,7 +574,11 @@ ACMD(do_mob_coward) if (!*arg1) { - ch->ChatPacket(CHAT_TYPE_INFO, "Usage: mc "); +#ifdef FIX_NEG_CMD_CORE_DOWNER + ch->ChatPacket(CHAT_TYPE_INFO, "Usage: /mc "); +#else + ch->ChatPacket(CHAT_TYPE_INFO, "Usage: /mc "); +#endif return; } @@ -597,14 +601,23 @@ ACMD(do_mob_coward) if (vnum == 0) { +#ifdef FIX_NEG_CMD_CORE_DOWNER + ch->ChatPacket(CHAT_TYPE_INFO, "No such mob (%s) by that vnum", arg1); +#else ch->ChatPacket(CHAT_TYPE_INFO, "No such mob by that vnum"); +#endif return; } int iCount = 0; if (*arg2) + { str_to_number(iCount, arg2); +#ifdef FIX_NEG_CMD_CORE_DOWNER + iCount = MINMAX(1, iCount, 40); +#endif + } else iCount = 1; @@ -632,7 +645,7 @@ ACMD(do_mob_map) if (!*arg1) { - ch->ChatPacket(CHAT_TYPE_INFO, "Syntax: mm "); + ch->ChatPacket(CHAT_TYPE_INFO, "Syntax: /mm "); return; } @@ -656,7 +669,11 @@ ACMD(do_mob_aggresive) if (!*arg1) { - ch->ChatPacket(CHAT_TYPE_INFO, "Usage: mob "); +#ifdef FIX_NEG_CMD_CORE_DOWNER + ch->ChatPacket(CHAT_TYPE_INFO, "Usage: /mob "); +#else + ch->ChatPacket(CHAT_TYPE_INFO, "Usage: /mob "); +#endif return; } @@ -679,14 +696,23 @@ ACMD(do_mob_aggresive) if (vnum == 0) { +#ifdef FIX_NEG_CMD_CORE_DOWNER + ch->ChatPacket(CHAT_TYPE_INFO, "No such mob (%s) by that vnum", arg1); +#else ch->ChatPacket(CHAT_TYPE_INFO, "No such mob by that vnum"); +#endif return; } int iCount = 0; if (*arg2) + { str_to_number(iCount, arg2); +#ifdef FIX_NEG_CMD_CORE_DOWNER + iCount = MINMAX(1, iCount, 40); +#endif + } else iCount = 1; @@ -716,7 +742,11 @@ ACMD(do_mob) if (!*arg1) { - ch->ChatPacket(CHAT_TYPE_INFO, "Usage: mob "); +#ifdef FIX_NEG_CMD_CORE_DOWNER + ch->ChatPacket(CHAT_TYPE_INFO, "Usage: /mob "); +#else + ch->ChatPacket(CHAT_TYPE_INFO, "Usage: /mob "); +#endif return; } @@ -739,14 +769,23 @@ ACMD(do_mob) if (vnum == 0) { +#ifdef FIX_NEG_CMD_CORE_DOWNER + ch->ChatPacket(CHAT_TYPE_INFO, "No such mob (%s) by that vnum", arg1); +#else ch->ChatPacket(CHAT_TYPE_INFO, "No such mob by that vnum"); +#endif return; } int iCount = 0; if (*arg2) + { str_to_number(iCount, arg2); +#ifdef FIX_NEG_CMD_CORE_DOWNER + iCount = MINMAX(1, iCount, 40); +#endif + } else iCount = 1; @@ -777,7 +816,11 @@ ACMD(do_mob_ld) if (!*arg1) { - ch->ChatPacket(CHAT_TYPE_INFO, "Usage: mob "); +#ifdef FIX_NEG_CMD_CORE_DOWNER + ch->ChatPacket(CHAT_TYPE_INFO, "Usage: /mob "); +#else + ch->ChatPacket(CHAT_TYPE_INFO, "Usage: /mob "); +#endif return; } @@ -1300,7 +1343,7 @@ ACMD(do_disconnect) if (!*arg1) { - ch->ChatPacket(CHAT_TYPE_INFO, "ex) /dc "); + ch->ChatPacket(CHAT_TYPE_INFO, "(ex) /dc "); return; } @@ -1329,7 +1372,7 @@ ACMD(do_kill) if (!*arg1) { - ch->ChatPacket(CHAT_TYPE_INFO, "ex) /kill "); + ch->ChatPacket(CHAT_TYPE_INFO, "(ex) /kill "); return; } @@ -1408,10 +1451,20 @@ ACMD(do_set) int before_gold = tch->GetGold(); tch->PointChange(POINT_GOLD, gold, true); int after_gold = tch->GetGold(); + if (0 == after_gold && 0 != before_gold) { LogManager::instance().CharLog(tch, gold, "ZERO_GOLD", "GM"); } + +#ifdef FIX_NEG_CMD_CORE_DOWNER + if (after_gold > GOLD_MAX) + { + int difference = after_gold - GOLD_MAX; // If you use extended yang limit, change this int with long long int!!! - [MT2Dev Note] - 19/04/2024 + tch->PointChange (POINT_GOLD, -difference, true); + after_gold = GOLD_MAX; + } +#endif } break; @@ -1510,12 +1563,12 @@ ACMD(do_respawn) if (*arg1 && !strcasecmp(arg1, "all")) { - ch->ChatPacket(CHAT_TYPE_INFO, "Respaw everywhere"); + ch->ChatPacket(CHAT_TYPE_INFO, "Respawn everywhere"); regen_reset(0, 0); } else { - ch->ChatPacket(CHAT_TYPE_INFO, "Respaw around"); + ch->ChatPacket(CHAT_TYPE_INFO, "Respawn around"); regen_reset(ch->GetX(), ch->GetY()); } } @@ -1634,16 +1687,37 @@ ACMD(do_fishing_simul) int prob_idx = 0; int level = 100; - ch->ChatPacket(CHAT_TYPE_INFO, "Usage: fishing_simul "); + ch->ChatPacket(CHAT_TYPE_INFO, "Usage: /fishing_simul "); +#ifdef FIX_NEG_CMD_CORE_DOWNER + ch->ChatPacket(CHAT_TYPE_INFO, "Limit: "); +#endif if (*arg1) + { +#ifdef FIX_NEG_CMD_CORE_DOWNER + if (level > 100) + return; +#endif str_to_number(level, arg1); + } if (*arg2) + { +#ifdef FIX_NEG_CMD_CORE_DOWNER + if (prob_idx > 100) + return; +#endif str_to_number(prob_idx, arg2); + } if (*arg3) + { +#ifdef FIX_NEG_CMD_CORE_DOWNER + if (count < 0 || count > 100000) + return; +#endif str_to_number(count, arg3); + } fishing::Simulation(level, count, prob_idx, ch); } diff --git a/src/game/db.cpp b/src/game/db.cpp index 75c018a..6561e13 100644 --- a/src/game/db.cpp +++ b/src/game/db.cpp @@ -64,7 +64,18 @@ SQLMsg * DBManager::DirectQuery(const char * c_pszFormat, ...) vsnprintf(szQuery, sizeof(szQuery), c_pszFormat, args); va_end(args); - return m_sql_direct.DirectQuery(szQuery); + //return m_sql_direct.DirectQuery(szQuery); + + // DirectQuery LPHeart debuging trace 15/11/2015 06:38AM GMT + DWORD t = get_dword_time(); + SQLMsg* p = m_sql_direct.DirectQuery(szQuery); + DWORD dt = get_dword_time() - t; + + if (dt > 200) { + sys_err("[SLOW-GAME] DirectQuery took %u ms: %s", dt, szQuery); + } + + return p; } bool DBManager::IsConnected() diff --git a/src/game/input.h b/src/game/input.h index b41d34f..fe8566c 100644 --- a/src/game/input.h +++ b/src/game/input.h @@ -342,6 +342,10 @@ class CInputP2P : public CInputProcessor void LoginPing(LPDESC d, const char * c_pData); void BlockChat(const char * c_pData); void IamAwake(LPDESC d, const char * c_pData); +#ifdef CROSS_CHANNEL_FRIEND_REQUEST + void MessengerRequestAdd(const char* c_pData); + void MessengerResponse(const char* c_pData); +#endif protected: CPacketInfoGG m_packetInfoGG; diff --git a/src/game/input_login.cpp b/src/game/input_login.cpp index bbe718a..7483048 100644 --- a/src/game/input_login.cpp +++ b/src/game/input_login.cpp @@ -1073,6 +1073,11 @@ int CInputLogin::Analyze(LPDESC d, BYTE bHeader, const char * c_pData) break; ///////////////////////////////////// +#ifdef FIX_HEADER_CG_MARK_LOGIN + case HEADER_CG_MARK_LOGIN: + break; +#endif + case HEADER_CG_HACK: break; diff --git a/src/game/input_main.cpp b/src/game/input_main.cpp index 9184e5b..1e7f6c4 100644 --- a/src/game/input_main.cpp +++ b/src/game/input_main.cpp @@ -977,6 +977,14 @@ int CInputMain::Messenger(LPCHARACTER ch, const char* c_pData, size_t uiBytes) char name[CHARACTER_NAME_MAX_LEN + 1]; strlcpy(name, c_pData, sizeof(name)); +#ifdef FIX_MESSENGER_ACTION_SYNC + if (MessengerManager::instance().IsInList(ch->GetName(), name)) + { + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[Friends] You are already friends with %s."), name); + return CHARACTER_NAME_MAX_LEN; + } +#endif + if (ch->GetGMLevel() == GM_PLAYER && gm_get_level(name) != GM_PLAYER) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<๋ฉ”์‹ ์ ธ> ์šด์˜์ž๋Š” ๋ฉ”์‹ ์ ธ์— ์ถ”๊ฐ€ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")); @@ -986,11 +994,31 @@ int CInputMain::Messenger(LPCHARACTER ch, const char* c_pData, size_t uiBytes) LPCHARACTER tch = CHARACTER_MANAGER::instance().FindPC(name); if (!tch) + { +#ifdef CROSS_CHANNEL_FRIEND_REQUEST + const CCI* pkCCI = P2P_MANAGER::instance().Find(name); + + if (!pkCCI) + { + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s ๋‹˜์€ ์ ‘์†๋˜ ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค."), name); + return CHARACTER_NAME_MAX_LEN; + } + + // P2P request + MessengerManager::instance().P2PRequestToAdd_Stage1(ch, name); +#else ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s ๋‹˜์€ ์ ‘์†๋˜ ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค."), name); +#endif + } else { if (tch == ch) // ์ž์‹ ์€ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์—†๋‹ค. + { +#ifdef FIX_MESSENGER_ACTION_SYNC + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[Friends] You cannot add yourself as a friend.")); +#endif return CHARACTER_NAME_MAX_LEN; + } if (tch->IsBlockMode(BLOCK_MESSENGER_INVITE) == true) { @@ -1014,6 +1042,9 @@ int CInputMain::Messenger(LPCHARACTER ch, const char* c_pData, size_t uiBytes) char char_name[CHARACTER_NAME_MAX_LEN + 1]; strlcpy(char_name, c_pData, sizeof(char_name)); MessengerManager::instance().RemoveFromList(ch->GetName(), char_name); +#ifdef FIX_MESSENGER_ACTION_SYNC + MessengerManager::instance().RemoveFromList(char_name, ch->GetName());//friend removed from companion too. +#endif } return CHARACTER_NAME_MAX_LEN; @@ -3032,7 +3063,7 @@ void CInputMain::Refine(LPCHARACTER ch, const char* c_pData) } else { - ch->ChatPacket(CHAT_TYPE_INFO, "์‚ฌ๊ท€ ํƒ€์›Œ ์™„๋ฃŒ ๋ณด์ƒ์€ ํ•œ๋ฒˆ๊นŒ์ง€ ์‚ฌ์šฉ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค."); + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("์‚ฌ๊ท€ ํƒ€์›Œ ์™„๋ฃŒ ๋ณด์ƒ์€ ํ•œ๋ฒˆ๊นŒ์ง€ ์‚ฌ์šฉ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.")); } } } diff --git a/src/game/input_p2p.cpp b/src/game/input_p2p.cpp index 8edcbea..d05f8cb 100644 --- a/src/game/input_p2p.cpp +++ b/src/game/input_p2p.cpp @@ -20,6 +20,9 @@ #include "skill.h" #include "threeway_war.h" +#ifdef CROSS_CHANNEL_FRIEND_REQUEST +#include "crc32.h" +#endif //////////////////////////////////////////////////////////////////////////////// // Input Processor @@ -258,18 +261,84 @@ void CInputP2P::Setup(LPDESC d, const char * c_pData) d->SetP2P(d->GetHostName(), p->wPort, p->bChannel); } + +#ifdef CROSS_CHANNEL_FRIEND_REQUEST +void CInputP2P::MessengerRequestAdd(const char* c_pData) +{ + TPacketGGMessengerRequest* p = (TPacketGGMessengerRequest*)c_pData; + sys_log(0, "P2P: Messenger: Friend Request from %s to %s", p->account, p->target); + + LPCHARACTER tch = CHARACTER_MANAGER::Instance().FindPC(p->target); + MessengerManager::Instance().P2PRequestToAdd_Stage2(p->account, tch); +} + +void CInputP2P::MessengerResponse(const char* c_pData) +{ + TPacketGGMessengerResponse* p = (TPacketGGMessengerResponse*)c_pData; + + LPCHARACTER ch = CHARACTER_MANAGER::instance().FindPC(p->szRequester); + + if (!ch) + return; + + switch (p->bResponseType) + { + case 0: // already_sent + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[Friends] You already sent a friend request to %s."), p->szTarget); + break; + + case 1: // already_received_reverse + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[Friends] %s has already sent you a friend request."), p->szTarget); + break; + + case 2: // quest_running + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("์ƒ๋Œ€๋ฐฉ์ด ์นœ๊ตฌ ์ถ”๊ฐ€๋ฅผ ๋ฐ›์„ ์ˆ˜ ์—†๋Š” ์ƒํƒœ์ž…๋‹ˆ๋‹ค.")); + break; + + case 3: // blocking_requests + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("์ƒ๋Œ€๋ฐฉ์ด ๋ฉ”์‹ ์ ธ ์ถ”๊ฐ€ ๊ฑฐ๋ถ€ ์ƒํƒœ์ž…๋‹ˆ๋‹ค.")); + break; + } +} +#endif + void CInputP2P::MessengerAdd(const char * c_pData) { TPacketGGMessenger * p = (TPacketGGMessenger *) c_pData; sys_log(0, "P2P: Messenger Add %s %s", p->szAccount, p->szCompanion); MessengerManager::instance().__AddToList(p->szAccount, p->szCompanion); +#ifdef FIX_MESSENGER_ACTION_SYNC + MessengerManager::instance().__AddToList(p->szCompanion, p->szAccount, false); +#endif } void CInputP2P::MessengerRemove(const char * c_pData) { TPacketGGMessenger * p = (TPacketGGMessenger *) c_pData; sys_log(0, "P2P: Messenger Remove %s %s", p->szAccount, p->szCompanion); + +#ifdef FIX_MESSENGER_ACTION_SYNC + // Send removal packet to the person being removed (deletee) + LPCHARACTER deletee = CHARACTER_MANAGER::instance().FindPC(p->szCompanion); + + if (deletee && deletee->GetDesc()) + { + TPacketGCMessenger pack; + pack.header = HEADER_GC_MESSENGER; + pack.subheader = MESSENGER_SUBHEADER_GC_REMOVE_FRIEND; + pack.size = sizeof(TPacketGCMessenger) + sizeof(BYTE) + strlen(p->szAccount); + + BYTE bLen = strlen(p->szAccount); + deletee->GetDesc()->BufferedPacket(&pack, sizeof(pack)); + deletee->GetDesc()->BufferedPacket(&bLen, sizeof(BYTE)); + deletee->GetDesc()->Packet(p->szAccount, strlen(p->szAccount)); + } +#endif + MessengerManager::instance().__RemoveFromList(p->szAccount, p->szCompanion); +#ifdef FIX_MESSENGER_ACTION_SYNC + MessengerManager::instance().__RemoveFromList(p->szCompanion, p->szAccount, false); +#endif } void CInputP2P::FindPosition(LPDESC d, const char* c_pData) @@ -453,6 +522,16 @@ int CInputP2P::Analyze(LPDESC d, BYTE bHeader, const char * c_pData) MessengerAdd(c_pData); break; +#ifdef CROSS_CHANNEL_FRIEND_REQUEST + case HEADER_GG_MESSENGER_REQUEST_ADD: + MessengerRequestAdd(c_pData); + break; + + case HEADER_GG_MESSENGER_RESPONSE: + MessengerResponse(c_pData); + break; +#endif + case HEADER_GG_MESSENGER_REMOVE: MessengerRemove(c_pData); break; diff --git a/src/game/item.cpp b/src/game/item.cpp index 6e8fdab..250ca42 100644 --- a/src/game/item.cpp +++ b/src/game/item.cpp @@ -686,12 +686,12 @@ void CItem::ModifyPoints(bool bAdd) { if (bAdd) { - if (m_wCell == INVENTORY_MAX_NUM + WEAR_WEAPON) + if (m_wCell == (WORD)INVENTORY_MAX_NUM + (WORD)WEAR_WEAPON) m_pOwner->SetPart(PART_WEAPON, GetVnum()); } else { - if (m_wCell == INVENTORY_MAX_NUM + WEAR_WEAPON) + if (m_wCell == (WORD)INVENTORY_MAX_NUM + (WORD)WEAR_WEAPON) m_pOwner->SetPart(PART_WEAPON, m_pOwner->GetOriginalPart(PART_WEAPON)); } } @@ -701,12 +701,12 @@ void CItem::ModifyPoints(bool bAdd) { if (bAdd) { - if (m_wCell == INVENTORY_MAX_NUM + WEAR_WEAPON) + if (m_wCell == (WORD)INVENTORY_MAX_NUM + (WORD)WEAR_WEAPON) m_pOwner->SetPart(PART_WEAPON, GetVnum()); } else { - if (m_wCell == INVENTORY_MAX_NUM + WEAR_WEAPON) + if (m_wCell == (WORD)INVENTORY_MAX_NUM + (WORD)WEAR_WEAPON) m_pOwner->SetPart(PART_WEAPON, m_pOwner->GetOriginalPart(PART_WEAPON)); } } @@ -824,7 +824,7 @@ bool CItem::EquipTo(LPCHARACTER ch, BYTE bWearCell) // ์šฉํ˜ผ์„ ์Šฌ๋กฏ index๋Š” WEAR_MAX_NUM ๋ณด๋‹ค ํผ. if (IsDragonSoul()) { - if (bWearCell < WEAR_MAX_NUM || bWearCell >= WEAR_MAX_NUM + DRAGON_SOUL_DECK_MAX_NUM * DS_SLOT_MAX) + if (bWearCell < WEAR_MAX_NUM || bWearCell >= WEAR_MAX_NUM + (DWORD)DRAGON_SOUL_DECK_MAX_NUM * (DWORD)DS_SLOT_MAX) { sys_err("EquipTo: invalid dragon soul cell (this: #%d %s wearflag: %d cell: %d)", GetOriginalVnum(), GetName(), GetSubType(), bWearCell - WEAR_MAX_NUM); return false; @@ -869,10 +869,11 @@ bool CItem::EquipTo(LPCHARACTER ch, BYTE bWearCell) for (int i = 0; i < WEAR_MAX_NUM; ++i) { - if (item=m_pOwner->GetWear(i)) + if ((item = m_pOwner->GetWear(i))) { if (item->GetImmuneFlag() != 0) SET_BIT(dwImmuneFlag, item->GetImmuneFlag()); + if (item->GetAttributeCount() > 0) { if (item->HasAttr(APPLY_IMMUNE_STUN)) @@ -974,7 +975,7 @@ bool CItem::Unequip() for (int i = 0; i < WEAR_MAX_NUM; ++i) { - if (item=m_pOwner->GetWear(i)) + if ((item = m_pOwner->GetWear(i))) { if (item->GetImmuneFlag() != 0) SET_BIT(dwImmuneFlag, item->GetImmuneFlag()); diff --git a/src/game/item_manager.cpp b/src/game/item_manager.cpp index 585c13f..1358593 100644 --- a/src/game/item_manager.cpp +++ b/src/game/item_manager.cpp @@ -836,7 +836,7 @@ bool ITEM_MANAGER::GetDropPct(LPCHARACTER pkChr, LPCHARACTER pkKiller, OUT int& iRandRange = iRandRange * 100 / (100 + CPrivManager::instance().GetPriv(pkKiller, PRIV_ITEM_DROP) + - pkKiller->IsEquipUniqueItem(UNIQUE_ITEM_DOUBLE_ITEM)?100:0); + (pkKiller->IsEquipUniqueItem(UNIQUE_ITEM_DOUBLE_ITEM) ? 100 : 0)); if (distribution_test_server) iRandRange /= 3; diff --git a/src/game/item_manager_read_tables.cpp b/src/game/item_manager_read_tables.cpp index 3859949..e115ff7 100644 --- a/src/game/item_manager_read_tables.cpp +++ b/src/game/item_manager_read_tables.cpp @@ -1,4 +1,4 @@ -๏ปฟ#include "stdafx.h" +#include "stdafx.h" #include "utils.h" #include "config.h" #include "char.h" @@ -79,7 +79,7 @@ bool ITEM_MANAGER::ReadCommonDropItemFile(const char * c_pszFileName) if (!ITEM_MANAGER::instance().GetVnumByOriginalName(d[i].szItemName, dwItemVnum)) { - // ภฬธงภธทฮ ธ๘รฃภธธ้ น๘ศฃทฮ ฐหป๖ + // ๏ฟฝฬธ๏ฟฝ๏ฟฝ๏ฟฝ๏ฟฝ๏ฟฝ ๏ฟฝ๏ฟฝรฃ๏ฟฝ๏ฟฝ๏ฟฝ๏ฟฝ ๏ฟฝ๏ฟฝศฃ๏ฟฝ๏ฟฝ ๏ฟฝหป๏ฟฝ str_to_number(dwItemVnum, d[i].szItemName); if (!ITEM_MANAGER::instance().GetTable(dwItemVnum)) { @@ -224,7 +224,7 @@ bool ITEM_MANAGER::ReadSpecialDropItemFile(const char * c_pszFileName) if (!GetVnumByOriginalName(name.c_str(), dwVnum)) { - if (name == "ฐๆว่ฤก" || name == "exp") + if (name == "exp") { dwVnum = CSpecialItemGroup::EXP; } @@ -373,7 +373,8 @@ bool ITEM_MANAGER::ConvSpecialDropItemFile() if (!GetVnumByOriginalName(name.c_str(), dwVnum)) { - if ( name == "ฐๆว่ฤก" || + //if ( name == "๏ฟฝ๏ฟฝ๏ฟฝ๏ฟฝฤก" || + if (name == "exp" || name == "mob" || name == "slow" || name == "drain_hp" || @@ -406,7 +407,7 @@ bool ITEM_MANAGER::ConvSpecialDropItemFile() str_to_number(iRarePct, pTok->at(3).c_str()); } - // 1 "ฑโผ๚ ผ๖ทรผญ" 1 100 + // 1 "๏ฟฝ๏ฟฝ๏ฟฝ ๏ฟฝ๏ฟฝ๏ฟฝรผ๏ฟฝ" 1 100 if (0 == dwVnum) fprintf(fp, " %d %s %d %d\n", k, name.c_str(), iCount, iProb); else diff --git a/src/game/messenger_manager.cpp b/src/game/messenger_manager.cpp index 4a10135..eca7945 100644 --- a/src/game/messenger_manager.cpp +++ b/src/game/messenger_manager.cpp @@ -12,6 +12,11 @@ #include "char_manager.h" #include "questmanager.h" +#ifdef FIX_MESSENGER_ACTION_SYNC +static char __account[CHARACTER_NAME_MAX_LEN * 2 + 1]; +static char __companion[CHARACTER_NAME_MAX_LEN * 2 + 1]; +#endif + MessengerManager::MessengerManager() { } @@ -43,6 +48,13 @@ void MessengerManager::Login(MessengerManager::keyA account) if (m_set_loginAccount.find(account) != m_set_loginAccount.end()) return; +#ifdef FIX_MESSENGER_ACTION_SYNC + DBManager::instance().EscapeString(__account, sizeof(__account), account.c_str(), account.size()); + + if (account.compare(__account)) + return; +#endif + DBManager::instance().FuncQuery(std::bind(&MessengerManager::LoadList, this, std::placeholders::_1), "SELECT account, companion FROM messenger_list%s WHERE account='%s'", get_table_postfix(), account.c_str()); @@ -110,13 +122,131 @@ void MessengerManager::Logout(MessengerManager::keyA account) m_Relation.erase(account); //m_map_stMobile.erase(account); + +#ifdef FIX_MESSENGER_ACTION_SYNC + // remove any pending requests from/to this account so they don't get stuck + EraseRequestsForAccount(account); +#endif } +#ifdef CROSS_CHANNEL_FRIEND_REQUEST +void MessengerManager::RegisterRequestToAdd(const char* name, const char* targetName) +{ + uint32_t dw1 = GetCRC32(name, strlen(name)); + uint32_t dw2 = GetCRC32(targetName, strlen(targetName)); + + char buf[64]{ 0, }; + snprintf(buf, sizeof(buf), "%u:%u", dw1, dw2); + buf[63] = '\0'; + + uint32_t dwComplex = GetCRC32(buf, strlen(buf)); + +#ifdef FIX_MESSENGER_ACTION_SYNC + // Check if this requester already sent the same request + if (m_set_requestToAdd.find(dwComplex) != m_set_requestToAdd.end()) + { + // Send P2P response back to requester's core + TPacketGGMessengerResponse p2pResp{}; + p2pResp.bHeader = HEADER_GG_MESSENGER_RESPONSE; + strlcpy(p2pResp.szRequester, name, sizeof(p2pResp.szRequester)); + strlcpy(p2pResp.szTarget, targetName, sizeof(p2pResp.szTarget)); + p2pResp.bResponseType = 0; // already_sent + P2P_MANAGER::Instance().Send(&p2pResp, sizeof(TPacketGGMessengerResponse)); + return; + } + + // Clear any old incoming requests for this target before adding new one + EraseIncomingRequestsForTarget(targetName); + RegisterRequestComplex(dw1, dw2, dwComplex); +#else + m_set_requestToAdd.insert(dwComplex); +#endif +} + +// stage 1: starts on the core where "ch" resides. Validate ch and move to stage 2 +void MessengerManager::P2PRequestToAdd_Stage1(LPCHARACTER ch, const char* targetName) +{ + LPCHARACTER pkTarget = CHARACTER_MANAGER::Instance().FindPC(targetName); + + uint32_t dw1 = GetCRC32(ch->GetName(), strlen(ch->GetName())); + uint32_t dw2 = GetCRC32(targetName, strlen(targetName)); + + char buf[64]{ 0, }; + snprintf(buf, sizeof(buf), "%u:%u", dw2, dw1); + buf[63] = '\0'; + + uint32_t dwComplex = GetCRC32(buf, strlen(buf)); + + // Check if target already sent a request to requester (reverse) + if (m_set_requestToAdd.find(dwComplex) != m_set_requestToAdd.end()) + { + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[Friends] %s has already sent you a friend request."), targetName); + return; + } + + if (!pkTarget) + { + if (!ch || !ch->IsPC()) + return; + + if (quest::CQuestManager::instance().GetPCForce(ch->GetPlayerID())->IsRunning() == true) + { + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("์ƒ๋Œ€๋ฐฉ์ด ์นœ๊ตฌ ์ถ”๊ฐ€๋ฅผ ๋ฐ›์„ ์ˆ˜ ์—†๋Š” ์ƒํƒœ์ž…๋‹ˆ๋‹ค.")); + return; + } + + TPacketGGMessengerRequest p2pp{}; + p2pp.header = HEADER_GG_MESSENGER_REQUEST_ADD; + strlcpy(p2pp.account, ch->GetName(), CHARACTER_NAME_MAX_LEN + 1); + strlcpy(p2pp.target, targetName, CHARACTER_NAME_MAX_LEN + 1); + P2P_MANAGER::Instance().Send(&p2pp, sizeof(TPacketGGMessengerRequest)); + } + else // if we have both, just continue normally + RequestToAdd(ch, pkTarget); +} + +// stage 2: ends up on the core where the target resides +void MessengerManager::P2PRequestToAdd_Stage2(const char* characterName, LPCHARACTER target) +{ + LPCHARACTER ch = CHARACTER_MANAGER::Instance().FindPC(characterName); + + if (!target || !target->IsPC()) + return; + + if (quest::CQuestManager::instance().GetPCForce(target->GetPlayerID())->IsRunning()) + { + // Send response back to requester's core + TPacketGGMessengerResponse p2pResp{}; + p2pResp.bHeader = HEADER_GG_MESSENGER_RESPONSE; + strlcpy(p2pResp.szRequester, characterName, sizeof(p2pResp.szRequester)); + strlcpy(p2pResp.szTarget, target->GetName(), sizeof(p2pResp.szTarget)); + p2pResp.bResponseType = 2; // quest_running + P2P_MANAGER::Instance().Send(&p2pResp, sizeof(TPacketGGMessengerResponse)); + return; + } + + if (target->IsBlockMode(BLOCK_MESSENGER_INVITE)) + { + // Send response back to requester's core + TPacketGGMessengerResponse p2pResp{}; + p2pResp.bHeader = HEADER_GG_MESSENGER_RESPONSE; + strlcpy(p2pResp.szRequester, characterName, sizeof(p2pResp.szRequester)); + strlcpy(p2pResp.szTarget, target->GetName(), sizeof(p2pResp.szTarget)); + p2pResp.bResponseType = 3; // blocking_requests + P2P_MANAGER::Instance().Send(&p2pResp, sizeof(TPacketGGMessengerResponse)); + return; + } + + MessengerManager::Instance().RegisterRequestToAdd(characterName, target->GetName()); + target->ChatPacket(CHAT_TYPE_COMMAND, "messenger_auth %s", characterName); +} +#endif + void MessengerManager::RequestToAdd(LPCHARACTER ch, LPCHARACTER target) { if (!ch->IsPC() || !target->IsPC()) return; - + if (quest::CQuestManager::instance().GetPCForce(ch->GetPlayerID())->IsRunning() == true) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("์ƒ๋Œ€๋ฐฉ์ด ์นœ๊ตฌ ์ถ”๊ฐ€๋ฅผ ๋ฐ›์„ ์ˆ˜ ์—†๋Š” ์ƒํƒœ์ž…๋‹ˆ๋‹ค.")); @@ -133,7 +263,43 @@ void MessengerManager::RequestToAdd(LPCHARACTER ch, LPCHARACTER target) snprintf(buf, sizeof(buf), "%u:%u", dw1, dw2); DWORD dwComplex = GetCRC32(buf, strlen(buf)); +#ifdef FIX_MESSENGER_ACTION_SYNC + std::string requester = ch->GetName(); + std::string companion = target->GetName(); + + char buf2[64]; + snprintf(buf2, sizeof(buf2), "%u:%u", dw2, dw1); + DWORD dwComplexRev = GetCRC32(buf2, strlen(buf2)); + + // In-memory quick check (fast, works if lists are loaded) + if (IsInList(requester, companion) || IsInList(companion, requester)) + { + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[Friends] You are already friends with %s."), companion.c_str()); + return; + } + + // Check if this requester already sent the same request + if (m_set_requestToAdd.find(dwComplex) != m_set_requestToAdd.end()) + { + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[Friends] You already sent a friend request to %s."), companion.c_str()); + return; + } + + // Check if target already sent a request to requester (reverse) + if (m_set_requestToAdd.find(dwComplexRev) != m_set_requestToAdd.end()) + { + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[Friends] %s has already sent you a friend request."), companion.c_str()); + + return; + } + + // Clear any old incoming requests for this target before adding new one + EraseIncomingRequestsForTarget(target->GetName()); + // register complex indexed mappings so we can erase them on disconnect + RegisterRequestComplex(dw1, dw2, dwComplex); +#else m_set_requestToAdd.insert(dwComplex); +#endif target->ChatPacket(CHAT_TYPE_COMMAND, "messenger_auth %s", ch->GetName()); } @@ -177,7 +343,22 @@ bool MessengerManager::AuthToAdd(MessengerManager::keyA account, MessengerManage return false; } +#ifndef FIX_MESSENGER_ACTION_SYNC m_set_requestToAdd.erase(dwComplex); +#else + RemoveComplex(dwComplex); + + // In-memory quick check (fast, works if lists are loaded) + if (IsInList(account, companion) || IsInList(companion, account)) + { + LPCHARACTER acc_ch = CHARACTER_MANAGER::instance().FindPC(account.c_str()); + + if (acc_ch) + acc_ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[Friends] You are already friends with %s."), companion.c_str()); + + return false; + } +#endif if (!bDeny) { @@ -188,7 +369,122 @@ bool MessengerManager::AuthToAdd(MessengerManager::keyA account, MessengerManage return true; } +#ifdef FIX_MESSENGER_ACTION_SYNC +void MessengerManager::RegisterRequestComplex(DWORD dw1, DWORD dw2, DWORD dwComplex) +{ + // avoid duplicates + if (m_set_requestToAdd.find(dwComplex) != m_set_requestToAdd.end()) + return; + + m_set_requestToAdd.insert(dwComplex); + m_map_requestComplex[dwComplex] = std::make_pair(dw1, dw2); + m_map_requestsFrom[dw1].insert(dwComplex); + m_map_requestsTo[dw2].insert(dwComplex); +} + +void MessengerManager::RemoveComplex(DWORD dwComplex) +{ + auto it = m_map_requestComplex.find(dwComplex); + + if (it == m_map_requestComplex.end()) + { + m_set_requestToAdd.erase(dwComplex); + return; + } + + DWORD dw1 = it->second.first; + DWORD dw2 = it->second.second; + + // erase complex mapping + m_map_requestComplex.erase(it); + + // remove from requester index + auto itFrom = m_map_requestsFrom.find(dw1); + + if (itFrom != m_map_requestsFrom.end()) + { + itFrom->second.erase(dwComplex); + + if (itFrom->second.empty()) + m_map_requestsFrom.erase(itFrom); + } + + // remove from target index + auto itTo = m_map_requestsTo.find(dw2); + + if (itTo != m_map_requestsTo.end()) + { + itTo->second.erase(dwComplex); + + if (itTo->second.empty()) + m_map_requestsTo.erase(itTo); + } + + // remove from master set + m_set_requestToAdd.erase(dwComplex); +} + +void MessengerManager::EraseRequestsForAccount(keyA account) +{ + DWORD dw = GetCRC32(account.c_str(), account.length()); + + std::vector toRemove; + + auto itFrom = m_map_requestsFrom.find(dw); + + if (itFrom != m_map_requestsFrom.end()) + { + for (DWORD c : itFrom->second) + toRemove.push_back(c); + } + + auto itTo = m_map_requestsTo.find(dw); + + if (itTo != m_map_requestsTo.end()) + { + for (DWORD c : itTo->second) + toRemove.push_back(c); + } + + if (toRemove.empty()) + return; + + // uniqueify to avoid double removals + std::sort(toRemove.begin(), toRemove.end()); + toRemove.erase(std::unique(toRemove.begin(), toRemove.end()), toRemove.end()); + + for (DWORD c : toRemove) + RemoveComplex(c); +} + + +void MessengerManager::EraseIncomingRequestsForTarget(const char* targetName) +{ + DWORD dwTarget = GetCRC32(targetName, strlen(targetName)); + + std::vector toRemove; + + // Find all requests where this person is the target (incoming requests) + auto itTo = m_map_requestsTo.find(dwTarget); + + if (itTo != m_map_requestsTo.end()) + { + for (DWORD c : itTo->second) + toRemove.push_back(c); + } + + if (toRemove.empty()) + return; + + // Remove all found requests + for (DWORD c : toRemove) + RemoveComplex(c); +} + +void MessengerManager::__AddToList(MessengerManager::keyA account, MessengerManager::keyA companion, bool isRequester) +#else void MessengerManager::__AddToList(MessengerManager::keyA account, MessengerManager::keyA companion) +#endif { m_Relation[account].insert(companion); m_InverseRelation[companion].insert(account); @@ -196,14 +492,22 @@ void MessengerManager::__AddToList(MessengerManager::keyA account, MessengerMana LPCHARACTER ch = CHARACTER_MANAGER::instance().FindPC(account.c_str()); LPDESC d = ch ? ch->GetDesc() : NULL; +#ifdef FIX_MESSENGER_ACTION_SYNC + if (d && isRequester) +#else if (d) +#endif { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<๋ฉ”์‹ ์ ธ> %s ๋‹˜์„ ์นœ๊ตฌ๋กœ ์ถ”๊ฐ€ํ•˜์˜€์Šต๋‹ˆ๋‹ค."), companion.c_str()); } LPCHARACTER tch = CHARACTER_MANAGER::instance().FindPC(companion.c_str()); +#ifdef CROSS_CHANNEL_FRIEND_REQUEST + if (tch || P2P_MANAGER::Instance().Find(companion.c_str())) +#else if (tch) +#endif SendLogin(account, companion); else SendLogout(account, companion); @@ -217,7 +521,16 @@ void MessengerManager::AddToList(MessengerManager::keyA account, MessengerManage if (m_Relation[account].find(companion) != m_Relation[account].end()) return; +#ifdef FIX_MESSENGER_ACTION_SYNC + DBManager::instance().EscapeString(__account, sizeof(__account), account.c_str(), account.size()); + DBManager::instance().EscapeString(__companion, sizeof(__companion), companion.c_str(), companion.size()); + + if (account.compare(__account) || companion.compare(__companion)) + return; +#endif + sys_log(0, "Messenger Add %s %s", account.c_str(), companion.c_str()); + DBManager::instance().Query("INSERT INTO messenger_list%s VALUES ('%s', '%s')", get_table_postfix(), account.c_str(), companion.c_str()); @@ -231,16 +544,46 @@ void MessengerManager::AddToList(MessengerManager::keyA account, MessengerManage P2P_MANAGER::instance().Send(&p2ppck, sizeof(TPacketGGMessenger)); } +#ifdef FIX_MESSENGER_ACTION_SYNC +void MessengerManager::__RemoveFromList(MessengerManager::keyA account, MessengerManager::keyA companion, bool isRequester) +#else void MessengerManager::__RemoveFromList(MessengerManager::keyA account, MessengerManager::keyA companion) +#endif { m_Relation[account].erase(companion); m_InverseRelation[companion].erase(account); +#ifdef FIX_MESSENGER_ACTION_SYNC + m_Relation[companion].erase(account); + m_InverseRelation[account].erase(companion); +#endif LPCHARACTER ch = CHARACTER_MANAGER::instance().FindPC(account.c_str()); LPDESC d = ch ? ch->GetDesc() : NULL; +#ifdef FIX_MESSENGER_ACTION_SYNC + if (d && isRequester) +#else if (d) +#endif ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<๋ฉ”์‹ ์ ธ> %s ๋‹˜์„ ๋ฉ”์‹ ์ €์—์„œ ์‚ญ์ œํ•˜์˜€์Šต๋‹ˆ๋‹ค."), companion.c_str()); + +#ifdef FIX_MESSENGER_ACTION_SYNC + LPCHARACTER tch = CHARACTER_MANAGER::Instance().FindPC(companion.c_str()); + + if (tch && tch->GetDesc()) + { + TPacketGCMessenger p; + + p.header = HEADER_GC_MESSENGER; + p.subheader = MESSENGER_SUBHEADER_GC_REMOVE_FRIEND; + p.size = sizeof(TPacketGCMessenger) + sizeof(BYTE) + account.size(); + + BYTE bLen = account.size(); + tch->GetDesc()->BufferedPacket(&p, sizeof(p)); + tch->GetDesc()->BufferedPacket(&bLen, sizeof(BYTE)); + tch->GetDesc()->Packet(account.c_str(), account.size()); + } +#endif } bool MessengerManager::IsInList(MessengerManager::keyA account, MessengerManager::keyA companion) // Fix @@ -265,8 +608,17 @@ void MessengerManager::RemoveFromList(MessengerManager::keyA account, MessengerM if (!IsInList(account, companion)) // Fix return; +#ifdef FIX_MESSENGER_ACTION_SYNC + DBManager::instance().EscapeString(__account, sizeof(__account), account.c_str(), account.size()); + DBManager::instance().EscapeString(__companion, sizeof(__companion), companion.c_str(), companion.size()); + + if (account.compare(__account) || companion.compare(__companion)) + return; +#else char companionEscaped[CHARACTER_NAME_MAX_LEN * 2 + 1]; - DBManager::instance().EscapeString(companionEscaped, sizeof(companionEscaped), companion.c_str(), companion.length()); + + DBManager::instance().EscapeString(companionEscaped, sizeof(companionEscaped), companion.c_str(), companion.length()); +#endif sys_log(1, "Messenger Remove %s %s", account.c_str(), companion.c_str()); @@ -274,8 +626,13 @@ void MessengerManager::RemoveFromList(MessengerManager::keyA account, MessengerM // get_table_postfix(), account.c_str(), companion.c_str()); // Fix +#ifdef FIX_MESSENGER_ACTION_SYNC + DBManager::instance().Query("DELETE FROM messenger_list%s WHERE (account='%s' AND companion = '%s') OR (account = '%s' AND companion = '%s')", + get_table_postfix(), account.c_str(), companion.c_str(), companion.c_str(), account.c_str()); +#else DBManager::instance().Query("DELETE FROM messenger_list%s WHERE account='%s' AND companion = '%s'", - get_table_postfix(), account.c_str(), companionEscaped); + get_table_postfix(), account.c_str(), companion.c_str()); +#endif __RemoveFromList(account, companion); @@ -291,6 +648,13 @@ void MessengerManager::RemoveAllList(keyA account) { std::set company(m_Relation[account]); +#ifdef FIX_MESSENGER_ACTION_SYNC + DBManager::instance().EscapeString(__account, sizeof(__account), account.c_str(), account.size()); + + if (account.compare(__account)) + return; +#endif + /* SQL Data ์‚ญ์ œ */ DBManager::instance().Query("DELETE FROM messenger_list%s WHERE account='%s' OR companion='%s'", get_table_postfix(), account.c_str(), account.c_str()); @@ -301,6 +665,9 @@ void MessengerManager::RemoveAllList(keyA account) iter++ ) { this->RemoveFromList(account, *iter); +#ifdef FIX_MESSENGER_ACTION_SYNC + this->RemoveFromList(*iter, account); +#endif } /* ๋ณต์‚ฌํ•œ ๋ฐ์ดํƒ€ ์‚ญ์ œ */ @@ -314,7 +681,6 @@ void MessengerManager::RemoveAllList(keyA account) company.clear(); } - void MessengerManager::SendList(MessengerManager::keyA account) { LPCHARACTER ch = CHARACTER_MANAGER::instance().FindPC(account.c_str()); diff --git a/src/game/messenger_manager.h b/src/game/messenger_manager.h index fc428ff..fa72a63 100644 --- a/src/game/messenger_manager.h +++ b/src/game/messenger_manager.h @@ -3,6 +3,11 @@ #include "db.h" +#ifdef FIX_MESSENGER_ACTION_SYNC +#include +#include +#endif + class MessengerManager : public singleton { public: @@ -20,14 +25,29 @@ class MessengerManager : public singleton void Logout(keyA account); void RequestToAdd(LPCHARACTER ch, LPCHARACTER target); + +#ifdef CROSS_CHANNEL_FRIEND_REQUEST + void RegisterRequestToAdd(const char* szAccount, const char* szTarget); + void P2PRequestToAdd_Stage1(LPCHARACTER ch, const char* targetName); + void P2PRequestToAdd_Stage2(const char* characterName, LPCHARACTER target); +#endif + // void AuthToAdd(keyA account, keyA companion, bool bDeny); bool AuthToAdd(keyA account, keyA companion, bool bDeny); +#ifdef FIX_MESSENGER_ACTION_SYNC + void __AddToList(keyA account, keyA companion, bool isRequester = true); // ์‹ค์ œ m_Relation, m_InverseRelation ์ˆ˜์ •ํ•˜๋Š” ๋ฉ”์†Œ๋“œ +#else void __AddToList(keyA account, keyA companion); // ์‹ค์ œ m_Relation, m_InverseRelation ์ˆ˜์ •ํ•˜๋Š” ๋ฉ”์†Œ๋“œ +#endif void AddToList(keyA account, keyA companion); +#ifdef FIX_MESSENGER_ACTION_SYNC + void __RemoveFromList(keyA account, keyA companion, bool isRequester = true); // ์‹ค์ œ m_Relation, m_InverseRelation ์ˆ˜์ •ํ•˜๋Š” ๋ฉ”์†Œ๋“œ +#else void __RemoveFromList(keyA account, keyA companion); // ์‹ค์ œ m_Relation, m_InverseRelation ์ˆ˜์ •ํ•˜๋Š” ๋ฉ”์†Œ๋“œ - void RemoveFromList(keyA account, keyA companion); +#endif + void RemoveFromList(keyA account, keyA companion); void RemoveAllList(keyA account); @@ -44,10 +64,27 @@ class MessengerManager : public singleton void Destroy(); +#ifdef FIX_MESSENGER_ACTION_SYNC + // Helpers to manage friend-request index so requests involving a disconnecting character can be removed + void RegisterRequestComplex(DWORD dw1, DWORD dw2, DWORD dwComplex); + void RemoveComplex(DWORD dwComplex); + void EraseRequestsForAccount(keyA account); + void EraseIncomingRequestsForTarget(const char* targetName); +#endif + std::set m_set_loginAccount; std::map > m_Relation; std::map > m_InverseRelation; std::set m_set_requestToAdd; + +#ifdef FIX_MESSENGER_ACTION_SYNC + // Map complex -> (dw1, dw2) + std::unordered_map> m_map_requestComplex; + // requester CRC -> set of complex values + std::unordered_map> m_map_requestsFrom; + // target CRC -> set of complex values + std::unordered_map> m_map_requestsTo; +#endif }; #endif diff --git a/src/game/packet.h b/src/game/packet.h index b6be7c6..26912c0 100644 --- a/src/game/packet.h +++ b/src/game/packet.h @@ -304,6 +304,11 @@ enum HEADER_GG_CHECK_CLIENT_VERSION = 21, HEADER_GG_BLOCK_CHAT = 22, +#ifdef CROSS_CHANNEL_FRIEND_REQUEST + HEADER_GG_MESSENGER_REQUEST_ADD = 23, + HEADER_GG_MESSENGER_RESPONSE = 24, +#endif + HEADER_GG_SIEGE = 25, HEADER_GG_MONARCH_NOTICE = 26, HEADER_GG_MONARCH_TRANSFER = 27, @@ -443,6 +448,23 @@ typedef struct SPacketGGMessenger char szCompanion[CHARACTER_NAME_MAX_LEN + 1]; } TPacketGGMessenger; +#ifdef CROSS_CHANNEL_FRIEND_REQUEST +typedef struct SPacketGGMessengerRequest +{ + uint8_t header; + char account[CHARACTER_NAME_MAX_LEN + 1]; + char target[CHARACTER_NAME_MAX_LEN + 1]; +} TPacketGGMessengerRequest; + +typedef struct SPacketGGMessengerResponse +{ + BYTE bHeader; + char szRequester[CHARACTER_NAME_MAX_LEN + 1]; + char szTarget[CHARACTER_NAME_MAX_LEN + 1]; + BYTE bResponseType; // 0=already_sent, 1=already_received_reverse, 2=quest_running, 3=blocking_requests +} TPacketGGMessengerResponse; +#endif + typedef struct SPacketGGMessengerMobile { uint8_t bHeader; @@ -581,8 +603,38 @@ typedef struct command_attack uint32_t dwVID; uint8_t bCRCMagicCubeProcPiece; uint8_t bCRCMagicCubeFilePiece; +#ifdef FIX_POS_SYNC + BOOL bPacket; + LONG lSX; + LONG lSY; + LONG lX; + LONG lY; + float fSyncDestX; + float fSyncDestY; + DWORD dwBlendDuration; + DWORD dwComboMotion; + DWORD dwTime; +#endif } TPacketCGAttack; +#ifdef FIX_POS_SYNC +typedef struct packet_attack +{ + BYTE bHeader; + BYTE bType; + DWORD dwAttacakerVID; + DWORD dwVID; + BOOL bPacket; + LONG lSX; + LONG lSY; + LONG lX; + LONG lY; + float fSyncDestX; + float fSyncDestY; + DWORD dwBlendDuration; +} TPacketGCAttack; +#endif + enum EMoveFuncType { FUNC_WAIT, @@ -1421,7 +1473,10 @@ enum MESSENGER_SUBHEADER_GC_LOGIN, MESSENGER_SUBHEADER_GC_LOGOUT, MESSENGER_SUBHEADER_GC_INVITE, - MESSENGER_SUBHEADER_GC_MOBILE + MESSENGER_SUBHEADER_GC_MOBILE, +#ifdef FIX_MESSENGER_ACTION_SYNC + MESSENGER_SUBHEADER_GC_REMOVE_FRIEND +#endif }; typedef struct packet_messenger diff --git a/src/game/packet_info.cpp b/src/game/packet_info.cpp index d80d681..07799ed 100644 --- a/src/game/packet_info.cpp +++ b/src/game/packet_info.cpp @@ -243,6 +243,10 @@ CPacketInfoGG::CPacketInfoGG() Set(HEADER_GG_SHOUT, sizeof(TPacketGGShout), "Shout", false); Set(HEADER_GG_DISCONNECT, sizeof(TPacketGGDisconnect), "Disconnect", false); Set(HEADER_GG_MESSENGER_ADD, sizeof(TPacketGGMessenger), "MessengerAdd", false); +#ifdef CROSS_CHANNEL_FRIEND_REQUEST + Set(HEADER_GG_MESSENGER_REQUEST_ADD, sizeof(TPacketGGMessengerRequest), "MessengerRequestAdd", false); + Set(HEADER_GG_MESSENGER_RESPONSE, sizeof(TPacketGGMessengerResponse), "MessengerResponse", false); +#endif Set(HEADER_GG_MESSENGER_REMOVE, sizeof(TPacketGGMessenger), "MessengerRemove", false); Set(HEADER_GG_FIND_POSITION, sizeof(TPacketGGFindPosition), "FindPosition", false); Set(HEADER_GG_WARP_CHARACTER, sizeof(TPacketGGWarpCharacter), "WarpCharacter", false); @@ -258,6 +262,7 @@ CPacketInfoGG::CPacketInfoGG() // BLOCK_CHAT Set(HEADER_GG_BLOCK_CHAT, sizeof(TPacketGGBlockChat), "BlockChat", false); // END_OF_BLOCK_CHAT + Set(HEADER_GG_SIEGE, sizeof(TPacketGGSiege), "Siege", false); Set(HEADER_GG_MONARCH_NOTICE, sizeof(TPacketGGMonarchNotice), "MonarchNotice", false); diff --git a/src/game/questlua_dungeon.cpp b/src/game/questlua_dungeon.cpp index 4550362..2b7d6f2 100644 --- a/src/game/questlua_dungeon.cpp +++ b/src/game/questlua_dungeon.cpp @@ -1277,7 +1277,7 @@ namespace quest else { sys_err("not in a dungeon"); - lua_pushnumber(L, LONG_MAX); + lua_pushnumber(L, static_cast(LONG_MAX)); } return 1; diff --git a/src/game/questlua_global.cpp b/src/game/questlua_global.cpp index df3000b..7637c3c 100644 --- a/src/game/questlua_global.cpp +++ b/src/game/questlua_global.cpp @@ -797,7 +797,7 @@ namespace quest return 1; } - // ๏ฟฝ๏ฟฝ๏ฟฝฮฟ๏ฟฝ state๏ฟฝ๏ฟฝ ๏ฟฝ๏ฟฝ๏ฟฝ๏ฟฝ๏ฟฝ. + // ฮฟ state . int _set_quest_state(lua_State* L) { if (!lua_isstring(L, 1) || !lua_isstring(L, 2)) @@ -957,7 +957,7 @@ namespace quest event_create(warp_all_to_village_event, info, PASSES_PER_SEC(iSec)); - SendNoticeMap(LC_TEXT("๏ฟฝ๏ฟฝ๏ฟฝ๏ฟฝ๏ฟฝ ๏ฟฝ๏ฟฝ๏ฟฝ ๏ฟฝ๏ฟฝ๏ฟฝ๏ฟฝ๏ฟฝ๏ฟฝ ๏ฟฝฬต๏ฟฝ๏ฟฝหดฯด๏ฟฝ."), iMapIndex, false); + SendNoticeMap(LC_TEXT("์ž ์‹œํ›„ ๋ชจ๋‘ ๋งˆ์„๋กœ ์ด๋™๋ฉ๋‹ˆ๋‹ค."), iMapIndex, false); return 0; } @@ -1031,7 +1031,7 @@ namespace quest return 0; } - //๏ฟฝ๏ฟฝ๏ฟฝ๏ฟฝ: ๏ฟฝ๏ฟฝ ๏ฟฝ๏ฟฝ๏ฟฝ๏ฟฝ๏ฟฝ๏ฟฝ ๏ฟฝศตวด๏ฟฝ ๏ฟฝสฟ๏ฟฝ๏ฟฝ๏ฟฝ๏ฟฝ๏ฟฝ ๏ฟฝ๏ฟฝ๏ฟฝ + // : ศตวด สฟ int _regen_in_map( lua_State * L ) { int iMapIndex = static_cast(lua_tonumber(L, 1)); diff --git a/src/game/shop_manager.cpp b/src/game/shop_manager.cpp index 86f2144..aebc656 100644 --- a/src/game/shop_manager.cpp +++ b/src/game/shop_manager.cpp @@ -281,7 +281,7 @@ void CShopManager::Sell(LPCHARACTER ch, BYTE bCell, BYTE bCount) if (item->IsEquipped() == true) { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("์ฐฉ์šฉ ์ค‘์ธ ์•„์ดํ…œ์€ ํŒ๋งคํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")); + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("์žฅ๋น„์ค‘์ธ ์•„์ดํ…œ์€ ๊ฐœ์ธ์ƒ์ ์—์„œ ํŒ๋งคํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")); return; } diff --git a/src/game/trigger.cpp b/src/game/trigger.cpp index 35f6127..6737c8a 100644 --- a/src/game/trigger.cpp +++ b/src/game/trigger.cpp @@ -7,6 +7,8 @@ #include "affect.h" #include "shop_manager.h" +#include + int OnClickShop(TRIGGERPARAM); int OnClickTalk(TRIGGERPARAM); @@ -61,7 +63,8 @@ class FuncFindMobVictim public: FuncFindMobVictim(LPCHARACTER pkChr, int iMaxDistance) : m_pkChr(pkChr), - m_iMinDistance(~(1L << 31)), + //m_iMinDistance(~(1L << 31)), + m_iMinDistance(INT32_MIN), m_iMaxDistance(iMaxDistance), m_lx(pkChr->GetX()), m_ly(pkChr->GetY()), diff --git a/src/game/utils.cpp b/src/game/utils.cpp index 677e623..194e91c 100644 --- a/src/game/utils.cpp +++ b/src/game/utils.cpp @@ -148,7 +148,11 @@ int CalculateDuration(int iSpd, int iDur) } double uniform_random(double a, double b) { - return thecore_random() / (RAND_MAX + 1.f) * (b - a) + a; + // Uses 64-bit precision and the full range of the 32-bit DWORD + const double MAX_DIVISOR = 4294967296.0; + + return (static_cast(thecore_random()) / MAX_DIVISOR) * (b - a) + a; + //return thecore_random() / (RAND_MAX + 1.f) * (b - a) + a; } float gauss_random(float avg, float sigma) diff --git a/src/liblua/src/llex.c b/src/liblua/src/llex.c index 4a6d920..00fa163 100644 --- a/src/liblua/src/llex.c +++ b/src/liblua/src/llex.c @@ -282,7 +282,7 @@ static void read_string (LexState *LS, int del, SemInfo *seminfo) { else { switch (b_current) { - case EOZ: + case (unsigned char)EOZ: save(LS, '\0', l); luaX_lexerror(LS, "unfinished string", TK_EOS); break; /* to avoid warnings */ diff --git a/src/liblua/src/llimits.h b/src/liblua/src/llimits.h index 9684b76..26f36e8 100644 --- a/src/liblua/src/llimits.h +++ b/src/liblua/src/llimits.h @@ -10,6 +10,7 @@ #include #include +#include #include "lua.h" @@ -69,7 +70,7 @@ typedef unsigned char lu_byte; ** this is for hashing only; there is no problem if the integer ** cannot hold the whole pointer value */ -#define IntPoint(p) ((lu_hash)(p)) +#define IntPoint(p) ((lu_hash)(uintptr_t)(p)) diff --git a/src/liblua/src/ltable.c b/src/liblua/src/ltable.c index 5bfffb4..a0e3930 100644 --- a/src/liblua/src/ltable.c +++ b/src/liblua/src/ltable.c @@ -67,7 +67,7 @@ ** for some types, it is better to avoid modulus by power of 2, as ** they tend to have many 2 factors. */ -#define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1)))) +#define hashmod(t,n) (gnode(t, (lu_hash)((n) % ((sizenode(t)-1)|1)))) #define hashpointer(t,p) hashmod(t, IntPoint(p)) diff --git a/src/liblua/src/ltable.h b/src/liblua/src/ltable.h index b84047e..b20e05a 100644 --- a/src/liblua/src/ltable.h +++ b/src/liblua/src/ltable.h @@ -10,7 +10,7 @@ #include "lobject.h" -#define gnode(t,i) (&(t)->node[i]) +#define gnode(t,i) (&(t)->node[(i)]) #define gkey(n) (&(n)->i_key) #define gval(n) (&(n)->i_val) diff --git a/src/libthecore/main.cpp b/src/libthecore/main.cpp index 265b013..6ebdc5a 100644 --- a/src/libthecore/main.cpp +++ b/src/libthecore/main.cpp @@ -1,12 +1,14 @@ ๏ปฟ#include "stdafx.h" #include "memory.h" +#include + extern void GOST_Init(); LPHEART thecore_heart = NULL; -volatile int shutdowned = FALSE; -volatile int tics = 0; +std::atomic shutdowned = FALSE; +std::atomic tics = 0; unsigned int thecore_profiler[NUM_PF]; static int pid_init(void) @@ -64,14 +66,14 @@ int thecore_init(int fps, HEARTFUNC heartbeat_func) void thecore_shutdown() { - shutdowned = TRUE; + shutdowned.store(TRUE); } int thecore_idle(void) { thecore_tick(); - if (shutdowned) + if (shutdowned.load()) return 0; int pulses; @@ -110,7 +112,7 @@ float thecore_time(void) int thecore_is_shutdowned(void) { - return shutdowned; + return shutdowned.load(); } void thecore_tick(void) diff --git a/src/libthecore/main.h b/src/libthecore/main.h index 04e4862..a565d0e 100644 --- a/src/libthecore/main.h +++ b/src/libthecore/main.h @@ -1,7 +1,9 @@ ๏ปฟ#pragma once -extern volatile int tics; -extern volatile int shutdowned; +#include + +extern std::atomic tics; +extern std::atomic shutdowned; #include "heart.h" diff --git a/src/libthecore/signal.cpp b/src/libthecore/signal.cpp index ca6f2f7..e6ae8a2 100644 --- a/src/libthecore/signal.cpp +++ b/src/libthecore/signal.cpp @@ -16,13 +16,13 @@ RETSIGTYPE reap(int sig) RETSIGTYPE checkpointing(int sig) { - if (!tics) + if (!tics.load()) { - sys_err("CHECKPOINT shutdown: tics did not updated."); - abort(); + sys_err("CHECKPOINT shutdown: tics did not updated."); + abort(); } else - tics = 0; + tics.store(0); } diff --git a/src/qc/CMakeLists.txt b/src/qc/CMakeLists.txt index 4080fe6..7ef5c64 100644 --- a/src/qc/CMakeLists.txt +++ b/src/qc/CMakeLists.txt @@ -7,7 +7,7 @@ target_link_libraries(qc ) if (WIN32) - target_link_libraries(db ws2_32) + target_link_libraries(qc ws2_32) else() - target_link_libraries(db pthread md) + target_link_libraries(qc pthread md) endif() diff --git a/src/qc/qc.cpp b/src/qc/qc.cpp index 0b042c2..81b14d2 100644 --- a/src/qc/qc.cpp +++ b/src/qc/qc.cpp @@ -515,7 +515,7 @@ void parse(char * filename) if (lexstate.lookahead.token == TK_OR) { - // ดูม฿ when name + // ๏ฟฝ๏ฟฝ๏ฟฝ๏ฟฝ when name // push to somewhere -.- ps = ST_WHEN_NAME; when_name_arg_vector.push_back(make_pair(current_when_name, current_when_argument)); @@ -535,7 +535,7 @@ void parse(char * filename) current_when_condition = ""; if (t.token == TK_WITH) { - // here comes มถฐวฝฤ + // here comes ๏ฟฝ๏ฟฝ๏ฟฝวฝ๏ฟฝ next(&lexstate); ostringstream os; os << (lexstate.t); @@ -580,7 +580,7 @@ void parse(char * filename) string callname; bool registered = false; if (prev.t.token == '.') - prev.t.token == TK_DO; // any token + prev.t.token = TK_DO; // any token while (1) { if (lexstate.t.token == TK_DO || lexstate.t.token == TK_IF /*|| lexstate.t.token == TK_FOR*/ || lexstate.t.token == TK_BEGIN || lexstate.t.token == TK_FUNCTION) @@ -844,7 +844,7 @@ void parse(char * filename) } } - // quest functionต้ภป ฑโทฯ + // quest function๏ฟฝ๏ฟฝ๏ฟฝ๏ฟฝ ๏ฟฝ๏ฟฝ๏ฟฝ ouf << all_functions; ouf << "}";