Skip to content

Commit 2531422

Browse files
francinumLemonInTheDarkSmArtKar
authored
Ports 2 PRs related to client movement: tg#8146, tg#85379 (#1051)
* Ports 2 PRs related to client movement tgstation/tgstation#81464 tgstation/tgstation#85379 Co-authored-by: LemonInTheDark <[email protected]> Co-authored-by: SmArtKar <[email protected]> * Changelogs * Fixes locked directional movement ports tgstation/tgstation#81505 fixes #1064 --------- Co-authored-by: LemonInTheDark <[email protected]> Co-authored-by: SmArtKar <[email protected]>
1 parent 5dacfac commit 2531422

File tree

8 files changed

+88
-38
lines changed

8 files changed

+88
-38
lines changed

code/modules/client/client_defines.dm

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

code/modules/client/client_procs.dm

+1
Original file line numberDiff line numberDiff line change
@@ -1170,6 +1170,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
11701170
winset(src, "default-[REF(key)]", "parent=default;name=[key];command=looc")
11711171
if("Me")
11721172
winset(src, "default-[REF(key)]", "parent=default;name=[key];command=me")
1173+
calculate_move_dir()
11731174

11741175
/client/proc/change_view(new_size)
11751176
if (isnull(new_size))

code/modules/keybindings/bindings_atom.dm

+24-9
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,41 @@
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

21-
if(user?.movement_locked)
30+
if(user.movement_locked)
2231
keybind_face_direction(movement_dir)
2332
else
24-
user?.Move(get_step(src, movement_dir), movement_dir)
33+
user.Move(get_step(src, movement_dir), movement_dir)
2534
return !!movement_dir //true if there was actually any player input
2635

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

code/modules/keybindings/bindings_client.dm

+8-6
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,10 @@
4444

4545
//the time a key was pressed isn't actually used anywhere (as of 2019-9-10) but this allows easier access usage/checking
4646
keys_held[_key] = world.time
47-
if(!movement_locked)
48-
var/movement = movement_keys[_key]
49-
if(!(next_move_dir_sub & movement))
47+
var/movement = movement_keys[_key]
48+
if(movement)
49+
calculate_move_dir()
50+
if(!movement_locked && !(next_move_dir_sub & movement))
5051
next_move_dir_add |= movement
5152

5253
// Client-level keybindings are ones anyone should be able to do at any time
@@ -98,9 +99,10 @@
9899
if(update_pointer == TRUE)
99100
mob.update_mouse_pointer()
100101

101-
if(!movement_locked)
102-
var/movement = movement_keys[_key]
103-
if(!(next_move_dir_add & movement))
102+
var/movement = movement_keys[_key]
103+
if(movement)
104+
calculate_move_dir()
105+
if(!movement_locked && !(next_move_dir_add & movement))
104106
next_move_dir_sub |= movement
105107

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

code/modules/mob/living/living.dm

+41-21
Original file line numberDiff line numberDiff line change
@@ -116,13 +116,9 @@
116116
if(now_pushing)
117117
return TRUE
118118

119-
var/they_can_move = TRUE
120-
var/their_combat_mode = FALSE
121119

122120
if(isliving(M))
123121
var/mob/living/L = M
124-
their_combat_mode = L.combat_mode
125-
they_can_move = L.mobility_flags & MOBILITY_MOVE
126122
//Also spread diseases
127123
for(var/thing in diseases)
128124
var/datum/disease/D = thing
@@ -154,23 +150,7 @@
154150
return TRUE
155151

156152
if(!M.buckled && !M.has_buckled_mobs())
157-
var/mob_swap = FALSE
158-
var/too_strong = (M.move_resist > move_force) //can't swap with immovable objects unless they help us
159-
if(!they_can_move) //we have to physically move them
160-
if(!too_strong)
161-
mob_swap = TRUE
162-
else
163-
//You can swap with the person you are dragging on grab intent, and restrained people in most cases
164-
if(is_grabbing(M) && !too_strong)
165-
mob_swap = TRUE
166-
else if(
167-
!(HAS_TRAIT(M, TRAIT_NOMOBSWAP) || HAS_TRAIT(src, TRAIT_NOMOBSWAP))&&\
168-
((HAS_TRAIT(M, TRAIT_ARMS_RESTRAINED) && !too_strong) || !their_combat_mode) &&\
169-
(HAS_TRAIT(src, TRAIT_ARMS_RESTRAINED) || !combat_mode)
170-
)
171-
mob_swap = TRUE
172-
173-
if(mob_swap)
153+
if(can_mobswap_with(M))
174154
//switch our position with M
175155
if(loc && !loc.MultiZAdjacent(M.loc))
176156
return TRUE
@@ -213,6 +193,46 @@
213193
if(I.try_block_attack(M, src, "the push", 0, LEAP_ATTACK)) //close enough?
214194
return TRUE
215195

196+
/mob/living/proc/can_mobswap_with(mob/other)
197+
if (HAS_TRAIT(other, TRAIT_NOMOBSWAP) || HAS_TRAIT(src, TRAIT_NOMOBSWAP))
198+
return FALSE
199+
200+
var/they_can_move = TRUE
201+
var/their_combat_mode = FALSE
202+
203+
if(isliving(other))
204+
var/mob/living/other_living = other
205+
their_combat_mode = other_living.combat_mode
206+
they_can_move = other_living.mobility_flags & MOBILITY_MOVE
207+
208+
var/too_strong = other.move_resist > move_force
209+
210+
// They cannot move, see if we can push through them
211+
if (!they_can_move)
212+
return !too_strong
213+
214+
// We are pulling them and can move through
215+
if (is_grabbing(other) && !too_strong)
216+
return TRUE
217+
218+
// If we're in combat mode and not restrained we don't try to pass through people
219+
if (combat_mode && !HAS_TRAIT(src, TRAIT_ARMS_RESTRAINED))
220+
return FALSE
221+
222+
// Nor can we pass through non-restrained people in combat mode (or if they're restrained but still too strong for us)
223+
if (their_combat_mode && (!HAS_TRAIT(other, TRAIT_ARMS_RESTRAINED) || too_strong))
224+
return FALSE
225+
226+
if (isnull(other.client) || isnull(client))
227+
return TRUE
228+
229+
// If both of us are trying to move in the same direction, let the fastest one through first
230+
if (client.intended_direction == other.client.intended_direction)
231+
return movement_delay < other.movement_delay
232+
233+
// Else, sure, let us pass
234+
return TRUE
235+
216236
/mob/living/get_photo_description(obj/item/camera/camera)
217237
var/list/mob_details = list()
218238
var/list/holding = list()

code/modules/mob/mob_movement.dm

+2-2
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)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
author: "LemonInTheDark"
2+
delete-after: True
3+
changes:
4+
- refactor: "Fucks with how movement keys are handled. Please report any bugs"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
author: "SmArtKar"
2+
delete-after: True
3+
changes:
4+
- qol: "You no longer goofily swap with others trying to move in the same direction as you if you're not faster than them"
5+
- code_imp: "Moved mobswap check logic into a separate proc and made it more readable"

0 commit comments

Comments
 (0)