Dynamic Drop Reduction for Bot Users in vSRO?

12/28/2025 10:02 SuperWizzard#1
Greetings SRO community,

I’m currently working on some custom developments for my server and wanted to ask if anyone has encountered or implemented something similar in vSRO files.

In SRO-R, there is a Battery/Macro system that dynamically changes drop / EXP / SP rates when it is activated. I’m trying to achieve a similar behavior on vSRO.

I’m using vPlus filter, which can already detect whether a player is using a bot or not. Based on that detection, my idea was to dynamically reduce the drop rate (and possibly EXP/SP) for botting characters.

As an experiment, I tried modifying CurLevel in the _Char table. This partially worked in the sense that mobs stopped dropping items. However, it introduced several issues:
  1. When the character levels up, no stat points are granted
  2. Mag/Phy balance becomes incorrect
  3. Character progression breaks overall

So while it technically affected drops, it clearly caused side effects and isn’t a viable solution.

I realize this may not be the correct approach, but I wanted to test the limits and understand how the system reacts. If anyone has experience implementing bot-based reward penalties (drop/EXP/SP) in vSRO, I’d appreciate any guidance or suggestions on the proper way to handle this.
01/05/2026 01:33 fuat21#2
I will also develop something similar for my server. I haven’t checked it in detail yet, but my idea is to hook the drop manager on the game server side and create a buff similar to a premium buff, then connect it to the drop manager. When this buff is active (which will be active when Macro is on), my hook will intercept the drop manager and reduce the drop rate. I believe there are some calculations involved that I haven’t checked yet, but it should work this way. It’s better to handle this on the game server side rather than through the database.
01/13/2026 22:22 SuperWizzard#3
Quote:
Originally Posted by fuat21 View Post
I will also develop something similar for my server. I haven’t checked it in detail yet, but my idea is to hook the drop manager on the game server side and create a buff similar to a premium buff, then connect it to the drop manager. When this buff is active (which will be active when Macro is on), my hook will intercept the drop manager and reduce the drop rate. I believe there are some calculations involved that I haven’t checked yet, but it should work this way. It’s better to handle this on the game server side rather than through the database.
Might as well, not much of an expert when it comes to modifying GS, not to mention that I'm using vPlus which means that I don't have that much of control over it.

Would love to hear back from you if you achieved such a thing.
01/14/2026 03:40 fuat21#4
Quote:
Originally Posted by SuperWizzard View Post
Might as well, not much of an expert when it comes to modifying GS, not to mention that I'm using vPlus which means that I don't have that much of control over it.

Would love to hear back from you if you achieved such a thing.
I found this inside the ECSRO gameserver, and there is probably the same function inside the VSRO gameserver. This function is responsible for EXP/SP calculation for the player. I tested it and it worked. I simply multiplied the final result by my own custom multiplier. This way, I can even set EXP/SP to 0 for a specific player.

You just need to do the same thing for the VSRO gameserver. However, if you are using Guard, that might be a problem. In that case, you may need to ask the filter developer to add this functionality.

By the way, these are for EXP and SP. I’m still searching for the drop system,I’ve found some clues, but I need more time to go deeper.There is a specific drop manager, and there is a calculation that happens before the mob is killed. The game server performs this calculation to decide the drops in advance.If I find a reliable solution that works, I will share it as well.

Code:
void __userpurge sub_475830(
    _DWORD *a1@<ecx>, // this (CGObjPC)
    double a2@<st0>,  // ??? FPU REGS ???
    double a3@<st1>,  // ??? FPU REGS ???
    int a4,           // dwExpSourceObjUniqueID (

That’s how I implemented it in the code.

Code:
void __fastcall CGObjPC::MyOffsetExpPoint(CGObjPC* pPC, void* /* edx*/, 
    DWORD dwExpSourceObjUniqueID, long long qwLevelExp, long long qwSkillExp, DWORD& dwUnk)
{
    if (pPC)
    {
        DWORD dwJID = pPC->GetJID();
        if (dwJID > 0)
        {
            float fExpRate = ExpSpRateController::GetStoredPlayerExpRate(dwJID);
            float fSpRate = ExpSpRateController::GetStoredPlayerSpRate(dwJID);
            
            if (fExpRate != 1.0f && qwLevelExp > 0)
                qwLevelExp = (long long)((double)qwLevelExp * fExpRate);
            if (fSpRate != 1.0f && qwSkillExp > 0)
                qwSkillExp = (long long)((double)qwSkillExp * fSpRate);
        }
    }
    s_pfnOffsetExpPoint(pPC, dwExpSourceObjUniqueID, qwLevelExp, qwSkillExp, dwUnk);
}
01/14/2026 16:31 SuperWizzard#5
Quote:
Originally Posted by fuat21 View Post
I found this inside the ECSRO gameserver, and there is probably the same function inside the VSRO gameserver. This function is responsible for EXP/SP calculation for the player. I tested it and it worked. I simply multiplied the final result by my own custom multiplier. This way, I can even set EXP/SP to 0 for a specific player.

You just need to do the same thing for the VSRO gameserver. However, if you are using Guard, that might be a problem. In that case, you may need to ask the filter developer to add this functionality.

By the way, these are for EXP and SP. I’m still searching for the drop system,I’ve found some clues, but I need more time to go deeper.There is a specific drop manager, and there is a calculation that happens before the mob is killed. The game server performs this calculation to decide the drops in advance.If I find a reliable solution that works, I will share it as well.

Code:
void __userpurge sub_475830(
    _DWORD *a1@<ecx>, // this (CGObjPC)
    double a2@<st0>,  // ??? FPU REGS ???
    double a3@<st1>,  // ??? FPU REGS ???
    int a4,           // dwExpSourceObjUniqueID (

That’s how I implemented it in the code.

Code:
void __fastcall CGObjPC::MyOffsetExpPoint(CGObjPC* pPC, void* /* edx*/, 
    DWORD dwExpSourceObjUniqueID, long long qwLevelExp, long long qwSkillExp, DWORD& dwUnk)
{
    if (pPC)
    {
        DWORD dwJID = pPC->GetJID();
        if (dwJID > 0)
        {
            float fExpRate = ExpSpRateController::GetStoredPlayerExpRate(dwJID);
            float fSpRate = ExpSpRateController::GetStoredPlayerSpRate(dwJID);
            
            if (fExpRate != 1.0f && qwLevelExp > 0)
                qwLevelExp = (long long)((double)qwLevelExp * fExpRate);
            if (fSpRate != 1.0f && qwSkillExp > 0)
                qwSkillExp = (long long)((double)qwSkillExp * fSpRate);
        }
    }
    s_pfnOffsetExpPoint(pPC, dwExpSourceObjUniqueID, qwLevelExp, qwSkillExp, dwUnk);
}
That's so interesting, never thought of messing with the EXP/SP ratio directly from GS tbh.

The guard is saving me some effort when it comes to EXP/SP. I managed to get the drop ratio tho, it just increases the ratio of dropping gold, not the gold itself. Thought there might be something related to the items/elixirs around there but couldn't find a thing. Is there a thing where the gold can be reduced like the battery in SroR? Where you get less Gold, maybe the same mechanism can be applied there
01/14/2026 21:38 fuat21#6
Quote:
Originally Posted by SuperWizzard View Post
Might as well, not much of an expert when it comes to modifying GS, not to mention that I'm using vPlus which means that I don't have that much of control over it.

Would love to hear back from you if you achieved such a thing.
Quote:
Originally Posted by SuperWizzard View Post
That's so interesting, never thought of messing with the EXP/SP ratio directly from GS tbh.

The guard is saving me some effort when it comes to EXP/SP. I managed to get the drop ratio tho, it just increases the ratio of dropping gold, not the gold itself. Thought there might be something related to the items/elixirs around there but couldn't find a thing. Is there a thing where the gold can be reduced like the battery in SroR? Where you get less Gold, maybe the same mechanism can be applied there
There’s something similar for drops as well. As far as I can see, the drop manager runs before every mob is killed.

For EXP/SP, I let the GameServer perform its own calculation first. Before the final EXP/SP is applied, I use my own multiplier. If I don’t want to give EXP/SP, I simply set this multiplier to 0, so the character receives 0 EXP/SP until I clear it.

The same logic applies to drops. I just multiply my own ratio in the drop manager so the character doesn’t receive any drops. I don’t change any existing ratios.

However, gold and item drop ratios work differently. As I mentioned, I’m not sure if this can be done from the database side; the only viable way seems to be on the GameServer side.

Finally, I found how to manage drops. Gold drops and normal drops work differently, but they actually follow the same workflow. I managed to control drops directly for the targeted player, and it works perfectly. However, as I said, you need to contact the filter developer and ask them to implement it.

Code:
int __fastcall Hooked_ItemDrop(void* pThis, void* /*edx*/, void* pDeathContext)
{
    if (pDeathContext)
    {
        DWORD dwKillerUID = *(DWORD*)((DWORD)pDeathContext + 36);
        if (dwKillerUID)
        {
            void* pKiller = GetObjByUID(dwKillerUID);  // sub_4581F0
            if (pKiller)
            {
                DWORD dwPtrKey = (DWORD)pKiller + 4;
                float fDropMult = GetStoredPtrDropRate(dwPtrKey);
                
                // Rate 0 = NO drops
                if (fDropMult <= 0.0f)
                    return 1;
                
                // Rate > 1 = multiply
                if (fDropMult > 1.0f)
                {
                    float fOrigRate = *g_pGlobalDropRatio;
                    *g_pGlobalDropRatio = fOrigRate * fDropMult;
                    int result = s_pOriginalItemDrop(pThis, pDeathContext);
                    *g_pGlobalDropRatio = fOrigRate;
                    return result;
                }
            }
        }
    }
    return s_pOriginalItemDrop(pThis, pDeathContext);
}