diff --git a/README.CLIENT.md b/README.CLIENT.md index 27667cb..173535d 100644 --- a/README.CLIENT.md +++ b/README.CLIENT.md @@ -48,6 +48,16 @@ This is a compilations of ASM/editions for vSRO (1.188) that you'll need to chan 006BA767 | 68 FFE30B54 | push 540BE3FF | ``` +### SERVER_RESURRECT_SAME_POINT_LEVEL_MAX + +0xA = 10 + +``` +00645688 | 3C 0A | cmp al,A | Show message + +00797E21 | 3C 0A | cmp al,A | Unlock action +``` + ### RACE_CH_TOTAL_MASTERIES 0x14A = 330, 0xDC = 220 diff --git a/README.md b/README.md index c448df7..ec8c30d 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,13 @@ Customize Silkroad Online server files (v1.188) behavior through DLL injection. 1. Make a backup from your `SR_GameServer.exe` and `SR_ShardManager.exe` just in case something goes wrong 2. Download, install, and execute [*Stud_PE*](http://www.cgsoftlabs.ro/zip/Stud_PE.zip) -3. Drag & drop `SR_GameServer.exe` into *Stud_PE* -4. Go to `Functions` tab, right click into any line at left blue panel and click `Add New Import` -5. Click `Dll Select` and find `vSRO-GameServer.dll` -6. Click `Select func` and select the one there, then `OK` -7. Click `Add to list` and click `ADD`, then `OK` -8. Extract `vSRO-ServerAddon.bin.zip` to the same folder where is located `SR_GameServer.exe` -9. Done! Just repeat Step 3 to 7 using `SR_ShardManager.exe` and `vSRO-ShardManager.dll` +3. Extract `vSRO-ServerAddon.bin.zip` to the folder where your server files are located +4. Drag & drop `SR_GameServer.exe` into *Stud_PE* +5. Go to `Functions` tab, right click into any line at left blue panel and click `Add New Import` +6. Click `Dll Select` and find `vSRO-GameServer.dll` +7. Click `Select func` and select the one there, then `OK` +8. Click `Add to list` and click `ADD`, then `OK` +9. Done! Just repeat Step 4 to 8 using `SR_ShardManager.exe` and `vSRO-ShardManager.dll` ## Gameserver Actions @@ -342,6 +342,23 @@ VALUES ); ``` +18. Updates PVP cape type from player +```sql +INSERT INTO [SRO_VT_SHARD].[dbo].[_ExeGameServer] +( + Action_ID, + CharName16, + Param02 -- PVP Type (0 = None, 1 = Red, 2 = Gray, 3 = Blue, 4 = White, 5 = Yellow) +) +VALUES +( + 18, + 'JellyBitz', + 5 -- Yellow (All are enemies) +); +``` + + ### Action Result Code ```C++ diff --git a/vSRO-GameServer/AppManager.cpp b/vSRO-GameServer/AppManager.cpp index bc25cde..25e7f7a 100644 --- a/vSRO-GameServer/AppManager.cpp +++ b/vSRO-GameServer/AppManager.cpp @@ -19,6 +19,7 @@ bool AppManager::m_IsInitialized; DatabaseLink AppManager::m_dbLink, AppManager::m_dbLinkHelper, AppManager::m_dbUniqueLog; bool AppManager::m_IsRunningDatabaseFetch; +std::string AppManager::m_CTF_ITEM_WINNING_REWARD, AppManager::m_CTF_ITEM_KILLING_REWARD, AppManager::m_BA_ITEM_REWARD; void AppManager::Initialize() { @@ -51,11 +52,14 @@ void AppManager::InitConfigFile() ini.SetLongValue("Server", "STALL_PRICE_LIMIT", 9999999999, "; Maximum price that can be stalled"); ini.SetLongValue("Server", "PARTY_MOB_MEMBERS_REQUIRED", 2, "; Party members required to find monsters party type"); ini.SetLongValue("Server", "PARTY_MOB_SPAWN_PROBABILITY", 50, "; % Probability for party mob spawns"); - ini.SetLongValue("Server", "PENALTY_DROP_PROBABILITY", 5, "; % Probability to drop an item when a player dies"); ini.SetLongValue("Server", "PK_LEVEL_REQUIRED", 20, "; Level required to kill other player"); + ini.SetLongValue("Server", "PENALTY_DROP_LEVEL_MIN", 10, "; Minimum level to apply drop penalty"); + ini.SetLongValue("Server", "PENALTY_DROP_PROBABILITY", 5, "; % Probability to drop an item when a player dies"); + ini.SetLongValue("Server", "RESURRECT_SAME_POINT_LEVEL_MAX", 10, "; Maximum level for resurrect at the same map position"); ini.SetLongValue("Server", "NPC_RETURN_DEAD_LEVEL_MAX", 20, "; Maximum level for using \"Return to last dead point\" from NPC Guide"); ini.SetLongValue("Server", "BEGINNER_MARK_LEVEL_MAX", 19, "; Maximum level to show the beginner mark"); ini.SetLongValue("Job", "LEVEL_MAX", 7, "; Maximum level that can be reached on job suit"); + ini.SetBoolValue("Job", "DISABLE_MOB_SPAWN", false, "; Disable Thief/Hunter monster spawn while trading"); ini.SetLongValue("Race", "CH_TOTAL_MASTERIES", 330, "; Masteries amount Chinese will obtain"); ini.SetLongValue("Guild", "MEMBERS_LIMIT_LEVEL1", 15, "; Guild members capacity at level 1"); ini.SetLongValue("Guild", "MEMBERS_LIMIT_LEVEL2", 20, "; Guild members capacity at level 2"); @@ -66,16 +70,18 @@ void AppManager::InitConfigFile() ini.SetLongValue("Guild", "STORAGE_SLOTS_INCREASE", 30, "; Storage slots increased per level"); ini.SetLongValue("Guild", "UNION_LIMIT", 8, "; Union participants limit"); ini.SetLongValue("Guild", "UNION_CHAT_PARTICIPANTS", 12, "; Union chat participants allowed by guild"); - ini.SetLongValue("Academy", "GRADUATE_BEGINNER_LEVEL", 40, "; Graduation level for the beginner members"); ini.SetLongValue("Academy", "DISBAND_PENALTY_TIME", 604800, "; Penalty time (seconds) to create again the group"); ini.SetLongValue("Alchemy", "FUSING_DELAY", 3, "; Waiting delay (seconds) after fusing alchemy elements"); - ini.SetValue("Event","CTF_ITEM_REWARD","ITEM_ETC_E070919_TROPHY","; Item reward from Capture The Flag"); - ini.SetLongValue("Event", "CTF_ITEM_REWARD_AMOUNT", 1, "; Amount to obtain per every kill"); + ini.SetLongValue("Alchemy", "STONE_ASTRAL_VALUE", 4, "; Value from astral stones used to stop and prevent +0"); + ini.SetValue("Event", "CTF_ITEM_WIN_REWARD", "ITEM_ETC_E080723_ICETROPHY", "; Item reward from winning Capture The Flag"); + ini.SetLongValue("Event", "CTF_ITEM_WIN_REWARD_AMOUNT", 1, "; Amount to obtain by winning"); + ini.SetValue("Event", "CTF_ITEM_KILL_REWARD", "ITEM_ETC_E080723_ICETROPHY", "; Item reward from killing at Capture The Flag"); + ini.SetLongValue("Event", "CTF_ITEM_KILL_REWARD_AMOUNT", 1, "; Amount to obtain by kill"); ini.SetValue("Event","BA_ITEM_REWARD","ITEM_ETC_ARENA_COIN","; Item reward from Battle Arena"); ini.SetLongValue("Event", "BA_ITEM_REWARD_GJ_W_AMOUNT", 7, "; Amount to obtain winning on Guild/Job mode"); ini.SetLongValue("Event", "BA_ITEM_REWARD_GJ_L_AMOUNT", 2, "; Amount to obtain loosing"); - ini.SetLongValue("Event", "BA_ITEM_REWARD_PR_W_AMOUNT", 7, "; Amount to obtain winning on Party/Random mode"); - ini.SetLongValue("Event", "BA_ITEM_REWARD_PR_L_AMOUNT", 2, "; Amount to obtain loosing"); + ini.SetLongValue("Event", "BA_ITEM_REWARD_PR_W_AMOUNT", 5, "; Amount to obtain winning on Party/Random mode"); + ini.SetLongValue("Event", "BA_ITEM_REWARD_PR_L_AMOUNT", 1, "; Amount to obtain loosing"); ini.SetLongValue("Fix", "AGENT_SERVER_CAPACITY", 1000, "; Set capacity supported by the connected agent server"); ini.SetBoolValue("Fix", "HIGH_RATES_CONFIG", true, "; Fix rates (ExpRatio/1000) to use higher values than 2500"); ini.SetBoolValue("Fix", "UNIQUE_LOGS", true, "; Log unique spawn/killed into _AddLogChar as EventID = 32/33"); @@ -228,12 +234,24 @@ void AppManager::InitPatchValues() printf(" - SERVER_PK_LEVEL_REQUIRED (%d) -> (%d)\r\n", byteValue, newValue); WriteMemoryValue(0x005295DA + 1, newValue); } + if (ReadMemoryValue(0x004E6A33 + 1, byteValue)) + { + uint8_t newValue = ini.GetLongValue("Server", "PENALTY_DROP_LEVEL_MIN", 10); + printf(" - SERVER_PENALTY_DROP_LEVEL_MIN (%d) -> (%d)\r\n", byteValue, newValue); + WriteMemoryValue(0x004E6A33 + 1, newValue); + } if (ReadMemoryValue(0x004E696D + 1, byteValue)) { uint8_t newValue = ini.GetLongValue("Server", "PENALTY_DROP_PROBABILITY", 5); printf(" - SERVER_PENALTY_DROP_PROBABILITY (%d) -> (%d)\r\n", byteValue, newValue); WriteMemoryValue(0x004E696D + 1, newValue); } + if (ReadMemoryValue(0x0051017F + 1, byteValue)) + { + uint8_t newValue = ini.GetLongValue("Server", "RESURRECT_SAME_POINT_LEVEL_MAX", 10); + printf(" - SERVER_RESURRECT_SAME_POINT_LEVEL_MAX (%d) -> (%d)\r\n", byteValue, newValue); + WriteMemoryValue(0x0051017F + 1, newValue); + } if (ReadMemoryValue(0x004F36F3 + 1, byteValue)) { uint8_t newValue = ini.GetLongValue("Server", "NPC_RETURN_DEAD_LEVEL_MAX", 20); @@ -255,7 +273,12 @@ void AppManager::InitPatchValues() printf(" - JOB_LEVEL_MAX (%d) -> (%d)\r\n", byteValue, newValue); WriteMemoryValue(0x0060DE69 + 3, newValue); } - + if (ini.GetBoolValue("Job", "DISABLE_MOB_SPAWN", false)) + { + printf(" - JOB_DISABLE_MOB_SPAWN\r\n"); + WriteMemoryValue(0x0060C4AB, 0xC031); // mov eax,esi -> xor eax,eax + } + // Race if (ReadMemoryValue(0x0059C5E6 + 1, uintValue)) { @@ -327,13 +350,6 @@ void AppManager::InitPatchValues() } // Academy - if (ReadMemoryValue(0x00519883 + 2, byteValue)) - { - uint8_t newValue = ini.GetLongValue("Academy", "GRADUATE_BEGINNER_LEVEL", 40); - printf(" - ACADEMY_GRADUATE_BEGINNER_LEVEL (%d) -> (%d)\r\n", byteValue, newValue); - WriteMemoryValue(0x00519883 + 2, newValue); - WriteMemoryValue(0x005196CD + 1, newValue); - } if (ReadMemoryValue(0x005DD36A + 1, uintValue)) { uint32_t newValue = ini.GetLongValue("Academy", "DISBAND_PENALTY_TIME", 604800); @@ -349,42 +365,71 @@ void AppManager::InitPatchValues() printf(" - ALCHEMY_FUSING_DELAY (%d) -> (%d)\r\n", byteValue, newValue); WriteMemoryValue(0x0052ADAA + 6, newValue); } + if (ReadMemoryValue(0x00506D92 + 2, byteValue)) + { + uint8_t newValue = ini.GetLongValue("Alchemy", "STONE_ASTRAL_VALUE", 4); + printf(" - ALCHEMY_STONE_ASTRAL_VALUE (%d) -> (%d)\r\n", byteValue, newValue); + WriteMemoryValue(0x00506D92 + 2, newValue); + WriteMemoryValue(0x00506DD2 + 1, newValue); + } // Event { - const char* newValue = ini.GetValue("Event", "CTF_ITEM_REWARD", "ITEM_ETC_E070919_TROPHY"); - auto newValueLen = strlen(newValue); - // Change value if it's not empty and the CodeName is shorter than 128 bytes - if (newValueLen != 0 && newValueLen <= 128) + auto currentValue = ReadMemoryString(0x00646D42 + 1); + if (!currentValue.empty()) { - auto currentValue = ReadMemoryString(0x00646D42 + 1); - printf(" - EVENT_CTF_ITEM_REWARD (%s) -> (%s)\r\n", currentValue.c_str(), newValue); - // Overwrites new char* into empty memory - WriteMemoryString(0x00AD8FFD - 130, newValue); - // Set char* pointer to the new value - WriteMemoryValue(0x00646D42 + 1, 0x00AD8FFD - 130); - WriteMemoryValue(0x005F19A9 + 1, 0x00AD8FFD - 130); - WriteMemoryValue(0x00876935 + 6, 0x00AD8FFD - 130); + m_CTF_ITEM_WINNING_REWARD = ini.GetValue("Event", "CTF_ITEM_WIN_REWARD", "ITEM_ETC_E080723_ICETROPHY"); + auto newValueLen = m_CTF_ITEM_WINNING_REWARD.size(); + // Check value it's not empty and shorter than 128 bytes + if (newValueLen != 0 && newValueLen <= 128) + { + printf(" - EVENT_CTF_ITEM_WIN_REWARD (%s) -> (%s)\r\n", currentValue.c_str(), m_CTF_ITEM_WINNING_REWARD.c_str()); + // Set char* pointer to the new value + WriteMemoryValue(0x00646D42 + 1, (uint32_t)m_CTF_ITEM_WINNING_REWARD.c_str()); // Winning Reward + WriteMemoryValue(0x00876935 + 6, (uint32_t)m_CTF_ITEM_WINNING_REWARD.c_str()); // Just in case, something about Quest reward required probably + } } } - if (ReadMemoryValue(0x00646C93 + 4, byteValue)) + if (ReadMemoryValue(0x00646D40 + 1, byteValue)) { - uint8_t newValue = ini.GetLongValue("Event", "CTF_ITEM_REWARD_AMOUNT", 1); - printf(" - EVENT_CTF_ITEM_REWARD_AMOUNT (%d) -> (%d)\r\n", byteValue, newValue); - WriteMemoryValue(0x00646C93 + 4, newValue); + uint8_t newValue = ini.GetLongValue("Event", "CTF_ITEM_WIN_REWARD_AMOUNT", 1); + printf(" - EVENT_CTF_ITEM_WIN_REWARD_AMOUNT (%d) -> (%d)\r\n", byteValue, newValue); + WriteMemoryValue(0x00646D40 + 1, newValue); } { - const char* newValue = ini.GetValue("Event", "BA_ITEM_REWARD", "ITEM_ETC_ARENA_COIN"); - auto newValueLen = strlen(newValue); - // Change value if it's not empty and the CodeName is shorter than 128 bytes - if (newValueLen != 0 && newValueLen <= 128) + auto currentValue = ReadMemoryString(0x005F19A9 + 1); + if (!currentValue.empty()) { - auto currentValue = ReadMemoryString(0x006691C6 + 1); - printf(" - EVENT_BA_ITEM_REWARD (%s) -> (%s)\r\n", currentValue.c_str(), newValue); - // Overwrites new char* into empty memory - WriteMemoryString(0x00AD8FFD - 130 - 130, newValue); - // Set char* pointer to the new value - WriteMemoryValue(0x006691C6 + 1, 0x00AD8FFD - 130 - 130); + m_CTF_ITEM_KILLING_REWARD = ini.GetValue("Event", "CTF_ITEM_KILL_REWARD", "ITEM_ETC_E080723_ICETROPHY"); + auto newValueLen = m_CTF_ITEM_KILLING_REWARD.size(); + // Check value it's not empty and shorter than 128 bytes + if (newValueLen != 0 && newValueLen <= 128) + { + printf(" - EVENT_CTF_ITEM_KILL_REWARD (%s) -> (%s)\r\n", currentValue.c_str(), m_CTF_ITEM_KILLING_REWARD.c_str()); + // Set char* pointer to the new value + WriteMemoryValue(0x005F19A9 + 1, (uint32_t)m_CTF_ITEM_KILLING_REWARD.c_str()); // Killing Reward + } + } + } + if (ReadMemoryValue(0x005F1997 + 1, byteValue)) + { + uint8_t newValue = ini.GetLongValue("Event", "CTF_ITEM_KILL_REWARD_AMOUNT", 1); + printf(" - EVENT_CTF_ITEM_KILL_REWARD_AMOUNT (%d) -> (%d)\r\n", byteValue, newValue); + WriteMemoryValue(0x005F1997 + 1, newValue); + } + { + auto currentValue = ReadMemoryString(0x006691C6 + 1); + if (!currentValue.empty()) + { + m_BA_ITEM_REWARD = ini.GetValue("Event", "BA_ITEM_REWARD", "ITEM_ETC_ARENA_COIN"); + auto newValueLen = m_BA_ITEM_REWARD.size(); + // Check value it's not empty and shorter than 128 bytes + if (newValueLen != 0 && newValueLen <= 128) + { + printf(" - EVENT_BA_ITEM_REWARD (%s) -> (%s)\r\n", currentValue.c_str(), m_BA_ITEM_REWARD.c_str()); + // Set char* pointer to the new value + WriteMemoryValue(0x006691C6 + 1, (uint32_t)m_BA_ITEM_REWARD.c_str()); + } } } if (ReadMemoryValue(0x00669158 + 4, byteValue)) @@ -401,13 +446,13 @@ void AppManager::InitPatchValues() } if (ReadMemoryValue(0x0066915F + 4, byteValue)) { - uint8_t newValue = ini.GetLongValue("Event", "BA_ITEM_REWARD_PR_W_AMOUNT", 7); + uint8_t newValue = ini.GetLongValue("Event", "BA_ITEM_REWARD_PR_W_AMOUNT", 5); printf(" - EVENT_BA_ITEM_REWARD_PR_W_AMOUNT (%d) -> (%d)\r\n", byteValue, newValue); WriteMemoryValue(0x0066915F + 4, newValue); } if (ReadMemoryValue(0x0066917A + 4, byteValue)) { - uint8_t newValue = ini.GetLongValue("Event", "BA_ITEM_REWARD_PR_L_AMOUNT", 2); + uint8_t newValue = ini.GetLongValue("Event", "BA_ITEM_REWARD_PR_L_AMOUNT", 1); printf(" - EVENT_BA_ITEM_REWARD_PR_L_AMOUNT (%d) -> (%d)\r\n", byteValue, newValue); WriteMemoryValue(0x0066917A + 4, newValue); } @@ -477,7 +522,7 @@ void AppManager::InitDatabaseFetch() connString << "SERVER=" << ini.GetValue("Sql", "HOST", "localhost") << ", " << ini.GetValue("Sql", "PORT", "1433") << ";"; connString << "DATABASE=" << ini.GetValue("Sql", "DB_SHARD", "SRO_VT_SHARD") << ";"; connString << "UID=" << ini.GetValue("Sql", "USER", "sa") << ";"; - connString << "PWD=" << ini.GetValue("Sql", "PASS", "12341") << ";"; + connString << "PWD=" << ini.GetValue("Sql", "PASS", "1234") << ";"; if (m_dbLink.sqlConn.Open((SQLWCHAR*)connString.str().c_str()) && m_dbLink.sqlCmd.Open(m_dbLink.sqlConn) && m_dbLinkHelper.sqlConn.Open((SQLWCHAR*)connString.str().c_str()) && m_dbLinkHelper.sqlCmd.Open(m_dbLinkHelper.sqlConn)) @@ -842,6 +887,18 @@ DWORD WINAPI AppManager::DatabaseFetchThread() actionResult = FETCH_ACTION_STATE::CHARNAME_NOT_FOUND; } } break; + case 18: // Update PVP cape type + { + SQLUSMALLINT cParam02; + if (m_dbLink.sqlCmd.GetData(5, SQL_C_USHORT, &cParam02, 0, NULL)) + { + CGObjPC* player = CGObjManager::GetObjPCByCharName16(cCharName); + if (player) + player->UpdatePVPCapeType(cParam02); + else + actionResult = FETCH_ACTION_STATE::CHARNAME_NOT_FOUND; + } + } break; case 3312: // For testing references { CGObjPC* player = CGObjManager::GetObjPCByCharName16(cCharName); diff --git a/vSRO-GameServer/AppManager.h b/vSRO-GameServer/AppManager.h index 62523f9..b6e12f0 100644 --- a/vSRO-GameServer/AppManager.h +++ b/vSRO-GameServer/AppManager.h @@ -3,6 +3,7 @@ #include "Database/SQLConnection.h" #include "Database/SQLCommand.h" #include +#include // All states fetching can generate enum FETCH_ACTION_STATE { @@ -31,6 +32,10 @@ class AppManager static DatabaseLink m_dbLink, m_dbLinkHelper, m_dbUniqueLog; // Flag to keep thread safe static bool m_IsRunningDatabaseFetch; + // Keeps in memory the value assigned + static std::string m_CTF_ITEM_WINNING_REWARD; + static std::string m_CTF_ITEM_KILLING_REWARD; + static std::string m_BA_ITEM_REWARD; public: // Public Methods // Initialize manager static void Initialize(); diff --git a/vSRO-GameServer/Silkroad/Object/CGObjPC.cpp b/vSRO-GameServer/Silkroad/Object/CGObjPC.cpp index d671f55..33c99f7 100644 --- a/vSRO-GameServer/Silkroad/Object/CGObjPC.cpp +++ b/vSRO-GameServer/Silkroad/Object/CGObjPC.cpp @@ -28,7 +28,7 @@ void CGObjPC::UpdateGold(int64_t Offset) } void CGObjPC::UpdateHwan(uint8_t Level) { - reinterpret_cast(0x004A9F40)(this, Level); + return CallVirtual(this, 197)(this, Level); } void CGObjPC::UpdateExperience(int64_t ExpOffset) { @@ -46,6 +46,12 @@ void CGObjPC::UpdateHPMP(int32_t Health, int32_t Mana, uint16_t DisplayEffectTyp { CallVirtual(this, 194)(this, Health, Mana, DisplayEffectType); } +void CGObjPC::UpdatePVPCapeType(uint8_t CapeType) +{ + // Avoid unnecesary updates + if (CapeType <= 5) + reinterpret_cast(0x004F0E90)(this, CapeType); +} bool CGObjPC::MoveTo(uint16_t RegionId, float PosX, float PosY, float PosZ) { uint32_t gwid = 0; diff --git a/vSRO-GameServer/Silkroad/Object/CGObjPC.h b/vSRO-GameServer/Silkroad/Object/CGObjPC.h index 4dd63bf..fe1f6ec 100644 --- a/vSRO-GameServer/Silkroad/Object/CGObjPC.h +++ b/vSRO-GameServer/Silkroad/Object/CGObjPC.h @@ -31,6 +31,8 @@ class CGObjPC : public CGObjChar void AddSPExperience(uint32_t SPExpOffset); // Updates the HP and MP void UpdateHPMP(int32_t Health, int32_t Mana, uint16_t DisplayEffectType); + // Updates the cape state from PVP + void UpdatePVPCapeType(uint8_t CapeType); // Moves the player to the map location. Return success bool MoveTo(uint16_t RegionId, float PosX, float PosY, float PosZ); // Moves the player to the gameworld and map location. Return success