-
-
Notifications
You must be signed in to change notification settings - Fork 444
/
Copy pathdrag_drop.dm
217 lines (186 loc) · 8.06 KB
/
drag_drop.dm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
/*
MouseDrop:
Called on the atom you're dragging. In a lot of circumstances we want to use the
receiving object instead, so that's the default action. This allows you to drag
almost anything into a trash can.
*/
/atom/MouseDrop(atom/over, src_location, over_location, src_control, over_control, params)
if(!usr || !over)
return
if(SEND_SIGNAL(src, COMSIG_MOUSEDROP_ONTO, over, usr) & COMPONENT_NO_MOUSEDROP) //Whatever is receiving will verify themselves for adjacency.
return
var/proximity_check = usr.client.check_drag_proximity(src, over, src_location, over_location, src_control, over_control, params)
if(proximity_check)
return proximity_check
if(!Adjacent(usr) || !over.Adjacent(usr))
return // should stop you from dragging through windows
over.MouseDrop_T(src,usr, params)
return
/// Handles treating drags as clicks if they're within some conditions
/// Does some other stuff adjacent to trying to figure out what the user actually "wanted" to click
/// Returns TRUE if it caused a click, FALSE otherwise
/client/proc/check_drag_proximity(atom/dragging, atom/over, src_location, over_location, src_control, over_control, params)
// We will swap which thing we're trying to check for clickability based off the type
// Assertion is if you drag a turf to anything else, you really just wanted to click the anything else
// And slightly misseed. I'm not interested in making this game pixel percise, so if it fits our other requirements
// Lets just let that through yeah?
var/atom/attempt_click = dragging
var/atom/click_from = over
var/location_to_use = src_location
var/control_to_use = src_control
if(isturf(attempt_click) && !isturf(over))
// swapppp
attempt_click = over
click_from = dragging
location_to_use = over_location
control_to_use = over_control
if(is_drag_clickable(attempt_click, click_from, params))
Click(attempt_click, location_to_use, control_to_use, params)
return TRUE
return FALSE
/// Distance in pixels that we consider "acceptable" from the initial click to the release
/// Note: this does not account for the position of the object, just where it is on the screen
#define LENIENCY_DISTANCE 16
/// Accepted time in seconds between the initial click and drag release
/// Go higher then this and we just don't care anymore
#define LENIENCY_TIME (0.1 SECONDS)
/// Does the logic for checking if a drag counts as a click or not
/// Returns true if it does, false otherwise
/client/proc/is_drag_clickable(atom/dragging, atom/over, params)
if(dragging == over)
return TRUE
if(world.time - drag_start > LENIENCY_TIME) // Time's up bestie
return FALSE
if(!get_turf(dragging)) // If it isn't in the world, drop it. This is for things that can move, and we assume hud elements will not have this problem
return FALSE
// Basically, are you trying to buckle someone down, or drag them onto you?
// If so, we know you must be right about what you want
if(ismovable(over))
var/atom/movable/over_movable = over
// The buckle bit will cover most mobs, for stupid reasons. still useful here tho
if(over_movable.can_buckle || over_movable == eye)
return FALSE
var/list/modifiers = params2list(params)
var/list/old_offsets = screen_loc_to_offset(LAZYACCESS(drag_details, SCREEN_LOC), view)
var/list/new_offsets = screen_loc_to_offset(LAZYACCESS(modifiers, SCREEN_LOC), view)
var/distance = sqrt(((old_offsets[1] - new_offsets[1]) ** 2) + ((old_offsets[2] - new_offsets[2]) ** 2))
if(distance > LENIENCY_DISTANCE)
return FALSE
return TRUE
// receive a mousedrop
/atom/proc/MouseDrop_T(atom/dropping, mob/user)
SEND_SIGNAL(src, COMSIG_MOUSEDROPPED_ONTO, dropping, user)
/client
var/list/atom/selected_target[2]
var/obj/item/active_mousedown_item = null
var/mouseParams = ""
///Used in MouseDrag to preserve the last mouse-entered location. Weakref
var/datum/weakref/mouse_location_ref = null
///Used in MouseDrag to preserve the last mouse-entered object. Weakref
var/datum/weakref/mouse_object_ref
var/mouseControlObject = null
var/middragtime = 0
//Middle-mouse-button clicked object control for aimbot exploit detection. Weakref
var/datum/weakref/middle_drag_atom_ref
//When we started the currently active drag
var/drag_start = 0
//The params we were passed at the start of the drag, in list form
var/list/drag_details
/client/MouseDown(datum/object, location, control, params)
if(!control)
return
if(QDELETED(object)) //Yep, you can click on qdeleted things before they have time to nullspace. Fun.
return
SEND_SIGNAL(src, COMSIG_CLIENT_MOUSEDOWN, object, location, control, params)
if(mouse_down_icon)
mouse_pointer_icon = mouse_down_icon
var/delay = mob.CanMobAutoclick(object, location, params)
if(delay)
selected_target[1] = object
selected_target[2] = params
while(selected_target[1])
Click(selected_target[1], location, control, selected_target[2])
sleep(delay)
active_mousedown_item = mob.canMobMousedown(object, location, params)
if(active_mousedown_item)
active_mousedown_item.onMouseDown(object, location, params, mob)
/client/MouseUp(object, location, control, params)
if(!control)
return
if(SEND_SIGNAL(src, COMSIG_CLIENT_MOUSEUP, object, location, control, params) & COMPONENT_CLIENT_MOUSEUP_INTERCEPT)
click_intercept_time = world.time
if(mouse_up_icon)
mouse_pointer_icon = mouse_up_icon
selected_target[1] = null
if(active_mousedown_item)
active_mousedown_item.onMouseUp(object, location, params, mob)
active_mousedown_item = null
/mob/proc/CanMobAutoclick(object, location, params)
/mob/living/carbon/CanMobAutoclick(atom/object, location, params)
if(!object.IsAutoclickable())
return
var/obj/item/h = get_active_held_item()
if(h)
. = h.CanItemAutoclick(object, location, params)
/mob/proc/canMobMousedown(atom/object, location, params)
/mob/living/carbon/canMobMousedown(atom/object, location, params)
var/obj/item/H = get_active_held_item()
if(H)
. = H.canItemMouseDown(object, location, params)
/obj/item/proc/CanItemAutoclick(object, location, params)
/obj/item/proc/canItemMouseDown(object, location, params)
if(canMouseDown)
return src
/obj/item/proc/onMouseDown(object, location, params, mob)
return
/obj/item/proc/onMouseUp(object, location, params, mob)
return
/atom/proc/IsAutoclickable()
return TRUE
/atom/movable/screen/IsAutoclickable()
return FALSE
/atom/movable/screen/click_catcher/IsAutoclickable()
return TRUE
//Please don't roast me too hard
/client/MouseMove(object,location,control,params)
mouseParams = params
mouse_location_ref = WEAKREF(location)
mouse_object_ref = WEAKREF(object)
mouseControlObject = control
if(mob && LAZYLEN(mob.mousemove_intercept_objects))
for(var/datum/D in mob.mousemove_intercept_objects)
D.onMouseMove(object, location, control, params)
..()
/datum/proc/onMouseMove(object, location, control, params)
return
/client/MouseDrag(src_object,atom/over_object,src_location,over_location,src_control,over_control,params)
var/list/modifiers = params2list(params)
if (LAZYACCESS(modifiers, MIDDLE_CLICK))
if (src_object && src_location != over_location)
middragtime = world.time
middle_drag_atom_ref = WEAKREF(src_object)
else
middragtime = 0
middle_drag_atom_ref = null
if(!drag_start) // If we're just starting to drag
drag_start = world.time
drag_details = modifiers.Copy()
mouseParams = params
mouse_location_ref = WEAKREF(over_location)
mouse_object_ref = WEAKREF(over_object)
if(selected_target[1] && over_object?.IsAutoclickable())
selected_target[1] = over_object
selected_target[2] = params
if(active_mousedown_item)
active_mousedown_item.onMouseDrag(src_object, over_object, src_location, over_location, params, mob)
SEND_SIGNAL(src, COMSIG_CLIENT_MOUSEDRAG, src_object, over_object, src_location, over_location, src_control, over_control, params)
return ..()
/obj/item/proc/onMouseDrag(src_object, over_object, src_location, over_location, params, mob)
return
/client/MouseDrop(atom/src_object, atom/over_object, atom/src_location, atom/over_location, src_control, over_control, params)
if (IS_WEAKREF_OF(src_object, middle_drag_atom_ref))
middragtime = 0
middle_drag_atom_ref = null
..()
drag_start = 0
drag_details = null