Авто добавление статов при удержании кнопки

Grim4ik

New Pirate
Server Owner
Registered
Mood
LV
0
 
Joined
Dec 27, 2025
Messages
4
Reaction score
1
Points
3
UIStateForm.cpp

1) Находим строку:

C++:
using namespace GUI;

Под ней вставляем:
C++:
namespace {

enum class EStatBtn { NONE, STR, AGI, CON, STA, DEX };

static bool      s_holdActive = false;
static EStatBtn  s_activeBtn  = EStatBtn::NONE;
static int       s_stage      = 0;   
static DWORD     s_intervalMs = 300;
static DWORD     s_nextTick   = 0;
static int       s_holdCount  = 0;

static EStatBtn ResolveStatBtnByName(const std::string& n) {
    if (n == "btnStr") return EStatBtn::STR;
    if (n == "btnAgi") return EStatBtn::AGI;
    if (n == "btnCon") return EStatBtn::CON;
    if (n == "btnSta") return EStatBtn::STA;
    if (n == "btnDex") return EStatBtn::DEX;
    return EStatBtn::NONE;
}

static int AttrIdFromBtn(EStatBtn b) {
    switch (b) {
        case EStatBtn::STR: return ATTR_STR;
        case EStatBtn::AGI: return ATTR_AGI;
        case EStatBtn::CON: return ATTR_CON;
        case EStatBtn::STA: return ATTR_STA;
        case EStatBtn::DEX: return ATTR_DEX;
        default:            return -1;
    }
}

static void DoAddOne(EStatBtn btn) {
    const int attrId = AttrIdFromBtn(btn);
    if (attrId < 0) return;

    CCharacter* pCha = g_stUIBoat.GetHuman();
    if (!pCha) return;
    SGameAttr* ga = pCha->getGameAttr();
    if (!ga || ga->get(ATTR_AP) <= 0) return;

    CChaAttr attr;
    attr.ResetChangeFlag();
    attr.DirectSetAttr(attrId, 1);
    attr.SetChangeBitFlag(attrId);
    if (auto* proCir = (CProCirculateCS*)g_NetIF->GetProCir())
        proCir->SynBaseAttribute(&attr);
}

static POINT GetClientCursor(HWND hwnd) {
    POINT p; ::GetCursorPos(&p);
    if (hwnd) ::ScreenToClient(hwnd, &p);
    return p;
}

static bool IsMouseOverBtn(HWND hwnd, CForm* frm, CGuiData* btn) {
    if (!frm || !btn || !btn->GetIsShow()) return false;
    POINT c = GetClientCursor(hwnd);

    const int x = frm->GetLeft() + btn->GetLeft();
    const int y = frm->GetTop()  + btn->GetTop();
    const int w = btn->GetWidth();
    const int h = btn->GetHeight();

    return (c.x >= x && c.x < x + w && c.y >= y && c.y < y + h);
}

static CGuiData* ButtonByEnum(CTextButton* btnStr, CTextButton* btnAgi,
                              CTextButton* btnCon, CTextButton* btnSta,
                              CTextButton* btnDex, EStatBtn b) {
    switch (b) {
        case EStatBtn::STR: return btnStr;
        case EStatBtn::AGI: return btnAgi;
        case EStatBtn::CON: return btnCon;
        case EStatBtn::STA: return btnSta;
        case EStatBtn::DEX: return btnDex;
        default:            return nullptr;
    }
}

static void StartHold(EStatBtn b) {
    s_activeBtn  = b;
    s_holdActive = (b != EStatBtn::NONE);
    s_stage      = 0;
    s_intervalMs = 300;                   
    s_nextTick   = ::GetTickCount() + s_intervalMs;
    s_holdCount  = 0;

}

static void StopHold() {
    s_holdActive = false;
    s_activeBtn  = EStatBtn::NONE;
}

}

2) Находим существующую функцию:
C++:
void CStateMgr::FrameMove(DWORD dwTime)
{
    if( frmState->GetIsShow() )
    {
        static CTimeWork time(100);
        if( time.IsTimeOut( dwTime ) )
            RefreshStateFrm();
    }
}

Заменяем целиком функцию на:
C++:
void CStateMgr::FrameMove(DWORD dwTime)
{
    if (frmState->GetIsShow())
    {
        static CTimeWork time(100);
        if (time.IsTimeOut(dwTime))
            RefreshStateFrm();
    }

    HWND hwnd = ::GetActiveWindow();

    const bool lmbDown = (::GetAsyncKeyState(VK_LBUTTON) & 0x8000) != 0;

    if (lmbDown && !s_holdActive) {
        if (IsMouseOverBtn(hwnd, frmState, btnStr))      StartHold(EStatBtn::STR);
        else if (IsMouseOverBtn(hwnd, frmState, btnAgi)) StartHold(EStatBtn::AGI);
        else if (IsMouseOverBtn(hwnd, frmState, btnCon)) StartHold(EStatBtn::CON);
        else if (IsMouseOverBtn(hwnd, frmState, btnSta)) StartHold(EStatBtn::STA);
        else if (IsMouseOverBtn(hwnd, frmState, btnDex)) StartHold(EStatBtn::DEX);
    }

    if (s_holdActive) {
        CGuiData* activeBtnPtr = ButtonByEnum(btnStr, btnAgi, btnCon, btnSta, btnDex, s_activeBtn);
        const bool stillOver = IsMouseOverBtn(hwnd, frmState, activeBtnPtr);
        if (!lmbDown || !stillOver) {
            StopHold();
        }
    }

    if (s_holdActive) {
        DWORD now = ::GetTickCount();
if (now >= s_nextTick) {
    if (s_holdCount >= 25) {
        StopHold();
        return;
    }

    CCharacter* pCha = g_stUIBoat.GetHuman();
    if (!pCha) { StopHold(); return; }
    SGameAttr* ga = pCha->getGameAttr();
    if (!ga || ga->get(ATTR_AP) <= 0) { StopHold(); return; }

    DoAddOne(s_activeBtn);
    ++s_holdCount;

    if      (s_stage == 0) s_intervalMs = 150;
    else if (s_stage == 1) s_intervalMs = 100;
    else                   s_intervalMs = 80;
    ++s_stage;
    s_nextTick = now + s_intervalMs;
}
    }
}

3) Найти функцию:

C++:
void CStateMgr::MainMouseDown(CGuiData *pSender, int x, int y, DWORD key)

Если в функции есть строки ниже, их удалить или замутить, остальное без изменения:
Code:
s_activeBtn  = ResolveStatBtnByName(name);   // ← Delete or mute
s_holdActive = true;                      // ← Delete or mute

Это все!