Skip to content

Commit 9164713

Browse files
AbsolucyGhommienikothedudesan7890MrsTonedOne
authored
Some misc upstream fixes (mostly 516 and movement related) (#5945)
## About The Pull Request ports the following PRs from tg: - tgstation/tgstation#75029 - tgstation/tgstation#75103 - tgstation/tgstation#79322 - tgstation/tgstation#81464 - tgstation/tgstation#81505 - tgstation/tgstation#81869 - tgstation/tgstation#86692 - tgstation/tgstation#89956 - tgstation/tgstation#90039 - ~~tgstation/tgstation#90057 ## Why It's Good For The Game ## Changelog :cl: code: (nikothedude) TGUI input datums can now accept custom ui_states. fix: (Ghommie) Fixed the tgui text input trimming the last character of the input if it hits the maximum length. fix: (itsmeow) Fixed TGUI assets and icons sometimes not showing up until you refreshed the page on 516 clients. fix: (Aylong) Fixed TGUI text inputs that allows only 1 symbol instead infinity. /:cl: --------- Co-authored-by: Ghom <[email protected]> Co-authored-by: nikothedude <[email protected]> Co-authored-by: san7890 <[email protected]> Co-authored-by: Kyle Spier-Swenson <[email protected]> Co-authored-by: Aylong <[email protected]> Co-authored-by: LemonInTheDark <[email protected]>
1 parent 1709bca commit 9164713

File tree

15 files changed

+133
-56
lines changed

15 files changed

+133
-56
lines changed

code/__DEFINES/text.dm

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@
5858
/// Removes everything enclose in < and > inclusive of the bracket, and limits the length of the message.
5959
#define STRIP_HTML_FULL(text, limit) (GLOB.html_tags.Replace(copytext(text, 1, limit), ""))
6060

61+
/**
62+
* stuff like `copytext(input, length(input))` will trim the last character of the input,
63+
* because DM does it so it copies until the char BEFORE the `end` arg, so we need to bump `end` by 1 in these cases.
64+
*/
65+
#define PREVENT_CHARACTER_TRIM_LOSS(integer) (integer + 1)
66+
6167
/// Folder directory for strings
6268
#define STRING_DIRECTORY "strings"
6369

code/datums/components/jetpack.dm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@
114114
return
115115
if(user.throwing)//You don't must use jet if you thrown
116116
return
117-
if(length(user.client.keys_held & user.client.movement_keys))//You use jet when press keys. yes.
117+
if(user.client.intended_direction)//You use jet when press keys. yes.
118118
thrust()
119119

120120
/datum/component/jetpack/proc/pre_move_react(mob/user)

code/datums/components/scope.dm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
stop_zooming(user_mob)
3636
return
3737
tracker.calculate_params()
38-
if(!length(user_client.keys_held & user_client.movement_keys))
38+
if(!user_client.intended_direction)
3939
user_mob.face_atom(tracker.given_turf)
4040
animate(user_client, world.tick_lag, pixel_x = tracker.given_x, pixel_y = tracker.given_y)
4141

code/modules/client/client_defines.dm

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,9 @@
248248
var/list/keys_held = list()
249249
/// A buffer for combinations such of modifiers + keys (ex: CtrlD, AltE, ShiftT). Format: `"key"` -> `"combo"` (ex: `"D"` -> `"CtrlD"`)
250250
var/list/key_combos_held = list()
251+
/// The direction we WANT to move, based off our keybinds
252+
/// Will be udpated to be the actual direction later on
253+
var/intended_direction = NONE
251254
/*
252255
** These next two vars are to apply movement for keypresses and releases made while move delayed.
253256
** Because discarding that input makes the game less responsive.

code/modules/client/client_procs.dm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1176,6 +1176,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
11761176
winset(src, "default-[REF(key)]", "parent=default;name=[key];command=[msay]")
11771177
else
11781178
winset(src, "default-[REF(key)]", "parent=default;name=[key];command=")
1179+
calculate_move_dir()
11791180

11801181
/client/proc/change_view(new_size)
11811182
if (isnull(new_size))

code/modules/keybindings/bindings_atom.dm

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,43 @@
22
// Only way to do that is to tie the behavior into the focus's keyLoop().
33

44
/atom/movable/keyLoop(client/user)
5-
var/movement_dir = NONE
6-
for(var/_key in user?.keys_held)
7-
movement_dir = movement_dir | user.movement_keys[_key]
8-
if(user?.next_move_dir_add)
9-
movement_dir |= user.next_move_dir_add
10-
if(user?.next_move_dir_sub)
5+
// Clients don't go null randomly. They do go null unexpectedly though, when they're poked in particular ways
6+
// keyLoop is called by a for loop over mobs. We're guarenteed that all the mobs have clients at the START
7+
// But the move of one mob might poke the client of another, so we do this
8+
if(!user)
9+
return FALSE
10+
var/movement_dir = user.intended_direction | user.next_move_dir_add
11+
// If we're not movin anywhere, we aren't movin anywhere
12+
// Safe because nothing adds to movement_dir after this moment
13+
if(!movement_dir)
14+
// No input == our removal would have done nothing
15+
// So we can safely forget about it
16+
user.next_move_dir_sub = NONE
17+
return FALSE
18+
19+
if(user.next_move_dir_sub)
1120
movement_dir &= ~user.next_move_dir_sub
1221
// Sanity checks in case you hold left and right and up to make sure you only go up
1322
if((movement_dir & NORTH) && (movement_dir & SOUTH))
1423
movement_dir &= ~(NORTH|SOUTH)
1524
if((movement_dir & EAST) && (movement_dir & WEST))
1625
movement_dir &= ~(EAST|WEST)
1726

18-
if(user && movement_dir) //If we're not moving, don't compensate, as byond will auto-fill dir otherwise
27+
if(user.dir != NORTH && movement_dir) //If we're not moving, don't compensate, as byond will auto-fill dir otherwise
1928
movement_dir = turn(movement_dir, -dir2angle(user.dir)) //By doing this we ensure that our input direction is offset by the client (camera) direction
2029

2130
//turn without moving while using the movement lock key, unless something wants to ignore it and move anyway
22-
if(user?.movement_locked && !(SEND_SIGNAL(src, COMSIG_MOVABLE_KEYBIND_FACE_DIR, movement_dir) & COMSIG_IGNORE_MOVEMENT_LOCK))
31+
if(user.movement_locked && !(SEND_SIGNAL(src, COMSIG_MOVABLE_KEYBIND_FACE_DIR, movement_dir) & COMSIG_IGNORE_MOVEMENT_LOCK))
2332
keybind_face_direction(movement_dir)
24-
else
25-
user?.Move(get_step(src, movement_dir), movement_dir)
33+
// Null check cause of the signal above
34+
else if(user)
35+
user.Move(get_step(src, movement_dir), movement_dir)
2636
return !!movement_dir //true if there was actually any player input
2737

2838
return FALSE
39+
40+
/client/proc/calculate_move_dir()
41+
var/movement_dir = NONE
42+
for(var/_key in keys_held)
43+
movement_dir |= movement_keys[_key]
44+
intended_direction = movement_dir

code/modules/keybindings/bindings_client.dm

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,10 @@
4747

4848
//the time a key was pressed isn't actually used anywhere (as of 2019-9-10) but this allows easier access usage/checking
4949
keys_held[_key] = world.time
50-
if(!movement_locked)
51-
var/movement = movement_keys[_key]
52-
if(!(next_move_dir_sub & movement))
50+
var/movement = movement_keys[_key]
51+
if(movement)
52+
calculate_move_dir()
53+
if(!movement_locked && !(next_move_dir_sub & movement))
5354
next_move_dir_add |= movement
5455

5556
// Client-level keybindings are ones anyone should be able to do at any time
@@ -94,9 +95,10 @@
9495

9596
keys_held -= _key
9697

97-
if(!movement_locked)
98-
var/movement = movement_keys[_key]
99-
if(!(next_move_dir_add & movement))
98+
var/movement = movement_keys[_key]
99+
if(movement)
100+
calculate_move_dir()
101+
if(!movement_locked && !(next_move_dir_add & movement))
100102
next_move_dir_sub |= movement
101103

102104
// We don't do full key for release, because for mod keys you

code/modules/mob/mob_movement.dm

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@
6666
/client/Move(new_loc, direct)
6767
if(world.time < move_delay) //do not move anything ahead of this check please
6868
return FALSE
69-
next_move_dir_add = 0
70-
next_move_dir_sub = 0
69+
next_move_dir_add = NONE
70+
next_move_dir_sub = NONE
7171
var/old_move_delay = move_delay
7272
move_delay = world.time + world.tick_lag //this is here because Move() can now be called mutiple times per tick
7373
if(!direct || !new_loc)

code/modules/tgui_input/alert.dm

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,19 @@
1010
* * timeout - The timeout of the alert, after which the modal will close and qdel itself. Set to zero for no timeout.
1111
* * autofocus - The bool that controls if this alert should grab window focus.
1212
*/
13-
/proc/tgui_alert(mob/user, message = "", title, list/buttons = list("Ok"), timeout = 0, autofocus = TRUE)
13+
/proc/tgui_alert(mob/user, message = "", title, list/buttons = list("Ok"), timeout = 0, autofocus = TRUE, ui_state = GLOB.always_state)
1414
if (!user)
1515
user = usr
1616
if (!istype(user))
1717
if (istype(user, /client))
1818
var/client/client = user
1919
user = client.mob
2020
else
21-
return
21+
return null
22+
23+
if(isnull(user.client))
24+
return null
25+
2226
// A gentle nudge - you should not be using TGUI alert for anything other than a simple message.
2327
if(length(buttons) > 3)
2428
log_tgui(user, "Error: TGUI Alert initiated with too many buttons. Use a list.", "TguiAlert")
@@ -29,7 +33,7 @@
2933
return alert(user, message, title, buttons[1], buttons[2])
3034
if(length(buttons) == 3)
3135
return alert(user, message, title, buttons[1], buttons[2], buttons[3])
32-
var/datum/tgui_alert/alert = new(user, message, title, buttons, timeout, autofocus)
36+
var/datum/tgui_alert/alert = new(user, message, title, buttons, timeout, autofocus, ui_state)
3337
alert.ui_interact(user)
3438
alert.wait()
3539
if (alert)
@@ -59,19 +63,23 @@
5963
var/autofocus
6064
/// Boolean field describing if the tgui_alert was closed by the user.
6165
var/closed
66+
/// The TGUI UI state that will be returned in ui_state(). Default: always_state
67+
var/datum/ui_state/state
6268

63-
/datum/tgui_alert/New(mob/user, message, title, list/buttons, timeout, autofocus)
69+
/datum/tgui_alert/New(mob/user, message, title, list/buttons, timeout, autofocus, ui_state)
6470
src.autofocus = autofocus
6571
src.buttons = buttons.Copy()
6672
src.message = message
6773
src.title = title
74+
src.state = ui_state
6875
if (timeout)
6976
src.timeout = timeout
7077
start_time = world.time
7178
QDEL_IN(src, timeout)
7279

7380
/datum/tgui_alert/Destroy(force)
7481
SStgui.close_uis(src)
82+
state = null
7583
QDEL_NULL(buttons)
7684
return ..()
7785

@@ -94,7 +102,7 @@
94102
closed = TRUE
95103

96104
/datum/tgui_alert/ui_state(mob/user)
97-
return GLOB.always_state
105+
return state
98106

99107
/datum/tgui_alert/ui_static_data(mob/user)
100108
var/list/data = list()

code/modules/tgui_input/checkboxes.dm

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,24 @@
1010
* max_checked - The maximum number of checkboxes that can be checked (optional)
1111
* timeout - The timeout for the input (optional)
1212
*/
13-
/proc/tgui_input_checkboxes(mob/user, message, title = "Select", list/items, min_checked = 1, max_checked = 50, timeout = 0)
13+
/proc/tgui_input_checkboxes(mob/user, message, title = "Select", list/items, min_checked = 1, max_checked = 50, timeout = 0, ui_state = GLOB.always_state)
1414
if (!user)
1515
user = usr
1616
if(!length(items))
17-
return
17+
return null
1818
if (!istype(user))
1919
if (istype(user, /client))
2020
var/client/client = user
2121
user = client.mob
2222
else
23-
return
23+
return null
24+
25+
if(isnull(user.client))
26+
return null
27+
2428
if(!user.client.prefs.read_preference(/datum/preference/toggle/tgui_input))
2529
return input(user, message, title) as null|anything in items
26-
var/datum/tgui_checkbox_input/input = new(user, message, title, items, min_checked, max_checked, timeout)
30+
var/datum/tgui_checkbox_input/input = new(user, message, title, items, min_checked, max_checked, timeout, ui_state)
2731
input.ui_interact(user)
2832
input.wait()
2933
if (input)
@@ -50,13 +54,16 @@
5054
var/min_checked
5155
/// Maximum number of checkboxes that can be checked
5256
var/max_checked
57+
/// The TGUI UI state that will be returned in ui_state(). Default: always_state
58+
var/datum/ui_state/state
5359

54-
/datum/tgui_checkbox_input/New(mob/user, message, title, list/items, min_checked, max_checked, timeout)
60+
/datum/tgui_checkbox_input/New(mob/user, message, title, list/items, min_checked, max_checked, timeout, ui_state)
5561
src.title = title
5662
src.message = message
5763
src.items = items.Copy()
5864
src.min_checked = min_checked
5965
src.max_checked = max_checked
66+
src.state = ui_state
6067

6168
if (timeout)
6269
src.timeout = timeout
@@ -65,6 +72,7 @@
6572

6673
/datum/tgui_checkbox_input/Destroy(force)
6774
SStgui.close_uis(src)
75+
state = null
6876
QDEL_NULL(items)
6977

7078
return ..()
@@ -84,7 +92,7 @@
8492
closed = TRUE
8593

8694
/datum/tgui_checkbox_input/ui_state(mob/user)
87-
return GLOB.always_state
95+
return state
8896

8997
/datum/tgui_checkbox_input/ui_data(mob/user)
9098
var/list/data = list()

code/modules/tgui_input/list.dm

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,25 @@
1010
* * default - If an option is already preselected on the UI. Current values, etc.
1111
* * timeout - The timeout of the input box, after which the menu will close and qdel itself. Set to zero for no timeout.
1212
*/
13-
/proc/tgui_input_list(mob/user, message, title = "Select", list/items, default, timeout = 0)
13+
/proc/tgui_input_list(mob/user, message, title = "Select", list/items, default, timeout = 0, ui_state = GLOB.always_state)
1414
if (!user)
1515
user = usr
1616
if(!length(items))
17-
return
17+
return null
1818
if (!istype(user))
1919
if (istype(user, /client))
2020
var/client/client = user
2121
user = client.mob
2222
else
23-
return
23+
return null
24+
25+
if(isnull(user.client))
26+
return null
27+
2428
/// Client does NOT have tgui_input on: Returns regular input
2529
if(!user.client.prefs.read_preference(/datum/preference/toggle/tgui_input))
2630
return input(user, message, title, default) as null|anything in items
27-
var/datum/tgui_list_input/input = new(user, message, title, items, default, timeout)
31+
var/datum/tgui_list_input/input = new(user, message, title, items, default, timeout, ui_state)
2832
input.ui_interact(user)
2933
input.wait()
3034
if (input)
@@ -56,13 +60,16 @@
5660
var/timeout
5761
/// Boolean field describing if the tgui_list_input was closed by the user.
5862
var/closed
63+
/// The TGUI UI state that will be returned in ui_state(). Default: always_state
64+
var/datum/ui_state/state
5965

60-
/datum/tgui_list_input/New(mob/user, message, title, list/items, default, timeout)
66+
/datum/tgui_list_input/New(mob/user, message, title, list/items, default, timeout, ui_state)
6167
src.title = title
6268
src.message = message
6369
src.items = list()
6470
src.items_map = list()
6571
src.default = default
72+
src.state = ui_state
6673
var/list/repeat_items = list()
6774
// Gets rid of illegal characters
6875
var/static/regex/whitelistedWords = regex(@{"([^\u0020-\u8000]+)"})
@@ -81,6 +88,7 @@
8188

8289
/datum/tgui_list_input/Destroy(force)
8390
SStgui.close_uis(src)
91+
state = null
8492
QDEL_NULL(items)
8593
return ..()
8694

@@ -103,7 +111,7 @@
103111
closed = TRUE
104112

105113
/datum/tgui_list_input/ui_state(mob/user)
106-
return GLOB.always_state
114+
return state
107115

108116
/datum/tgui_list_input/ui_static_data(mob/user)
109117
var/list/data = list()

code/modules/tgui_input/number.dm

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,24 @@
1515
* * timeout - The timeout of the number input, after which the modal will close and qdel itself. Set to zero for no timeout.
1616
* * round_value - whether the inputted number is rounded down into an integer.
1717
*/
18-
/proc/tgui_input_number(mob/user, message, title = "Number Input", default = 0, max_value = 10000, min_value = 0, timeout = 0, round_value = TRUE)
18+
/proc/tgui_input_number(mob/user, message, title = "Number Input", default = 0, max_value = 10000, min_value = 0, timeout = 0, round_value = TRUE, ui_state = GLOB.always_state)
1919
if (!user)
2020
user = usr
2121
if (!istype(user))
2222
if (istype(user, /client))
2323
var/client/client = user
2424
user = client.mob
2525
else
26-
return
26+
return null
27+
28+
if (isnull(user.client))
29+
return null
30+
2731
// Client does NOT have tgui_input on: Returns regular input
2832
if(!user.client.prefs.read_preference(/datum/preference/toggle/tgui_input))
2933
var/input_number = input(user, message, title, default) as null|num
3034
return clamp(round_value ? round(input_number) : input_number, min_value, max_value)
31-
var/datum/tgui_input_number/number_input = new(user, message, title, default, max_value, min_value, timeout, round_value)
35+
var/datum/tgui_input_number/number_input = new(user, message, title, default, max_value, min_value, timeout, round_value, ui_state)
3236
number_input.ui_interact(user)
3337
number_input.wait()
3438
if (number_input)
@@ -62,14 +66,17 @@
6266
var/timeout
6367
/// The title of the TGUI window
6468
var/title
69+
/// The TGUI UI state that will be returned in ui_state(). Default: always_state
70+
var/datum/ui_state/state
6571

66-
/datum/tgui_input_number/New(mob/user, message, title, default, max_value, min_value, timeout, round_value)
72+
/datum/tgui_input_number/New(mob/user, message, title, default, max_value, min_value, timeout, round_value, ui_state)
6773
src.default = default
6874
src.max_value = max_value
6975
src.message = message
7076
src.min_value = min_value
7177
src.title = title
7278
src.round_value = round_value
79+
src.state = ui_state
7380
if (timeout)
7481
src.timeout = timeout
7582
start_time = world.time
@@ -87,6 +94,7 @@
8794

8895
/datum/tgui_input_number/Destroy(force)
8996
SStgui.close_uis(src)
97+
state = null
9098
return ..()
9199

92100
/**
@@ -108,7 +116,7 @@
108116
closed = TRUE
109117

110118
/datum/tgui_input_number/ui_state(mob/user)
111-
return GLOB.always_state
119+
return state
112120

113121
/datum/tgui_input_number/ui_static_data(mob/user)
114122
var/list/data = list()

0 commit comments

Comments
 (0)