Skip to content

Commit ed01c1e

Browse files
authored
Sokoban-ificator - adds pallet jacks! (#7196)
## About The Pull Request This was inspired by stray discussions in the discord musing the potential of adding pallet jacks to the game. We threw our two cents in proposing that they control like sokoban, and reception was positive! ![dreamseeker_6jUDxkPEcE](https://github.com/user-attachments/assets/8bbdbdc7-abdf-4200-a321-37bc3fec765d) (Wheelchair sprites are placeholder!) Pallet jacks have sprites created by Keekenox! ![dreamseeker_VI9CaX7zN7](https://github.com/user-attachments/assets/f8b0fed6-e36e-4798-b432-640087d7a6ab) Pallet jacks have fairly interesting behavior. Notably: - They can only be pulled cardinally. Attempting to pull them diagonally will break the pull. - They cannot move sideways relative to where they're facing. They can only move forward and back. - They can only be pulled from the side that the handle is present on. - They don't attempt to follow you if you're still adjacent to them when moving. - They will always face the mob pulling them. ## Why It's Good For The Game It'll give cargo an interesting low-tech alternative to ripley mechs if crates that require more oomph than a spaceman body on its own are added to the game. The quirks in their movement are likely to make for some fairly amusing logistics, particularly when it comes to players unfamiliar with sokoban puzzles! ## Changelog :cl: Bhijn and Myr, plus Keekenox for sprites add: Added pallet jacks! These have fairly peculiar movement quirks, being fairly reminiscent of push/pull sokoban puzzles. /:cl:
1 parent 81db67d commit ed01c1e

6 files changed

Lines changed: 232 additions & 2 deletions

File tree

citadel.dme

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2033,6 +2033,7 @@
20332033
#include "code\game\objects\structures\mop_bucket.dm"
20342034
#include "code\game\objects\structures\morgue.dm"
20352035
#include "code\game\objects\structures\noticeboard.dm"
2036+
#include "code\game\objects\structures\palletjack.dm"
20362037
#include "code\game\objects\structures\plasticflaps.dm"
20372038
#include "code\game\objects\structures\railing.dm"
20382039
#include "code\game\objects\structures\safe.dm"

code/game/atoms/movable/movable-movement.dm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@
309309
else
310310
//puller and pullee more than one tile away or in diagonal position
311311
var/pull_dir = get_dir(src, pulling)
312-
if(get_dist(src, pulling) > 1 || (moving_diagonally != SECOND_DIAG_STEP && ((pull_dir - 1) & pull_dir)))
312+
if(pulling.can_move_pulled(src) && (get_dist(src, pulling) > 1 || (moving_diagonally != SECOND_DIAG_STEP && ((pull_dir - 1) & pull_dir))))
313313
pulling.moving_from_pull = src
314314
var/success = pulling.Move(T, get_dir(pulling, T), glide_size) //the pullee tries to reach our previous position
315315
pulling.moving_from_pull = null

code/game/atoms/movable/pulling.dm

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
return
1717
if(!Process_Spacemove(get_dir(pulling.loc, A)))
1818
return
19+
if(!pulling.can_move_pulled(src))
20+
return
1921
if(step(pulling, get_dir(pulling.loc, A)))
2022
on_move_pulled(pulling)
2123

@@ -61,7 +63,7 @@
6163
. = pulling
6264
pulling.pulledby = null
6365
pulling.reset_glide_size()
64-
pulling.on_stop_pulled_by()
66+
pulling.on_stop_pulled_by(src)
6567
pulling = null
6668

6769
/**
@@ -184,3 +186,6 @@
184186
*/
185187
/atom/movable/proc/on_stop_pulled_by(atom/movable/puller)
186188
return
189+
190+
/atom/movable/proc/can_move_pulled(atom/movable/puller)
191+
return TRUE
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
//Formally known as the Sokoban-ificator
2+
/obj/structure/palletjack
3+
name = "\improper pallet jack"
4+
desc = "An ancient device used for jacking pallets. Do not stand on it!\
5+
\nIt can only be pulled by the handle, and cannot be pulled diagonally.\
6+
\nAdditionally, it can only move forward and back.\
7+
\nIf it gets stuck, you can click and drag it around to move it forward or back."
8+
icon = 'icons/obj/palletjack.dmi'
9+
icon_state = "jack down"
10+
var/icon_state_base = "jack"
11+
var/arm_state_base = "jack arm"
12+
var/color_state_base = "color overlay"
13+
var/up_suffix = " up"
14+
var/down_suffix = " down"
15+
var/overlay_color
16+
layer = TABLE_LAYER
17+
density = TRUE
18+
atom_flags = ATOM_BORDER
19+
pass_flags = NONE
20+
pass_flags_self = ATOM_PASS_OVERHEAD_THROW | ATOM_PASS_THROWN
21+
generic_canpass = FALSE
22+
23+
economic_category_obj = ECONOMIC_CATEGORY_OBJ_INDUSTRIAL
24+
worth_intrinsic = 25
25+
26+
/obj/structure/palletjack/Initialize(mapload)
27+
. = ..()
28+
return INITIALIZE_HINT_LATELOAD
29+
30+
/obj/structure/palletjack/LateInitialize()
31+
update_appearance(UPDATE_ICON)
32+
33+
/obj/structure/palletjack/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change)
34+
. = ..()
35+
if(has_gravity())
36+
playsound(src, 'sound/effects/roll.ogg', 50, TRUE)
37+
38+
/obj/structure/palletjack/update_icon_state()
39+
if(contents.len)
40+
icon_state = "[icon_state_base][up_suffix]"
41+
else
42+
icon_state = "[icon_state_base][down_suffix]"
43+
. = ..()
44+
45+
/obj/structure/palletjack/update_overlays()
46+
. = ..()
47+
var/up_or_down = contents.len ? up_suffix : down_suffix
48+
49+
if(overlay_color != null)
50+
var/color_state = "[color_state_base][up_or_down]"
51+
var/mutable_appearance/color_layer = mutable_appearance(icon, color_state, layer, plane)
52+
color_layer.appearance_flags |= RESET_COLOR
53+
color_layer.color = overlay_color
54+
. += color_layer
55+
56+
var/arm_state = "[arm_state_base][up_or_down]"
57+
var/mutable_appearance/front_layer = mutable_appearance(icon, arm_state, ABOVE_MOB_LAYER, plane)
58+
. += front_layer
59+
60+
for(var/atom/movable/M in contents)
61+
var/mutable_appearance/content_appearance = new
62+
content_appearance.appearance = M.appearance
63+
content_appearance.pixel_z += 4
64+
content_appearance.appearance_flags |= RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM | KEEP_APART
65+
. += content_appearance
66+
67+
/obj/structure/palletjack/update_icon(updates)
68+
. = ..()
69+
if(updates & UPDATE_OVERLAYS)
70+
compile_overlays() //forcefully compiles overlays to get reduce the annoying-ass flickering when taking things on/off
71+
72+
/obj/structure/palletjack/proc/absorb_tile_contents()
73+
var/picked_up = FALSE
74+
for(var/atom/movable/M in loc)
75+
if(M == src || M.anchored || M.atom_flags & ATOM_ABSTRACT || istype(M, /obj/effect))
76+
continue
77+
M.forceMove(src)
78+
picked_up = TRUE
79+
if(picked_up)
80+
playsound(src, 'sound/effects/metalscrape1.ogg', 50, TRUE)
81+
update_appearance(UPDATE_ICON)
82+
atom_flags &= ~ATOM_BORDER
83+
if(contents.len == 1)
84+
visible_message("[src] lifts up [contents[1]].")
85+
else
86+
visible_message("[src] lifts up the objects on top of it.") // why? Funni. :>
87+
88+
/obj/structure/palletjack/proc/expel_contents()
89+
if(contents.len)
90+
for(var/atom/movable/M in contents)
91+
M.forceMove(loc)
92+
playsound(src, 'sound/effects/metal_close.ogg', 50, TRUE)
93+
update_appearance(UPDATE_ICON)
94+
atom_flags |= ATOM_BORDER
95+
96+
/obj/structure/palletjack/on_attack_hand(datum/event_args/actor/clickchain/clickchain, clickchain_flags)
97+
. = ..()
98+
if(. & CLICKCHAIN_FLAGS_INTERACT_ABORT)
99+
return
100+
101+
if(!contents.len)
102+
absorb_tile_contents()
103+
else
104+
expel_contents()
105+
106+
//shamelessly plagiarized from thin windows
107+
/obj/structure/palletjack/CanAllowThrough(atom/movable/mover, turf/target)
108+
. = ..()
109+
if(. || contents.len)
110+
return
111+
if(get_dir(mover, target) & dir)
112+
return !density
113+
return TRUE
114+
115+
/obj/structure/palletjack/CanPassThrough(atom/blocker, turf/target, blocker_opinion)
116+
. = ..()
117+
if(!contents.len && !. && ismovable(blocker))
118+
var/atom/movable/AM = blocker
119+
if(istype(AM, /obj/structure/palletjack) && dir == AM.dir)
120+
return .
121+
if(AM.density && !AM.anchored && get_dir(src, target) & dir)
122+
return TRUE
123+
124+
/obj/structure/palletjack/CheckExit(atom/movable/AM, atom/newLoc)
125+
. = ..()
126+
if(contents.len)
127+
return
128+
if(istype(AM) && (check_standard_flag_pass(AM)))
129+
return TRUE
130+
if(get_dir(src, newLoc) & global.reverse_dir[dir])
131+
return !density
132+
return TRUE
133+
134+
/obj/structure/palletjack/Move(atom/newloc, direct, step_x, step_y, glide_size_override)
135+
if(direct != dir && direct != global.reverse_dir[dir])
136+
return FALSE
137+
138+
var/old_dir = dir
139+
140+
if(!contents.len && direct == dir)
141+
for (var/atom/movable/AM in loc)
142+
if(AM != src && AM.density && !AM.anchored)
143+
absorb_tile_contents()
144+
return FALSE
145+
146+
. = ..()
147+
148+
setDir(old_dir)
149+
150+
/obj/structure/palletjack/proc/check_adjust_dir(atom/movable/mover, atom/oldloc, direction)
151+
var/target_dir = get_dir(mover, src)
152+
153+
if(target_dir != dir && IS_CARDINAL(target_dir))
154+
setDir(target_dir)
155+
playsound(src, 'sound/effects/roll.ogg', 50, TRUE)
156+
157+
/obj/structure/palletjack/can_be_pulled(atom/movable/user, force)
158+
. = ..()
159+
if(.)
160+
if(dir & NORTH)
161+
return y > user.y
162+
else if(dir & SOUTH)
163+
return y < user.y
164+
else if (dir & WEST)
165+
return x < user.x
166+
else if (dir & EAST)
167+
return x > user.x
168+
169+
/obj/structure/palletjack/can_move_pulled(atom/movable/puller)
170+
if(Adjacent(puller))
171+
return FALSE
172+
return TRUE
173+
174+
/obj/structure/palletjack/on_start_pulled_by(atom/movable/puller)
175+
RegisterSignal(puller, COMSIG_MOVABLE_MOVED, PROC_REF(check_adjust_dir))
176+
. = ..()
177+
178+
/obj/structure/palletjack/on_stop_pulled_by(atom/movable/puller)
179+
. = ..()
180+
UnregisterSignal(puller, COMSIG_MOVABLE_MOVED)
181+
182+
/obj/structure/palletjack/relaymove(mob/user, direction)
183+
user.forceMove(loc)
184+
update_appearance(UPDATE_ICON)
185+
if(!contents.len)
186+
atom_flags |= ATOM_BORDER
187+
188+
/obj/structure/palletjack/OnMouseDrop(atom/over, mob/user, proximity, params)
189+
if(proximity && isturf(over) && over != loc && Adjacent(over) && CanMouseDrop(over, user))
190+
step_towards(src, over)
191+
return CLICKCHAIN_FLAGS_INTERACT_ABORT
192+
. = ..()
193+
194+
195+
/obj/structure/palletjack/engineering
196+
overlay_color = COLOR_SUN
197+
198+
/obj/structure/palletjack/atmos
199+
overlay_color = COLOR_ATMOSPHERICS_CYAN
200+
201+
/obj/structure/palletjack/science
202+
overlay_color = COLOR_PURPLE_GRAY
203+
204+
/obj/structure/palletjack/explo
205+
overlay_color = COLOR_EXPLO_VIOLET
206+
207+
/obj/structure/palletjack/cargo
208+
overlay_color = COLOR_CARGO_BROWN
209+
210+
/obj/structure/palletjack/service
211+
overlay_color = COLOR_PALE_BTL_GREEN
212+
213+
/obj/structure/palletjack/medical
214+
overlay_color = COLOR_BABY_BLUE
215+
216+
/obj/structure/palletjack/security
217+
overlay_color = COLOR_SECURITY_RED
218+
219+
/obj/structure/palletjack/command
220+
overlay_color = COLOR_COMMAND_BLUE
221+
222+
/obj/structure/palletjack/darkmode
223+
overlay_color = "#666666"

code/modules/mob/pulling.dm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373

7474
pulling = AM
7575
AM.pulledby = src
76+
AM.on_start_pulled_by(src)
7677
recursive_glidesize_update()
7778

7879
//SEND_SIGNAL(src, COMSIG_LIVING_START_PULL, AM)

icons/obj/palletjack.dmi

1.55 KB
Binary file not shown.

0 commit comments

Comments
 (0)