mirror of
https://github.com/VOREStation/VOREStation.git
synced 2026-05-17 20:30:46 +01:00
fb81ffbe83
* Fixes necrosis steps setting bone Makes it so you the 'cut away' step doesn't set bones to open. This is entirely a non-internal fix (you're working on the flesh, not the organs inside) so you don't need the bone retracted. * Update other.dm * Crowbar Augment * descriptors * Update carbon.dm * no typecasting * removes unused proc * Limb status * Makes butchering take time Gives a warning as well when starting it. * Update organ.dm * Update organ.dm * Closing surgical stages and desc. Opened organs have descriptions that they're opened. Organs inform you that they have SPECIAL MECHANICS THAT'VE BEEN IN FOR 10 YEARS that you can do to them. Allows fixing amputated organs A BUNCH of stuff * Update organ.dm * Keep the washing * Update external_repair.dm * Update other.dm * Organizes surgeries * fix a typo * Update surgery.dm * More surgery * Nerve Surgery Adds template for nerve surgery * Prevents pain from limbs that feel no pain * Update external_repair.dm
261 lines
10 KiB
Plaintext
261 lines
10 KiB
Plaintext
/* SURGERY STEPS */
|
|
|
|
/obj/
|
|
///How clean an object is for surgery purposes. Cleaner = less chance of infection.
|
|
var/surgery_cleanliness = 0 // Used for tables/etc which can have surgery done of them.
|
|
|
|
/datum/surgery_step
|
|
var/priority = 0 //steps with higher priority would be attempted first
|
|
|
|
var/req_open = 1 //1 means the part must be cut open, 0 means it doesn't
|
|
|
|
// type path referencing tools that can be used for this step, and how well are they suited for it
|
|
var/list/allowed_tools = null
|
|
|
|
// List of procs that can be called if allowed_tools fails
|
|
var/list/allowed_procs = null
|
|
|
|
// type paths referencing races that this step applies to.
|
|
var/list/allowed_species = null
|
|
var/list/disallowed_species = null
|
|
|
|
// duration of the step
|
|
var/min_duration = 0
|
|
var/max_duration = 0
|
|
|
|
// evil infection stuff that will make everyone hate me
|
|
var/can_infect = 0
|
|
// How much blood this step can get on surgeon. 1 - hands, 2 - full body.
|
|
var/blood_level = 0
|
|
// What the surgery will be called in the rare event of multiple surgery steps being shown to the user.
|
|
var/surgery_name = "CONTACT A DEVELOPER TO NAME THIS STEP."
|
|
// If the surgery stops you from being able to perform another surgery.
|
|
var/list/excludes_steps = list()
|
|
|
|
|
|
//returns how well tool is suited for this step
|
|
/datum/surgery_step/proc/tool_quality(obj/item/tool)
|
|
for (var/T in allowed_tools)
|
|
if (istype(tool,T))
|
|
return allowed_tools[T]
|
|
|
|
for(var/P in allowed_procs)
|
|
switch(P)
|
|
if(IS_SCREWDRIVER)
|
|
if(tool.has_tool_quality(TOOL_SCREWDRIVER))
|
|
return allowed_procs[P]
|
|
if(IS_CROWBAR)
|
|
if(tool.has_tool_quality(TOOL_CROWBAR))
|
|
return allowed_procs[P]
|
|
if(IS_WIRECUTTER)
|
|
if(tool.has_tool_quality(TOOL_WIRECUTTER))
|
|
return allowed_procs[P]
|
|
if(IS_WRENCH)
|
|
if(tool.has_tool_quality(TOOL_WRENCH))
|
|
return allowed_procs[P]
|
|
return 0
|
|
|
|
|
|
// Checks if this step applies to the user mob at all
|
|
/datum/surgery_step/proc/is_valid_target(mob/living/carbon/human/target)
|
|
if(!ishuman(target))
|
|
return 0
|
|
|
|
if(allowed_species)
|
|
for(var/species in allowed_species)
|
|
if(target.species.get_bodytype() == species)
|
|
return 1
|
|
|
|
if(disallowed_species)
|
|
for(var/species in disallowed_species)
|
|
if(target.species.get_bodytype() == species)
|
|
return 0
|
|
|
|
return 1
|
|
|
|
// Let's check if stuff blocks us from doing surgery on them
|
|
// TODO: make it based on area coverage rather than just forbid spacesuits?
|
|
// Returns true if target organ is covered
|
|
/datum/surgery_step/proc/coverage_check(mob/living/user, mob/living/carbon/human/target, obj/item/organ/external/affected, obj/item/tool)
|
|
if(!affected)
|
|
return FALSE
|
|
|
|
if(affected.organ_tag == BP_HEAD)
|
|
if(target.head && istype(target.head,/obj/item/clothing/head/helmet/space))
|
|
return TRUE
|
|
else
|
|
if(target.wear_suit && istype(target.wear_suit,/obj/item/clothing/suit/space))
|
|
return TRUE
|
|
|
|
return FALSE
|
|
|
|
// checks whether this step can be applied with the given user and target
|
|
/datum/surgery_step/proc/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
|
|
return 0
|
|
|
|
// does stuff to begin the step, usually just printing messages. Moved germs transfering and bloodying here too
|
|
/datum/surgery_step/proc/begin_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
|
|
var/obj/item/organ/external/affected = target.get_organ(target_zone)
|
|
if (can_infect && affected)
|
|
spread_germs_to_organ(affected, user)
|
|
if (ishuman(user) && prob(60))
|
|
var/mob/living/carbon/human/H = user
|
|
if (blood_level)
|
|
H.bloody_hands(target,0)
|
|
if (blood_level > 1)
|
|
H.bloody_body(target,0)
|
|
return
|
|
|
|
// does stuff to end the step, which is normally print a message + do whatever this step changes
|
|
/datum/surgery_step/proc/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
|
|
return
|
|
|
|
// stuff that happens when the step fails
|
|
/datum/surgery_step/proc/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
|
|
return null
|
|
|
|
|
|
|
|
/proc/spread_germs_to_organ(var/obj/item/organ/external/E, var/mob/living/carbon/human/user)
|
|
if(!istype(user) || !istype(E)) return
|
|
|
|
var/germ_level = user.germ_level
|
|
if(user.gloves)
|
|
germ_level = user.gloves.germ_level
|
|
|
|
E.germ_level = max(germ_level,E.germ_level) //as funny as scrubbing microbes out with clean gloves is - no.
|
|
|
|
|
|
/obj/item/proc/can_do_surgery(mob/living/carbon/M, mob/living/user)
|
|
// if(M == user)
|
|
// return 0
|
|
if(!ishuman(M))
|
|
return 1
|
|
|
|
return 1
|
|
|
|
/obj/item/proc/do_surgery(mob/living/carbon/M, mob/living/user)
|
|
if(!can_do_surgery(M, user))
|
|
return FALSE
|
|
if(!istype(M))
|
|
return FALSE
|
|
if (user.a_intent == I_HURT) //check for Hippocratic Oath
|
|
//Insert intentional hurt medical code here.
|
|
return FALSE
|
|
var/zone = user.zone_sel.selecting
|
|
if(zone in M.op_stage.in_progress) //Can't operate on someone repeatedly.
|
|
to_chat(user, span_warning("You can't operate on this area while surgery is already in progress."))
|
|
return TRUE
|
|
///How 'clean' the surace we're doing surgery on is.
|
|
///100 = fully clean, 0 = filthy
|
|
var/cleanliness = M.get_surgery_cleanliness(user)
|
|
if(isnull(cleanliness)) //They're standing upright.
|
|
return FALSE
|
|
|
|
var/list/datum/surgery_step/available_surgeries = list()
|
|
for(var/datum/surgery_step/S in GLOB.surgery_steps)
|
|
//check if tool is right or close enough and if this step is possible
|
|
if(S.tool_quality(src))
|
|
var/step_is_valid = S.can_use(user, M, zone, src)
|
|
if(step_is_valid && S.is_valid_target(M))
|
|
if(step_is_valid == SURGERY_FAILURE)
|
|
continue
|
|
available_surgeries[S.surgery_name] = S //Adds the surgery name to the list and sets it equal to S. (Ex: "Cauterize" = surgery_step/cauterize)
|
|
continue
|
|
|
|
if(!available_surgeries.len) //No available surgeries. Failure.
|
|
return 0
|
|
|
|
// Having trouble with an ASSOSCIATED LIST? or REMOVING SOMETHING FROM AN ASSOCIATED LIST? Look here for a quick guide, developed out of frustration.
|
|
// Note: This is an ultra edge case. Like, what is being done here is horrible and is so rare this should never happen again in the code.
|
|
// This block of code caused hours of suffering.
|
|
|
|
for(var/surgical_check_name in available_surgeries) // Get the name from available_surgeries. available_surgeries = list("NAME" = DATUM)
|
|
var/datum/surgery_step/surgical_check = available_surgeries[surgical_check_name] // We then get the datum.
|
|
if(isnull(surgical_check)) // This is here so it doesn't try to keep searching if the thing we're about to check has been deleted.
|
|
continue
|
|
if(surgical_check.excludes_steps.len) // We check for it's 'excluded_steps' list and see if it has anything in it.
|
|
for(var/removal_candidate_name in available_surgeries) // We then look in available_surgeries once again, grabbing the name.
|
|
var/datum/surgery_step/removal_candidate = available_surgeries[removal_candidate_name] // We then get the datum while searching.
|
|
if(is_path_in_list(removal_candidate.type, surgical_check.excludes_steps)) // We then check the datum and see if it's a path in the list that we want to remove.
|
|
available_surgeries -= removal_candidate_name // We then, finally, remove the surgery step.
|
|
// All of this just to make it so you are forced to do bloodless surgery with a laser scalpel.
|
|
|
|
if(M == user) // Once we determine if we can actually do a step at all, give a slight delay to self-surgery to confirm attempts.
|
|
to_chat(user, span_critical("You focus on attempting to perform surgery upon yourself."))
|
|
if(!do_after(user, 3 SECONDS, target = M))
|
|
return FALSE
|
|
|
|
var/datum/surgery_step/selected_surgery
|
|
if(available_surgeries.len > 1) //More than one possible? Ask them which one.
|
|
selected_surgery = tgui_input_list(user, "Select which surgery step you wish to perform", "Surgery Select", available_surgeries) //Shows the name in the list.
|
|
else
|
|
selected_surgery = pick(available_surgeries)
|
|
|
|
if(isnull(selected_surgery)) //They clicked 'cancel'
|
|
return TRUE
|
|
var/obj/item/organ/external/affected = M.get_organ(zone)
|
|
selected_surgery = available_surgeries[selected_surgery] //Sets the name they selected to be the datum.
|
|
if(istype(selected_surgery,/datum/surgery_step/generic/amputate))
|
|
to_chat(user, span_danger("You are preparing to amputate \the [M]'s [affected.name]!"))
|
|
if(!do_after(user, 3 SECONDS, target = M))
|
|
to_chat(user, span_warning("You reconsider performing an amputation..."))
|
|
return FALSE
|
|
M.op_stage.in_progress += zone
|
|
selected_surgery.begin_step(user, M, zone, src) //start on it
|
|
var/success = TRUE
|
|
|
|
// Bad tools make it less likely to succeed.
|
|
if(!prob(selected_surgery.tool_quality(src)))
|
|
success = FALSE
|
|
|
|
// Not staying still fails you too.
|
|
if(success)
|
|
var/calc_duration = rand(selected_surgery.min_duration, selected_surgery.max_duration)
|
|
calc_duration *= CLAMP((100-cleanliness)/10 + 1, 1, 10)
|
|
if(!do_after(user, calc_duration * toolspeed, M, target_zone = zone, max_distance = reach))
|
|
success = FALSE
|
|
to_chat(user, span_warning("You must remain close to and keep focused on your patient to conduct surgery."))
|
|
user.balloon_alert(user, "you must stay focused on your patient!")
|
|
|
|
if(!affected) // If the limb was just attached, get it to adjust germ levels
|
|
affected = M.get_organ(zone)
|
|
|
|
if(success)
|
|
selected_surgery.end_step(user, M, zone, src)
|
|
if(affected && prob(100-cleanliness)) //Infection chance based on cleanliness.
|
|
affected.adjust_germ_level(rand(10,20))
|
|
else
|
|
selected_surgery.fail_step(user, M, zone, src)
|
|
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) //Gets rid of instakill mechanics.
|
|
|
|
M.op_stage.in_progress -= zone // Clear the in-progress flag.
|
|
if (ishuman(M))
|
|
var/mob/living/carbon/human/H = M
|
|
H.update_surgery()
|
|
return TRUE //don't want to do weapony things after surgery
|
|
|
|
/proc/sort_surgeries()
|
|
var/gap = GLOB.surgery_steps.len
|
|
var/swapped = 1
|
|
while (gap > 1 || swapped)
|
|
swapped = 0
|
|
if(gap > 1)
|
|
gap = round(gap / 1.247330950103979)
|
|
if(gap < 1)
|
|
gap = 1
|
|
for(var/i = 1; gap + i <= GLOB.surgery_steps.len; i++)
|
|
var/datum/surgery_step/l = GLOB.surgery_steps[i] //Fucking hate
|
|
var/datum/surgery_step/r = GLOB.surgery_steps[gap+i] //how lists work here
|
|
if(l.priority < r.priority)
|
|
GLOB.surgery_steps.Swap(i, gap + i)
|
|
swapped = 1
|
|
|
|
/datum/surgery_status
|
|
var/eyes = 0
|
|
var/face = 0
|
|
var/brainstem = 0
|
|
var/head_reattach = 0
|
|
var/current_organ = "organ"
|
|
var/list/in_progress = list()
|