Files
Aurora.3/code/modules/surgery/implant.dm
T
AlaunusLuxandGitHub 6bf406067c Various Borer fixes (#18969)
I changed add_antag to add_antag_mind in borer/LateLogin because the
former proc re-created the borer, causing it to drop the src/client
reference. The only notable difference I observe is the antag noise
doesn't play, which could be added manually if needed. Alternative
methods to solve this would be welcome, though. I did have an
alternative method
[here](https://github.com/Aurorastation/Aurora.3/commit/5d4157588baa0998f499aba7678bf8c6551247ca),
but that only "fixed" the ghost spawner, not admin possession. I also
say "fixed" because that method does not give the post ghost-spawn
message.


Fixes #18600 

- The implant check was only checking for objs, which the borer implant
is not. The borer was also erroneously being removed from the implants
list when releasing control back to their host.

Fixes #18281 

- This had a few pain points. psi was null, so it made the callback for
activating powers fail. Once that was fixed, it caused many RTEs when
trying to draw the HUD/screen for the powers. Refactoring a few
encoding/decoding procs fixed that.
Fixing these issues fixed borer monkeys not being able to speak TCB,
which is strange because I thought I'd seen a borer monkey speaking TCB
during a round where the psychic bug existed.

Fixes #9621 

- For this, I switched rejuvenate to revive. This lets them move, and
also does not kill them again due to brain damage. If it proves to be
too strong, it can be tweaked, but I did want to get brain devouring
working for this PR.

- There's also the jumpstart verb, which seems will never be used with
this revive in place (or even before, with the rejuvenate). I suppose it
can be used if they die again after reviving.

- Should a message be added to the revive given during the devouring
process? Jumpstart gives one:

`visible_message(SPAN_WARNING("With a hideous, rattling moan, [src]
shudders back to life!"))`

Fixes #9523


Also fixes borers not being able to infest someone they are being held
by.

Existing Issues not addressed by this PR:
- Infesting a monkey does not give you the monkey's health HUD (because
it doesn't exist?). Assuming and releasing control will show it, though.
- Borer antag overlay icons on Mobs seems inconsistent. potentially due
to testing methods with clientless mobs
- Borers cannot use psychic lance while being held
- Psi aura on first receiving powers. Equip first ability and drop to
fix.

---------

Signed-off-by: AlaunusLux <89751433+AlaunusLux@users.noreply.github.com>
2024-06-08 16:54:28 +00:00

230 lines
9.8 KiB
Plaintext

//Procedures in this file: Putting items in body cavity. Implant removal. Items removal.
//////////////////////////////////////////////////////////////////
// ITEM PLACEMENT SURGERY //
//////////////////////////////////////////////////////////////////
/singleton/surgery_step/cavity
priority = 1
/singleton/surgery_step/cavity/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
if(!..())
return FALSE
var/obj/item/organ/external/affected = target.get_organ(target_zone)
return affected && IS_ORGAN_FULLY_OPEN && !(affected.status & ORGAN_BLEEDING)
/singleton/surgery_step/cavity/proc/get_max_wclass(var/obj/item/organ/external/affected)
switch(affected.name)
if(BP_HEAD)
return ITEMSIZE_TINY
if("upper body")
return ITEMSIZE_NORMAL
if("lower body")
return ITEMSIZE_SMALL
return 0
/singleton/surgery_step/cavity/proc/get_cavity(var/obj/item/organ/external/affected)
switch(affected.name)
if(BP_HEAD)
return "cranial"
if("upper body")
return "thoracic"
if("lower body")
return "abdominal"
return ""
/singleton/surgery_step/cavity/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
var/obj/item/organ/external/chest/affected = target.get_organ(target_zone)
user.visible_message(SPAN_WARNING("[user]'s hand slips, scraping around inside [target]'s [affected.name] with \the [tool]!"), \
SPAN_WARNING("Your hand slips, scraping around inside [target]'s [affected.name] with \the [tool]!"))
target.apply_damage(20, DAMAGE_BRUTE, target_zone, 0, tool, damage_flags = tool.damage_flags())
/singleton/surgery_step/cavity/make_space
name = "Hollow Out Cavity"
allowed_tools = list(
/obj/item/surgery/surgicaldrill = 100, \
/obj/item/pen = 75, \
/obj/item/stack/rods = 50
)
min_duration = 50
max_duration = 70
/singleton/surgery_step/cavity/make_space/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
if(!..())
return FALSE
var/obj/item/organ/external/affected = target.get_organ(target_zone)
return affected && !affected.cavity
/singleton/surgery_step/cavity/make_space/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
var/obj/item/organ/external/affected = target.get_organ(target_zone)
user.visible_message("[user] starts making some space inside [target]'s [get_cavity(affected)] cavity with \the [tool].", \
"You start making some space inside [target]'s [get_cavity(affected)] cavity with \the [tool]." )
target.custom_pain("The pain in your chest is living hell!",1)
affected.cavity = CAVITY_OPEN
..()
/singleton/surgery_step/cavity/make_space/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
var/obj/item/organ/external/chest/affected = target.get_organ(target_zone)
user.visible_message("<b>[user]</b> pushes apart some organs inside [target]'s [get_cavity(affected)] cavity with \the [tool].", \
SPAN_NOTICE("You make some space inside [target]'s [get_cavity(affected)] cavity with \the [tool].") )
/singleton/surgery_step/cavity/close_space
name = "Close Cavity"
priority = 2
allowed_tools = list(
/obj/item/surgery/cautery = 100, \
/obj/item/clothing/mask/smokable/cigarette = 75, \
/obj/item/flame/lighter = 50, \
/obj/item/weldingtool = 25
)
min_duration = 50
max_duration = 70
/singleton/surgery_step/cavity/close_space/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
if(!..())
return FALSE
var/obj/item/organ/external/affected = target.get_organ(target_zone)
return affected && affected.cavity
/singleton/surgery_step/cavity/close_space/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
var/obj/item/organ/external/affected = target.get_organ(target_zone)
user.visible_message("<b>[user]</b> starts mending [target]'s [get_cavity(affected)] cavity wall with \the [tool].", \
"You start mending [target]'s [get_cavity(affected)] cavity wall with \the [tool]." )
target.custom_pain("The pain in your chest is living hell!", 75)
affected.cavity = CAVITY_CLOSED
..()
/singleton/surgery_step/cavity/close_space/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
var/obj/item/organ/external/chest/affected = target.get_organ(target_zone)
user.visible_message("<b>[user]</b> mends [target]'s [get_cavity(affected)] cavity walls with \the [tool].", \
SPAN_NOTICE("You mend [target]'s [get_cavity(affected)] cavity walls with \the [tool].") )
/singleton/surgery_step/cavity/place_item
name = "Place Item in Cavity"
priority = 0
allowed_tools = list(/obj/item = 100)
min_duration = 60
max_duration = 80
/singleton/surgery_step/cavity/place_item/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
if(!..())
return FALSE
var/obj/item/organ/external/affected = target.get_organ(target_zone)
if(istype(user,/mob/living/silicon/robot))
return
if(affected && affected.cavity)
var/total_volume = tool.w_class
for(var/obj/item/I in affected.implants)
if(istype(I,/obj/item/implant))
continue
total_volume += I.w_class
return total_volume <= get_max_wclass(affected)
/singleton/surgery_step/cavity/place_item/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
var/obj/item/organ/external/affected = target.get_organ(target_zone)
user.visible_message("<b>[user]</b> starts putting \the [tool] inside [target]'s [get_cavity(affected)] cavity.", \
SPAN_NOTICE("You start putting \the [tool] inside [target]'s [get_cavity(affected)] cavity." ))
target.custom_pain("The pain in your chest is living hell!", 75)
playsound(target.loc, 'sound/effects/squelch1.ogg', 50, 1)
..()
/singleton/surgery_step/cavity/place_item/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
var/obj/item/organ/external/chest/affected = target.get_organ(target_zone)
user.visible_message("<b>[user]</b> puts \the [tool] inside [target]'s [get_cavity(affected)] cavity.", \
SPAN_NOTICE("You put \the [tool] inside [target]'s [get_cavity(affected)] cavity.") )
if(tool.w_class > get_max_wclass(affected)/2 && prob(50) && !BP_IS_ROBOTIC(affected))
to_chat(user, SPAN_WARNING("You tear \the [affected.artery_name] trying to fit an object so big!"))
affected.sever_artery()
affected.owner.custom_pain("You feel something rip in your [affected.name]!", 1)
user.drop_item()
affected.implants += tool
if(istype(tool, /obj/item/device/gps))
var/obj/item/device/gps/gps = tool
GLOB.moved_event.register(target, gps, TYPE_PROC_REF(/obj/item/device/gps, update_position))
gps.implanted_into = target
tool.forceMove(affected)
affected.cavity = CAVITY_CLOSED
//////////////////////////////////////////////////////////////////
// IMPLANT/ITEM REMOVAL SURGERY //
//////////////////////////////////////////////////////////////////
/singleton/surgery_step/cavity/implant_removal
name = "Remove Foreign Body"
allowed_tools = list(
/obj/item/surgery/hemostat = 100, \
WIRECUTTER = 75, \
/obj/item/material/kitchen/utensil/fork = 20
)
min_duration = 60
max_duration = 80
/singleton/surgery_step/cavity/implant_removal/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
if(!..())
return FALSE
var/obj/item/organ/external/affected = target.get_organ(target_zone)
return affected
/singleton/surgery_step/cavity/implant_removal/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
var/obj/item/organ/external/affected = target.get_organ(target_zone)
user.visible_message("[user] starts poking around inside [target]'s [affected.name] with \the [tool].", \
"You start poking around inside [target]'s [affected.name] with \the [tool]." )
target.custom_pain("The pain in your [affected.name] is living hell!", 50)
..()
/singleton/surgery_step/cavity/implant_removal/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
var/obj/item/organ/external/chest/affected = target.get_organ(target_zone)
if(length(affected.implants))
var/list/implants = list()
var/shrapnel_present = FALSE
for(var/I in affected.implants)
implants += I
if(!istype(I, /obj/item/implant))
shrapnel_present = TRUE
for(var/I in implants)
/// Prioritize shrapnel instead of stuff like loyalty implants.
if(shrapnel_present && istype(I, /obj/item/implant))
continue
if(do_mob(user, target, 0.5 SECONDS))
user.visible_message("<b>[user]</b> takes [I] out of incision on [target]'s [affected.name] with \the [tool].", \
SPAN_NOTICE("You take [I] out of incision on [target]'s [affected.name]s with \the [tool].") )
target.remove_implant(I, TRUE, affected)
BITSET(target.hud_updateflag, IMPLOYAL_HUD)
//Handle possessive brain borers.
if(istype(I, /mob/living/simple_animal/borer))
var/mob/living/simple_animal/borer/worm = I
if(worm.controlling)
target.release_control()
worm.detach()
worm.leave_host()
else if(istype(I, /obj/item/device/gps))
var/obj/item/device/gps/gps = I
GLOB.moved_event.unregister(target, gps)
gps.implanted_into = null
playsound(target.loc, 'sound/effects/squelch1.ogg', 50, 1)
else
user.visible_message("<b>[user]</b> could not find anything inside [target]'s [affected.name], and pulls \the [tool] out.", \
SPAN_NOTICE("You could not find anything inside [target]'s [affected.name].") )
/singleton/surgery_step/cavity/implant_removal/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
..()
var/obj/item/organ/external/chest/affected = target.get_organ(target_zone)
user.visible_message(SPAN_WARNING("[user] loses their grip and stabs [target] with \the [tool]!"), SPAN_WARNING("You lose your grip on \the [tool] and stab [target]!"))
affected.sever_artery()
target.apply_damage(25, DAMAGE_BRUTE, target_zone)