Refactors some embed stuff (#14183)

* Converts embedding into a proc

also adds a embed tic proc that is called whenever the embedde has a life tick

* a

* b
This commit is contained in:
nmajask
2022-05-21 22:45:46 -04:00
committed by GitHub
parent 983721ac92
commit dff69c9205
13 changed files with 192 additions and 108 deletions

View File

@@ -241,9 +241,9 @@ If you're feeling frisky, examine yourself and click the underlined item to pull
icon_state = "embeddedobject" icon_state = "embeddedobject"
/obj/screen/alert/embeddedobject/Click() /obj/screen/alert/embeddedobject/Click()
if(isliving(usr)) if(iscarbon(usr))
var/mob/living/carbon/human/M = usr var/mob/living/carbon/C = usr
return M.help_shake_act(M) return C.try_remove_embedded_object(C)
/obj/screen/alert/weightless /obj/screen/alert/weightless
name = "Weightless" name = "Weightless"

View File

@@ -878,3 +878,20 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
if(ismob(loc)) if(ismob(loc))
var/mob/mob_loc = loc var/mob/mob_loc = loc
mob_loc.regenerate_icons() mob_loc.regenerate_icons()
/**
* Called when this object is first embedded into a carbon
*/
/obj/item/proc/on_embed(mob/living/carbon/human/embedde, obj/item/bodypart/part)
return TRUE
/**
* Called when this object is no longer embedded into a carbon
*/
/obj/item/proc/on_embed_removal(mob/living/carbon/human/embedde)
return TRUE
/**
* Called every life tick when the object is embedded in a carbon
*/
/obj/item/proc/embed_tick(mob/living/carbon/human/embedde, obj/item/bodypart/part)
return

View File

@@ -274,6 +274,26 @@
visible_message(span_danger("[usr] [internal ? "opens" : "closes"] the valve on [src]'s [ITEM.name]."), \ visible_message(span_danger("[usr] [internal ? "opens" : "closes"] the valve on [src]'s [ITEM.name]."), \
span_userdanger("[usr] [internal ? "opens" : "closes"] the valve on [src]'s [ITEM.name].")) span_userdanger("[usr] [internal ? "opens" : "closes"] the valve on [src]'s [ITEM.name]."))
// Embed Stuff
if(href_list["embedded_object"] && usr.canUseTopic(src, BE_CLOSE, NO_DEXTERY))
var/obj/item/bodypart/L = locate(href_list["embedded_limb"]) in bodyparts
if(!L)
return
var/obj/item/I = locate(href_list["embedded_object"]) in L.embedded_objects
if(!I || I.loc != src) //no item, no limb, or item is not in limb or in the person anymore
return
var/time_taken = I.embedding.embedded_unsafe_removal_time*I.w_class
usr.visible_message(span_warning("[usr] attempts to remove [I] from [usr.p_their()] [L.name]."),span_notice("You attempt to remove [I] from your [L.name]... (It will take [DisplayTimeText(time_taken)].)"))
if(do_after(usr, time_taken, needhand = 1, target = src))
if(!I || !L || I.loc != src)
return
var/damage_amount = I.embedding.embedded_unsafe_removal_pain_multiplier * I.w_class
L.receive_damage(damage_amount, sharpness = SHARP_EDGED)//It hurts to rip it out, get surgery you dingus.
if(remove_embedded_object(I, get_turf(src), damage_amount))
usr.put_in_hands(I)
usr.visible_message("[usr] successfully rips [I] out of [usr.p_their()] [L.name]!", span_notice("You successfully remove [I] from your [L.name]."))
return
/mob/living/carbon/fall(forced) /mob/living/carbon/fall(forced)
if(loc) if(loc)
loc.handle_fall(src, forced)//it's loc so it doesn't call the mob's handle_fall which does nothing loc.handle_fall(src, forced)//it's loc so it doesn't call the mob's handle_fall which does nothing

View File

@@ -50,10 +50,15 @@
return TRUE return TRUE
/mob/living/carbon/hitby(atom/movable/AM, skipcatch, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum) /mob/living/carbon/hitby(atom/movable/AM, skipcatch, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum)
if(!skipcatch) //ugly, but easy var/obj/item/I = AM
if(can_catch_item()) if(istype(I, /obj/item))
if(istype(AM, /obj/item)) if(((throwingdatum ? throwingdatum.speed : I.throw_speed) >= EMBED_THROWSPEED_THRESHOLD) || I.embedding.embedded_ignore_throwspeed_threshold)
var/obj/item/I = AM var/obj/item/bodypart/body_part = pick(bodyparts)
if(prob(clamp(I.embedding.embed_chance - run_armor_check(body_part, MELEE), 0, 100)) && embed_object(I, deal_damage = TRUE))
hitpush = FALSE
skipcatch = TRUE //can't catch the now embedded item
if(!skipcatch) //ugly, but easy
if(can_catch_item())
if(I.item_flags & UNCATCHABLE) if(I.item_flags & UNCATCHABLE)
return FALSE return FALSE
if(isturf(I.loc)) if(isturf(I.loc))
@@ -68,6 +73,83 @@
return TRUE return TRUE
..() ..()
/**
* Embeds an object into this carbon
*/
/mob/living/carbon/proc/embed_object(obj/item/embedding, part, deal_damage, silent, forced)
if(!(forced || (can_embed(embedding) && !HAS_TRAIT(src, TRAIT_PIERCEIMMUNE))))
return FALSE
var/obj/item/bodypart/body_part = part
// In case its a zone
if(!istype(body_part) && body_part)
body_part = get_bodypart(body_part)
// Otherwise pick one
if(!istype(body_part))
body_part = pick(bodyparts)
// Thats probably not good
if(!istype(body_part))
return FALSE
if(!embedding.on_embed(src, body_part))
return
body_part.embedded_objects |= embedding
embedding.add_mob_blood(src)//it embedded itself in you, of course it's bloody!
embedding.forceMove(src)
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "embedded", /datum/mood_event/embedded)
if(deal_damage)
body_part.receive_damage(embedding.w_class*embedding.embedding.embedded_impact_pain_multiplier, wound_bonus=-30, sharpness = TRUE)
if(!silent)
throw_alert("embeddedobject", /obj/screen/alert/embeddedobject)
visible_message(span_danger("[embedding] embeds itself in [src]'s [body_part.name]!"), span_userdanger("[embedding] embeds itself in your [body_part.name]!"))
return TRUE
/**
* Removes the given embedded object from this carbon
*/
/mob/living/carbon/proc/remove_embedded_object(obj/item/embedded, new_loc, silent, forced)
var/obj/item/bodypart/body_part
for(var/obj/item/bodypart/part in bodyparts)
if(embedded in part.embedded_objects)
body_part = part
if(!body_part)
return
if(!embedded.on_embed_removal(src))
return
body_part.embedded_objects -= embedded
if(!silent)
emote("scream")
if(!has_embedded_objects())
clear_alert("embeddedobject")
SEND_SIGNAL(usr, COMSIG_CLEAR_MOOD_EVENT, "embedded")
if(new_loc)
embedded.forceMove(new_loc)
return TRUE
/**
* Called when a mob tries to remove an embedded object from this carbon
*/
/mob/living/carbon/proc/try_remove_embedded_object(mob/user)
var/list/choice_list = list()
var/obj/item/bodypart/body_part
for(var/obj/item/bodypart/part in bodyparts)
for(var/obj/item/embedded in part.embedded_objects)
choice_list[embedded] = image(embedded)
var/obj/item/choice = show_radial_menu(user, src, choice_list, tooltips = TRUE)
for(var/obj/item/bodypart/part in bodyparts)
if(choice in part.embedded_objects)
body_part = part
if(!istype(choice) || !(choice in choice_list))
return
var/time_taken = choice.embedding.embedded_unsafe_removal_time * choice.w_class
user.visible_message(span_warning("[user] attempts to remove [choice] from [usr.p_their()] [body_part.name]."),span_notice("You attempt to remove [choice] from your [body_part.name]... (It will take [DisplayTimeText(time_taken)].)"))
if(!do_after(user, time_taken, needhand = 1, target = src) && !(choice in body_part.embedded_objects))
return
var/damage_amount = choice.embedding.embedded_unsafe_removal_pain_multiplier * choice.w_class
body_part.receive_damage(damage_amount > 0, sharpness = SHARP_EDGED)//It hurts to rip it out, get surgery you dingus.
if(remove_embedded_object(choice, get_turf(src), damage_amount))
user.put_in_hands(choice)
user.visible_message("[user] successfully rips [choice] out of [user == src? p_their() : "[src]'s"] [body_part.name]!", span_notice("You successfully remove [choice] from your [body_part.name]."))
return TRUE
/mob/living/carbon/proc/get_interaction_efficiency(zone) /mob/living/carbon/proc/get_interaction_efficiency(zone)
var/obj/item/bodypart/limb = get_bodypart(zone) var/obj/item/bodypart/limb = get_bodypart(zone)
if(!limb) if(!limb)

View File

@@ -32,6 +32,17 @@
else if(get_bodypart(BODY_ZONE_HEAD)) else if(get_bodypart(BODY_ZONE_HEAD))
. += span_deadsay("It appears that [t_his] brain is missing...") . += span_deadsay("It appears that [t_his] brain is missing...")
var/list/disabled = list()
for(var/X in bodyparts)
var/obj/item/bodypart/body_part = X
if(body_part.bodypart_disabled)
disabled += body_part
for(var/obj/item/I in body_part.embedded_objects)
. += "<B>[t_He] [t_has] \a [icon2html(I, user)] [I] embedded in [t_his] [body_part.name]!</B>\n"
for(var/i in body_part.wounds)
var/datum/wound/iter_wound = i
. += "[iter_wound.get_examine_description(user)]\n"
var/list/missing = get_missing_limbs() var/list/missing = get_missing_limbs()
for(var/t in missing) for(var/t in missing)
if(t==BODY_ZONE_HEAD) if(t==BODY_ZONE_HEAD)
@@ -68,12 +79,6 @@
else else
msg += "<b>[t_He] [t_is] severely deformed!</b>\n" msg += "<b>[t_He] [t_is] severely deformed!</b>\n"
for(var/X in bodyparts)
var/obj/item/bodypart/BP = X
for(var/i in BP.wounds)
var/datum/wound/W = i
msg += "[W.get_examine_description(user)]\n"
if(HAS_TRAIT(src, TRAIT_DUMB)) if(HAS_TRAIT(src, TRAIT_DUMB))
msg += "[t_He] seem[p_s()] to be clumsy and unable to think.\n" msg += "[t_He] seem[p_s()] to be clumsy and unable to think.\n"

View File

@@ -231,29 +231,6 @@
spreadFire(AM) spreadFire(AM)
/mob/living/carbon/human/Topic(href, href_list) /mob/living/carbon/human/Topic(href, href_list)
if(href_list["embedded_object"] && usr.canUseTopic(src, BE_CLOSE, NO_DEXTERY))
var/obj/item/bodypart/L = locate(href_list["embedded_limb"]) in bodyparts
if(!L)
return
var/obj/item/I = locate(href_list["embedded_object"]) in L.embedded_objects
if(!I || I.loc != src) //no item, no limb, or item is not in limb or in the person anymore
return
var/time_taken = I.embedding.embedded_unsafe_removal_time*I.w_class
usr.visible_message(span_warning("[usr] attempts to remove [I] from [usr.p_their()] [L.name]."),span_notice("You attempt to remove [I] from your [L.name]... (It will take [DisplayTimeText(time_taken)].)"))
if(do_after(usr, time_taken, needhand = 1, target = src))
if(!I || !L || I.loc != src || !(I in L.embedded_objects))
return
L.embedded_objects -= I
L.receive_damage(I.embedding.embedded_unsafe_removal_pain_multiplier*I.w_class, sharpness=SHARP_EDGED)//It hurts to rip it out, get surgery you dingus.
I.forceMove(get_turf(src))
usr.put_in_hands(I)
usr.emote("scream")
usr.visible_message("[usr] successfully rips [I] out of [usr.p_their()] [L.name]!",span_notice("You successfully remove [I] from your [L.name]."))
if(!has_embedded_objects())
clear_alert("embeddedobject")
SEND_SIGNAL(usr, COMSIG_CLEAR_MOOD_EVENT, "embedded")
return
if(href_list["item"]) //canUseTopic check for this is handled by mob/Topic() if(href_list["item"]) //canUseTopic check for this is handled by mob/Topic()
var/slot = text2num(href_list["item"]) var/slot = text2num(href_list["item"])
if(slot in check_obscured_slots(TRUE)) if(slot in check_obscured_slots(TRUE))

View File

@@ -169,21 +169,6 @@
hitpush = FALSE hitpush = FALSE
skipcatch = TRUE skipcatch = TRUE
blocked = TRUE blocked = TRUE
else if(I)
if(((throwingdatum ? throwingdatum.speed : I.throw_speed) >= EMBED_THROWSPEED_THRESHOLD) || I.embedding.embedded_ignore_throwspeed_threshold)
if(can_embed(I))
if(prob(I.embedding.embed_chance) && !HAS_TRAIT(src, TRAIT_PIERCEIMMUNE))
throw_alert("embeddedobject", /obj/screen/alert/embeddedobject)
var/obj/item/bodypart/L = pick(bodyparts)
L.embedded_objects |= I
I.add_mob_blood(src)//it embedded itself in you, of course it's bloody!
I.forceMove(src)
L.receive_damage(I.w_class*I.embedding.embedded_impact_pain_multiplier, wound_bonus=-30, sharpness = TRUE)
visible_message(span_danger("[I] embeds itself in [src]'s [L.name]!"),span_userdanger("[I] embeds itself in your [L.name]!"))
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "embedded", /datum/mood_event/embedded)
hitpush = FALSE
skipcatch = TRUE //can't catch the now embedded item
return ..() return ..()
/mob/living/carbon/human/grippedby(mob/living/user, instant = FALSE) /mob/living/carbon/human/grippedby(mob/living/user, instant = FALSE)

View File

@@ -38,10 +38,6 @@
//heart attack stuff //heart attack stuff
handle_heart() handle_heart()
if(stat != DEAD)
//Stuff jammed in your limbs hurts
handle_embedded_objects()
dna.species.spec_life(src) // for mutantraces dna.species.spec_life(src) // for mutantraces
else else
for(var/i in all_wounds) for(var/i in all_wounds)
@@ -307,31 +303,6 @@
return TRUE return TRUE
return ..() return ..()
/mob/living/carbon/human/proc/handle_embedded_objects()
for(var/X in bodyparts)
var/obj/item/bodypart/BP = X
for(var/obj/item/I in BP.embedded_objects)
var/pain_chance_current = I.embedding.embedded_pain_chance
if(!(mobility_flags & MOBILITY_STAND))
pain_chance_current *= 0.2
if(prob(pain_chance_current))
BP.receive_damage(I.w_class*I.embedding.embedded_pain_multiplier, wound_bonus = CANT_WOUND)
to_chat(src, span_userdanger("[I] embedded in your [BP.name] hurts!"))
var/fall_chance_current = I.embedding.embedded_fall_chance
if(!(mobility_flags & MOBILITY_STAND))
fall_chance_current *= 0.2
if(prob(fall_chance_current))
BP.receive_damage(I.w_class*I.embedding.embedded_fall_pain_multiplier, wound_bonus = CANT_WOUND) // can wound
BP.embedded_objects -= I
I.forceMove(drop_location())
visible_message(span_danger("[I] falls out of [name]'s [BP.name]!"),span_userdanger("[I] falls out of your [BP.name]!"))
if(!has_embedded_objects())
clear_alert("embeddedobject")
SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "embedded")
/mob/living/carbon/human/proc/handle_heart() /mob/living/carbon/human/proc/handle_heart()
var/we_breath = !HAS_TRAIT_FROM(src, TRAIT_NOBREATH, SPECIES_TRAIT) var/we_breath = !HAS_TRAIT_FROM(src, TRAIT_NOBREATH, SPECIES_TRAIT)

View File

@@ -37,6 +37,10 @@
if(stat != DEAD) if(stat != DEAD)
handle_liver() handle_liver()
if(stat != DEAD)
//Stuff jammed in your limbs hurts
handle_embedded_objects()
else else
. = ..() . = ..()
@@ -650,6 +654,35 @@ GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put
var/datum/brain_trauma/BT = T var/datum/brain_trauma/BT = T
BT.on_life() BT.on_life()
////////////
// EMBEDS //
////////////
/mob/living/carbon/proc/handle_embedded_objects()
for(var/X in bodyparts)
var/obj/item/bodypart/BP = X
for(var/obj/item/I in BP.embedded_objects)
I.embed_tick(src, BP)
var/pain_chance_current = I.embedding.embedded_pain_chance
if(!(mobility_flags & MOBILITY_STAND))
pain_chance_current *= 0.2
if(prob(pain_chance_current))
BP.receive_damage(I.w_class*I.embedding.embedded_pain_multiplier, wound_bonus = CANT_WOUND)
to_chat(src, span_userdanger("[I] embedded in your [BP.name] hurts!"))
var/fall_chance_current = I.embedding.embedded_fall_chance
if(!(mobility_flags & MOBILITY_STAND))
fall_chance_current *= 0.2
if(prob(fall_chance_current))
BP.receive_damage(I.w_class*I.embedding.embedded_fall_pain_multiplier, wound_bonus = CANT_WOUND) // can wound
remove_embedded_object(I, drop_location(), FALSE)
visible_message(span_danger("[I] falls out of [name]'s [BP.name]!"), span_userdanger("[I] falls out of your [BP.name]!"))
if(!has_embedded_objects())
clear_alert("embeddedobject")
SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "embedded")
///////////////////////////////////// /////////////////////////////////////
//MONKEYS WITH TOO MUCH CHOLOESTROL// //MONKEYS WITH TOO MUCH CHOLOESTROL//
///////////////////////////////////// /////////////////////////////////////

View File

@@ -86,11 +86,8 @@
for(var/X in C.bodyparts) for(var/X in C.bodyparts)
var/obj/item/bodypart/part = X var/obj/item/bodypart/part = X
if(item_to_retrieve in part.embedded_objects) if(item_to_retrieve in part.embedded_objects)
part.embedded_objects -= item_to_retrieve C.remove_embedded_object(item_to_retrieve, silent = TRUE, forced = TRUE)
to_chat(C, span_warning("The [item_to_retrieve] that was embedded in your [L] has mysteriously vanished. How fortunate!")) to_chat(C, span_warning("The [item_to_retrieve] that was embedded in your [L] has mysteriously vanished. How fortunate!"))
if(!C.has_embedded_objects())
C.clear_alert("embeddedobject")
SEND_SIGNAL(C, COMSIG_CLEAR_MOOD_EVENT, "embedded")
break break
else else

View File

@@ -104,8 +104,7 @@
break break
for(var/obj/item/I in embedded_objects) for(var/obj/item/I in embedded_objects)
embedded_objects -= I phantom_owner.remove_embedded_object(I, src, TRUE, TRUE)
I.forceMove(src)
if(!phantom_owner.has_embedded_objects()) if(!phantom_owner.has_embedded_objects())
phantom_owner.clear_alert("embeddedobject") phantom_owner.clear_alert("embeddedobject")
SEND_SIGNAL(phantom_owner, COMSIG_CLEAR_MOOD_EVENT, "embedded") SEND_SIGNAL(phantom_owner, COMSIG_CLEAR_MOOD_EVENT, "embedded")

View File

@@ -161,6 +161,7 @@
for(var/X in bodyparts) for(var/X in bodyparts)
var/obj/item/bodypart/L = X var/obj/item/bodypart/L = X
for(var/obj/item/I in L.embedded_objects) for(var/obj/item/I in L.embedded_objects)
remove_embedded_object(I, T, TRUE, TRUE)
L.embedded_objects -= I L.embedded_objects -= I
I.forceMove(T) I.forceMove(T)
@@ -168,11 +169,11 @@
SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "embedded") SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "embedded")
/mob/living/carbon/proc/has_embedded_objects() /mob/living/carbon/proc/has_embedded_objects()
. = 0 . = FALSE
for(var/X in bodyparts) for(var/X in bodyparts)
var/obj/item/bodypart/L = X var/obj/item/bodypart/L = X
for(var/obj/item/I in L.embedded_objects) for(var/obj/item/I in L.embedded_objects)
return 1 return TRUE
//Helper for quickly creating a new limb - used by augment code in species.dm spec_attacked_by //Helper for quickly creating a new limb - used by augment code in species.dm spec_attacked_by

View File

@@ -1,14 +1,16 @@
/datum/surgery/embedded_removal /datum/surgery/embedded_removal
name = "Removal of embedded objects" name = "Removal of embedded objects"
steps = list(/datum/surgery_step/incise, /datum/surgery_step/remove_object) steps = list(/datum/surgery_step/incise, /datum/surgery_step/remove_object, /datum/surgery_step/close)
possible_locs = list(BODY_ZONE_R_ARM,BODY_ZONE_L_ARM,BODY_ZONE_R_LEG,BODY_ZONE_L_LEG,BODY_ZONE_CHEST,BODY_ZONE_HEAD) possible_locs = list(BODY_ZONE_R_ARM,BODY_ZONE_L_ARM,BODY_ZONE_R_LEG,BODY_ZONE_L_LEG,BODY_ZONE_CHEST,BODY_ZONE_HEAD)
/datum/surgery_step/remove_object /datum/surgery_step/remove_object
name = "remove embedded objects" name = "remove embedded objects"
time = 32 time = 1.5 SECONDS
accept_hand = 1 accept_hand = TRUE
fuckup_damage = 0 fuckup_damage = 0
repeatable = TRUE
var/obj/item/target_item = null
var/obj/item/bodypart/L = null var/obj/item/bodypart/L = null
@@ -25,25 +27,20 @@
/datum/surgery_step/remove_object/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) /datum/surgery_step/remove_object/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
if(L) if(L)
if(ishuman(target)) if(iscarbon(target))
var/mob/living/carbon/human/H = target if(L.embedded_objects)
var/objects = 0 var/mob/living/carbon/C = target
for(var/obj/item/I in L.embedded_objects) var/obj/item/I = pick(L.embedded_objects)
objects++ if(C.remove_embedded_object(I, C.drop_location(), TRUE))
I.forceMove(get_turf(H)) display_results(user, target, span_notice("You successfully remove \the [I] from [C]'s [L.name]."),
L.embedded_objects -= I "[user] successfully removes \the [I] from [C]'s [L]!",
if(!H.has_embedded_objects()) "[user] successfully removes \the [I] from [C]'s [L]!")
H.clear_alert("embeddedobject") else
SEND_SIGNAL(H, COMSIG_CLEAR_MOOD_EVENT, "embedded") to_chat(user, span_warning("You fail to remove \the [I] from [C]'s [L.name]!"))
if(objects > 0)
display_results(user, target, span_notice("You successfully remove [objects] objects from [H]'s [L.name]."),
"[user] successfully removes [objects] objects from [H]'s [L]!",
"[user] successfully removes [objects] objects from [H]'s [L]!")
else else
to_chat(user, span_warning("You find no objects embedded in [H]'s [L]!")) to_chat(user, span_warning("You find no objects embedded in [target]'s [L]!"))
else else
to_chat(user, span_warning("You can't find [target]'s [parse_zone(user.zone_selected)], let alone any objects embedded in it!")) to_chat(user, span_warning("You can't find [target]'s [parse_zone(user.zone_selected)], let alone any objects embedded in it!"))
return 1 return FALSE