int32_t GetCaptchaMinutesFromActivity(int32_t activity)
{
// Max 30 minutes, min 4 minutes, decreasing linearly
/*
0 > 30
25 > 24
50 > 17
75 > 10
100 > 4
*/
if (!activity)
return 0;
static constexpr auto ACTIVITY_CAP = 100;
return MINMAX(4, (int32_t)(30 - (26 * (activity * 1.0 / ACTIVITY_CAP))), 30);
}
bool CHARACTER::IsRecentLogin() const
{
static constexpr uint32_t LOGIN_THRESHOLD = 15000; // 15 seconds
return (get_dword_time() - m_dwPlayStartTime) < LOGIN_THRESHOLD;
}
bool CHARACTER::IsCaptchaCooldownActive() const
{
return m_dwNextCaptchaTime > 0 && get_dword_time() < m_dwNextCaptchaTime;
}
bool CHARACTER::HasCaptchaTimeFromActivityPassed() const
{
uint32_t activityMinutes = GetCaptchaMinutesFromActivity(GetActivity());
if (activityMinutes > 0)
{
const uint32_t dwActivityBasedCheckTime = m_dwLastCaptchaValidatedTime + (activityMinutes * 60 * 1000);
return get_dword_time() > dwActivityBasedCheckTime;
}
return false;
}
bool CHARACTER::ShouldSendCaptchaRequest() const
{
// If captcha cooldown is active, wait for it to pass
if (IsCaptchaCooldownActive())
{
if (!g_bIsLiveServer || test_server)
sys_log(0, "ShouldSendCaptchaRequest: %s has no active captcha cooldown", GetName());
return false;
}
// If the player is flagged as a failed captcha player, send the captcha request
if (IsKnownCaptchaFailedPlayer(GetPlayerID()))
{
if (!g_bIsLiveServer || test_server)
sys_log(0, "ShouldSendCaptchaRequest: %s is a known failed captcha player", GetName());
return true;
}
// If the player has logged in recently, send the captcha request
if (IsRecentLogin())
{
if (!g_bIsLiveServer || test_server)
sys_log(0, "ShouldSendCaptchaRequest: %s has logged in recently", GetName());
return true;
}
// If activity-based cooldown has passed, send the captcha request
if (HasCaptchaTimeFromActivityPassed())
{
if (!g_bIsLiveServer || test_server)
sys_log(0, "ShouldSendCaptchaRequest: %s has passed activity-based cooldown", GetName());
return true;
}
// Otherwise, ignore the captcha request
return false;
}
void CHARACTER::RegisterNextCaptchaTime()
{
m_dwNextCaptchaTime = get_dword_time() + number(CAPTCHA_INITIAL_TIME_MIN * 1000, CAPTCHA_INITIAL_TIME_MAX * 1000);
if (!g_bIsLiveServer || test_server)
sys_log(0, "RegisterNextCaptchaTime: %s next captcha time is %u current time is %u", GetName(), m_dwNextCaptchaTime, get_dword_time());
}