mirror of
https://github.com/vgstation-coders/vgstation13.git
synced 2025-12-09 16:14:13 +00:00
204 lines
8.6 KiB
Plaintext
204 lines
8.6 KiB
Plaintext
/* SURGERY STEPS */
|
|
|
|
/datum/surgery_step
|
|
var/priority = 0 //steps with higher priority would be attempted first
|
|
|
|
// type path referencing tools that can be used for this step, and how well are they suited for it
|
|
var/list/allowed_tools = null
|
|
// type paths referencing mutantraces that this step applies to.
|
|
var/list/allowed_species = null
|
|
var/list/disallowed_species = null
|
|
|
|
var/duration = 0
|
|
|
|
var/list/mob/doing_surgery = list() //who's doing this RIGHT NOW
|
|
|
|
// 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
|
|
//Whether or not the sound played will be a digging sound or the surgery sound designated by the tools used.
|
|
var/digging = FALSE
|
|
|
|
//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]
|
|
return 0
|
|
|
|
/datum/surgery_step/proc/check_anesthesia(var/mob/living/carbon/human/target)
|
|
if(target.sleeping > 0 || target.stat)
|
|
return 1
|
|
if(!target.feels_pain())
|
|
return 1
|
|
if(prob(25)) // Pain is tolerable? Pomf wanted this. - N3X
|
|
return 1
|
|
return 0
|
|
|
|
// Checks if this step applies to the mutantrace of the user.
|
|
/datum/surgery_step/proc/is_valid_mutantrace(mob/living/carbon/human/target)
|
|
if(!hasorgans(target))
|
|
return 0
|
|
|
|
if(allowed_species)
|
|
for(var/species in allowed_species)
|
|
if(target.dna.mutantrace == species)
|
|
return 1
|
|
|
|
if(disallowed_species)
|
|
for(var/species in disallowed_species)
|
|
if (target.dna.mutantrace == species)
|
|
return 0
|
|
|
|
return 1
|
|
|
|
// 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/datum/organ/external/affected = target.get_organ(target_zone)
|
|
if(!affected)
|
|
return 0
|
|
if (can_infect && affected)
|
|
spread_germs_to_organ(affected, user)
|
|
|
|
if(!(affected.status & (ORGAN_ROBOT|ORGAN_PEG)))//robot organs and pegs can't spread diseases or splatter blood
|
|
var/block = user.check_contact_sterility(HANDS)
|
|
var/bleeding = user.check_bodypart_bleeding(HANDS)
|
|
target.oneway_contact_diseases(user,block,bleeding)//potentially spreads diseases from us to them, wear latex gloves!
|
|
|
|
if (ishuman(user) && prob(60))
|
|
var/mob/living/carbon/human/H = user
|
|
if (blood_level)
|
|
H.bloody_hands(target,1)//potentially spreads diseases from them to us, wear latex gloves!
|
|
if (blood_level > 1)
|
|
H.bloody_body(target,0)//potentially spreads diseases from them to us, wear a bio suit, or at least a labcoat!
|
|
|
|
if(istype(tool,/obj/item/tool/scalpel/laser) || istype(tool,/obj/item/tool/retractor/manager))
|
|
tool.icon_state = "[initial(tool.icon_state)]_on"
|
|
spawn(duration * tool.toolspeed)//in case the player doesn't go all the way through the step (if he moves away, puts the tool away,...)
|
|
tool.icon_state = "[initial(tool.icon_state)]_off"
|
|
|
|
if((M_CLUMSY in user.mutations) && prob(20))
|
|
if ((istype(tool, /obj/item/tool/circular_saw)) || (istype(tool, /obj/item/tool/surgicaldrill)))
|
|
return
|
|
else
|
|
var/clownsound = null
|
|
clownsound = pick("toysqueak","partyhorn","bikehorn","quack")
|
|
playsound(target, "sound/items/[clownsound].ogg", 75, 2)
|
|
else
|
|
if(digging)
|
|
playsound(target, 'sound/items/hemostatdig.ogg', 75, 1)
|
|
else
|
|
tool.playsurgerysound(target, 75, 1)
|
|
|
|
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)
|
|
if(istype(tool,/obj/item/tool/scalpel/laser) || istype(tool,/obj/item/tool/retractor/manager))
|
|
tool.icon_state = "[initial(tool.icon_state)]_off"
|
|
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(datum/organ/external/E, 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
|
|
if(!(E.status & (ORGAN_ROBOT|ORGAN_PEG))) //Germs on robotic limbs bad
|
|
E.germ_level = max(germ_level,E.germ_level) //as funny as scrubbing microbes out with clean gloves is - no.
|
|
|
|
/proc/do_surgery(mob/living/M, mob/living/user, obj/item/tool, var/success_override = SURGERY_SUCCESS_NORMAL)
|
|
if(!ishuman(M) && !isslime(M))
|
|
return 0
|
|
if (user.a_intent == I_HURT) //check for Hippocratic Oath
|
|
return 0
|
|
var/sleep_fail = 0
|
|
var/clumsy = 0
|
|
if(ishuman(user))
|
|
var/mob/living/carbon/human/H = user
|
|
clumsy = (tool.clumsy_check(H) && prob(50))
|
|
if (!user.dexterity_check())
|
|
clumsy = 1
|
|
|
|
var/target_area = user.zone_sel ? user.zone_sel.selecting : get_random_zone_sel()
|
|
|
|
for(var/datum/surgery_step/S in surgery_steps)
|
|
//check if tool is right or close enough and if this step is possible
|
|
sleep_fail = 0
|
|
if(S.tool_quality(tool))
|
|
var/canuse = S.can_use(user, M, target_area, tool)
|
|
if(canuse == -1)
|
|
sleep_fail = 1
|
|
if(canuse && S.is_valid_mutantrace(M) && !(M in S.doing_surgery))
|
|
if(!can_operate(M, user))//never give the tool as 3rd arg here or you might cause an infinite loop
|
|
return 1
|
|
M.attack_log += text("\[[time_stamp()]\] <font color='orange'>Has had surgery [S.type] with \the [tool] started by [user.name] ([user.ckey])</font>")
|
|
user.attack_log += text("\[[time_stamp()]\] <font color='red'>Started surgery [S.type] with \the [tool] on [M.name] ([M.ckey])</font>")
|
|
log_attack("<font color='red'>[user.name] ([user.ckey]) used \the [tool] to perform surgery type [S.type] on [M.name] ([M.ckey])</font>")
|
|
S.doing_surgery += M
|
|
S.begin_step(user, M, target_area, tool) //start on it
|
|
|
|
var/selection = user.zone_sel ? user.zone_sel.selecting : null //Check if the zone selection hasn't changed
|
|
//We had proper tools! (or RNG smiled.) and user did not move or change hands.
|
|
if(do_mob(user, M, S.duration * tool.toolspeed) && (success_override == SURGERY_SUCCESS_ALWAYS || (success_override == SURGERY_SUCCESS_NORMAL && (prob(S.tool_quality(tool) / (sleep_fail + clumsy + 1))))) && (!user.zone_sel || selection == user.zone_sel.selecting)) //Last part checks whether the zone selection hasn't changed
|
|
M.attack_log += text("\[[time_stamp()]\] <font color='orange'>Has had surgery [S.type] with \the [tool] successfully completed by [user.name] ([user.ckey])</font>")
|
|
user.attack_log += text("\[[time_stamp()]\] <font color='red'>Successfully completed surgery [S.type] with \the [tool] on [M.name] ([M.ckey])</font>")
|
|
log_attack("<font color='red'>[user.name] ([user.ckey]) used \the [tool] to successfully complete surgery type [S.type] on [M.name] ([M.ckey])</font>")
|
|
S.end_step(user, M, target_area, tool) //finish successfully
|
|
else
|
|
if(sleep_fail)
|
|
to_chat(user, "<span class='warning'>The patient is squirming around in pain!</span>")
|
|
M.audible_scream()
|
|
M.attack_log += text("\[[time_stamp()]\] <font color='orange'>Has had surgery [S.type] with \the [tool] failed by [user.name] ([user.ckey])</font>")
|
|
user.attack_log += text("\[[time_stamp()]\] <font color='red'>Failed surgery [S.type] with \the [tool] on [M.name] ([M.ckey])</font>")
|
|
log_attack("<font color='red'>[user.name] ([user.ckey]) used \the [tool] to fail the surgery type [S.type] on [M.name] ([M.ckey])</font>")
|
|
S.fail_step(user, M, target_area, tool) //malpractice~
|
|
if(M) //good, we still exist
|
|
S.doing_surgery -= M
|
|
else
|
|
S.doing_surgery.Remove(null) //get rid of that now null reference
|
|
return 1 //don't want to do weapony things after surgery
|
|
if (user.a_intent == I_HELP)
|
|
to_chat(user, "<span class='warning'>You can't see any useful way to use [tool] on [M].</span>")
|
|
return 1
|
|
return 0
|
|
|
|
/proc/sort_surgeries()
|
|
var/gap = 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 <= surgery_steps.len; i++)
|
|
var/datum/surgery_step/l = surgery_steps[i] //Fucking hate
|
|
var/datum/surgery_step/r = surgery_steps[gap+i] //how lists work here
|
|
if(l.priority < r.priority)
|
|
surgery_steps.Swap(i, gap + i)
|
|
swapped = 1
|
|
|
|
/datum/surgery_status
|
|
var/eyes = 0
|
|
var/face = 0
|
|
var/appendix = 0
|
|
var/ribcage = 0
|
|
var/butt = 0
|
|
var/butt_replace = 0
|
|
var/genitals = 0
|
|
var/head_reattach = 0
|
|
var/tooth_replace = 0
|
|
var/tooth_extract = 0
|
|
var/current_organ
|