Add a new process option: Break Bone (#17855)

* Add a new process option: Break Bone

* Partial refactor of belly actions
This commit is contained in:
ShadowLarkens
2025-06-16 15:15:25 +02:00
committed by GitHub
parent 8ef73a7dc1
commit e0d5d01158
5 changed files with 119 additions and 50 deletions
@@ -358,6 +358,14 @@
parts += O
return parts
//Returns a list of fracturable organs
/mob/living/carbon/human/proc/get_fracturable_organs()
var/list/obj/item/organ/external/parts = list()
for(var/obj/item/organ/external/O in organs)
if(O.is_fracturable())
parts += O
return parts
//Heals ONE external organ, organ gets randomly selected from damaged ones.
//It automatically updates damage overlays if necesary
//It automatically updates health status
+20 -2
View File
@@ -289,6 +289,13 @@
//Continued damage to vital organs can kill you, and robot organs don't count towards total damage so no need to cap them.
return (vital || (robotic >= ORGAN_ROBOT) || brute_dam + burn_dam + additional_damage < max_damage)
/obj/item/organ/external/proc/is_fracturable()
if(robotic >= ORGAN_ROBOT)
return FALSE //ORGAN_BROKEN doesn't have the same meaning for robot limbs
if((status & ORGAN_BROKEN) || cannot_break)
return FALSE
return TRUE
/obj/item/organ/external/take_damage(brute, burn, sharp, edge, used_weapon = null, list/forbidden_limbs = list(), permutation = FALSE, projectile)
brute = round(brute * brute_mod, 0.1)
burn = round(burn * burn_mod, 0.1)
@@ -1138,12 +1145,23 @@ Note that amputating the affected organ does in fact remove the infection from t
status |= ORGAN_BROKEN
broken_description = pick("broken","fracture","hairline fracture")
if(owner)
if(organ_can_feel_pain() && !isbelly(owner.loc) && !isliving(owner.loc) && !owner.transforming)
var/show_message = TRUE
var/scream = TRUE
if(!organ_can_feel_pain() || owner.transforming)
show_message = FALSE
scream = FALSE
if(isbelly(owner.loc) || isliving(owner.loc))
scream = FALSE
if(!owner.digest_pain)
show_message = FALSE
if(show_message)
owner.visible_message(\
span_danger("You hear a loud cracking sound coming from \the [owner]."),\
span_danger("Something feels like it shattered in your [name]!"),\
span_danger("You hear a sickening crack."))
owner.emote("scream")
if(scream)
owner.emote("scream")
jostle_bone()
// Fractures have a chance of getting you out of restraints
+81
View File
@@ -0,0 +1,81 @@
/obj/belly/proc/instant_digest(mob/user, mob/living/target)
if(target.absorbed)
to_chat(user, span_vwarning("\The [target] is absorbed, and cannot presently be digested."))
return FALSE
if(tgui_alert(target, "\The [user] is attempting to instantly digest you. Is this something you are okay with happening to you?","Instant Digest", list("No", "Yes")) != "Yes")
to_chat(user, span_vwarning("\The [target] declined your digest attempt."))
to_chat(target, span_vwarning("You declined the digest attempt."))
return FALSE
// must be checked after alert
if(target.loc != src)
to_chat(user, span_vwarning("\The [target] is no longer in \the [src]."))
return FALSE
if(isliving(user))
var/mob/living/l = user
var/thismuch = target.health + 100
if(ishuman(l))
var/mob/living/carbon/human/h = l
thismuch = thismuch * h.species.digestion_nutrition_modifier
l.adjust_nutrition(thismuch)
target.death() // To make sure all on-death procs get properly called
if(target)
if(target.check_sound_preference(/datum/preference/toggle/digestion_noises))
if(!fancy_vore)
SEND_SOUND(target, sound(get_sfx("classic_death_sounds")))
else
SEND_SOUND(target, sound(get_sfx("fancy_death_prey")))
target.mind?.vore_death = TRUE
handle_digestion_death(target)
return TRUE
/obj/belly/proc/instant_break_bone(mob/user, mob/living/target)
if(!ishuman(target))
to_chat(user, span_vwarning("\The [target] has no breakable organs."))
return FALSE
if(target.absorbed)
to_chat(user, span_vwarning("\The [target] is absorbed, and cannot presently be broken."))
return FALSE
if(tgui_alert(target, "\The [user] is attempting to break one of your bones. Is this something you are okay with happening to you?","Break Bones", list("No", "Yes")) != "Yes")
to_chat(user, span_vwarning("\The [target] declined your breaking bones attempt."))
to_chat(target, span_vwarning("You declined the breaking bones attempt."))
return FALSE
if(target.loc != src)
to_chat(user, span_vwarning("\The [target] is no longer in \the [src]."))
return FALSE
var/mob/living/carbon/human/human_target = target
var/obj/item/organ/external/target_organ = pick(human_target.get_fracturable_organs())
if(!target_organ)
to_chat(user, span_vwarning("\The [target] has no breakable organs."))
return FALSE
to_chat(user, span_vwarning("You break [target]'s [target_organ]!"))
target_organ.fracture()
return TRUE
/obj/belly/proc/instant_absorb(mob/user, mob/living/target)
if(tgui_alert(target, "\The [user] is attempting to instantly absorb you. Is this something you are okay with happening to you?","Instant Absorb", list("No", "Yes")) != "Yes")
to_chat(user, span_vwarning("\The [target] declined your absorb attempt."))
to_chat(target, span_vwarning("You declined the absorb attempt."))
return FALSE
if(target.loc != src)
to_chat(user, span_vwarning("\The [target] is no longer in \the [src]."))
return FALSE
if(isliving(user))
var/mob/living/l = user
l.adjust_nutrition(target.nutrition)
var/n = 0 - target.nutrition
target.adjust_nutrition(n)
absorb_living(target)
return TRUE
/obj/belly/proc/instant_knockout(mob/user, mob/living/target)
if(tgui_alert(target, "\The [user] is attempting to instantly make you unconscious, you will be unable until ejected from the pred. Is this something you are okay with happening to you?","Instant Knockout", list("No", "Yes")) != "Yes")
to_chat(user, span_vwarning("\The [target] declined your knockout attempt."))
to_chat(target, span_vwarning("You declined the knockout attempt."))
return FALSE
if(target.loc != src)
to_chat(user, span_vwarning("\The [target] is no longer in \the [src]."))
return FALSE
target.AdjustSleeping(500000)
to_chat(target, span_vwarning("\The [user] has put you to sleep, you will remain unconscious until ejected from the belly."))
return TRUE
+9 -48
View File
@@ -1227,6 +1227,7 @@
if(ourtarget.digestable)
process_options += "Digest"
process_options += "Break Bone"
if(ourtarget.absorbable)
process_options += "Absorb"
@@ -1246,58 +1247,18 @@
to_chat(user, span_vwarning("You cannot instantly process [ourtarget]."))
return FALSE
var/obj/belly/b = ourtarget.loc
if(!istype(b) || b.owner != user)
to_chat(user, span_vwarning("[ourtarget] isn't in your belly."))
return FALSE
switch(ourchoice)
if("Digest")
if(ourtarget.absorbed)
to_chat(user, span_vwarning("\The [ourtarget] is absorbed, and cannot presently be digested."))
return FALSE
if(tgui_alert(ourtarget, "\The [user] is attempting to instantly digest you. Is this something you are okay with happening to you?","Instant Digest", list("No", "Yes")) != "Yes")
to_chat(user, span_vwarning("\The [ourtarget] declined your digest attempt."))
to_chat(ourtarget, span_vwarning("You declined the digest attempt."))
return FALSE
if(ourtarget.loc != b)
to_chat(user, span_vwarning("\The [ourtarget] is no longer in \the [b]."))
return FALSE
if(isliving(user))
var/mob/living/l = user
var/thismuch = ourtarget.health + 100
if(ishuman(l))
var/mob/living/carbon/human/h = l
thismuch = thismuch * h.species.digestion_nutrition_modifier
l.adjust_nutrition(thismuch)
ourtarget.death() // To make sure all on-death procs get properly called
if(ourtarget)
if(ourtarget.check_sound_preference(/datum/preference/toggle/digestion_noises))
if(!b.fancy_vore)
SEND_SOUND(ourtarget, sound(get_sfx("classic_death_sounds")))
else
SEND_SOUND(ourtarget, sound(get_sfx("fancy_death_prey")))
ourtarget.mind?.vore_death = TRUE
b.handle_digestion_death(ourtarget)
return b.instant_digest(user, ourtarget)
if("Break Bone")
return b.instant_break_bone(user, ourtarget)
if("Absorb")
if(tgui_alert(ourtarget, "\The [user] is attempting to instantly absorb you. Is this something you are okay with happening to you?","Instant Absorb", list("No", "Yes")) != "Yes")
to_chat(user, span_vwarning("\The [ourtarget] declined your absorb attempt."))
to_chat(ourtarget, span_vwarning("You declined the absorb attempt."))
return FALSE
if(ourtarget.loc != b)
to_chat(user, span_vwarning("\The [ourtarget] is no longer in \the [b]."))
return FALSE
if(isliving(user))
var/mob/living/l = user
l.adjust_nutrition(ourtarget.nutrition)
var/n = 0 - ourtarget.nutrition
ourtarget.adjust_nutrition(n)
b.absorb_living(ourtarget)
return b.instant_absorb(user, ourtarget)
if("Knockout")
if(tgui_alert(ourtarget, "\The [user] is attempting to instantly make you unconscious, you will be unable until ejected from the pred. Is this something you are okay with happening to you?","Instant Knockout", list("No", "Yes")) != "Yes")
to_chat(user, span_vwarning("\The [ourtarget] declined your knockout attempt."))
to_chat(ourtarget, span_vwarning("You declined the knockout attempt."))
return FALSE
if(ourtarget.loc != b)
to_chat(user, span_vwarning("\The [ourtarget] is no longer in \the [b]."))
return FALSE
ourtarget.AdjustSleeping(500000)
to_chat(ourtarget, span_vwarning("\The [user] has put you to sleep, you will remain unconscious until ejected from the belly."))
return b.instant_knockout(user, ourtarget)
if("Cancel")
return FALSE
if("Health Check")