modules - E to L

This commit is contained in:
deathride58
2018-01-04 00:53:38 -05:00
parent 0dbc2241ea
commit 5dc3f29ad4
83 changed files with 1377 additions and 641 deletions
@@ -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 ..()
+79
View File
@@ -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 ..()
+20
View File
@@ -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
+40
View File
@@ -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.
+55
View File
@@ -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")