/
surgery_initiator.dm
162 lines (137 loc) · 6.36 KB
/
surgery_initiator.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
/**
*
* Allows parent (obj) to initiate surgeries.
*
*/
/datum/component/surgery_initiator
dupe_mode = COMPONENT_DUPE_UNIQUE
///allows for post-selection manipulation of parent
var/datum/callback/after_select_cb
/datum/component/surgery_initiator/Initialize(_after_select_cb)
. = ..()
if(!isitem(parent))
return COMPONENT_INCOMPATIBLE
after_select_cb = _after_select_cb
/datum/component/surgery_initiator/RegisterWithParent()
RegisterSignal(parent, COMSIG_ITEM_ATTACK, .proc/initiate_surgery_moment)
/datum/component/surgery_initiator/UnregisterFromParent()
UnregisterSignal(parent, COMSIG_ITEM_ATTACK)
/datum/component/surgery_initiator/Destroy()
if(after_select_cb)
QDEL_NULL(after_select_cb)
return ..()
/**
*
* Does the surgery initiation.
*
*/
/datum/component/surgery_initiator/proc/initiate_surgery_moment(datum/source, atom/target, mob/user)
SIGNAL_HANDLER
if(!isliving(target))
return
INVOKE_ASYNC(src, .proc/do_initiate_surgery_moment, source, target, user)
return COMPONENT_CANCEL_ATTACK_CHAIN
/datum/component/surgery_initiator/proc/do_initiate_surgery_moment(datum/source, atom/target, mob/user)
var/mob/living/livingtarget = target
var/mob/living/carbon/carbontarget
var/obj/item/bodypart/affecting
var/selected_zone = user.zone_selected
if(iscarbon(livingtarget))
carbontarget = livingtarget
affecting = carbontarget.get_bodypart(check_zone(selected_zone))
var/datum/surgery/current_surgery
for(var/i_one in livingtarget.surgeries)
var/datum/surgery/surgeryloop = i_one
if(surgeryloop.location == selected_zone)
current_surgery = surgeryloop
if(!current_surgery)
var/list/all_surgeries = GLOB.surgeries_list.Copy()
var/list/available_surgeries = list()
for(var/i_two in all_surgeries)
var/datum/surgery/surgeryloop_two = i_two
if(!surgeryloop_two.possible_locs.Find(selected_zone))
continue
if(affecting)
if(!surgeryloop_two.requires_bodypart)
continue
if(surgeryloop_two.requires_bodypart_type && affecting.status != surgeryloop_two.requires_bodypart_type)
continue
if(surgeryloop_two.requires_real_bodypart && affecting.is_pseudopart)
continue
else if(carbontarget && surgeryloop_two.requires_bodypart) //mob with no limb in surgery zone when we need a limb
continue
if(surgeryloop_two.lying_required && livingtarget.body_position != LYING_DOWN)
continue
if(!surgeryloop_two.can_start(user, livingtarget))
continue
for(var/path in surgeryloop_two.target_mobtypes)
if(istype(livingtarget, path))
available_surgeries[surgeryloop_two.name] = surgeryloop_two
break
if(!available_surgeries.len)
return
var/pick_your_surgery = input("Begin which procedure?", "Surgery", null, null) as null|anything in sortList(available_surgeries)
if(pick_your_surgery && user?.Adjacent(livingtarget) && (parent in user))
var/datum/surgery/surgeryinstance_notonmob = available_surgeries[pick_your_surgery]
for(var/i_three in livingtarget.surgeries)
var/datum/surgery/surgeryloop_three = i_three
if(surgeryloop_three.location == selected_zone)
return //during the input() another surgery was started at the same location.
//we check that the surgery is still doable after the input() wait.
if(carbontarget)
affecting = carbontarget.get_bodypart(check_zone(selected_zone))
if(affecting)
if(!surgeryinstance_notonmob.requires_bodypart)
return
if(surgeryinstance_notonmob.requires_bodypart_type && affecting.status != surgeryinstance_notonmob.requires_bodypart_type)
return
else if(carbontarget && surgeryinstance_notonmob.requires_bodypart)
return
if(surgeryinstance_notonmob.lying_required && livingtarget.body_position != LYING_DOWN)
return
if(!surgeryinstance_notonmob.can_start(user, livingtarget))
return
if(surgeryinstance_notonmob.ignore_clothes || get_location_accessible(livingtarget, selected_zone))
var/datum/surgery/procedure = new surgeryinstance_notonmob.type(livingtarget, selected_zone, affecting)
user.visible_message("<span class='notice'>[user] drapes [parent] over [livingtarget]'s [parse_zone(selected_zone)] to prepare for surgery.</span>", \
"<span class='notice'>You drape [parent] over [livingtarget]'s [parse_zone(selected_zone)] to prepare for \an [procedure.name].</span>")
log_combat(user, livingtarget, "operated on", null, "(OPERATION TYPE: [procedure.name]) (TARGET AREA: [selected_zone])")
after_select_cb?.Invoke()
else
to_chat(user, "<span class='warning'>You need to expose [livingtarget]'s [parse_zone(selected_zone)] first!</span>")
else if(!current_surgery.step_in_progress)
attempt_cancel_surgery(current_surgery, parent, livingtarget, user)
/**
*
* Does the surgery de-initiation.
*
*/
/datum/component/surgery_initiator/proc/attempt_cancel_surgery(datum/surgery/the_surgery, obj/item/the_item, mob/living/the_patient, mob/user)
var/selected_zone = user.zone_selected
if(the_surgery.status == 1)
the_patient.surgeries -= the_surgery
user.visible_message("<span class='notice'>[user] removes [the_item] from [the_patient]'s [parse_zone(selected_zone)].</span>", \
"<span class='notice'>You remove [the_item] from [the_patient]'s [parse_zone(selected_zone)].</span>")
qdel(the_surgery)
return
if(!the_surgery.can_cancel)
return
var/required_tool_type = TOOL_CAUTERY
var/obj/item/close_tool = user.get_inactive_held_item()
var/is_robotic = the_surgery.requires_bodypart_type == BODYPART_ROBOTIC
if(is_robotic)
required_tool_type = TOOL_SCREWDRIVER
if(iscyborg(user))
close_tool = locate(/obj/item/cautery) in user.held_items
if(!close_tool)
to_chat(user, "<span class='warning'>You need to equip a cautery in an inactive slot to stop [the_patient]'s surgery!</span>")
return
else if(!close_tool || close_tool.tool_behaviour != required_tool_type)
to_chat(user, "<span class='warning'>You need to hold a [is_robotic ? "screwdriver" : "cautery"] in your inactive hand to stop [the_patient]'s surgery!</span>")
return
if(the_surgery.operated_bodypart)
the_surgery.operated_bodypart.generic_bleedstacks -= 5
the_patient.surgeries -= the_surgery
user.visible_message("<span class='notice'>[user] closes [the_patient]'s [parse_zone(selected_zone)] with [close_tool] and removes [the_item].</span>", \
"<span class='notice'>You close [the_patient]'s [parse_zone(selected_zone)] with [close_tool] and remove [the_item].</span>")
qdel(the_surgery)