-
-
Notifications
You must be signed in to change notification settings - Fork 444
/
Copy pathmedical.dm
533 lines (470 loc) · 19.9 KB
/
medical.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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
/obj/item/stack/medical
name = "medical pack"
singular_name = "medical pack"
icon = 'icons/obj/stack_medical.dmi'
amount = 6
max_amount = 6
w_class = WEIGHT_CLASS_TINY
full_w_class = WEIGHT_CLASS_TINY
throw_speed = 3
throw_range = 7
resistance_flags = FLAMMABLE
max_integrity = 40
novariants = FALSE
item_flags = NOBLUDGEON
var/self_delay = 50
var/other_delay = 0
/// Sound/Sounds to play when this is applied
var/apply_sounds
var/repeating = FALSE
/// How much brute we heal per application
var/heal_brute
/// How much burn we heal per application
var/heal_burn
/// How much we reduce bleeding per application on cut wounds
var/stop_bleeding
/// How much sanitization to apply to burns on application
var/sanitization
/// How much we add to flesh_healing for burn wounds on application
var/flesh_regeneration
/// If set and this used as a splint for a broken bone wound, this is used as a multiplier for applicable slowdowns (lower = better) (also for speeding up burn recoveries)
var/splint_factor
/// How much blood flow this stack can absorb if used as a bandage on a cut wound, note that absorption is how much we lower the flow rate, not the raw amount of blood we suck up
var/absorption_capacity
/// How quickly we lower the blood flow on a cut wound we're bandaging. Expected lifetime of this bandage in ticks is thus absorption_capacity/absorption_rate, or until the cut heals, whichever comes first
var/absorption_rate
/// Coefficient for applying this stack to a wound
var/treatment_speed = 1
/obj/item/stack/medical/attack(mob/living/M, mob/user)
. = ..()
try_heal(M, user)
/obj/item/stack/medical/get_belt_overlay()
return mutable_appearance('icons/obj/clothing/belt_overlays.dmi', "stack_medical")
/obj/item/stack/medical/proc/try_heal(mob/living/M, mob/user, silent = FALSE)
if(!M.can_inject(user, TRUE))
return
if(DOING_INTERACTION_WITH_TARGET(user, M))
return
if(M == user)
playsound(src, pick(apply_sounds), 25)
if(!silent)
user.visible_message(span_notice("[user] starts to apply \the [src] on [user.p_them()]self..."), span_notice("You begin applying \the [src] on yourself..."))
if(!do_after(user, self_delay, M, extra_checks=CALLBACK(M, TYPE_PROC_REF(/mob/living, can_inject), user, TRUE), skill_check = SKILL_PHYSIOLOGY))
return
else if(other_delay)
playsound(src, pick(apply_sounds), 25)
if(!silent)
user.visible_message(span_notice("[user] starts to apply \the [src] on [M]."), span_notice("You begin applying \the [src] on [M]..."))
if(!do_after(user, other_delay, M, extra_checks=CALLBACK(M, TYPE_PROC_REF(/mob/living, can_inject), user, TRUE), skill_check = SKILL_PHYSIOLOGY))
return
if(heal(M, user))
log_combat(user, M, "healed", src.name)
use(1)
if(repeating && amount > 0)
try_heal(M, user, TRUE)
/obj/item/stack/medical/proc/heal(mob/living/M, mob/user)
return
/obj/item/stack/medical/proc/heal_carbon(mob/living/carbon/C, mob/user, brute, burn)
var/obj/item/bodypart/affecting = C.get_bodypart(check_zone(user.zone_selected))
var/list/damaged_parts = C.get_damaged_bodyparts(brute, burn, status = BODYPART_ORGANIC) // list of bodyparts that have the damage types we are able to heal
if(damaged_parts.len && !(affecting in damaged_parts) && C == user)
affecting = pick(damaged_parts) // pick from the list of damaged bodyparts if the targeted one is fine
if(!affecting) //Missing limb?
to_chat(user, span_warning("[C] doesn't have \a [parse_zone(user.zone_selected)]!"))
return
if(affecting.status != BODYPART_ORGANIC) //Limb must be organic to be healed - RR
to_chat(user, span_warning("[src] won't work on a robotic limb!"))
return
if(affecting.brute_dam && brute || affecting.burn_dam && burn)
user.visible_message(span_green("[user] applies [src] on [C]'s [affecting.name]."), span_green("You apply [src] on [C]'s [affecting.name]."))
var/previous_damage = affecting.get_damage()
if(affecting.heal_damage(brute, burn))
C.update_damage_overlays()
post_heal_effects(max(previous_damage - affecting.get_damage(), 0), C, user)
return TRUE
to_chat(user, span_warning("[C]'s [affecting.name] can not be healed with \the [src]!"))
return FALSE
///Override this proc for special post heal effects.
/obj/item/stack/medical/proc/post_heal_effects(amount_healed, mob/living/carbon/healed_mob, mob/user)
return
/obj/item/stack/medical/bruise_pack
name = "bruise pack"
singular_name = "bruise pack"
desc = "A therapeutic gel pack and bandages designed to treat blunt-force trauma."
icon_state = "brutepack"
lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
apply_sounds = list('sound/effects/rip1.ogg','sound/effects/rip2.ogg')
heal_brute = 40
self_delay = 40
other_delay = 20
grind_results = list(/datum/reagent/medicine/c2/libital = 10)
/obj/item/stack/medical/bruise_pack/heal(mob/living/M, mob/user)
if(M.stat == DEAD)
to_chat(user, span_warning("[M] is dead! You can not help [M.p_them()]."))
return
if(isanimal(M))
var/mob/living/simple_animal/critter = M
if (!(critter.healable))
to_chat(user, span_warning("You cannot use \the [src] on [M]!"))
return FALSE
else if (critter.health == critter.maxHealth)
to_chat(user, span_notice("[M] is at full health."))
return FALSE
user.visible_message(span_green("[user] applies \the [src] on [M]."), span_green("You apply \the [src] on [M]."))
M.heal_bodypart_damage((heal_brute/2))
return TRUE
if(iscarbon(M))
return heal_carbon(M, user, heal_brute, heal_burn)
to_chat(user, span_warning("You can't heal [M] with \the [src]!"))
/obj/item/stack/medical/bruise_pack/suicide_act(mob/user)
user.visible_message(span_suicide("[user] is bludgeoning [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to commit suicide!"))
return (BRUTELOSS)
/obj/item/stack/medical/gauze
name = "medical gauze"
desc = "A roll of elastic cloth, perfect for stabilizing all kinds of wounds, from cuts and burns, to broken bones. "
gender = PLURAL
singular_name = "medical gauze"
icon_state = "gauze"
apply_sounds = list('sound/effects/rip1.ogg','sound/effects/rip2.ogg')
self_delay = 50
other_delay = 20
max_amount = 12
amount = 6
grind_results = list(/datum/reagent/cellulose = 2)
custom_price = 100
absorption_rate = 0.25
absorption_capacity = 5
splint_factor = 0.35
// gauze is only relevant for wounds, which are handled in the wounds themselves
/obj/item/stack/medical/gauze/try_heal(mob/living/M, mob/user, silent)
var/obj/item/bodypart/limb = M.get_bodypart(check_zone(user.zone_selected))
if(!limb)
to_chat(user, span_notice("There's nothing there to bandage!"))
return
if(!LAZYLEN(limb.wounds))
to_chat(user, span_notice("There's no wounds that require bandaging on [user==M ? "your" : "[M]'s"] [limb.name]!")) // good problem to have imo
return
var/gauzeable_wound = FALSE
for(var/i in limb.wounds)
var/datum/wound/woundies = i
if(woundies.wound_flags & ACCEPTS_GAUZE)
gauzeable_wound = TRUE
break
if(!gauzeable_wound)
to_chat(user, span_notice("There's no wounds that require bandaging on [user==M ? "your" : "[M]'s"] [limb.name]!")) // good problem to have imo
return
if(limb.current_gauze && (limb.current_gauze.absorption_capacity * 0.8 > absorption_capacity)) // ignore if our new wrap is < 20% better than the current one, so someone doesn't bandage it 5 times in a row
to_chat(user, span_warning("The bandage currently on [user==M ? "your" : "[M]'s"] [limb.name] is still in good condition!"))
return
user.visible_message(span_warning("[user] begins wrapping the wounds on [M]'s [limb.name] with [src]..."), span_warning("You begin wrapping the wounds on [user == M ? "your" : "[M]'s"] [limb.name] with [src]..."))
playsound(src, 'sound/effects/rip2.ogg', 25)
/// Use other_delay if healing someone else (usually 1 second)
/// Use self_delay if healing yourself (usually 3 seconds)
/// Reduce delay by 20% if medical
if(!do_after(user, (user == M ? self_delay : other_delay) * (IS_MEDICAL(user) ? 0.8 : 1), M, skill_check = SKILL_PHYSIOLOGY))
return
playsound(src, 'sound/effects/rip1.ogg', 25)
user.visible_message(span_green("[user] applies [src] to [M]'s [limb.name]."), span_green("You bandage the wounds on [user == M ? "yourself" : "[M]'s"] [limb.name]."))
limb.apply_gauze(src)
/obj/item/stack/medical/gauze/twelve
amount = 12
/obj/item/stack/medical/gauze/attackby(obj/item/I, mob/user, params)
if(I.tool_behaviour == TOOL_WIRECUTTER || I.sharpness)
if(get_amount() < 2)
to_chat(user, span_warning("You need at least two gauzes to do this!"))
return
new /obj/item/stack/sheet/cloth(user.drop_location())
user.visible_message(span_notice("[user] cuts [src] into pieces of cloth with [I]."), \
span_notice("You cut [src] into pieces of cloth with [I]."), \
span_hear("You hear cutting."))
use(2)
else
return ..()
/obj/item/stack/medical/gauze/suicide_act(mob/living/user)
user.visible_message(span_suicide("[user] begins tightening \the [src] around [user.p_their()] neck! It looks like [user.p_they()] forgot how to use medical supplies!"))
return OXYLOSS
/obj/item/stack/medical/gauze/improvised
name = "improvised gauze"
singular_name = "improvised gauze"
desc = "A roll of cloth roughly cut from something that does a decent job of stabilizing wounds, but less efficiently so than real medical gauze."
self_delay = 60
other_delay = 30
absorption_rate = 0.15
absorption_capacity = 4
/obj/item/stack/medical/gauze/cyborg
custom_materials = null
is_cyborg = 1
cost = 250
/obj/item/stack/medical/suture
name = "suture"
desc = "Basic sterile sutures used to seal up cuts and lacerations and stop bleeding."
gender = PLURAL
singular_name = "suture"
icon_state = "suture"
self_delay = 30
other_delay = 10
amount = 15
max_amount = 15
repeating = TRUE
heal_brute = 10
stop_bleeding = 0.6
grind_results = list(/datum/reagent/space_cleaner/sterilizine = 2)
/obj/item/stack/medical/suture/emergency
name = "emergency suture"
desc = "A value pack of cheap sutures, not very good at repairing damage, but still decent at stopping bleeding."
icon_state = "suture_green"
heal_brute = 5
grind_results = list(/datum/reagent/space_cleaner/sterilizine = 1)
/obj/item/stack/medical/suture/emergency/makeshift
name = "makeshift suture"
desc = "A makeshift suture, gnarly looking, but it...should work."
heal_brute = 4
stop_bleeding = 0.44
grind_results = null
/obj/item/stack/medical/suture/emergency/makeshift/tribal
name = "sinew suture"
desc = "A suture created from well processed sinew, with a bone needle"
icon_state = "suture_tribal"
heal_brute = 6
stop_bleeding = 0.55
grind_results = list(/datum/reagent/liquidgibs = 2)
/obj/item/stack/medical/suture/medicated
name = "medicated suture"
icon_state = "suture_purp"
desc = "A suture infused with drugs that speed up wound healing of the treated laceration."
amount = 25
max_amount = 25
heal_brute = 15
stop_bleeding = 0.75
treatment_speed = 0.5
grind_results = list(/datum/reagent/medicine/polypyr = 2)
/obj/item/stack/medical/suture/heal(mob/living/M, mob/user)
. = ..()
if(M.stat == DEAD)
to_chat(user, span_warning("[M] is dead! You can not help [M.p_them()]."))
return
if(iscarbon(M))
return heal_carbon(M, user, heal_brute, heal_burn)
if(isanimal(M))
var/mob/living/simple_animal/critter = M
if (!(critter.healable))
to_chat(user, span_warning("You cannot use \the [src] on [M]!"))
return FALSE
else if (critter.health == critter.maxHealth)
to_chat(user, span_notice("[M] is at full health."))
return FALSE
user.visible_message(span_green("[user] applies \the [src] on [M]."), span_green("You apply \the [src] on [M]."))
M.heal_bodypart_damage(heal_brute)
return TRUE
to_chat(user, span_warning("You can't heal [M] with \the [src]!"))
/obj/item/stack/medical/ointment
name = "burn ointment"
desc = "Basic burn ointment, rated effective for second degree burns with proper bandaging, though it's still an effective stabilizer for worse burns. Not terribly good at outright healing burns though."
gender = PLURAL
singular_name = "ointment"
icon_state = "ointment"
lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
apply_sounds = list('sound/effects/ointment.ogg')
amount = 15
max_amount = 15
self_delay = 4 SECONDS
other_delay = 2 SECONDS
repeating = TRUE
heal_burn = 5
flesh_regeneration = 2.5
sanitization = 0.25
grind_results = null
/obj/item/stack/medical/ointment/heal(mob/living/M, mob/user)
if(M.stat == DEAD)
to_chat(user, span_warning("[M] is dead! You can not help [M.p_them()]."))
return
if(iscarbon(M))
return heal_carbon(M, user, heal_brute, heal_burn)
to_chat(user, span_warning("You can't heal [M] with \the [src]!"))
/obj/item/stack/medical/ointment/suicide_act(mob/living/user)
user.visible_message(span_suicide("[user] is squeezing \the [src] into [user.p_their()] mouth! [user.p_do(TRUE)]n't [user.p_they()] know that stuff is toxic?"))
return TOXLOSS
/obj/item/stack/medical/ointment/antiseptic
name = "antiseptic ointment"
desc = "A specialized ointment, designed with preventing infections in mind."
icon_state = "aointment"
sanitization = 1.0 // its main purpose is to disinfect
grind_results = list(/datum/reagent/silver = 5)
/obj/item/stack/medical/mesh
name = "regenerative mesh"
desc = "A bacteriostatic mesh used to dress burns."
gender = PLURAL
singular_name = "regenerative mesh"
icon_state = "regen_mesh"
self_delay = 30
other_delay = 10
amount = 15
max_amount = 15
heal_burn = 10
repeating = TRUE
sanitization = 0.75
flesh_regeneration = 3
var/is_open = TRUE ///This var determines if the sterile packaging of the mesh has been opened.
grind_results = list(/datum/reagent/space_cleaner/sterilizine = 2)
/obj/item/stack/medical/mesh/Initialize(mapload)
. = ..()
if(amount == max_amount) //only seal full mesh packs
is_open = FALSE
update_appearance(UPDATE_ICON)
/obj/item/stack/medical/mesh/update_icon_state()
. = ..()
if(is_open)
return
icon_state = "regen_mesh_closed"
/obj/item/stack/medical/mesh/heal(mob/living/M, mob/user)
. = ..()
if(M.stat == DEAD)
to_chat(user, span_warning("[M] is dead! You can not help [M.p_them()]."))
return
if(iscarbon(M))
return heal_carbon(M, user, heal_brute, heal_burn)
to_chat(user, span_warning("You can't heal [M] with \the [src]!"))
/obj/item/stack/medical/mesh/try_heal(mob/living/M, mob/user, silent = FALSE)
if(!is_open)
to_chat(user, span_warning("You need to open [src] first."))
return
. = ..()
/obj/item/stack/medical/mesh/AltClick(mob/living/user)
if(!is_open)
to_chat(user, span_warning("You need to open [src] first."))
return
. = ..()
/obj/item/stack/medical/mesh/attack_hand(mob/user)
if(!is_open && user.get_inactive_held_item() == src)
to_chat(user, span_warning("You need to open [src] first."))
return
. = ..()
/obj/item/stack/medical/mesh/attack_self(mob/user)
if(!is_open)
is_open = TRUE
to_chat(user, span_notice("You open the sterile mesh package."))
update_appearance(UPDATE_ICON)
playsound(src, 'sound/items/poster_ripped.ogg', 20, TRUE)
return
. = ..()
/obj/item/stack/medical/mesh/advanced
name = "advanced regenerative mesh"
desc = "An advanced mesh made with sterilizing chemicals, used to treat burns."
gender = PLURAL
singular_name = "advanced regenerative mesh"
icon_state = "aloe_mesh"
amount = 25
max_amount = 25
heal_burn = 15
sanitization = 1.25
flesh_regeneration = 3.5
grind_results = list(/datum/reagent/consumable/aloejuice = 1)
/obj/item/stack/medical/mesh/advanced/update_icon_state()
. = ..()
if(is_open)
return
icon_state = "aloe_mesh_closed"
/obj/item/stack/medical/aloe
name = "aloe cream"
desc = "A healing paste you can apply on wounds."
icon_state = "aloe_paste"
apply_sounds = list('sound/effects/ointment.ogg')
self_delay = 20
other_delay = 10
novariants = TRUE
repeating = TRUE
amount = 20
max_amount = 20
var/heal = 5 //aloe is good for the burns but does not sterilize much at all
sanitization = 0.1
grind_results = list(/datum/reagent/consumable/aloejuice = 1)
/obj/item/stack/medical/aloe/heal(mob/living/M, mob/user)
. = ..()
if(M.stat == DEAD)
to_chat(user, span_warning("[M] is dead! You can not help [M.p_them()]."))
return FALSE
if(iscarbon(M))
M.adjustFireLoss(-heal, TRUE) //there's other, infinitely better ways to heal brute damage.
return
if(isanimal(M))
var/mob/living/simple_animal/critter = M
if (!(critter.healable))
to_chat(user, span_warning("You cannot use \the [src] on [M]!"))
return FALSE
else if (critter.health == critter.maxHealth)
to_chat(user, span_notice("[M] is at full health."))
return FALSE
user.visible_message(span_green("[user] applies \the [src] on [M]."), span_green("You apply \the [src] on [M]."))
M.heal_bodypart_damage(heal, heal)
return TRUE
to_chat(user, span_warning("You can't heal [M] with the \the [src]!"))
/*
The idea is for these medical devices to work like a hybrid of the old brute packs and tend wounds,
they heal a little at a time, have reduced healing density and does not allow for rapid healing while in combat.
However they provice graunular control of where the healing is directed, this makes them better for curing work-related cuts and scrapes.
The interesting limb targeting mechanic is retained and i still believe they will be a viable choice, especially when healing others in the field.
*/
/obj/item/stack/medical/bone_gel
name = "bone gel"
singular_name = "bone gel"
desc = "A potent medical gel that, when applied to a damaged bone in a proper surgical setting, triggers an intense melding reaction to repair the wound. Can be directly applied alongside surgical sticky tape to a broken bone in dire circumstances, though this is very harmful to the patient and not recommended."
icon = 'icons/obj/surgery.dmi'
icon_state = "bone-gel"
lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
apply_sounds = list('sound/effects/ointment.ogg')
amount = 4
self_delay = 20
grind_results = list(/datum/reagent/medicine/c2/libital = 10)
novariants = TRUE
/obj/item/stack/medical/bone_gel/attack(mob/living/M, mob/user)
to_chat(user, span_warning("Bone gel can only be used on fractured limbs!"))
return
/obj/item/stack/medical/bone_gel/suicide_act(mob/user)
if(iscarbon(user))
var/mob/living/carbon/C = user
C.visible_message(span_suicide("[C] is squirting all of \the [src] into [C.p_their()] mouth! That's not proper procedure! It looks like [C.p_theyre()] trying to commit suicide!"))
if(do_after(C, 2 SECONDS))
C.emote("scream")
for(var/i in C.bodyparts)
var/obj/item/bodypart/bone = i
var/datum/wound/blunt/severe/oof_ouch = new
oof_ouch.apply_wound(bone)
var/datum/wound/blunt/critical/oof_OUCH = new
oof_OUCH.apply_wound(bone)
for(var/i in C.bodyparts)
var/obj/item/bodypart/bone = i
bone.receive_damage(brute=60)
use(1)
return (BRUTELOSS)
else
C.visible_message(span_suicide("[C] screws up like an idiot and still dies anyway!"))
return (BRUTELOSS)
/obj/item/stack/medical/bone_gel/cyborg
custom_materials = null
is_cyborg = 1
cost = 250
/obj/item/stack/medical/poultice
name = "mourning poultices"
singular_name = "mourning poultice"
desc = "A type of primitive herbal poultice.\nWhile traditionally used to prepare corpses for the mourning feast, it can also treat scrapes and burns on the living, however, it is liable to cause shortness of breath when employed in this manner.\nIt is imbued with ancient wisdom."
icon_state = "poultice"
apply_sounds = list('sound/misc/soggy.ogg')
amount = 15
max_amount = 15
heal_brute = 10
heal_burn = 10
self_delay = 40
other_delay = 10
repeating = TRUE
hitsound = 'sound/misc/moist_impact.ogg'
merge_type = /obj/item/stack/medical/poultice
/obj/item/stack/medical/poultice/heal(mob/living/M, mob/user)
if(iscarbon(M))
return heal_carbon(M, user, heal_brute, heal_burn)
return ..()
/obj/item/stack/medical/poultice/post_heal_effects(amount_healed, mob/living/carbon/healed_mob, mob/user)
. = ..()
healed_mob.adjustOxyLoss(amount_healed)