Rebindable Hotkeys (#12138)

* demodularize interface

* keybindings

* binds

* prefs

* loose ends

* globals

* changes

* s

* datum ref lists

* ok

* fixes

* fixes

* fix

* ok

* sigh

* sigh

* indicators

* let's play the move code around game

* let's play the i didn't comma my lists game

* let's play the indent game

* let's play hte spelling bee

* let's fail the spelling bee

* LET'S PLAY THe HOW HARd  IS  IT TO SPELL A PROC GAME

* let's play the bugfix game

* bugfixes

* improvements

* Update bindings_client.dm

* pixel shift

* A

* wups
This commit is contained in:
kevinz000
2020-05-20 14:40:20 -07:00
committed by GitHub
parent f73f5211f9
commit b57e1c1e93
41 changed files with 1346 additions and 879 deletions
-7
View File
@@ -83,10 +83,3 @@
#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 max held keys
#define MAX_HELD_KEYS 15
+18
View File
@@ -0,0 +1,18 @@
// Defines for managed input/keybinding system.
/// Max length of a keypress command before it's considered to be a forged packet/bogus command
#define MAX_KEYPRESS_COMMANDLENGTH 16
/// Maximum keys that can be bound to one button
#define MAX_COMMANDS_PER_KEY 5
/// Maximum keys per keybind
#define MAX_KEYS_PER_KEYBIND 3
/// Max amount of keypress messages per second over two seconds before client is autokicked
#define MAX_KEYPRESS_AUTOKICK 100
/// Max keys that can be held down at once by a client
#define MAX_HELD_KEYS 15
/// Macroset name of hotkeys/keybind only/modern mode
#define SKIN_MACROSET_HOTKEYS "hotkeys"
/// Macroset name of classic hotkey mode
#define SKIN_MACROSET_CLASSIC_HOTKEYS "oldhotkeys"
/// Macroset name of classic input mode
#define SKIN_MACROSET_CLASSIC_INPUT "oldinput"
+2
View File
@@ -75,6 +75,8 @@
var/datum/emote/E = new path()
E.emote_list[E.key] = E
init_keybindings()
//Uplink Items
for(var/path in subtypesof(/datum/uplink_item))
var/datum/uplink_item/I = path
+6
View File
@@ -18,6 +18,12 @@
return text
return default
/proc/sanitize_islist(value, default)
if(islist(value) && length(value))
return value
if(default)
return default
/proc/sanitize_inlist(value, list/List, default)
if(value in List)
return value
+21
View File
@@ -0,0 +1,21 @@
GLOBAL_LIST_EMPTY(classic_keybinding_list_by_key)
GLOBAL_LIST_EMPTY(hotkey_keybinding_list_by_key)
GLOBAL_LIST_EMPTY(keybindings_by_name)
// This is a mapping from JS keys to Byond - ref: https://keycode.info/
GLOBAL_LIST_INIT(_kbMap, list(
"UP" = "North",
"RIGHT" = "East",
"DOWN" = "South",
"LEFT" = "West",
"INSERT" = "Insert",
"HOME" = "Northwest",
"PAGEUP" = "Northeast",
"DEL" = "Delete",
"END" = "Southwest",
"PAGEDOWN" = "Southeast",
"SPACEBAR" = "Space",
"ALT" = "Alt",
"SHIFT" = "Shift",
"CONTROL" = "Ctrl"
))
+31
View File
@@ -0,0 +1,31 @@
/// Creates and sorts all the keybinding datums
/proc/init_keybindings()
for(var/KB in subtypesof(/datum/keybinding))
var/datum/keybinding/keybinding = KB
if(!initial(keybinding.hotkey_keys))
continue
add_keybinding(new keybinding)
// init_emote_keybinds() - Disabled - I don't particularly want this.
/// Adds an instanced keybinding to the global tracker
/proc/add_keybinding(datum/keybinding/instance)
GLOB.keybindings_by_name[instance.name] = instance
// Classic
if(LAZYLEN(instance.classic_keys))
for(var/bound_key in instance.classic_keys)
LAZYADD(GLOB.classic_keybinding_list_by_key[bound_key], list(instance.name))
// Hotkey
if(LAZYLEN(instance.hotkey_keys))
for(var/bound_key in instance.hotkey_keys)
LAZYADD(GLOB.hotkey_keybinding_list_by_key[bound_key], list(instance.name))
/proc/init_emote_keybinds()
for(var/i in subtypesof(/datum/emote))
var/datum/emote/faketype = i
if(!initial(faketype.key))
continue
var/datum/keybinding/emote/emote_kb = new
emote_kb.link_to_emote(faketype)
add_keybinding(emote_kb)
+70 -88
View File
@@ -6,13 +6,20 @@ SUBSYSTEM_DEF(input)
priority = FIRE_PRIORITY_INPUT
runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY
var/list/macro_sets
var/list/movement_keys
/// Classic mode input focused macro set. Manually set because we can't define ANY or ANY+UP for classic.
var/static/list/macroset_classic_input
/// Classic mode map focused macro set. Manually set because it needs to be clientside and go to macroset_classic_input.
var/static/list/macroset_classic_hotkey
/// New hotkey mode macro set. All input goes into map, game keeps incessently setting your focus to map, we can use ANY all we want here; we don't care about the input bar, the user has to force the input bar every time they want to type.
var/static/list/macroset_hotkey
/// Macro set for hotkeys
var/list/hotkey_mode_macros
/// Macro set for classic.
var/list/input_mode_macros
/datum/controller/subsystem/input/Initialize()
setup_default_macro_sets()
setup_default_movement_keys()
setup_macrosets()
initialized = TRUE
@@ -20,94 +27,68 @@ SUBSYSTEM_DEF(input)
return ..()
// This is for when macro sets are eventualy datumized
/datum/controller/subsystem/input/proc/setup_default_macro_sets()
var/list/static/default_macro_sets
if(default_macro_sets)
macro_sets = default_macro_sets
return
default_macro_sets = list(
"default" = list(
"Tab" = "\".winset \\\"input.focus=true?map.focus=true input.background-color=[COLOR_INPUT_DISABLED]:input.focus=true input.background-color=[COLOR_INPUT_ENABLED]\\\"\"",
"O" = "ooc",
"Ctrl+O" = "looc",
"T" = "say",
"Ctrl+T" = "say_indicator",
"Y" = "whisper",
"M" = "me",
"Ctrl+M" = "me_indicator",
"5" = "subtle",
"Back" = "\".winset \\\"input.text=\\\"\\\"\\\"\"", // This makes it so backspace can remove default inputs
"Any" = "\"KeyDown \[\[*\]\]\"",
"Any+UP" = "\"KeyUp \[\[*\]\]\"",
),
"old_default" = list(
"Tab" = "\".winset \\\"mainwindow.macro=old_hotkeys map.focus=true input.background-color=[COLOR_INPUT_DISABLED]\\\"\"",
"Ctrl+T" = "say",
"Ctrl+O" = "ooc",
),
"old_hotkeys" = list(
"Tab" = "\".winset \\\"mainwindow.macro=old_default input.focus=true input.background-color=[COLOR_INPUT_ENABLED]\\\"\"",
"O" = "ooc",
"L" = "looc",
"T" = "say",
"Ctrl+T" = "say_indicator",
"M" = "me",
"Ctrl+M" = "me_indicator",
"Back" = "\".winset \\\"input.text=\\\"\\\"\\\"\"", // This makes it so backspace can remove default inputs
"Any" = "\"KeyDown \[\[*\]\]\"",
"Any+UP" = "\"KeyUp \[\[*\]\]\"",
),
)
// Because i'm lazy and don't want to type all these out twice
var/list/old_default = default_macro_sets["old_default"]
var/list/static/oldmode_keys = list(
/// Sets up the key list for classic mode for when badmins screw up vv's.
/datum/controller/subsystem/input/proc/setup_macrosets()
// First, let's do the snowflake keyset!
macroset_classic_input = list()
var/list/classic_mode_keys = list(
"North", "East", "South", "West",
"Northeast", "Southeast", "Northwest", "Southwest",
"Insert", "Delete", "Ctrl", "Alt",
"Insert", "Delete", "Ctrl", "Alt", "Shift",
"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12",
)
for(var/key in classic_mode_keys)
macroset_classic_input[key] = "\"KeyDown [key]\""
macroset_classic_input["[key]+UP"] = "\"KeyUp [key]\""
// LET'S PLAY THE BIND EVERY KEY GAME!
// oh except for Backspace and Enter; if you want to use those you shouldn't have used oldmode!
var/list/classic_ctrl_override_keys = list(
"\[", "\]", "\\", ";", "'", ",", ".", "/", "-", "\\=", "`"
)
// i'm lazy let's play the list iteration game of numbers
for(var/i in 0 to 9)
classic_ctrl_override_keys += "[i]"
// let's play the ascii game of A to Z (UPPERCASE)
for(var/i in 65 to 90)
classic_ctrl_override_keys += ascii2text(i)
// let's play the game of clientside bind overrides!
classic_ctrl_override_keys -= list("T", "O", "M", "L")
macroset_classic_input["Ctrl+T"] = "say"
macroset_classic_input["Ctrl+O"] = "ooc"
macroset_classic_input["Ctrl+L"] = "looc"
// let's play the list iteration game x2
for(var/key in classic_ctrl_override_keys)
macroset_classic_input["Ctrl+[key]"] = "\"KeyDown [key]\""
macroset_classic_input["Ctrl+[key]+UP"] = "\"KeyUp [key]\""
// Misc
macroset_classic_input["Tab"] = "\".winset \\\"mainwindow.macro=[SKIN_MACROSET_CLASSIC_HOTKEYS] map.focus=true input.background-color=[COLOR_INPUT_DISABLED]\\\"\""
macroset_classic_input["Escape"] = "\".winset \\\"input.text=\\\"\\\"\\\"\""
for(var/i in 1 to oldmode_keys.len)
var/key = oldmode_keys[i]
old_default[key] = "\"KeyDown [key]\""
old_default["[key]+UP"] = "\"KeyUp [key]\""
// FINALLY, WE CAN DO SOMETHING MORE NORMAL FOR THE SNOWFLAKE-BUT-LESS KEYSET.
macroset_classic_hotkey = list(
"Any" = "\"KeyDown \[\[*\]\]\"",
"Any+UP" = "\"KeyUp \[\[*\]\]\"",
"Tab" = "\".winset \\\"mainwindow.macro=[SKIN_MACROSET_CLASSIC_INPUT] input.focus=true input.background-color=[COLOR_INPUT_ENABLED]\\\"\"",
"Escape" = "\".winset \\\"input.text=\\\"\\\"\\\"\"",
"Back" = "\".winset \\\"input.text=\\\"\\\"\\\"\"",
"O" = "ooc",
"T" = "say",
"L" = "looc",
"M" = "me"
)
var/list/static/oldmode_ctrl_override_keys = list(
"W" = "W", "A" = "A", "S" = "S", "D" = "D", // movement
"1" = "1", "2" = "2", "3" = "3", "4" = "4", // intent
"B" = "B", // resist
"E" = "E", // quick equip
"F" = "F", // intent left
"G" = "G", // intent right
"H" = "H", // stop pulling
"Q" = "Q", // drop
"R" = "R", // throw
"X" = "X", // switch hands
"Y" = "Y", // activate item
"Z" = "Z", // activate item
)
for(var/i in 1 to oldmode_ctrl_override_keys.len)
var/key = oldmode_ctrl_override_keys[i]
var/override = oldmode_ctrl_override_keys[key]
old_default["Ctrl+[key]"] = "\"KeyDown [override]\""
old_default["Ctrl+[key]+UP"] = "\"KeyUp [override]\""
macro_sets = default_macro_sets
// For initially setting up or resetting to default the movement keys
/datum/controller/subsystem/input/proc/setup_default_movement_keys()
var/static/list/default_movement_keys = list(
"W" = NORTH, "A" = WEST, "S" = SOUTH, "D" = EAST, // WASD
"North" = NORTH, "West" = WEST, "South" = SOUTH, "East" = EAST, // Arrow keys & Numpad
)
movement_keys = default_movement_keys.Copy()
// And finally, the modern set.
macroset_hotkey = list(
"Any" = "\"KeyDown \[\[*\]\]\"",
"Any+UP" = "\"KeyUp \[\[*\]\]\"",
"Tab" = "\".winset \\\"input.focus=true?map.focus=true input.background-color=[COLOR_INPUT_DISABLED]:input.focus=true input.background-color=[COLOR_INPUT_ENABLED]\\\"\"",
"Escape" = "\".winset \\\"input.text=\\\"\\\"\\\"\"",
"Back" = "\".winset \\\"input.text=\\\"\\\"\\\"\"",
"O" = "ooc",
"T" = "say",
"L" = "looc",
"M" = "me"
)
// Badmins just wanna have fun ♪
/datum/controller/subsystem/input/proc/refresh_client_macro_sets()
@@ -115,9 +96,10 @@ SUBSYSTEM_DEF(input)
for(var/i in 1 to clients.len)
var/client/user = clients[i]
user.set_macros()
user.update_movement_keys()
/datum/controller/subsystem/input/fire()
var/list/clients = GLOB.clients // Let's sing the list cache song
for(var/i in 1 to length(clients))
for(var/i in 1 to clients.len)
var/client/C = clients[i]
C.keyLoop()
-59
View File
@@ -69,11 +69,6 @@
<A href='?src=[REF(src)];[HrefToken()];secrets=floorlava'>The floor is lava! (DANGEROUS: extremely lame)</A><BR>
<A href='?src=[REF(src)];[HrefToken()];secrets=customportal'>Spawn a custom portal storm</A><BR>
<BR>
<A href='?src=[REF(src)];[HrefToken()];secrets=flipmovement'>Flip client movement directions</A><BR>
<A href='?src=[REF(src)];[HrefToken()];secrets=randommovement'>Randomize client movement directions</A><BR>
<A href='?src=[REF(src)];[HrefToken()];secrets=custommovement'>Set each movement direction manually</A><BR>
<A href='?src=[REF(src)];[HrefToken()];secrets=resetmovement'>Reset movement directions to default</A><BR>
<BR>
<A href='?src=[REF(src)];[HrefToken()];secrets=changebombcap'>Change bomb cap</A><BR>
<A href='?src=[REF(src)];[HrefToken()];secrets=masspurrbation'>Mass Purrbation</A><BR>
<A href='?src=[REF(src)];[HrefToken()];secrets=massremovepurrbation'>Mass Remove Purrbation</A><BR>
@@ -603,60 +598,6 @@
purrbation.")
log_admin("[key_name(usr)] has removed everyone from purrbation.")
if("flipmovement")
if(!check_rights(R_FUN))
return
if(alert("Flip all movement controls?","Confirm","Yes","Cancel") == "Cancel")
return
var/list/movement_keys = SSinput.movement_keys
for(var/i in 1 to movement_keys.len)
var/key = movement_keys[i]
movement_keys[key] = turn(movement_keys[key], 180)
message_admins("[key_name_admin(usr)] has flipped all movement directions.")
log_admin("[key_name(usr)] has flipped all movement directions.")
if("randommovement")
if(!check_rights(R_FUN))
return
if(alert("Randomize all movement controls?","Confirm","Yes","Cancel") == "Cancel")
return
var/list/movement_keys = SSinput.movement_keys
for(var/i in 1 to movement_keys.len)
var/key = movement_keys[i]
movement_keys[key] = turn(movement_keys[key], 45 * rand(1, 8))
message_admins("[key_name_admin(usr)] has randomized all movement directions.")
log_admin("[key_name(usr)] has randomized all movement directions.")
if("custommovement")
if(!check_rights(R_FUN))
return
if(alert("Are you sure you want to change every movement key?","Confirm","Yes","Cancel") == "Cancel")
return
var/list/movement_keys = SSinput.movement_keys
var/list/new_movement = list()
for(var/i in 1 to movement_keys.len)
var/key = movement_keys[i]
var/msg = "Please input the new movement direction when the user presses [key]. Ex. northeast"
var/title = "New direction for [key]"
var/new_direction = text2dir(input(usr, msg, title) as text|null)
if(!new_direction)
new_direction = movement_keys[key]
new_movement[key] = new_direction
SSinput.movement_keys = new_movement
message_admins("[key_name_admin(usr)] has configured all movement directions.")
log_admin("[key_name(usr)] has configured all movement directions.")
if("resetmovement")
if(!check_rights(R_FUN))
return
if(alert("Are you sure you want to reset movement keys to default?","Confirm","Yes","Cancel") == "Cancel")
return
SSinput.setup_default_movement_keys()
message_admins("[key_name_admin(usr)] has reset all movement keys.")
log_admin("[key_name(usr)] has reset all movement keys.")
if("customportal")
if(!check_rights(R_FUN))
return
+14
View File
@@ -80,10 +80,24 @@
var/list/char_render_holders //Should only be a key-value list of north/south/east/west = obj/screen.
/// Keys currently held
var/list/keys_held = list()
/// 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
/// Amount of keydowns in the last keysend checking interval
var/client_keysend_amount = 0
/// World tick time where client_keysend_amount will reset
var/next_keysend_reset = 0
/// World tick time where keysend_tripped will reset back to false
var/next_keysend_trip_reset = 0
/// When set to true, user will be autokicked if they trip the keysends in a second limit again
var/keysend_tripped = FALSE
/// custom movement keys for this client
var/list/movement_keys = list()
/// Messages currently seen by this client
var/list/seen_messages
+20 -3
View File
@@ -265,6 +265,9 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
else
prefs = new /datum/preferences(src)
GLOB.preferences_datums[ckey] = prefs
if(SSinput.initialized)
set_macros()
update_movement_keys(prefs)
prefs.last_ip = address //these are gonna be used for banning
prefs.last_id = computer_id //these are gonna be used for banning
@@ -328,9 +331,6 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
qdel(src)
return
if(SSinput.initialized)
set_macros()
chatOutput.start() // Starts the chat
if(alert_mob_dupe_login)
@@ -892,6 +892,23 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
y = clamp(y+change, min,max)
change_view("[x]x[y]")
/client/proc/update_movement_keys(datum/preferences/direct_prefs)
var/datum/preferences/D = prefs || direct_prefs
if(!D?.key_bindings)
return
movement_keys = list()
for(var/key in D.key_bindings)
for(var/kb_name in D.key_bindings[key])
switch(kb_name)
if("North")
movement_keys[key] = NORTH
if("East")
movement_keys[key] = EAST
if("West")
movement_keys[key] = WEST
if("South")
movement_keys[key] = SOUTH
/client/proc/change_view(new_size)
if (isnull(new_size))
CRASH("change_view called without argument.")
+162 -17
View File
@@ -46,6 +46,11 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/chat_on_map = TRUE
var/max_chat_length = CHAT_MESSAGE_MAX_LENGTH
var/see_chat_non_mob = TRUE
/// Custom Keybindings
var/list/key_bindings = list()
var/tgui_fancy = TRUE
var/tgui_lock = TRUE
var/windowflashing = TRUE
@@ -184,9 +189,6 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/uplink_spawn_loc = UPLINK_PDA
var/sprint_spacebar = FALSE
var/sprint_toggle = FALSE
var/hud_toggle_flash = TRUE
var/hud_toggle_color = "#ffffff"
@@ -245,6 +247,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
return
//we couldn't load character data so just randomize the character appearance + name
random_character() //let's create a random character then - rather than a fat, bald and naked man.
key_bindings = deepCopyList(GLOB.hotkey_keybinding_list_by_key) // give them default keybinds and update their movement keys
C?.update_movement_keys(src)
real_name = pref_species.random_name(gender,1)
if(!loaded_preferences_successfully)
save_preferences()
@@ -266,6 +270,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "<a href='?_src_=prefs;preference=tab;tab=3' [current_tab == 3 ? "class='linkOn'" : ""]>Loadout</a>"
dat += "<a href='?_src_=prefs;preference=tab;tab=1' [current_tab == 1 ? "class='linkOn'" : ""]>Game Preferences</a>"
dat += "<a href='?_src_=prefs;preference=tab;tab=4' [current_tab == 4 ? "class='linkOn'" : ""]>Content Preferences</a>"
dat += "<a href='?_src_=prefs;preference=tab;tab=5' [current_tab == 5 ? "class='linkOn'" : ""]>Keybindings</a>"
if(!path)
dat += "<div class='notice'>Please create an account to save your preferences</div>"
@@ -855,7 +860,6 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "<b>See Runechat for non-mobs:</b> <a href='?_src_=prefs;preference=see_chat_non_mob'>[see_chat_non_mob ? "Enabled" : "Disabled"]</a><br>"
dat += "<br>"
dat += "<b>Action Buttons:</b> <a href='?_src_=prefs;preference=action_buttons'>[(buttons_locked) ? "Locked In Place" : "Unlocked"]</a><br>"
dat += "<b>Keybindings:</b> <a href='?_src_=prefs;preference=hotkeys'>[(hotkeys) ? "Hotkeys" : "Default"]</a><br>"
dat += "<br>"
dat += "<b>PDA Color:</b> <span style='border:1px solid #161616; background-color: [pda_color];'>&nbsp;&nbsp;&nbsp;</span> <a href='?_src_=prefs;preference=pda_color;task=input'>Change</a><BR>"
dat += "<b>PDA Style:</b> <a href='?_src_=prefs;task=input;preference=pda_style'>[pda_style]</a><br>"
@@ -951,8 +955,6 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "</a><br>"
dat += "<b>Ambient Occlusion:</b> <a href='?_src_=prefs;preference=ambientocclusion'>[ambientocclusion ? "Enabled" : "Disabled"]</a><br>"
dat += "<b>Fit Viewport:</b> <a href='?_src_=prefs;preference=auto_fit_viewport'>[auto_fit_viewport ? "Auto" : "Manual"]</a><br>"
dat += "<b>Sprint Key:</b> <a href='?_src_=prefs;preference=sprint_key'>[sprint_spacebar ? "Space" : "Shift"]</a><br>"
dat += "<b>Toggle Sprint:</b> <a href='?_src_=prefs;preference=sprint_toggle'>[sprint_toggle ? "Enabled" : "Disabled"]</a><br>"
dat += "<b>HUD Button Flashes:</b> <a href='?_src_=prefs;preference=hud_toggle_flash'>[hud_toggle_flash ? "Enabled" : "Disabled"]</a><br>"
dat += "<b>HUD Button Flash Color:</b> <span style='border: 1px solid #161616; background-color: [hud_toggle_color];'>&nbsp;&nbsp;&nbsp;</span> <a href='?_src_=prefs;preference=hud_toggle_color;task=input'>Change</a><br>"
@@ -1075,6 +1077,56 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "<b>Ass Slapping:</b> <a href='?_src_=prefs;preference=ass_slap'>[(cit_toggles & NO_ASS_SLAP) ? "Disallowed" : "Allowed"]</a><br>"
dat += "</tr></table>"
dat += "<br>"
if(5) // Custom keybindings
dat += "<b>Keybindings:</b> <a href='?_src_=prefs;preference=hotkeys'>[(hotkeys) ? "Hotkeys" : "Input"]</a><br>"
dat += "Keybindings mode controls how the game behaves with tab and map/input focus.<br>If it is on <b>Hotkeys</b>, the game will always attempt to force you to map focus, meaning keypresses are sent \
directly to the map instead of the input. You will still be able to use the command bar, but you need to tab to do it every time you click on the game map.<br>\
If it is on <b>Input</b>, the game will not force focus away from the input bar, and you can switch focus using TAB between these two modes: If the input bar is pink, that means that you are in non-hotkey mode, sending all keypresses of the normal \
alphanumeric characters, punctuation, spacebar, backspace, enter, etc, typing keys into the input bar. If the input bar is white, you are in hotkey mode, meaning all keypresses go into the game's keybind handling system unless you \
manually click on the input bar to shift focus there.<br>\
Input mode is the closest thing to the old input system.<br>\
<b>IMPORTANT:</b> While in input mode's non hotkey setting (tab toggled), Ctrl + KEY will send KEY to the keybind system as the key itself, not as Ctrl + KEY. This means Ctrl + T/W/A/S/D/all your familiar stuff still works, but you \
won't be able to access any regular Ctrl binds.<br>"
// Create an inverted list of keybindings -> key
var/list/user_binds = list()
for (var/key in key_bindings)
for(var/kb_name in key_bindings[key])
user_binds[kb_name] += list(key)
var/list/kb_categories = list()
// Group keybinds by category
for (var/name in GLOB.keybindings_by_name)
var/datum/keybinding/kb = GLOB.keybindings_by_name[name]
kb_categories[kb.category] += list(kb)
dat += "<style>label { display: inline-block; width: 200px; }</style><body>"
for (var/category in kb_categories)
dat += "<h3>[category]</h3>"
for (var/i in kb_categories[category])
var/datum/keybinding/kb = i
if(!length(user_binds[kb.name]))
dat += "<label>[kb.full_name]</label> <a href ='?_src_=prefs;preference=keybindings_capture;keybinding=[kb.name];old_key=["Unbound"]'>Unbound</a>"
var/list/default_keys = hotkeys ? kb.hotkey_keys : kb.classic_keys
if(LAZYLEN(default_keys))
dat += "| Default: [default_keys.Join(", ")]"
dat += "<br>"
else
var/bound_key = user_binds[kb.name][1]
dat += "<label>[kb.full_name]</label> <a href ='?_src_=prefs;preference=keybindings_capture;keybinding=[kb.name];old_key=[bound_key]'>[bound_key]</a>"
for(var/bound_key_index in 2 to length(user_binds[kb.name]))
bound_key = user_binds[kb.name][bound_key_index]
dat += " | <a href ='?_src_=prefs;preference=keybindings_capture;keybinding=[kb.name];old_key=[bound_key]'>[bound_key]</a>"
if(length(user_binds[kb.name]) < MAX_KEYS_PER_KEYBIND)
dat += "| <a href ='?_src_=prefs;preference=keybindings_capture;keybinding=[kb.name]'>Add Secondary</a>"
var/list/default_keys = hotkeys ? kb.classic_keys : kb.hotkey_keys
if(LAZYLEN(default_keys))
dat += "| Default: [default_keys.Join(", ")]"
dat += "<br>"
dat += "<br><br>"
dat += "<a href ='?_src_=prefs;preference=keybindings_reset'>\[Reset to default\]</a>"
dat += "</body>"
dat += "<hr><center>"
@@ -1095,6 +1147,31 @@ GLOBAL_LIST_EMPTY(preferences_datums)
#undef APPEARANCE_CATEGORY_COLUMN
#undef MAX_MUTANT_ROWS
/datum/preferences/proc/CaptureKeybinding(mob/user, datum/keybinding/kb, var/old_key)
var/HTML = {"
<div id='focus' style="outline: 0;" tabindex=0>Keybinding: [kb.full_name]<br>[kb.description]<br><br><b>Press any key to change<br>Press ESC to clear</b></div>
<script>
var deedDone = false;
document.onkeyup = function(e) {
if(deedDone){ return; }
var alt = e.altKey ? 1 : 0;
var ctrl = e.ctrlKey ? 1 : 0;
var shift = e.shiftKey ? 1 : 0;
var numpad = (95 < e.keyCode && e.keyCode < 112) ? 1 : 0;
var escPressed = e.keyCode == 27 ? 1 : 0;
var url = 'byond://?_src_=prefs;preference=keybindings_set;keybinding=[kb.name];old_key=[old_key];clear_key='+escPressed+';key='+e.key+';alt='+alt+';ctrl='+ctrl+';shift='+shift+';numpad='+numpad+';key_code='+e.keyCode;
window.location=url;
deedDone = true;
}
document.getElementById('focus').focus();
</script>
"}
winshow(user, "capturekeypress", TRUE)
var/datum/browser/popup = new(user, "capturekeypress", "<div align='center'>Keybindings</div>", 350, 300)
popup.set_content(HTML)
popup.open(FALSE)
onclose(user, "capturekeypress", src)
/datum/preferences/proc/SetChoices(mob/user, limit = 17, list/splitJobs = list("Chief Engineer"), widthPerColumn = 295, height = 620)
if(!SSjob)
return
@@ -2275,10 +2352,73 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if("hotkeys")
hotkeys = !hotkeys
if(hotkeys)
winset(user, null, "input.focus=true input.background-color=[COLOR_INPUT_ENABLED] mainwindow.macro=default")
else
winset(user, null, "input.focus=true input.background-color=[COLOR_INPUT_ENABLED] mainwindow.macro=old_default")
user.client.set_macros()
if("keybindings_capture")
var/datum/keybinding/kb = GLOB.keybindings_by_name[href_list["keybinding"]]
var/old_key = href_list["old_key"]
CaptureKeybinding(user, kb, old_key)
return
if("keybindings_set")
var/kb_name = href_list["keybinding"]
if(!kb_name)
user << browse(null, "window=capturekeypress")
ShowChoices(user)
return
var/clear_key = text2num(href_list["clear_key"])
var/old_key = href_list["old_key"]
if(clear_key)
if(key_bindings[old_key])
key_bindings[old_key] -= kb_name
if(!length(key_bindings[old_key]))
key_bindings -= old_key
user << browse(null, "window=capturekeypress")
save_preferences()
ShowChoices(user)
return
var/new_key = uppertext(href_list["key"])
var/AltMod = text2num(href_list["alt"]) ? "Alt" : ""
var/CtrlMod = text2num(href_list["ctrl"]) ? "Ctrl" : ""
var/ShiftMod = text2num(href_list["shift"]) ? "Shift" : ""
var/numpad = text2num(href_list["numpad"]) ? "Numpad" : ""
// var/key_code = text2num(href_list["key_code"])
if(GLOB._kbMap[new_key])
new_key = GLOB._kbMap[new_key]
var/full_key
switch(new_key)
if("Alt")
full_key = "[new_key][CtrlMod][ShiftMod]"
if("Ctrl")
full_key = "[AltMod][new_key][ShiftMod]"
if("Shift")
full_key = "[AltMod][CtrlMod][new_key]"
else
full_key = "[AltMod][CtrlMod][ShiftMod][numpad][new_key]"
if(key_bindings[old_key])
key_bindings[old_key] -= kb_name
if(!length(key_bindings[old_key]))
key_bindings -= old_key
key_bindings[full_key] += list(kb_name)
key_bindings[full_key] = sortList(key_bindings[full_key])
user << browse(null, "window=capturekeypress")
user.client.update_movement_keys()
save_preferences()
if("keybindings_reset")
var/choice = tgalert(user, "Would you prefer 'hotkey' or 'classic' defaults?", "Setup keybindings", "Hotkey", "Classic", "Cancel")
if(choice == "Cancel")
ShowChoices(user)
return
hotkeys = (choice == "Hotkey")
key_bindings = (hotkeys) ? deepCopyList(GLOB.hotkey_keybinding_list_by_key) : deepCopyList(GLOB.classic_keybinding_list_by_key)
user.client.update_movement_keys()
if("chat_on_map")
chat_on_map = !chat_on_map
if("see_chat_non_mob")
@@ -2409,13 +2549,6 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if(auto_fit_viewport && parent)
parent.fit_viewport()
if("sprint_key")
sprint_spacebar = !sprint_spacebar
if("sprint_toggle")
sprint_toggle = !sprint_toggle
if("hud_toggle_flash")
hud_toggle_flash = !hud_toggle_flash
@@ -2595,6 +2728,18 @@ GLOBAL_LIST_EMPTY(preferences_datums)
cached_holoform_icons[filter_type] = process_holoform_icon_filter(custom_holoform_icon, filter_type)
return cached_holoform_icons[filter_type]
//Used in savefile update 32, can be removed once that is no longer relevant.
/datum/preferences/proc/force_reset_keybindings()
var/choice = tgalert(parent.mob, "Your basic keybindings need to be reset, emotes will remain as before. Would you prefer 'hotkey' or 'classic' mode?", "Reset keybindings", "Hotkey", "Classic")
hotkeys = (choice != "Classic")
var/list/oldkeys = key_bindings
key_bindings = (hotkeys) ? deepCopyList(GLOB.hotkey_keybinding_list_by_key) : deepCopyList(GLOB.classic_keybinding_list_by_key)
for(var/key in oldkeys)
if(!key_bindings[key])
key_bindings[key] = oldkeys[key]
parent.update_movement_keys()
/datum/preferences/proc/is_loadout_slot_available(slot)
var/list/L
LAZYINITLIST(L)
+8 -8
View File
@@ -5,7 +5,7 @@
// You do not need to raise this if you are adding new values that have sane defaults.
// Only raise this value when changing the meaning/format/name/layout of an existing value
// where you would want the updater procs below to run
#define SAVEFILE_VERSION_MAX 31
#define SAVEFILE_VERSION_MAX 32
/*
SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Carn
@@ -42,7 +42,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
//if your savefile is 3 months out of date, then 'tough shit'.
/datum/preferences/proc/update_preferences(current_version, savefile/S)
return
if(current_version < 32) //If you remove this, remove force_reset_keybindings() too.
addtimer(CALLBACK(src, .proc/force_reset_keybindings), 30) //No mob available when this is run, timer allows user choice.
/datum/preferences/proc/update_character(current_version, savefile/S)
if(current_version < 19)
@@ -250,8 +251,6 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["parallax"] >> parallax
S["ambientocclusion"] >> ambientocclusion
S["auto_fit_viewport"] >> auto_fit_viewport
S["sprint_spacebar"] >> sprint_spacebar
S["sprint_toggle"] >> sprint_toggle
S["hud_toggle_flash"] >> hud_toggle_flash
S["hud_toggle_color"] >> hud_toggle_color
S["menuoptions"] >> menuoptions
@@ -261,6 +260,9 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["pda_color"] >> pda_color
S["pda_skin"] >> pda_skin
// Custom hotkeys
S["key_bindings"] >> key_bindings
//citadel code
S["arousable"] >> arousable
S["screenshake"] >> screenshake
@@ -295,8 +297,6 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
parallax = sanitize_integer(parallax, PARALLAX_INSANE, PARALLAX_DISABLE, null)
ambientocclusion = sanitize_integer(ambientocclusion, 0, 1, initial(ambientocclusion))
auto_fit_viewport = sanitize_integer(auto_fit_viewport, 0, 1, initial(auto_fit_viewport))
sprint_spacebar = sanitize_integer(sprint_spacebar, 0, 1, initial(sprint_spacebar))
sprint_toggle = sanitize_integer(sprint_toggle, 0, 1, initial(sprint_toggle))
hud_toggle_flash = sanitize_integer(hud_toggle_flash, 0, 1, initial(hud_toggle_flash))
hud_toggle_color = sanitize_hexcolor(hud_toggle_color, 6, 1, initial(hud_toggle_color))
ghost_form = sanitize_inlist(ghost_form, GLOB.ghost_forms, initial(ghost_form))
@@ -315,6 +315,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
cit_toggles = sanitize_integer(cit_toggles, 0, 16777215, initial(cit_toggles))
auto_ooc = sanitize_integer(auto_ooc, 0, 1, initial(auto_ooc))
no_tetris_storage = sanitize_integer(no_tetris_storage, 0, 1, initial(no_tetris_storage))
key_bindings = sanitize_islist(key_bindings, list())
return 1
@@ -362,8 +363,6 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["parallax"], parallax)
WRITE_FILE(S["ambientocclusion"], ambientocclusion)
WRITE_FILE(S["auto_fit_viewport"], auto_fit_viewport)
WRITE_FILE(S["sprint_spacebar"], sprint_spacebar)
WRITE_FILE(S["sprint_toggle"], sprint_toggle)
WRITE_FILE(S["hud_toggle_flash"], hud_toggle_flash)
WRITE_FILE(S["hud_toggle_color"], hud_toggle_color)
WRITE_FILE(S["menuoptions"], menuoptions)
@@ -372,6 +371,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["pda_style"], pda_style)
WRITE_FILE(S["pda_color"], pda_color)
WRITE_FILE(S["pda_skin"], pda_skin)
WRITE_FILE(S["key_bindings"], key_bindings)
//citadel code
WRITE_FILE(S["screenshake"], screenshake)
@@ -1,24 +0,0 @@
/datum/admins/key_down(_key, client/user)
switch(_key)
if("F3")
user.get_admin_say()
return
if("F5")
user.admin_ghost()
return
if("F6")
player_panel_new()
return
if("F7")
user.togglebuildmodeself()
return
if("F8")
if(user.keys_held["Ctrl"])
user.stealth()
else
user.invisimin()
return
if("F10")
user.get_dead_say()
return
..()
+1 -1
View File
@@ -5,7 +5,7 @@
if(!user.keys_held["Ctrl"])
var/movement_dir = NONE
for(var/_key in user.keys_held)
movement_dir = movement_dir | SSinput.movement_keys[_key]
movement_dir = movement_dir | user.movement_keys[_key]
if(user.next_move_dir_add)
movement_dir |= user.next_move_dir_add
if(user.next_move_dir_sub)
@@ -1,9 +0,0 @@
/mob/living/carbon/key_down(_key, client/user)
switch(_key)
if("R", "Southwest") // Southwest is End
toggle_throw_mode()
return
if("C")
user_toggle_intentional_combat_mode()
return
return ..()
+42 -28
View File
@@ -33,55 +33,69 @@
to_chat(src, "<span class='userdanger'>Invalid KeyDown detected! You have been disconnected from the server automatically.</span>")
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)
qdel(src)
return
if(_key == "Tab")
ForceAllKeysUp() //groan, more hacky kevcode
return
if(length(keys_held) > MAX_HELD_KEYS)
keys_held.Cut(1,2)
keys_held[_key] = TRUE
var/movement = SSinput.movement_keys[_key]
var/movement = movement_keys[_key]
if(!(next_move_dir_sub & movement) && !keys_held["Ctrl"])
next_move_dir_add |= movement
// Client-level keybindings are ones anyone should be able to do at any time
// Things like taking screenshots, hitting tab, and adminhelps.
var/AltMod = keys_held["Alt"] ? "Alt" : ""
var/CtrlMod = keys_held["Ctrl"] ? "Ctrl" : ""
var/ShiftMod = keys_held["Shift"] ? "Shift" : ""
var/full_key
switch(_key)
if("F1")
if(keys_held["Ctrl"] && keys_held["Shift"]) // Is this command ever used?
winset(src, null, "command=.options")
else
get_adminhelp()
return
if("F2") // Screenshot. Hold shift to choose a name and location to save in
winset(src, null, "command=.screenshot [!keys_held["shift"] ? "auto" : ""]")
return
if("F12") // Toggles minimal HUD
mob.button_pressed_F12()
return
if("Alt", "Ctrl", "Shift")
full_key = "[AltMod][CtrlMod][ShiftMod]"
else
full_key = "[AltMod][CtrlMod][ShiftMod][_key]"
var/keycount = 0
for(var/kb_name in prefs.key_bindings[full_key])
keycount++
var/datum/keybinding/kb = GLOB.keybindings_by_name[kb_name]
if(kb.can_use(src) && kb.down(src) && keycount >= MAX_COMMANDS_PER_KEY)
break
if(holder)
holder.key_down(_key, src)
if(mob.focus)
mob.focus.key_down(_key, src)
holder?.key_down(_key, src)
mob.focus?.key_down(_key, src)
/// Keyup's all keys held down.
/client/proc/ForceAllKeysUp()
// simulate a user releasing all keys except for the mod keys. groan. i hate this. thanks, byond. why aren't keyups able to be forced to fire on macro change aoaoaoao.
// groan
for(var/key in keys_held) // all of these won't be the 3 mod keys.
if((key == "Ctrl") || (key == "Alt") || (key == "Shift"))
continue
keyUp("[key]")
/client/verb/keyUp(_key as text)
set instant = TRUE
set hidden = TRUE
keys_held -= _key
var/movement = SSinput.movement_keys[_key]
var/movement = movement_keys[_key]
if(!(next_move_dir_add & movement))
next_move_dir_sub |= movement
if(holder)
holder.key_up(_key, src)
if(mob.focus)
mob.focus.key_up(_key, src)
// We don't do full key for release, because for mod keys you
// can hold different keys and releasing any should be handled by the key binding specifically
for (var/kb_name in prefs.key_bindings[_key])
var/datum/keybinding/kb = GLOB.keybindings_by_name[kb_name]
if(kb.can_use(src) && kb.up(src))
break
holder?.key_up(_key, src)
mob.focus?.key_up(_key, src)
// Called every game tick
/client/keyLoop()
if(holder)
holder.keyLoop(src)
if(mob.focus)
mob.focus.keyLoop(src)
holder?.keyLoop(src)
mob.focus?.keyLoop(src)
@@ -1,80 +0,0 @@
/mob/living/carbon/human/key_down(_key, client/user)
if(client.keys_held["Shift"])
switch(_key)
if("E") // Put held thing in belt or take out most recent thing from belt
var/obj/item/thing = get_active_held_item()
var/obj/item/storage/equipped_belt = get_item_by_slot(SLOT_BELT)
if(!equipped_belt) // We also let you equip a belt like this
if(!thing)
to_chat(user, "<span class='notice'>You have no belt to take something out of.</span>")
return
equip_to_slot_if_possible(thing, SLOT_BELT)
return
if(!istype(equipped_belt)) // not a storage item
if(!thing)
to_chat(user, "<span class='notice'>You have no belt to take something out of.</span>")
else
to_chat(user, "<span class='notice'>You can't fit anything in.</span>")
return
if(thing) // put thing in belt
if(!SEND_SIGNAL(equipped_belt, COMSIG_TRY_STORAGE_INSERT, thing, user.mob))
to_chat(user, "<span class='notice'>You can't fit anything in.</span>")
return
if(!equipped_belt.contents.len) // nothing to take out
to_chat(user, "<span class='notice'>There's nothing in your belt to take out.</span>")
return
var/obj/item/stored = equipped_belt.contents[equipped_belt.contents.len]
if(!stored || stored.on_found(src))
return
stored.attack_hand(src) // take out thing from belt
return
if("B") // Put held thing in backpack or take out most recent thing from backpack
var/obj/item/thing = get_active_held_item()
var/obj/item/storage/equipped_backpack = get_item_by_slot(SLOT_BACK)
if(!equipped_backpack) // We also let you equip a backpack like this
if(!thing)
to_chat(user, "<span class='notice'>You have no backpack to take something out of.</span>")
return
equip_to_slot_if_possible(thing, SLOT_BACK)
return
if(!istype(equipped_backpack)) // not a storage item
if(!thing)
to_chat(user, "<span class='notice'>You have no backpack to take something out of.</span>")
else
to_chat(user, "<span class='notice'>You can't fit anything in.</span>")
return
if(thing) // put thing in backpack
if(!SEND_SIGNAL(equipped_backpack, COMSIG_TRY_STORAGE_INSERT, thing, user.mob))
to_chat(user, "<span class='notice'>You can't fit anything in.</span>")
return
if(!equipped_backpack.contents.len) // nothing to take out
to_chat(user, "<span class='notice'>There's nothing in your backpack to take out.</span>")
return
var/obj/item/stored = equipped_backpack.contents[equipped_backpack.contents.len]
if(!stored || stored.on_found(src))
return
stored.attack_hand(src) // take out thing from backpack
return
switch(_key)
if("Shift")
if(!user.prefs.sprint_spacebar)
user.prefs.sprint_toggle ? default_toggle_sprint() : sprint_hotkey(TRUE) //Yes, this looks hacky. Yes, this works.
return
if("Space")
if(user.prefs.sprint_spacebar)
user.prefs.sprint_toggle ? default_toggle_sprint() : sprint_hotkey(TRUE)
return
return ..()
/mob/living/carbon/human/key_up(_key, client/user)
switch(_key)
if("Shift")
if(!user.prefs.sprint_spacebar && !user.prefs.sprint_toggle)
sprint_hotkey(FALSE)
return
if("Space")
if(user.prefs.sprint_spacebar && !user.prefs.sprint_toggle)
sprint_hotkey(FALSE)
return
return ..()
@@ -1,26 +0,0 @@
/mob/living/key_down(_key, client/user)
switch(_key)
if("B")
resist()
return
if("1")
if(possible_a_intents)
a_intent_change(INTENT_HELP)
return
if("2")
if(possible_a_intents)
a_intent_change(INTENT_DISARM)
return
if("3")
if(possible_a_intents)
a_intent_change(INTENT_GRAB)
return
if("4")
if(possible_a_intents)
a_intent_change(INTENT_HARM)
return
if ("V")
lay_down()
return
return ..()
-94
View File
@@ -1,94 +0,0 @@
// Technically the client argument is unncessary here since that SHOULD be src.client but let's not assume things
// All it takes is one badmin setting their focus to someone else's client to mess things up
// Or we can have NPC's send actual keypresses and detect that by seeing no client
/mob/key_down(_key, client/user)
switch(_key)
if("Delete", "H")
if(!pulling)
to_chat(src, "<span class='notice'>You are not pulling anything.</span>")
else
stop_pulling()
return
if("Insert", "G")
a_intent_change(INTENT_HOTKEY_RIGHT)
return
if("F")
a_intent_change(INTENT_HOTKEY_LEFT)
return
if("X", "Northeast") // Northeast is Page-up
swap_hand()
return
if("Y", "Z", "Southeast") // Southeast is Page-down
mode() // attack_self(). No idea who came up with "mode()"
return
if("Q", "Northwest") // Northwest is Home
var/obj/item/I = get_active_held_item()
if(!I)
to_chat(src, "<span class='warning'>You have nothing to drop in your hand!</span>")
else
dropItemToGround(I)
return
if("E")
quick_equip()
return
if("Alt")
toggle_move_intent()
return
//Bodypart selections
if("Numpad8")
user.body_toggle_head()
return
if("Numpad4")
user.body_r_arm()
return
if("Numpad5")
user.body_chest()
return
if("Numpad6")
user.body_l_arm()
return
if("Numpad1")
user.body_r_leg()
return
if("Numpad2")
user.body_groin()
return
if("Numpad3")
user.body_l_leg()
return
if(client.keys_held["Ctrl"])
switch(SSinput.movement_keys[_key])
if(NORTH)
if(client.keys_held["Shift"])
northshift()
else
northface()
return
if(SOUTH)
if(client.keys_held["Shift"])
southshift()
else
southface()
return
if(WEST)
if(client.keys_held["Shift"])
westshift()
else
westface()
return
if(EAST)
if(client.keys_held["Shift"])
eastshift()
else
eastface()
return
return ..()
/mob/key_up(_key, client/user)
switch(_key)
if("Alt")
toggle_move_intent()
return
return ..()
@@ -1,22 +0,0 @@
/mob/living/silicon/robot/key_down(_key, client/user)
switch(_key)
if("1", "2", "3")
toggle_module(text2num(_key))
return
if("4")
a_intent_change(INTENT_HOTKEY_LEFT)
return
if("Q")
uneq_active()
return
if("Shift")
sprint_hotkey(TRUE)
return
return ..()
/mob/living/silicon/robot/key_up(_key, client/user)
switch(_key)
if("Shift")
sprint_hotkey(FALSE)
return
return ..()
-3
View File
@@ -1,6 +1,3 @@
/mob
var/datum/focus //What receives our keyboard inputs. src by default
/mob/proc/set_focus(datum/new_focus)
if(focus == new_focus)
return
@@ -0,0 +1,20 @@
#define CATEGORY_CLIENT "CLIENT"
#define CATEGORY_EMOTE "EMOTE"
#define CATEGORY_ADMIN "ADMIN"
#define CATEGORY_XENO "XENO"
#define CATEGORY_CARBON "CARBON"
#define CATEGORY_HUMAN "HUMAN"
#define CATEGORY_ROBOT "ROBOT"
#define CATEGORY_MISC "MISC"
#define CATEGORY_MOVEMENT "MOVEMENT"
#define CATEGORY_TARGETING "TARGETING"
#define WEIGHT_HIGHEST 0
#define WEIGHT_ADMIN 10
#define WEIGHT_CLIENT 20
#define WEIGHT_ROBOT 30
#define WEIGHT_MOB 40
#define WEIGHT_LIVING 50
#define WEIGHT_DEAD 60
#define WEIGHT_EMOTE 70
#define WEIGHT_LOWEST 999
@@ -0,0 +1,24 @@
/datum/keybinding
var/list/hotkey_keys
var/list/classic_keys
var/name
var/full_name
var/description = ""
var/category = CATEGORY_MISC
var/weight = WEIGHT_LOWEST
var/keybind_signal
/datum/keybinding/New()
// Default keys to the master "hotkey_keys"
if(LAZYLEN(hotkey_keys) && !LAZYLEN(classic_keys))
classic_keys = hotkey_keys.Copy()
/datum/keybinding/proc/down(client/user)
return FALSE
/datum/keybinding/proc/up(client/user)
return FALSE
/datum/keybinding/proc/can_use(client/user)
return TRUE
+96
View File
@@ -0,0 +1,96 @@
/datum/keybinding/admin
category = CATEGORY_ADMIN
weight = WEIGHT_ADMIN
/datum/keybinding/admin/can_use(client/user)
return user.holder ? TRUE : FALSE
/datum/keybinding/admin/admin_say
hotkey_keys = list("F3")
name = "admin_say"
full_name = "Admin say"
description = "Talk with other admins."
/datum/keybinding/admin/admin_say/down(client/user)
user.get_admin_say()
return TRUE
/datum/keybinding/admin/admin_ghost
hotkey_keys = list("F5")
name = "admin_ghost"
full_name = "Aghost"
description = "Go ghost"
/datum/keybinding/admin/admin_ghost/down(client/user)
user.admin_ghost()
return TRUE
/datum/keybinding/admin/player_panel_new
hotkey_keys = list("F6")
name = "player_panel_new"
full_name = "Player Panel New"
description = "Opens up the new player panel"
/datum/keybinding/admin/player_panel_new/down(client/user)
user.holder.player_panel_new()
return TRUE
/datum/keybinding/admin/toggle_buildmode_self
hotkey_keys = list("F7")
name = "toggle_buildmode_self"
full_name = "Toggle Buildmode Self"
description = "Toggles buildmode"
/datum/keybinding/admin/toggle_buildmode_self/down(client/user)
user.togglebuildmodeself()
return TRUE
/datum/keybinding/admin/stealthmode
hotkey_keys = list("CtrlF8")
name = "stealth_mode"
full_name = "Stealth mode"
description = "Enters stealth mode"
/datum/keybinding/admin/stealthmode/down(client/user)
user.stealth()
return TRUE
/datum/keybinding/admin/invisimin
hotkey_keys = list("F8")
name = "invisimin"
full_name = "Admin invisibility"
description = "Toggles ghost-like invisibility (Don't abuse this)"
/datum/keybinding/admin/invisimin/down(client/user)
user.invisimin()
return TRUE
/datum/keybinding/admin/deadsay
hotkey_keys = list("F10")
name = "dsay"
full_name = "deadsay"
description = "Allows you to send a message to dead chat"
/datum/keybinding/admin/deadsay/down(client/user)
user.get_dead_say()
return TRUE
/datum/keybinding/admin/deadmin
hotkey_keys = list("Unbound")
name = "deadmin"
full_name = "Deadmin"
description = "Shed your admin powers"
/datum/keybinding/admin/deadmin/down(client/user)
user.deadmin()
return TRUE
/datum/keybinding/admin/readmin
hotkey_keys = list("Unbound")
name = "readmin"
full_name = "Readmin"
description = "Regain your admin powers"
/datum/keybinding/admin/readmin/down(client/user)
user.readmin()
return TRUE
@@ -0,0 +1,62 @@
/datum/keybinding/carbon
category = CATEGORY_CARBON
weight = WEIGHT_MOB
/datum/keybinding/carbon/can_use(client/user)
return iscarbon(user.mob)
/datum/keybinding/carbon/toggle_throw_mode
hotkey_keys = list("R", "Southwest") // END
name = "toggle_throw_mode"
full_name = "Toggle throw mode"
description = "Toggle throwing the current item or not."
category = CATEGORY_CARBON
/datum/keybinding/carbon/toggle_throw_mode/down(client/user)
var/mob/living/carbon/C = user.mob
C.toggle_throw_mode()
return TRUE
/datum/keybinding/carbon/select_help_intent
hotkey_keys = list("1")
name = "select_help_intent"
full_name = "Select help intent"
description = ""
category = CATEGORY_CARBON
/datum/keybinding/carbon/select_help_intent/down(client/user)
user.mob?.a_intent_change(INTENT_HELP)
return TRUE
/datum/keybinding/carbon/select_disarm_intent
hotkey_keys = list("2")
name = "select_disarm_intent"
full_name = "Select disarm intent"
description = ""
category = CATEGORY_CARBON
/datum/keybinding/carbon/select_disarm_intent/down(client/user)
user.mob?.a_intent_change(INTENT_DISARM)
return TRUE
/datum/keybinding/carbon/select_grab_intent
hotkey_keys = list("3")
name = "select_grab_intent"
full_name = "Select grab intent"
description = ""
category = CATEGORY_CARBON
/datum/keybinding/carbon/select_grab_intent/down(client/user)
user.mob?.a_intent_change(INTENT_GRAB)
return TRUE
/datum/keybinding/carbon/select_harm_intent
hotkey_keys = list("4")
name = "select_harm_intent"
full_name = "Select harm intent"
description = ""
category = CATEGORY_CARBON
/datum/keybinding/carbon/select_harm_intent/down(client/user)
user.mob?.a_intent_change(INTENT_HARM)
return TRUE
@@ -0,0 +1,33 @@
/datum/keybinding/client
category = CATEGORY_CLIENT
weight = WEIGHT_HIGHEST
/datum/keybinding/client/admin_help
hotkey_keys = list("F1")
name = "admin_help"
full_name = "Admin Help"
description = "Ask an admin for help."
/datum/keybinding/client/admin_help/down(client/user)
user.get_adminhelp()
return TRUE
/datum/keybinding/client/screenshot
hotkey_keys = list("F2")
name = "screenshot"
full_name = "Screenshot"
description = "Take a screenshot."
/datum/keybinding/client/screenshot/down(client/user)
winset(user, null, "command=.screenshot [!user.keys_held["shift"] ? "auto" : ""]")
return TRUE
/datum/keybinding/client/minimal_hud
hotkey_keys = list("F12")
name = "minimal_hud"
full_name = "Minimal HUD"
description = "Hide most HUD features"
/datum/keybinding/client/minimal_hud/down(client/user)
user.mob.button_pressed_F12()
return TRUE
+15
View File
@@ -0,0 +1,15 @@
/datum/keybinding/emote
category = CATEGORY_EMOTE
weight = WEIGHT_EMOTE
var/emote_key
/datum/keybinding/emote/proc/link_to_emote(datum/emote/faketype)
hotkey_keys = list("Unbound")
emote_key = initial(faketype.key)
name = initial(faketype.key)
full_name = capitalize(initial(faketype.key))
description = "Do the emote '*[emote_key]'"
/datum/keybinding/emote/down(client/user)
. = ..()
return user.mob.emote(emote_key, intentional=TRUE)
+39
View File
@@ -0,0 +1,39 @@
/datum/keybinding/human
category = CATEGORY_HUMAN
weight = WEIGHT_MOB
/datum/keybinding/human/can_use(client/user)
return ishuman(user.mob)
/datum/keybinding/human/quick_equip
hotkey_keys = list("E")
name = "quick_equip"
full_name = "Quick Equip"
description = "Quickly puts an item in the best slot available"
/datum/keybinding/human/quick_equip/down(client/user)
var/mob/living/carbon/human/H = user.mob
H.quick_equip()
return TRUE
/datum/keybinding/human/quick_equipbelt
hotkey_keys = list("ShiftE")
name = "quick_equipbelt"
full_name = "Quick equip belt"
description = "Put held thing in belt or take out most recent thing from belt"
/datum/keybinding/human/quick_equipbelt/down(client/user)
var/mob/living/carbon/human/H = user.mob
H.smart_equipbelt()
return TRUE
/datum/keybinding/human/bag_equip
hotkey_keys = list("ShiftB")
name = "bag_equip"
full_name = "Bag equip"
description = "Put held thing in backpack or take out most recent thing from backpack"
/datum/keybinding/human/bag_equip/down(client/user)
var/mob/living/carbon/human/H = user.mob
H.smart_equipbag()
return TRUE
@@ -0,0 +1,41 @@
/datum/keybinding/living
category = CATEGORY_HUMAN
weight = WEIGHT_MOB
/datum/keybinding/living/can_use(client/user)
return isliving(user.mob)
/datum/keybinding/living/resist
hotkey_keys = list("B")
name = "resist"
full_name = "Resist"
description = "Break free of your current state. Handcuffed? on fire? Resist!"
/datum/keybinding/living/resist/down(client/user)
var/mob/living/L = user.mob
L.resist()
return TRUE
/datum/keybinding/living/toggle_combat_mode
hotkey_keys = list("C")
name = "toggle_combat_mode"
full_name = "Toggle combat mode"
description = "Toggles whether or not you're in combat mode."
/datum/keybinding/living/toggle_combat_mode/can_use(client/user)
return iscarbon(user.mob) // for now, only carbons should be using combat mode, although all livings have combat mode implemented.
/datum/keybinding/living/toggle_combat_mode/down(client/user)
var/mob/living/carbon/C = user.mob
C.user_toggle_intentional_combat_mode()
return TRUE
/datum/keybinding/living/toggle_resting
hotkey_keys = list("V")
name = "toggle_resting"
full_name = "Toggle Resting"
description = "Toggles whether or not you are intentionally laying down."
/datum/keybinding/living/toggle_resting/down(client/user)
var/mob/living/L = user.mob
L.lay_down()
+123
View File
@@ -0,0 +1,123 @@
/datum/keybinding/mob
category = CATEGORY_HUMAN
weight = WEIGHT_MOB
/datum/keybinding/mob/stop_pulling
hotkey_keys = list("H", "Delete")
name = "stop_pulling"
full_name = "Stop pulling"
description = ""
/datum/keybinding/mob/stop_pulling/down(client/user)
var/mob/M = user.mob
if(!M.pulling)
to_chat(user, "<span class='notice'>You are not pulling anything.</span>")
else
M.stop_pulling()
return TRUE
/datum/keybinding/mob/cycle_intent_right
hotkey_keys = list("Northwest", "F") // HOME
name = "cycle_intent_right"
full_name = "Cycle Action Intent Right"
description = ""
/datum/keybinding/mob/cycle_intent_right/down(client/user)
var/mob/M = user.mob
M.a_intent_change(INTENT_HOTKEY_RIGHT)
return TRUE
/datum/keybinding/mob/cycle_intent_left
hotkey_keys = list("Insert", "G")
name = "cycle_intent_left"
full_name = "Cycle Action Intent Left"
description = ""
/datum/keybinding/mob/cycle_intent_left/down(client/user)
var/mob/M = user.mob
M.a_intent_change(INTENT_HOTKEY_LEFT)
return TRUE
/datum/keybinding/mob/swap_hands
hotkey_keys = list("X", "Northeast") // PAGEUP
name = "swap_hands"
full_name = "Swap hands"
description = ""
/datum/keybinding/mob/swap_hands/down(client/user)
var/mob/M = user.mob
M.swap_hand()
return TRUE
/datum/keybinding/mob/activate_inhand
hotkey_keys = list("Z", "Southeast") // PAGEDOWN
name = "activate_inhand"
full_name = "Activate in-hand"
description = "Uses whatever item you have inhand"
/datum/keybinding/mob/activate_inhand/down(client/user)
var/mob/M = user.mob
M.mode()
return TRUE
/datum/keybinding/mob/drop_item
hotkey_keys = list("Q")
name = "drop_item"
full_name = "Drop Item"
description = ""
/datum/keybinding/mob/drop_item/down(client/user)
if(iscyborg(user.mob)) //cyborgs can't drop items
return FALSE
var/mob/M = user.mob
var/obj/item/I = M.get_active_held_item()
if(!I)
to_chat(user, "<span class='warning'>You have nothing to drop in your hand!</span>")
else
user.mob.dropItemToGround(I)
return TRUE
/datum/keybinding/mob/say_with_indicator
hotkey_keys = list("CtrlT")
classic_keys = list()
name = "say_with_indicator"
full_name = "Say with Typing Indicator"
/datum/keybinding/mob/say_with_indicator/down(client/user)
var/mob/M = user.mob
M.say_typing_indicator()
return TRUE
/datum/keybinding/mob/me_with_indicator
hotkey_keys = list("CtrlM")
classic_keys = list()
name = "me_with_indicator"
full_name = "Me (emote) with Typing Indicator"
/datum/keybinding/mob/me_with_indicator/down(client/user)
var/mob/M = user.mob
M.me_typing_indicator()
return TRUE
/datum/keybinding/living/subtle
hotkey_keys = list("5")
classic_keys = list()
name = "subtle_emote"
full_name = "Subtle Emote"
/datum/keybinding/living/subtle/down(client/user)
var/mob/living/L = user.mob
L.subtle_keybind()
return TRUE
/datum/keybinding/mob/whisper
hotkey_keys = list("Y")
classic_keys = list()
name = "whisper"
full_name = "Whisper"
/datum/keybinding/mob/whisper/down(client/user)
var/mob/M = user.mob
M.whisper_keybind()
return TRUE
@@ -0,0 +1,175 @@
/datum/keybinding/movement
category = CATEGORY_MOVEMENT
weight = WEIGHT_HIGHEST
/datum/keybinding/movement/north
hotkey_keys = list("W", "North")
name = "North"
full_name = "Move North"
description = "Moves your character north"
/datum/keybinding/movement/south
hotkey_keys = list("S", "South")
name = "South"
full_name = "Move South"
description = "Moves your character south"
/datum/keybinding/movement/west
hotkey_keys = list("A", "West")
name = "West"
full_name = "Move West"
description = "Moves your character left"
/datum/keybinding/movement/east
hotkey_keys = list("D", "East")
name = "East"
full_name = "Move East"
description = "Moves your character east"
/datum/keybinding/mob/face_north
hotkey_keys = list("CtrlW", "CtrlNorth")
name = "face_north"
full_name = "Face North"
description = ""
category = CATEGORY_MOVEMENT
/datum/keybinding/mob/face_north/down(client/user)
var/mob/M = user.mob
M.northface()
return TRUE
/datum/keybinding/mob/face_east
hotkey_keys = list("CtrlD", "CtrlEast")
name = "face_east"
full_name = "Face East"
description = ""
category = CATEGORY_MOVEMENT
/datum/keybinding/mob/face_east/down(client/user)
var/mob/M = user.mob
M.eastface()
return TRUE
/datum/keybinding/mob/face_south
hotkey_keys = list("CtrlS", "CtrlSouth")
name = "face_south"
full_name = "Face South"
description = ""
category = CATEGORY_MOVEMENT
/datum/keybinding/mob/face_south/down(client/user)
var/mob/M = user.mob
M.southface()
return TRUE
/datum/keybinding/mob/shift_north
hotkey_keys = list("CtrlShiftW", "CtrlShiftNorth")
name = "pixel_shift_north"
full_name = "Pixel Shift North"
description = ""
category = CATEGORY_MOVEMENT
/datum/keybinding/mob/shift_north/down(client/user)
var/mob/M = user.mob
M.northshift()
return TRUE
/datum/keybinding/mob/shift_east
hotkey_keys = list("CtrlShiftD", "CtrlShiftEast")
name = "pixel_shift_east"
full_name = "Pixel Shift East"
description = ""
category = CATEGORY_MOVEMENT
/datum/keybinding/mob/shift_east/down(client/user)
var/mob/M = user.mob
M.eastshift()
return TRUE
/datum/keybinding/mob/shift_south
hotkey_keys = list("CtrlShiftS", "CtrlShiftSouth")
name = "pixel_shift_south"
full_name = "Pixel Shift South"
description = ""
category = CATEGORY_MOVEMENT
/datum/keybinding/mob/shift_south/down(client/user)
var/mob/M = user.mob
M.southshift()
return TRUE
/datum/keybinding/mob/shift_west
hotkey_keys = list("CtrlShiftA", "CtrlShiftWest")
name = "pixel_shift_west"
full_name = "Pixel Shift West"
description = ""
category = CATEGORY_MOVEMENT
/datum/keybinding/mob/shift_west/down(client/user)
var/mob/M = user.mob
M.westshift()
return TRUE
/datum/keybinding/living/hold_sprint
hotkey_keys = list("Shift")
name = "hold_sprint"
full_name = "Sprint (hold down)"
description = "Hold down to sprint"
category = CATEGORY_MOVEMENT
/datum/keybinding/living/hold_sprint/can_use(client/user)
return ishuman(user.mob) || iscyborg(user.mob)
/datum/keybinding/living/hold_sprint/down(client/user)
var/mob/living/L = user.mob
L.sprint_hotkey(TRUE)
return TRUE
/datum/keybinding/living/hold_sprint/up(client/user)
var/mob/living/L = user.mob
L.sprint_hotkey(FALSE)
return TRUE
/datum/keybinding/living/toggle_sprint
hotkey_keys = list()
name = "toggle_sprint"
full_name = "Sprint (toggle)"
description = "Press to toggle sprint"
category = CATEGORY_MOVEMENT
/datum/keybinding/living/toggle_sprint/can_use(client/user)
return ishuman(user.mob) || iscyborg(user.mob)
/datum/keybinding/living/toggle_sprint/down(client/user)
var/mob/living/L = user.mob
L.default_toggle_sprint(TRUE)
return TRUE
/datum/keybinding/mob/toggle_move_intent
hotkey_keys = list("Alt")
name = "toggle_move_intent"
full_name = "Hold to toggle move intent"
description = "Held down to cycle to the other move intent, release to cycle back"
category = CATEGORY_MOVEMENT
/datum/keybinding/mob/toggle_move_intent/down(client/user)
var/mob/M = user.mob
M.toggle_move_intent()
return TRUE
/datum/keybinding/mob/toggle_move_intent/up(client/user)
var/mob/M = user.mob
M.toggle_move_intent()
return TRUE
/datum/keybinding/mob/toggle_move_intent_alternative
hotkey_keys = list("Unbound")
name = "toggle_move_intent_alt"
full_name = "press to cycle move intent"
description = "Pressing this cycle to the opposite move intent, does not cycle back"
category = CATEGORY_MOVEMENT
/datum/keybinding/mob/toggle_move_intent_alternative/down(client/user)
var/mob/M = user.mob
M.toggle_move_intent()
return TRUE
+61
View File
@@ -0,0 +1,61 @@
/datum/keybinding/robot
category = CATEGORY_ROBOT
weight = WEIGHT_ROBOT
/datum/keybinding/robot/can_use(client/user)
return iscyborg(user.mob)
/datum/keybinding/robot/moduleone
hotkey_keys = list("1")
name = "module_one"
full_name = "Toggle module 1"
description = "Equips or unequips the first module"
/datum/keybinding/robot/moduleone/down(client/user)
var/mob/living/silicon/robot/R = user.mob
R.toggle_module(1)
return TRUE
/datum/keybinding/robot/moduletwo
hotkey_keys = list("2")
name = "module_two"
full_name = "Toggle module 2"
description = "Equips or unequips the second module"
/datum/keybinding/robot/moduletwo/down(client/user)
var/mob/living/silicon/robot/R = user.mob
R.toggle_module(2)
return TRUE
/datum/keybinding/robot/modulethree
hotkey_keys = list("3")
name = "module_three"
full_name = "Toggle module 3"
description = "Equips or unequips the third module"
/datum/keybinding/robot/modulethree/down(client/user)
var/mob/living/silicon/robot/R = user.mob
R.toggle_module(3)
return TRUE
/datum/keybinding/robot/intent_cycle
hotkey_keys = list("4")
name = "cycle_intent"
full_name = "Cycle intent left"
description = "Cycles the intent left"
/datum/keybinding/robot/intent_cycle/down(client/user)
var/mob/living/silicon/robot/R = user.mob
R.a_intent_change(INTENT_HOTKEY_LEFT)
return TRUE
/datum/keybinding/robot/unequip_module
hotkey_keys = list("Q")
name = "unequip_module"
full_name = "Unequip module"
description = "Unequips the active module"
/datum/keybinding/robot/unequip_module/down(client/user)
var/mob/living/silicon/robot/R = user.mob
R.uneq_active()
return TRUE
@@ -0,0 +1,76 @@
/datum/keybinding/mob/target_head_cycle
hotkey_keys = list("Numpad8")
name = "target_head_cycle"
full_name = "Target: Cycle head"
description = ""
category = CATEGORY_TARGETING
/datum/keybinding/mob/target_head_cycle/down(client/user)
user.body_toggle_head()
return TRUE
/datum/keybinding/mob/target_r_arm
hotkey_keys = list("Numpad4")
name = "target_r_arm"
full_name = "Target: right arm"
description = ""
category = CATEGORY_TARGETING
/datum/keybinding/mob/target_r_arm/down(client/user)
user.body_r_arm()
return TRUE
/datum/keybinding/mob/target_body_chest
hotkey_keys = list("Numpad5")
name = "target_body_chest"
full_name = "Target: Body"
description = ""
category = CATEGORY_TARGETING
/datum/keybinding/mob/target_body_chest/down(client/user)
user.body_chest()
return TRUE
/datum/keybinding/mob/target_left_arm
hotkey_keys = list("Numpad6")
name = "target_left_arm"
full_name = "Target: left arm"
description = ""
category = CATEGORY_TARGETING
/datum/keybinding/mob/target_left_arm/down(client/user)
user.body_l_arm()
return TRUE
/datum/keybinding/mob/target_right_leg
hotkey_keys = list("Numpad1")
name = "target_right_leg"
full_name = "Target: Right leg"
description = ""
category = CATEGORY_TARGETING
/datum/keybinding/mob/target_right_leg/down(client/user)
user.body_r_leg()
return TRUE
/datum/keybinding/mob/target_body_groin
hotkey_keys = list("Numpad2")
name = "target_body_groin"
full_name = "Target: Groin"
description = ""
category = CATEGORY_TARGETING
/datum/keybinding/mob/target_body_groin/down(client/user)
user.body_groin()
return TRUE
/datum/keybinding/mob/target_left_leg
hotkey_keys = list("Numpad3")
name = "target_left_leg"
full_name = "Target: left leg"
description = ""
category = CATEGORY_TARGETING
/datum/keybinding/mob/target_left_leg/down(client/user)
user.body_l_leg()
return TRUE
+26 -34
View File
@@ -1,55 +1,47 @@
/client
/// Keys currently held
var/list/keys_held = list()
/// 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
/datum/proc/key_down(key, client/user) // Called when a key is pressed down initially
return
/datum/proc/key_up(key, client/user) // Called when a key is released
return
/datum/proc/keyLoop(client/user) // Called once every frame
set waitfor = FALSE
return
// removes all the existing macros
/client/proc/erase_all_macros()
var/list/macro_sets = params2list(winget(src, null, "macros"))
var/erase_output = ""
for(var/i in 1 to macro_sets.len)
var/setname = macro_sets[i]
var/list/macro_set = params2list(winget(src, "[setname].*", "command")) // The third arg doesnt matter here as we're just removing them all
for(var/k in 1 to macro_set.len)
var/list/split_name = splittext(macro_set[k], ".")
var/macro_name = "[split_name[1]].[split_name[2]]" // [3] is "command"
erase_output = "[erase_output];[macro_name].parent=null"
var/list/macro_set = params2list(winget(src, "default.*", "command")) // The third arg doesnt matter here as we're just removing them all
for(var/k in 1 to length(macro_set))
var/list/split_name = splittext(macro_set[k], ".")
var/macro_name = "[split_name[1]].[split_name[2]]" // [3] is "command"
erase_output = "[erase_output];[macro_name].parent=null"
winset(src, null, erase_output)
/client/proc/set_macros()
/client/proc/apply_macro_set(name, list/macroset)
ASSERT(name)
ASSERT(islist(macroset))
winclone(src, "default", name)
for(var/i in 1 to length(macroset))
var/key = macroset[i]
var/command = macroset[key]
winset(src, "[name]-[REF(key)]", "parent=[name];name=[key];command=[command]")
/client/proc/set_macros(datum/preferences/prefs_override = prefs)
set waitfor = FALSE
keys_held.Cut()
erase_all_macros()
var/list/macro_sets = SSinput.macro_sets
for(var/i in 1 to macro_sets.len)
var/setname = macro_sets[i]
if(setname != "default")
winclone(src, "default", setname)
var/list/macro_set = macro_sets[setname]
for(var/k in 1 to macro_set.len)
var/key = macro_set[k]
var/command = macro_set[key]
winset(src, "[setname]-[REF(key)]", "parent=[setname];name=[key];command=[command]")
apply_macro_set(SKIN_MACROSET_HOTKEYS, SSinput.macroset_hotkey)
apply_macro_set(SKIN_MACROSET_CLASSIC_HOTKEYS, SSinput.macroset_classic_hotkey)
apply_macro_set(SKIN_MACROSET_CLASSIC_INPUT, SSinput.macroset_classic_input)
if(prefs.hotkeys)
winset(src, null, "input.focus=true input.background-color=[COLOR_INPUT_ENABLED] mainwindow.macro=default")
set_hotkeys_preference()
/client/proc/set_hotkeys_preference(datum/preferences/prefs_override = prefs)
if(prefs_override.hotkeys)
winset(src, null, "map.focus=true input.background-color=[COLOR_INPUT_DISABLED] mainwindow.macro=[SKIN_MACROSET_HOTKEYS]")
else
winset(src, null, "input.focus=true input.background-color=[COLOR_INPUT_ENABLED] mainwindow.macro=old_default")
winset(src, null, "input.focus=true input.background-color=[COLOR_INPUT_ENABLED] mainwindow.macro=[SKIN_MACROSET_CLASSIC_INPUT]")
@@ -277,3 +277,65 @@
qdel(slot)
for(var/obj/item/I in held_items)
qdel(I)
/mob/living/carbon/human/proc/smart_equipbag() // take most recent item out of bag or place held item in bag
if(incapacitated())
return
var/obj/item/thing = get_active_held_item()
var/obj/item/equipped_back = get_item_by_slot(SLOT_BACK)
if(!equipped_back) // We also let you equip a backpack like this
if(!thing)
to_chat(src, "<span class='warning'>You have no backpack to take something out of!</span>")
return
if(equip_to_slot_if_possible(thing, ITEM_SLOT_BACK))
update_inv_hands()
return
if(!SEND_SIGNAL(equipped_back, COMSIG_CONTAINS_STORAGE)) // not a storage item
if(!thing)
equipped_back.attack_hand(src)
else
to_chat(src, "<span class='warning'>You can't fit anything in!</span>")
return
if(thing) // put thing in backpack
if(!SEND_SIGNAL(equipped_back, COMSIG_TRY_STORAGE_INSERT, thing, src))
to_chat(src, "<span class='warning'>You can't fit anything in!</span>")
return
if(!equipped_back.contents.len) // nothing to take out
to_chat(src, "<span class='warning'>There's nothing in your backpack to take out!</span>")
return
var/obj/item/stored = equipped_back.contents[equipped_back.contents.len]
if(!stored || stored.on_found(src))
return
stored.attack_hand(src) // take out thing from backpack
return
/mob/living/carbon/human/proc/smart_equipbelt() // put held thing in belt or take most recent item out of belt
if(incapacitated())
return
var/obj/item/thing = get_active_held_item()
var/obj/item/equipped_belt = get_item_by_slot(SLOT_BELT)
if(!equipped_belt) // We also let you equip a belt like this
if(!thing)
to_chat(src, "<span class='warning'>You have no belt to take something out of!</span>")
return
if(equip_to_slot_if_possible(thing, ITEM_SLOT_BELT))
update_inv_hands()
return
if(!SEND_SIGNAL(equipped_belt, COMSIG_CONTAINS_STORAGE)) // not a storage item
if(!thing)
equipped_belt.attack_hand(src)
else
to_chat(src, "<span class='warning'>You can't fit anything in!</span>")
return
if(thing) // put thing in belt
if(!SEND_SIGNAL(equipped_belt, COMSIG_TRY_STORAGE_INSERT, thing, src))
to_chat(src, "<span class='warning'>You can't fit anything in!</span>")
return
if(!equipped_belt.contents.len) // nothing to take out
to_chat(src, "<span class='warning'>There's nothing in your belt to take out!</span>")
return
var/obj/item/stored = equipped_belt.contents[equipped_belt.contents.len]
if(!stored || stored.on_found(src))
return
stored.attack_hand(src) // take out thing from belt
return
+3
View File
@@ -12,6 +12,9 @@
vis_flags = VIS_INHERIT_PLANE //when this be added to vis_contents of something it inherit something.plane, important for visualisation of mob in openspace.
/// What receives our keyboard input. src by default.
var/datum/focus
var/lighting_alpha = LIGHTING_PLANE_ALPHA_VISIBLE
var/datum/mind/mind
var/list/datum/action/actions = list()
+6
View File
@@ -57,6 +57,12 @@
else
return ..()
/mob/proc/whisper_keybind()
var/message = input(src, "", "whisper") as text|null
if(!length(message))
return
return whisper_verb(message)
/mob/verb/whisper_verb(message as text)
set name = "Whisper"
set category = "IC"
+6
View File
@@ -129,6 +129,12 @@ proc/get_top_level_mob(var/mob/S)
user.visible_message(message=message,self_message=message,vision_distance=1, ignored_mobs = GLOB.dead_mob_list)
///////////////// VERB CODE
/mob/living/proc/subtle_keybind()
var/message = input(src, "", "subtle") as text|null
if(!length(message))
return
return subtle(message)
/mob/living/verb/subtle()
set name = "Subtle"
set category = "IC"