modules - E to L
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
/datum/admins/key_down(_key, client/user)
|
||||
switch(_key)
|
||||
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
|
||||
..()
|
||||
@@ -0,0 +1,18 @@
|
||||
/mob/living/carbon/key_down(_key, client/user)
|
||||
switch(_key)
|
||||
if("R", "Southwest") // Southwest is End
|
||||
toggle_throw_mode()
|
||||
return
|
||||
if("1")
|
||||
a_intent_change("help")
|
||||
return
|
||||
if("2")
|
||||
a_intent_change("disarm")
|
||||
return
|
||||
if("3")
|
||||
a_intent_change("grab")
|
||||
return
|
||||
if("4")
|
||||
a_intent_change("harm")
|
||||
return
|
||||
return ..()
|
||||
@@ -0,0 +1,50 @@
|
||||
// Clients aren't datums so we have to define these procs indpendently.
|
||||
// These verbs are called for all key press and release events
|
||||
/client/verb/keyDown(_key as text)
|
||||
set instant = TRUE
|
||||
set hidden = TRUE
|
||||
|
||||
keys_held[_key] = world.time
|
||||
var/movement = GLOB.movement_keys[_key]
|
||||
if(!(next_move_dir_sub & movement))
|
||||
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.
|
||||
|
||||
switch(_key)
|
||||
if("F1")
|
||||
if(keys_held["Ctrl"] && keys_held["Shift"]) // Is this command ever used?
|
||||
winset(src, null, "command=.options")
|
||||
else
|
||||
adminhelp()
|
||||
if("F2") // Screenshot. Hold shift to choose a name and location to save in
|
||||
winset(src, null, "command=.screenshot [!keys_held["shift"] ? "auto" : ""]")
|
||||
if("F12") // Toggles minimal HUD
|
||||
mob.button_pressed_F12()
|
||||
|
||||
if(holder)
|
||||
holder.key_down(_key, src)
|
||||
if(mob.focus)
|
||||
mob.focus.key_down(_key, src)
|
||||
|
||||
/client/verb/keyUp(_key as text)
|
||||
set instant = TRUE
|
||||
set hidden = TRUE
|
||||
|
||||
keys_held -= _key
|
||||
var/movement = GLOB.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)
|
||||
|
||||
// Called every game tick
|
||||
/client/keyLoop()
|
||||
if(holder)
|
||||
holder.keyLoop(src)
|
||||
if(mob.focus)
|
||||
mob.focus.keyLoop(src)
|
||||
@@ -0,0 +1,7 @@
|
||||
/mob/living/key_down(_key, client/user)
|
||||
switch(_key)
|
||||
if("B")
|
||||
resist()
|
||||
return
|
||||
|
||||
return ..()
|
||||
@@ -0,0 +1,79 @@
|
||||
// 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("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(GLOB.movement_keys[_key])
|
||||
if(NORTH)
|
||||
northface()
|
||||
return
|
||||
if(SOUTH)
|
||||
southface()
|
||||
return
|
||||
if(WEST)
|
||||
westface()
|
||||
return
|
||||
if(EAST)
|
||||
eastface()
|
||||
return
|
||||
return ..()
|
||||
|
||||
/mob/key_up(_key, client/user)
|
||||
switch(_key)
|
||||
if("Alt")
|
||||
toggle_move_intent()
|
||||
return
|
||||
return ..()
|
||||
@@ -0,0 +1,12 @@
|
||||
/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
|
||||
return ..()
|
||||
@@ -0,0 +1,20 @@
|
||||
/datum
|
||||
var/list/focusers //Only initialized when needed. Contains a list of mobs focusing on this.
|
||||
|
||||
/mob
|
||||
var/datum/focus //What receives our keyboard inputs. src by default
|
||||
|
||||
/mob/proc/set_focus(datum/new_focus)
|
||||
if(focus == new_focus)
|
||||
return
|
||||
|
||||
if(new_focus)
|
||||
if(!new_focus.focusers) //Set up the new focus
|
||||
new_focus.focusers = list()
|
||||
new_focus.focusers += src
|
||||
|
||||
if(focus)
|
||||
focus.focusers -= src //Tell the old focus we're done with it
|
||||
|
||||
focus = new_focus
|
||||
reset_perspective(focus) //Maybe this should be done manually? You figure it out, reader
|
||||
@@ -0,0 +1,40 @@
|
||||
# In-code keypress handling system
|
||||
|
||||
This whole system is heavily based off of forum_account's keyboard library.
|
||||
Thanks to forum_account for saving the day, the library can be found [here](http://www.byond.com/developer/Forum_account/Keyboard)!
|
||||
|
||||
.dmf macros have some very serious shortcomings. For example, they do not allow reusing parts
|
||||
of one macro in another, so giving cyborgs their own shortcuts to swap active module couldn't
|
||||
inherit the movement that all mobs should have anyways. The webclient only supports one macro,
|
||||
so having more than one was problematic. Additionally each keybind has to call an actual
|
||||
verb, which meant a lot of hidden verbs that just call one other proc. Also our existing
|
||||
macro was really bad and tied unrelated behavior into `Northeast()`, `Southeast()`, `Northwest()`,
|
||||
and `Southwest()`.
|
||||
|
||||
The basic premise of this system is to not screw with .dmf macro setup at all and handle
|
||||
pressing those keys in the code instead. We have every key call `client.keyDown()`
|
||||
or `client.keyUp()` with the pressed key as an argument. Certain keys get processed
|
||||
directly by the client because they should be doable at any time, then we call
|
||||
`keyDown()` or `keyUp()` on the client's holder and the client's mob's focus.
|
||||
By default `mob.focus` is the mob itself, but you can set it to any datum to give control of a
|
||||
client's keypresses to another object. This would be a good way to handle a menu or driving
|
||||
a mech. You can also set it to null to disregard input from a certain user.
|
||||
|
||||
Movement is handled by having each client call `client.keyLoop()` every game tick.
|
||||
As above, this calls holder and `focus.keyLoop()`. `atom/movable/keyLoop()` handles movement
|
||||
Try to keep the calculations in this proc light. It runs every tick for every client after all!
|
||||
|
||||
You can also tell which keys are being held down now. Each client a list of keys pressed called
|
||||
`keys_held`. Each entry is a key as a text string associated with the world.time when it was
|
||||
pressed.
|
||||
|
||||
No client-set keybindings at this time, but it shouldn't be too hard if someone wants.
|
||||
|
||||
Notes about certain keys
|
||||
`Tab` has client-sided behavior but acts normally
|
||||
`T`, `O`, and `M` move focus to the input when pressed. This fires the keyUp macro right away.
|
||||
`\` needs to be escaped in the dmf so any usage is `\\`
|
||||
|
||||
You cannot `TICK_CHECK` or check `world.tick_usage` inside of procs called by key down and up
|
||||
events. They happen outside of a byond tick and have no meaning there. Key looping
|
||||
works correctly since it's part of a subsystem, not direct input.
|
||||
@@ -0,0 +1,55 @@
|
||||
/client
|
||||
var/list/keys_held = list() // A list of any keys held currently
|
||||
// These next two vars are to apply movement for keypresses and releases made while move delayed.
|
||||
// Because discarding that input makes the game less responsive.
|
||||
var/next_move_dir_add // On next move, add this dir to the move that would otherwise be done
|
||||
var/next_move_dir_sub // On next move, subtract this dir from the move that would otherwise be done
|
||||
|
||||
// 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
|
||||
return
|
||||
|
||||
// Keys used for movement
|
||||
GLOBAL_LIST_INIT(movement_keys, list(
|
||||
"W" = NORTH, "A" = WEST, "S" = SOUTH, "D" = EAST, // WASD
|
||||
"North" = NORTH, "West" = WEST, "South" = SOUTH, "East" = EAST, // Arrow keys & Numpad
|
||||
))
|
||||
|
||||
// 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"
|
||||
winset(src, null, erase_output)
|
||||
|
||||
/client/proc/set_macros()
|
||||
set waitfor = FALSE
|
||||
|
||||
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]")
|
||||
|
||||
if(prefs.hotkeys)
|
||||
winset(src, null, "input.focus=true input.background-color=[COLOR_INPUT_ENABLED] mainwindow.macro=default")
|
||||
else
|
||||
winset(src, null, "input.focus=true input.background-color=[COLOR_INPUT_ENABLED] mainwindow.macro=old_default")
|
||||
Reference in New Issue
Block a user