Skip to content

Commit 333fe47

Browse files
authored
Advanced cable placement (#1009)
* advanced cable placement * old * incap check * face_atom * honestly this looks better * layer adjustment * should be on game plane
1 parent 37bb28d commit 333fe47

File tree

5 files changed

+325
-3
lines changed

5 files changed

+325
-3
lines changed

code/__HELPERS/turfs.dm

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,6 @@ Turf and target are separate in case you want to teleport some distance from a t
257257
LAZYSET(modifiers, ICON_Y, "[(click_turf_py - click_turf.pixel_y) + ((click_turf_y - click_turf.y) * world.icon_size)]")
258258
return click_turf
259259

260-
///Almost identical to the params_to_turf(), but unused (remove?)
261260
/proc/screen_loc_to_turf(text, turf/origin, client/C)
262261
if(!text)
263262
return null

code/datums/cable_click_manager.dm

Lines changed: 303 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,303 @@
1+
/datum/cable_click_manager
2+
var/obj/item/stack/cable_coil/parent
3+
var/mob/user
4+
5+
/// Mouse catcher
6+
var/atom/movable/screen/fullscreen/cursor_catcher/catcher
7+
var/image/phantom_wire
8+
var/image/phantom_knot
9+
10+
var/turf/tracked_turf
11+
var/position_1
12+
var/position_2
13+
14+
/datum/cable_click_manager/New(new_parent)
15+
parent = new_parent
16+
17+
phantom_knot = image('icons/obj/power_cond/cable.dmi', "0")
18+
phantom_knot.appearance_flags = APPEARANCE_UI
19+
phantom_knot.plane = ABOVE_LIGHTING_PLANE
20+
phantom_knot.color = parent.color
21+
phantom_knot.alpha = 128
22+
phantom_knot.filters += outline_filter(1, COLOR_RED)
23+
24+
phantom_wire = image('icons/obj/power_cond/cable.dmi')
25+
phantom_wire.appearance_flags = APPEARANCE_UI
26+
phantom_wire.plane = GAME_PLANE
27+
phantom_wire.layer = FLY_LAYER
28+
phantom_wire.color = parent.color
29+
phantom_wire.alpha = 128
30+
phantom_wire.filters += outline_filter(1, COLOR_RED)
31+
32+
/datum/cable_click_manager/Destroy(force, ...)
33+
set_user(null)
34+
parent = null
35+
STOP_PROCESSING(SSkinesis, src)
36+
return ..()
37+
38+
// WIRE_LAYER
39+
/datum/cable_click_manager/proc/set_user(mob/new_user)
40+
if(user == new_user)
41+
return
42+
43+
if(catcher)
44+
QDEL_NULL(catcher)
45+
46+
if(user)
47+
UnregisterSignal(user, list(COMSIG_MOB_LOGIN, COMSIG_MOB_LOGOUT, COMSIG_MOB_SWAP_HANDS, COMSIG_MOB_CLICKON))
48+
user.clear_fullscreen("cable_laying", FALSE)
49+
user.client?.images -= phantom_wire
50+
user.client?.images -= phantom_knot
51+
52+
position_1 = null
53+
position_2 = null
54+
STOP_PROCESSING(SSkinesis, src)
55+
56+
user = new_user
57+
if(!user)
58+
return
59+
60+
RegisterSignal(user, COMSIG_MOB_LOGIN, PROC_REF(on_login))
61+
RegisterSignal(user, COMSIG_MOB_LOGOUT, PROC_REF(on_logout))
62+
RegisterSignal(user, COMSIG_MOB_SWAP_HANDS, PROC_REF(on_swap_hands))
63+
RegisterSignal(user, COMSIG_MOB_CLICKON, PROC_REF(intercept_click))
64+
65+
if(user.client)
66+
create_catcher()
67+
disable_catcher()
68+
69+
/datum/cable_click_manager/proc/create_catcher()
70+
user.client.images |= phantom_wire
71+
user.client.images |= phantom_knot
72+
73+
catcher = user.overlay_fullscreen("cable_laying", /atom/movable/screen/fullscreen/cursor_catcher/cable, 0)
74+
catcher.assign_to_mob(user)
75+
76+
if(user.get_active_held_item() != parent)
77+
catcher.mouse_opacity = MOUSE_OPACITY_TRANSPARENT
78+
else
79+
START_PROCESSING(SSkinesis, src)
80+
81+
RegisterSignal(catcher, COMSIG_CLICK, PROC_REF(on_catcher_click))
82+
83+
/// Turn on the catcher.
84+
/datum/cable_click_manager/proc/enable_catcher()
85+
catcher.mouse_opacity = MOUSE_OPACITY_OPAQUE
86+
START_PROCESSING(SSkinesis, src)
87+
88+
/// Turn off the catcher and clear all state.
89+
/datum/cable_click_manager/proc/disable_catcher()
90+
catcher.mouse_opacity = MOUSE_OPACITY_TRANSPARENT
91+
clear_state()
92+
STOP_PROCESSING(SSkinesis, src)
93+
94+
/datum/cable_click_manager/proc/on_catcher_click(atom/source, location, control, params)
95+
SIGNAL_HANDLER
96+
97+
if(user.incapacitated())
98+
return
99+
100+
params = params2list(params)
101+
if(!length(params))
102+
return
103+
104+
if(params[RIGHT_CLICK])
105+
if(position_1)
106+
clear_state()
107+
return
108+
109+
disable_catcher()
110+
to_chat(usr, span_obviousnotice("Advanced wire placement disabled."))
111+
return
112+
113+
var/turf/T = parse_caught_click_modifiers(params, get_turf(user.client.eye), user.client)
114+
if(!T || (tracked_turf && T != tracked_turf))
115+
return
116+
117+
if(!T.Adjacent(user))
118+
return
119+
120+
var/list/screen_split = splittext(params[SCREEN_LOC], ",")
121+
var/list/x_split = splittext(screen_split[1], ":")
122+
var/list/y_split = splittext(screen_split[2], ":")
123+
124+
var/grid_cell = get_nonant_from_pixels(text2num(x_split[2]), text2num(y_split[2]))
125+
126+
if(T.underfloor_accessibility < UNDERFLOOR_INTERACTABLE || !T.can_have_cabling())
127+
to_chat(user, span_warning("[T] can not have cables."))
128+
clear_state()
129+
return
130+
131+
if(user.canface())
132+
user.face_atom(T)
133+
134+
if(!tracked_turf)
135+
position_1 = grid_cell
136+
phantom_knot.loc = T
137+
offset_image_to_nonant_cell(position_1, phantom_knot)
138+
tracked_turf = T
139+
return
140+
141+
if(try_place_wire(T, (position_1 | grid_cell)))
142+
clear_state()
143+
144+
/datum/cable_click_manager/process(delta_time)
145+
if(tracked_turf && !tracked_turf.Adjacent(user))
146+
clear_state()
147+
return
148+
149+
var/list/params = params2list(catcher.mouse_params)
150+
if(!length(params) || !params[SCREEN_LOC])
151+
return
152+
153+
var/turf/T = parse_caught_click_modifiers(params, get_turf(user.client.eye), user.client)
154+
if(!T)
155+
return
156+
157+
if(!T.Adjacent(user))
158+
phantom_wire.loc = null
159+
return
160+
161+
if(tracked_turf && (T != tracked_turf))
162+
return
163+
164+
var/list/screen_split = splittext(params[SCREEN_LOC], ",")
165+
var/list/x_split = splittext(screen_split[1], ":")
166+
var/list/y_split = splittext(screen_split[2], ":")
167+
168+
var/grid_cell = get_nonant_from_pixels(text2num(x_split[2]), text2num(y_split[2]))
169+
170+
if(isnull(position_1))
171+
phantom_wire.icon_state = "0"
172+
phantom_wire.loc = T
173+
offset_image_to_nonant_cell(grid_cell, phantom_wire)
174+
return
175+
176+
position_2 = grid_cell
177+
phantom_wire.loc = T
178+
phantom_wire.pixel_x = 0
179+
phantom_wire.pixel_y = 0
180+
phantom_wire.icon_state = "[position_1 | position_2]"
181+
182+
/datum/cable_click_manager/proc/try_place_wire(turf/T, cable_direction = NONE)
183+
return parent.place_turf(T, user, cable_direction)
184+
185+
/datum/cable_click_manager/proc/clear_state()
186+
tracked_turf = null
187+
phantom_knot.loc = null
188+
phantom_wire.loc = null
189+
position_1 = null
190+
position_2 = null
191+
192+
// Nonant grid
193+
// 1 2 3
194+
// 4 5 6
195+
// 7 8 9
196+
/// Returns the nonant cell the mouse is in based on the pixel offsets.
197+
/datum/cable_click_manager/proc/get_nonant_from_pixels(pixel_x = 0, pixel_y = 0)
198+
var/nonant_row
199+
var/nonant_column
200+
switch(pixel_x)
201+
if(0 to 10)
202+
nonant_row = 1
203+
if(11 to 22)
204+
nonant_row = 2
205+
else
206+
nonant_row = 3
207+
208+
switch(pixel_y)
209+
if(0 to 10)
210+
nonant_column = 6
211+
if(11 to 22)
212+
nonant_column = 3
213+
else
214+
nonant_column = 0
215+
216+
var/static/list/lookup = list(
217+
CABLE_NORTHWEST, CABLE_NORTH, CABLE_NORTHEAST,
218+
CABLE_WEST, 0 , CABLE_EAST,
219+
CABLE_SOUTHWEST, CABLE_SOUTH, CABLE_SOUTHEAST
220+
)
221+
222+
return lookup[nonant_row + nonant_column]
223+
224+
/datum/cable_click_manager/proc/offset_image_to_nonant_cell(cell, image/I)
225+
switch(cell)
226+
if(CABLE_NORTHWEST)
227+
I.pixel_x = 0
228+
I.pixel_y = 32
229+
if(CABLE_NORTH)
230+
I.pixel_x = 16
231+
I.pixel_y = 32
232+
if(CABLE_NORTHEAST)
233+
I.pixel_x = 32
234+
I.pixel_y = 32
235+
if(CABLE_WEST)
236+
I.pixel_x = 0
237+
I.pixel_y = 16
238+
if(0)
239+
I.pixel_x = 16
240+
I.pixel_y = 16
241+
if(CABLE_EAST)
242+
I.pixel_x = 32
243+
I.pixel_y = 16
244+
if(CABLE_SOUTHWEST)
245+
I.pixel_x = 0
246+
I.pixel_y = 0
247+
if(CABLE_SOUTH)
248+
I.pixel_x = 16
249+
I.pixel_y = 0
250+
if(CABLE_SOUTHEAST)
251+
I.pixel_x = 32
252+
I.pixel_y = 0
253+
254+
I.pixel_x -= 16
255+
I.pixel_y -= 16
256+
257+
/datum/cable_click_manager/proc/on_login()
258+
SIGNAL_HANDLER
259+
if(!user.client)
260+
return
261+
262+
if(!catcher)
263+
create_catcher()
264+
disable_catcher()
265+
else
266+
START_PROCESSING(SSkinesis, src)
267+
268+
/datum/cable_click_manager/proc/on_logout()
269+
SIGNAL_HANDLER
270+
STOP_PROCESSING(SSkinesis, src)
271+
272+
/datum/cable_click_manager/proc/on_swap_hands()
273+
SIGNAL_HANDLER
274+
if(!catcher)
275+
return
276+
277+
spawn(0) // There is no signal for AFTER you swap hands
278+
if(!user)
279+
return
280+
281+
if(user.get_active_held_item() == parent)
282+
catcher.mouse_opacity = MOUSE_OPACITY_OPAQUE
283+
START_PROCESSING(SSkinesis, src)
284+
else
285+
disable_catcher()
286+
287+
/datum/cable_click_manager/proc/intercept_click(datum/source, atom/A, params)
288+
SIGNAL_HANDLER
289+
290+
if(!catcher)
291+
return
292+
293+
if(!params[RIGHT_CLICK])
294+
return
295+
296+
if(catcher.mouse_opacity != MOUSE_OPACITY_OPAQUE)
297+
enable_catcher()
298+
to_chat(usr, span_obviousnotice("Advanced wire placement enabled."))
299+
return COMSIG_MOB_CANCEL_CLICKON
300+
301+
/atom/movable/screen/fullscreen/cursor_catcher/cable
302+
alpha = 0
303+
mouse_opacity = MOUSE_OPACITY_OPAQUE

code/game/objects/effects/cursor_catcher.dm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
icon_state = "fullscreen_blocker" // Fullscreen semi transparent icon
44
plane = HUD_PLANE
55
mouse_opacity = MOUSE_OPACITY_ICON
6+
private_screen = FALSE
67
/// The mob whose cursor we are tracking.
78
var/mob/owner
89
/// Client view size of the scoping mob.

code/modules/power/cable.dm

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,9 @@
478478
usesound = 'sound/items/deconstruct.ogg'
479479
cost = 1
480480
source = /datum/robot_energy_storage/wire
481+
482+
/// Handles the click foo.
483+
var/datum/cable_click_manager/click_manager
481484
/// Previous position stored for purposes of cable laying
482485
var/turf/previous_position = null
483486
/// Whether we are in a cable laying mode
@@ -491,8 +494,14 @@
491494
pixel_y = base_pixel_y + rand(-2, 2)
492495
update_appearance()
493496

497+
/obj/item/stack/cable_coil/Destroy(force)
498+
QDEL_NULL(click_manager)
499+
set_cable_layer_mode(FALSE)
500+
return ..()
501+
494502
/obj/item/stack/cable_coil/examine(mob/user)
495503
. = ..()
504+
. += "<b>Right Click</b> on the floor to enable Advanced Placement."
496505
. += "<b>Ctrl+Click</b> to change the layer you are placing on."
497506

498507
/obj/item/stack/cable_coil/update_name()
@@ -507,9 +516,18 @@
507516
. = ..()
508517
icon_state = "[base_icon_state][amount < 3 ? amount : ""]"
509518

510-
/obj/item/stack/cable_coil/Destroy(force)
519+
520+
/obj/item/stack/cable_coil/equipped(mob/user, slot)
511521
. = ..()
512-
set_cable_layer_mode(FALSE)
522+
if(slot == ITEM_SLOT_HANDS)
523+
if(isnull(click_manager))
524+
click_manager = new(src)
525+
526+
click_manager.set_user(user)
527+
528+
/obj/item/stack/cable_coil/dropped()
529+
. = ..()
530+
click_manager?.set_user(null)
513531

514532
/obj/item/stack/cable_coil/use(used, transfer, check)
515533
. = ..()

daedalus.dme

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,7 @@
635635
#include "code\datums\beam.dm"
636636
#include "code\datums\blood_types.dm"
637637
#include "code\datums\browser.dm"
638+
#include "code\datums\cable_click_manager.dm"
638639
#include "code\datums\callback.dm"
639640
#include "code\datums\cartesian_plane.dm"
640641
#include "code\datums\chatmessage.dm"

0 commit comments

Comments
 (0)