New macro detection features (#7359)
* Adds battle config macro_detection_punishment to ban or jail characters. * Adds battle config macro_detection_punishment_time to adjust the duration of ban/jail for players who fail the captcha challenges. * Adds script command macro_detector which invokes the captcha challenge. * General cleanups to the jail functions to remove duplicate code. * General cleanups to the macro punishment calls to remove duplicate code. * Ending SC_JAILED will now properly remove the jail status rather than trying to reset the timer to 1 second resolving any possibility of players getting stuck. Thanks to @Lemongrass3110!
This commit is contained in:
parent
5a533a7a12
commit
ee2dcf816e
@ -158,3 +158,14 @@ macro_detection_retry: 3
|
||||
// Amount of time in milliseconds before the macro detection will fail and the user will be banned.
|
||||
// Official: 60000
|
||||
macro_detection_timeout: 60000
|
||||
|
||||
// Macro Detector punishment type
|
||||
// 0 - Ban
|
||||
// 1 - Jail
|
||||
// Official: 0
|
||||
macro_detection_punishment: 0
|
||||
|
||||
// Macro Detector punishment duration
|
||||
// Amount of time in minutes that the punishment type is active for. Use 0 for infinite.
|
||||
// Official: 0
|
||||
macro_detection_punishment_time: 0
|
||||
|
@ -6579,6 +6579,28 @@ Examples:
|
||||
|
||||
---------------------------------------
|
||||
|
||||
macro_detector({<account ID>});
|
||||
macro_detector({"<character name>"});
|
||||
|
||||
This command will display the captcha UI challenge onto the invoking character or the given <account ID>/<character name>.
|
||||
|
||||
Example:
|
||||
// Use 'getareaunits' to gather an area of players to test.
|
||||
// Build an int array of the account IDs.
|
||||
.@num = getareaunits(BL_PC, "prontera", 150, 150, 160, 160, .@array[0]);
|
||||
|
||||
mes "The number of Players in Prontera in between 150x150 and 160x160 is " + .@num + " .";
|
||||
mes "Players to challenge:";
|
||||
freeloop(1); // If the list is too big
|
||||
for(.@i = 0; .@i < getarraysize(.@array); .@i++) {
|
||||
mes (.@i + 1) + " " + convertpcinfo(.@array[.@i], CPC_NAME);
|
||||
macro_detector .@array[.@i];
|
||||
}
|
||||
freeloop(0);
|
||||
end;
|
||||
|
||||
---------------------------------------
|
||||
|
||||
==================================
|
||||
|5.- Mob / NPC -related commands.|
|
||||
==================================
|
||||
|
@ -5218,8 +5218,7 @@ ACMD_FUNC(servertime)
|
||||
ACMD_FUNC(jail)
|
||||
{
|
||||
struct map_session_data *pl_sd;
|
||||
int x, y;
|
||||
unsigned short m_index;
|
||||
|
||||
nullpo_retr(-1, sd);
|
||||
|
||||
memset(atcmd_player_name, '\0', sizeof(atcmd_player_name));
|
||||
@ -5244,21 +5243,7 @@ ACMD_FUNC(jail)
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch(rnd() % 2) { //Jail Locations
|
||||
case 0:
|
||||
m_index = mapindex_name2id(MAP_JAIL);
|
||||
x = 24;
|
||||
y = 75;
|
||||
break;
|
||||
default:
|
||||
m_index = mapindex_name2id(MAP_JAIL);
|
||||
x = 49;
|
||||
y = 75;
|
||||
break;
|
||||
}
|
||||
|
||||
//Duration of INT_MAX to specify infinity.
|
||||
sc_start4(NULL,&pl_sd->bl,SC_JAILED,100,INT_MAX,m_index,x,y,1000);
|
||||
pc_jail(*pl_sd);
|
||||
clif_displaymessage(pl_sd->fd, msg_txt(sd,117)); // GM has send you in jails.
|
||||
clif_displaymessage(fd, msg_txt(sd,118)); // Player warped in jails.
|
||||
return 0;
|
||||
@ -5296,7 +5281,7 @@ ACMD_FUNC(unjail)
|
||||
}
|
||||
|
||||
//Reset jail time to 1 sec.
|
||||
sc_start(NULL,&pl_sd->bl,SC_JAILED,100,1,1000);
|
||||
pc_jail(*pl_sd, 0);
|
||||
clif_displaymessage(pl_sd->fd, msg_txt(sd,120)); // A GM has discharged you from jail.
|
||||
clif_displaymessage(fd, msg_txt(sd,121)); // Player unjailed.
|
||||
return 0;
|
||||
@ -5305,8 +5290,8 @@ ACMD_FUNC(unjail)
|
||||
ACMD_FUNC(jailfor) {
|
||||
struct map_session_data *pl_sd = NULL;
|
||||
char * modif_p;
|
||||
int jailtime = 0,x,y;
|
||||
short m_index = 0;
|
||||
int jailtime = 0;
|
||||
|
||||
nullpo_retr(-1, sd);
|
||||
|
||||
memset(atcmd_output, '\0', sizeof(atcmd_output));
|
||||
@ -5363,19 +5348,8 @@ ACMD_FUNC(jailfor) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Jail locations, add more as you wish.
|
||||
switch(rnd()%2) {
|
||||
case 1: // Jail #1
|
||||
m_index = mapindex_name2id(MAP_JAIL);
|
||||
x = 49; y = 75;
|
||||
break;
|
||||
default: // Default Jail
|
||||
m_index = mapindex_name2id(MAP_JAIL);
|
||||
x = 24; y = 75;
|
||||
break;
|
||||
}
|
||||
pc_jail(*pl_sd, jailtime);
|
||||
|
||||
sc_start4(NULL,&pl_sd->bl,SC_JAILED,100,jailtime,m_index,x,y,jailtime?60000:1000); //jailtime = 0: Time was reset to 0. Wait 1 second to warp player out (since it's done in status_change_timer).
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -10271,6 +10271,8 @@ static const struct _battle_data {
|
||||
{ "break_mob_equip", &battle_config.break_mob_equip, 0, 0, 1, },
|
||||
{ "macro_detection_retry", &battle_config.macro_detection_retry, 3, 1, INT_MAX, },
|
||||
{ "macro_detection_timeout", &battle_config.macro_detection_timeout, 60000, 0, INT_MAX, },
|
||||
{ "macro_detection_punishment", &battle_config.macro_detection_punishment, 0, 0, 1, },
|
||||
{ "macro_detection_punishment_time", &battle_config.macro_detection_punishment_time, 0, 0, INT_MAX, },
|
||||
|
||||
{ "feature.dynamicnpc_timeout", &battle_config.feature_dynamicnpc_timeout, 1000, 60000, INT_MAX, },
|
||||
{ "feature.dynamicnpc_rangex", &battle_config.feature_dynamicnpc_rangex, 2, 0, INT_MAX, },
|
||||
|
@ -714,6 +714,8 @@ struct Battle_Config
|
||||
int break_mob_equip;
|
||||
int macro_detection_retry;
|
||||
int macro_detection_timeout;
|
||||
int macro_detection_punishment;
|
||||
int macro_detection_punishment_time;
|
||||
|
||||
int feature_dynamicnpc_timeout;
|
||||
int feature_dynamicnpc_rangex;
|
||||
|
@ -24776,7 +24776,7 @@ void clif_parse_macro_reporter_ack(int fd, map_session_data *sd) {
|
||||
return;
|
||||
}
|
||||
|
||||
pc_macro_reporter_process(*sd, *tsd);
|
||||
pc_macro_reporter_process(*tsd, sd->status.account_id);
|
||||
clif_macro_reporter_status(*sd, MCR_MONITORING);
|
||||
#endif
|
||||
}
|
||||
|
102
src/map/pc.cpp
102
src/map/pc.cpp
@ -15235,6 +15235,76 @@ void pc_attendance_claim_reward( struct map_session_data* sd ){
|
||||
clif_attendence_response( sd, attendance_counter );
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a player to jail and determine the location to send in jail.
|
||||
* @param sd: Player data
|
||||
* @param duration: Duration in minutes (default INT_MAX = infinite)
|
||||
*/
|
||||
void pc_jail(map_session_data &sd, int32 duration) {
|
||||
uint16 m_index = mapindex_name2id(MAP_JAIL);
|
||||
int16 x, y;
|
||||
|
||||
switch (rnd() % 2) { // Jail Locations
|
||||
case 0: // Jail #1
|
||||
x = 49;
|
||||
y = 75;
|
||||
break;
|
||||
default: // Default Jail
|
||||
x = 24;
|
||||
y = 75;
|
||||
break;
|
||||
}
|
||||
|
||||
duration = i32max(0, duration); // Can't be less than 0 seconds.
|
||||
|
||||
// If duration > 0 then triggered via jailfor which checks every minute.
|
||||
// If duration == INT_MAX then triggered via jail for infinite duration.
|
||||
// If duration == 0 then triggered via unjail and end status.
|
||||
if (duration > 0)
|
||||
sc_start4(nullptr, &sd.bl, SC_JAILED, 100, duration, m_index, x, y, 60000);
|
||||
else
|
||||
status_change_end(&sd.bl, SC_JAILED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the punishment type when failing macro checks.
|
||||
* @param sd: Player data
|
||||
* @param stype: Macro detection status type (for banning)
|
||||
*/
|
||||
static void pc_macro_punishment(map_session_data &sd, e_macro_detect_status stype) {
|
||||
int32 duration = 0;
|
||||
|
||||
// Determine if there's a unique duration
|
||||
if (battle_config.macro_detection_punishment_time > 0) {
|
||||
char time[13];
|
||||
|
||||
safesnprintf(time, 13, "+%dnm", battle_config.macro_detection_punishment_time);
|
||||
duration = static_cast<int32>(solve_time(time));
|
||||
}
|
||||
|
||||
// Delete the timer
|
||||
if (sd.macro_detect.timer != INVALID_TIMER)
|
||||
delete_timer(sd.macro_detect.timer, pc_macro_detector_timeout);
|
||||
|
||||
// Clear the macro detect data
|
||||
sd.macro_detect = {};
|
||||
sd.macro_detect.timer = INVALID_TIMER;
|
||||
|
||||
// Unblock all actions for the player
|
||||
sd.state.block_action &= ~PCBLOCK_ALL;
|
||||
sd.state.block_action &= ~PCBLOCK_IMMUNE;
|
||||
|
||||
if (battle_config.macro_detection_punishment == 0) { // Ban
|
||||
clif_macro_detector_status(sd, stype);
|
||||
chrif_req_login_operation(sd.macro_detect.reporter_aid, sd.status.name, (duration == 0 ? CHRIF_OP_LOGIN_BLOCK : CHRIF_OP_LOGIN_BAN), duration, 0, 0);
|
||||
} else { // Jail
|
||||
// Send success to close the window without closing the client
|
||||
clif_macro_detector_status(sd, MCD_GOOD);
|
||||
|
||||
pc_jail(sd, (duration == 0 ? INT_MAX : duration / 60));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save a captcha image to memory via /macro_register.
|
||||
* @param sd: Player data
|
||||
@ -15320,9 +15390,8 @@ TIMER_FUNC(pc_macro_detector_timeout) {
|
||||
sd->macro_detect.retry -= 1;
|
||||
|
||||
if (sd->macro_detect.retry == 0) {
|
||||
// All attempts have been exhausted block the user
|
||||
clif_macro_detector_status(*sd, MCD_TIMEOUT);
|
||||
chrif_req_login_operation(sd->macro_detect.reporter_aid, sd->status.name, CHRIF_OP_LOGIN_BLOCK, 0, 0, 0);
|
||||
// All attempts have been exhausted, punish the user
|
||||
pc_macro_punishment(*sd, MCD_TIMEOUT);
|
||||
} else {
|
||||
// Update the client
|
||||
clif_macro_detector_request_show(*sd);
|
||||
@ -15373,10 +15442,9 @@ void pc_macro_detector_process_answer(map_session_data &sd, char captcha_answer[
|
||||
// Deduct an answering attempt
|
||||
sd.macro_detect.retry -= 1;
|
||||
|
||||
// All attempts have been exhausted block the user
|
||||
// All attempts have been exhausted, punish the user
|
||||
if (sd.macro_detect.retry <= 0) {
|
||||
clif_macro_detector_status(sd, MCD_INCORRECT);
|
||||
chrif_req_login_operation(sd.macro_detect.reporter_aid, sd.status.name, CHRIF_OP_LOGIN_BLOCK, 0, 0, 0);
|
||||
pc_macro_punishment(sd, MCD_INCORRECT);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -15399,9 +15467,9 @@ void pc_macro_detector_disconnect(map_session_data &sd) {
|
||||
sd.macro_detect.timer = INVALID_TIMER;
|
||||
}
|
||||
|
||||
// If the player disconnects before clearing the challenge the account is banned.
|
||||
// If the player disconnects before clearing the challenge the player is punished.
|
||||
if (sd.macro_detect.retry != 0)
|
||||
chrif_req_login_operation(sd.macro_detect.reporter_aid, sd.status.name, CHRIF_OP_LOGIN_BLOCK, 0, 0, 0);
|
||||
pc_macro_punishment(sd, MCD_TIMEOUT);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -15438,10 +15506,10 @@ void pc_macro_reporter_area_select(map_session_data &sd, const int16 x, const in
|
||||
|
||||
/**
|
||||
* Send out captcha check to player.
|
||||
* @param ssd: Source player data
|
||||
* @param tsd: Target player data
|
||||
* @param sd: Target player data
|
||||
* @param reporter_account_id: Account ID of reporter
|
||||
*/
|
||||
void pc_macro_reporter_process(map_session_data &ssd, map_session_data &tsd) {
|
||||
void pc_macro_reporter_process(map_session_data &sd, int32 reporter_account_id) {
|
||||
if (captcha_db.empty())
|
||||
return;
|
||||
|
||||
@ -15449,18 +15517,18 @@ void pc_macro_reporter_process(map_session_data &ssd, map_session_data &tsd) {
|
||||
const std::shared_ptr<s_captcha_data> cd = captcha_db.random();
|
||||
|
||||
// Set macro detection data.
|
||||
tsd.macro_detect.cd = cd;
|
||||
tsd.macro_detect.reporter_aid = ssd.status.account_id;
|
||||
tsd.macro_detect.retry = battle_config.macro_detection_retry;
|
||||
sd.macro_detect.cd = cd;
|
||||
sd.macro_detect.reporter_aid = reporter_account_id;
|
||||
sd.macro_detect.retry = battle_config.macro_detection_retry;
|
||||
|
||||
// Block all actions for the target player.
|
||||
tsd.state.block_action |= (PCBLOCK_ALL | PCBLOCK_IMMUNE);
|
||||
sd.state.block_action |= (PCBLOCK_ALL | PCBLOCK_IMMUNE);
|
||||
|
||||
// Open macro detect client side.
|
||||
clif_macro_detector_request(tsd);
|
||||
clif_macro_detector_request(sd);
|
||||
|
||||
// Start the timeout timer.
|
||||
tsd.macro_detect.timer = add_timer(gettick() + battle_config.macro_detection_timeout, pc_macro_detector_timeout, tsd.bl.id, 0);
|
||||
sd.macro_detect.timer = add_timer(gettick() + battle_config.macro_detection_timeout, pc_macro_detector_timeout, sd.bl.id, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1722,17 +1722,20 @@ bool pc_attendance_enabled();
|
||||
int32 pc_attendance_counter( struct map_session_data* sd );
|
||||
void pc_attendance_claim_reward( struct map_session_data* sd );
|
||||
|
||||
void pc_jail(map_session_data &sd, int32 duration = INT_MAX);
|
||||
|
||||
// Captcha Register
|
||||
void pc_macro_captcha_register(map_session_data &sd, uint16 image_size, char captcha_answer[CAPTCHA_ANSWER_SIZE]);
|
||||
void pc_macro_captcha_register_upload(map_session_data & sd, uint16 upload_size, char *upload_data);
|
||||
|
||||
// Macro Detector
|
||||
TIMER_FUNC(pc_macro_detector_timeout);
|
||||
void pc_macro_detector_process_answer(map_session_data &sd, char captcha_answer[CAPTCHA_ANSWER_SIZE]);
|
||||
void pc_macro_detector_disconnect(map_session_data &sd);
|
||||
|
||||
// Macro Reporter
|
||||
void pc_macro_reporter_area_select(map_session_data &sd, const int16 x, const int16 y, const int8 radius);
|
||||
void pc_macro_reporter_process(map_session_data &ssd, map_session_data &tsd);
|
||||
void pc_macro_reporter_process(map_session_data &sd, int32 reporter_account_id = -1);
|
||||
|
||||
#ifdef MAP_GENERATOR
|
||||
void pc_reputation_generate();
|
||||
|
@ -26829,6 +26829,25 @@ BUILDIN_FUNC(isdead) {
|
||||
return SCRIPT_CMD_SUCCESS;
|
||||
}
|
||||
|
||||
BUILDIN_FUNC(macro_detector) {
|
||||
map_session_data *sd;
|
||||
|
||||
if (script_hasdata(st, 2) && script_isstring(st, 2)) { // Character Name
|
||||
if (!script_nick2sd(2, sd)) {
|
||||
return SCRIPT_CMD_FAILURE;
|
||||
}
|
||||
} else { // Account ID
|
||||
if (!script_accid2sd(2, sd)) {
|
||||
return SCRIPT_CMD_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// Reporter Account ID as -1 for server.
|
||||
pc_macro_reporter_process(*sd);
|
||||
|
||||
return SCRIPT_CMD_SUCCESS;
|
||||
}
|
||||
|
||||
#include "../custom/script.inc"
|
||||
|
||||
// declarations that were supposed to be exported from npc_chat.cpp
|
||||
@ -27582,6 +27601,8 @@ struct script_function buildin_func[] = {
|
||||
BUILDIN_DEF(getfame, "?"),
|
||||
BUILDIN_DEF(getfamerank, "?"),
|
||||
BUILDIN_DEF(isdead, "?"),
|
||||
BUILDIN_DEF(macro_detector, "?"),
|
||||
|
||||
#include "../custom/script_def.inc"
|
||||
|
||||
{NULL,NULL,NULL},
|
||||
|
@ -11257,7 +11257,6 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
|
||||
break;
|
||||
case SC_JAILED:
|
||||
// Val1 is duration in minutes. Use INT_MAX to specify 'unlimited' time.
|
||||
tick = val1>0?1000:250;
|
||||
if (sd) {
|
||||
if (sd->mapindex != val2) {
|
||||
int pos = (bl->x&0xFFFF)|(bl->y<<16), // Current Coordinates
|
||||
@ -13275,9 +13274,6 @@ int status_change_end(struct block_list* bl, enum sc_type type, int tid)
|
||||
}
|
||||
break;
|
||||
case SC_JAILED:
|
||||
if(tid == INVALID_TIMER)
|
||||
break;
|
||||
// Natural expiration.
|
||||
if(sd && sd->mapindex == sce->val2)
|
||||
pc_setpos(sd,(unsigned short)sce->val3,sce->val4&0xFFFF, sce->val4>>16, CLR_TELEPORT);
|
||||
break; // Guess hes not in jail :P
|
||||
|
Loading…
x
Reference in New Issue
Block a user