diff --git a/code/__DEFINES/admin.dm b/code/__DEFINES/admin.dm index c7bf018a..f9427409 100644 --- a/code/__DEFINES/admin.dm +++ b/code/__DEFINES/admin.dm @@ -81,3 +81,10 @@ #define SPAM_TRIGGER_WARNING 5 //Number of identical messages required before the spam-prevention will warn you to stfu #define SPAM_TRIGGER_AUTOMUTE 10 //Number of identical messages required before the spam-prevention will automute you + +///Max length of a keypress command before it's considered to be a forged packet/bogus command +#define MAX_KEYPRESS_COMMANDLENGTH 16 +///Max amount of keypress messages per second over two seconds before client is autokicked +#define MAX_KEYPRESS_AUTOKICK 100 +///Length of held key rolling buffer +#define HELD_KEY_BUFFER_LENGTH 15 \ No newline at end of file diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm index 42094a4b..52f3515d 100644 --- a/code/_onclick/hud/human.dm +++ b/code/_onclick/hud/human.dm @@ -86,7 +86,7 @@ var/widescreenlayout = FALSE //CIT CHANGE - adds support for different hud layouts depending on widescreen pref if(owner.client && owner.client.prefs && owner.client.prefs.widescreenpref) //CIT CHANGE - ditto - widescreenlayout = TRUE // CIT CHANGE - ditto + widescreenlayout = FALSE // CIT CHANGE - ditto var/obj/screen/using var/obj/screen/inventory/inv_box diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm index 4106862c..4e7ec45b 100644 --- a/code/modules/client/client_defines.dm +++ b/code/modules/client/client_defines.dm @@ -75,3 +75,9 @@ var/datum/player_details/player_details //these persist between logins/logouts during the same round. var/list/char_render_holders //Should only be a key-value list of north/south/east/west = obj/screen. + + + var/client_keysend_amount = 0 + var/next_keysend_reset = 0 + var/next_keysend_trip_reset = 0 + var/keysend_tripped = FALSE \ No newline at end of file diff --git a/code/modules/holodeck/computer.dm b/code/modules/holodeck/computer.dm index 4ffc10f9..c7719dcb 100644 --- a/code/modules/holodeck/computer.dm +++ b/code/modules/holodeck/computer.dm @@ -111,6 +111,11 @@ if(A) load_program(A) if("safety") + if(!issilicon(usr) && !IsAdminGhost(usr)) + var/msg = "[key_name(usr)] attempted to emag the holodeck using a href they shouldn't have!" + message_admins(msg) + log_admin(msg) + return obj_flags ^= EMAGGED if((obj_flags & EMAGGED) && program && emag_programs[program.name]) emergency_shutdown() diff --git a/code/modules/keybindings/bindings_client.dm b/code/modules/keybindings/bindings_client.dm index 548a734f..0b1e526d 100644 --- a/code/modules/keybindings/bindings_client.dm +++ b/code/modules/keybindings/bindings_client.dm @@ -3,8 +3,42 @@ /client/verb/keyDown(_key as text) set instant = TRUE set hidden = TRUE + client_keysend_amount += 1 + var/cache = client_keysend_amount + + if(keysend_tripped && next_keysend_trip_reset <= world.time) + keysend_tripped = FALSE + + if(next_keysend_reset <= world.time) + client_keysend_amount = 0 + next_keysend_reset = world.time + (1 SECONDS) + + //The "tripped" system is to confirm that flooding is still happening after one spike + //not entirely sure how byond commands interact in relation to lag + //don't want to kick people if a lag spike results in a huge flood of commands being sent + if(cache >= MAX_KEYPRESS_AUTOKICK) + if(!keysend_tripped) + keysend_tripped = TRUE + next_keysend_trip_reset = world.time + (2 SECONDS) + else + log_admin("Client [ckey] was just autokicked for flooding keysends; likely abuse but potentially lagspike.") + message_admins("Client [ckey] was just autokicked for flooding keysends; likely abuse but potentially lagspike.") + QDEL_IN(src, 1) + return + + ///Check if the key is short enough to even be a real key + if(LAZYLEN(_key) > MAX_KEYPRESS_COMMANDLENGTH) + to_chat(src, "Invalid KeyDown detected! You have been disconnected from the server automatically.") + log_admin("Client [ckey] just attempted to send an invalid keypress. Keymessage was over [MAX_KEYPRESS_COMMANDLENGTH] characters, autokicking due to likely abuse.") + message_admins("Client [ckey] just attempted to send an invalid keypress. Keymessage was over [MAX_KEYPRESS_COMMANDLENGTH] characters, autokicking due to likely abuse.") + QDEL_IN(src, 1) + return + //offset by 1 because the buffer address is 0 indexed because the math was simpler + keys_held[current_key_address + 1] = _key + //the time a key was pressed isn't actually used anywhere (as of 2019-9-10) but this allows easier access usage/checking keys_held[_key] = world.time + current_key_address = ((current_key_address + 1) % HELD_KEY_BUFFER_LENGTH) var/movement = SSinput.movement_keys[_key] if(!(next_move_dir_sub & movement) && !keys_held["Ctrl"]) next_move_dir_add |= movement @@ -35,7 +69,11 @@ set instant = TRUE set hidden = TRUE - keys_held -= _key + //Can't just do a remove because it would alter the length of the rolling buffer, instead search for the key then null it out if it exists + for(var/i in 1 to HELD_KEY_BUFFER_LENGTH) + if(keys_held[i] == _key) + keys_held[i] = null + break var/movement = SSinput.movement_keys[_key] if(!(next_move_dir_add & movement)) next_move_dir_sub |= movement diff --git a/code/modules/keybindings/setup.dm b/code/modules/keybindings/setup.dm index 54df252f..a83e7241 100644 --- a/code/modules/keybindings/setup.dm +++ b/code/modules/keybindings/setup.dm @@ -1,9 +1,14 @@ /client - var/list/keys_held = list() // A list of any keys held currently - // These next two vars are to apply movement for keypresses and releases made while move delayed. - // Because discarding that input makes the game less responsive. - var/next_move_dir_add // On next move, add this dir to the move that would otherwise be done - var/next_move_dir_sub // On next move, subtract this dir from the move that would otherwise be done + /// A rolling buffer of any keys held currently + var/list/keys_held = list() + ///used to keep track of the current rolling buffer position + var/current_key_address = 0 + /// These next two vars are to apply movement for keypresses and releases made while move delayed. + /// Because discarding that input makes the game less responsive. + /// On next move, add this dir to the move that would otherwise be done + var/next_move_dir_add + /// On next move, subtract this dir from the move that would otherwise be done + var/next_move_dir_sub // Set a client's focus to an object and override these procs on that object to let it handle keypresses @@ -31,6 +36,12 @@ /client/proc/set_macros() set waitfor = FALSE + + //Reset and populate the rolling buffer + keys_held.Cut() + for(var/i in 1 to HELD_KEY_BUFFER_LENGTH) + keys_held += null + erase_all_macros() var/list/macro_sets = SSinput.macro_sets diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm index a0e73c4e..47fd657c 100644 --- a/code/modules/mob/dead/new_player/new_player.dm +++ b/code/modules/mob/dead/new_player/new_player.dm @@ -141,6 +141,13 @@ ViewManifest() if(href_list["SelectedJob"]) + if(!SSticker || !SSticker.IsRoundInProgress()) + var/msg = "[key_name(usr)] attempted to join the round using a href that shouldn't be available at this moment!" + log_admin(msg) + message_admins(msg) + to_chat(usr, "The round is either not ready, or has already finished...") + return + if(!GLOB.enter_allowed) to_chat(usr, "There is an administrative lock on entering the game!") diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index b7d013c8..1bfff1a9 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -163,6 +163,8 @@ missing -= BP.body_zone for(var/obj/item/I in BP.embedded_objects) msg += "[t_He] [t_has] \a [icon2html(I, user)] [I] embedded in [t_his] [BP.name]!\n" + if(BP.broken) + msg += "[t_He] [t_has] \a [I] broken [BP.name]!\n" for(var/X in disabled) var/obj/item/bodypart/BP = X diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 2a9a60f3..82a241ef 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -673,6 +673,7 @@ var/status = "" var/brutedamage = LB.brute_dam var/burndamage = LB.burn_dam + var/broken = LB.broken if(hallucination) if(prob(30)) brutedamage += rand(30,40) @@ -700,7 +701,8 @@ status += LB.medium_burn_msg else if(burndamage > 0) status += LB.light_burn_msg - + if(broken == 1) + status = "broken" if(status == "") status = "OK" var/no_damage @@ -711,6 +713,7 @@ for(var/obj/item/I in LB.embedded_objects) to_send += "\t There is \a [I] embedded in your [LB.name]!\n" + for(var/t in missing) for(var/t in missing) to_send += "Your [parse_zone(t)] is missing!\n" diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm index 1ccdf1a1..b0826b86 100644 --- a/code/modules/mob/living/simple_animal/bot/bot.dm +++ b/code/modules/mob/living/simple_animal/bot/bot.dm @@ -807,11 +807,16 @@ Pass a positive integer as an argument to override a bot's default speed. switch(href_list["operation"]) if("patrol") - auto_patrol = !auto_patrol - bot_reset() + if(!issilicon(usr) && !IsAdminGhost(usr) && !(bot_core.allowed(usr) || !locked)) + return TRUE if("remote") remote_disabled = !remote_disabled if("hack") + if(!issilicon(usr) && !IsAdminGhost(usr)) + var/msg = "[key_name(usr)] attempted to hack a bot with a href that shouldn't be available!" + message_admins(msg) + log_admin(msg) + return TRUE if(emagged != 2) emagged = 2 hacked = TRUE diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm index 2f4e1eea..4af79c1f 100644 --- a/code/modules/mob/living/simple_animal/bot/secbot.dm +++ b/code/modules/mob/living/simple_animal/bot/secbot.dm @@ -132,6 +132,9 @@ Auto Patrol: []"}, if(..()) return 1 + if(!issilicon(usr) && !IsAdminGhost(usr) && !(bot_core.allowed(usr) || !locked)) + return TRUE + switch(href_list["operation"]) if("idcheck") idcheck = !idcheck diff --git a/code/modules/surgery/bodyparts/bodyparts.dm b/code/modules/surgery/bodyparts/bodyparts.dm index 81b491e6..7c6d8e08 100644 --- a/code/modules/surgery/bodyparts/bodyparts.dm +++ b/code/modules/surgery/bodyparts/bodyparts.dm @@ -21,6 +21,8 @@ var/held_index = 0 //are we a hand? if so, which one! var/is_pseudopart = FALSE //For limbs that don't really exist, eg chainsaws + var/broken = FALSE //Broken bones + var/disabled = BODYPART_NOT_DISABLED //If disabled, limb is as good as missing var/body_damage_coeff = 1 //Multiplier of the limb's damage that gets applied to the mob var/stam_damage_coeff = 0.5 @@ -75,6 +77,8 @@ to_chat(user, "This limb has [brute_dam > 30 ? "severe" : "minor"] bruising.") if(burn_dam > DAMAGE_PRECISION) to_chat(user, "This limb has [burn_dam > 30 ? "severe" : "minor"] burns.") + if(broken == TRUE) + to_chat(user, "This limb is broken.") /obj/item/bodypart/blob_act() take_damage(max_damage) diff --git a/icons/mob/human_parts_greyscale.dmi b/icons/mob/human_parts_greyscale.dmi index 1bdc7e3c..97aeea4e 100644 Binary files a/icons/mob/human_parts_greyscale.dmi and b/icons/mob/human_parts_greyscale.dmi differ