diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm index ad3b71ceaa..994169dda6 100644 --- a/code/modules/mob/living/carbon/human/human_damage.dm +++ b/code/modules/mob/living/carbon/human/human_damage.dm @@ -409,6 +409,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 diff --git a/code/modules/organs/organ_external.dm b/code/modules/organs/organ_external.dm index 8cccedf6eb..4e28b0b544 100644 --- a/code/modules/organs/organ_external.dm +++ b/code/modules/organs/organ_external.dm @@ -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) @@ -1133,14 +1140,25 @@ Note that amputating the affected organ does in fact remove the infection from t return if(owner) - if(organ_can_feel_pain() && !isbelly(owner.loc) && !isliving(owner.loc) && !owner.transforming) - //CHOMPEdit Begin + 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) + // CHOMPEdit Start owner.custom_pain(pick(\ 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.")),brokenpain) - //CHOMPEdit End - owner.emote("scream") + span_danger("You hear a sickening crack.")), brokenpain) + // CHOMPEdit End + if(scream) + owner.emote("scream") jostle_bone() if(istype(owner.loc, /obj/belly)) //CHOMPedit, bone breaks in bellys should be whisper range to prevent bar wide blender prefbreak. This is a hacky passive hardcode, if a pref gets added, remove this if else diff --git a/code/modules/vore/eating/belly_actions.dm b/code/modules/vore/eating/belly_actions.dm new file mode 100644 index 0000000000..daa9cb068d --- /dev/null +++ b/code/modules/vore/eating/belly_actions.dm @@ -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 diff --git a/code/modules/vore/eating/vorepanel_vr.dm b/code/modules/vore/eating/vorepanel_vr.dm index 2639037df7..96c9f5b95a 100644 --- a/code/modules/vore/eating/vorepanel_vr.dm +++ b/code/modules/vore/eating/vorepanel_vr.dm @@ -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") diff --git a/vorestation.dme b/vorestation.dme index 2e16e50d44..e13eb49146 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -4660,6 +4660,7 @@ #include "code\modules\vore\appearance\preferences_vr.dm" #include "code\modules\vore\appearance\sprite_accessories_yw.dm" #include "code\modules\vore\appearance\update_icons_vr.dm" +#include "code\modules\vore\eating\belly_actions.dm" #include "code\modules\vore\eating\belly_dat_vr.dm" #include "code\modules\vore\eating\belly_import.dm" #include "code\modules\vore\eating\belly_messages.dm"