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
-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"