Skip to content
This repository was archived by the owner on May 22, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions code/_onclick/hud/alert.dm
Original file line number Diff line number Diff line change
Expand Up @@ -241,9 +241,9 @@ If you're feeling frisky, examine yourself and click the underlined item to pull
icon_state = "embeddedobject"

/obj/screen/alert/embeddedobject/Click()
if(isliving(usr))
var/mob/living/carbon/human/M = usr
return M.help_shake_act(M)
if(iscarbon(usr))
var/mob/living/carbon/C = usr
return C.try_remove_embedded_object(C)

/obj/screen/alert/weightless
name = "Weightless"
Expand Down
17 changes: 17 additions & 0 deletions code/game/objects/items.dm
Original file line number Diff line number Diff line change
Expand Up @@ -878,3 +878,20 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
if(ismob(loc))
var/mob/mob_loc = loc
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
20 changes: 20 additions & 0 deletions code/modules/mob/living/carbon/carbon.dm
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,26 @@
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]."))

// 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)
if(loc)
loc.handle_fall(src, forced)//it's loc so it doesn't call the mob's handle_fall which does nothing
Expand Down
90 changes: 86 additions & 4 deletions code/modules/mob/living/carbon/carbon_defense.dm
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,15 @@
return TRUE

/mob/living/carbon/hitby(atom/movable/AM, skipcatch, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum)
if(!skipcatch) //ugly, but easy
if(can_catch_item())
if(istype(AM, /obj/item))
var/obj/item/I = AM
var/obj/item/I = AM
if(istype(I, /obj/item))
if(((throwingdatum ? throwingdatum.speed : I.throw_speed) >= EMBED_THROWSPEED_THRESHOLD) || I.embedding.embedded_ignore_throwspeed_threshold)
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)
return FALSE
if(isturf(I.loc))
Expand All @@ -68,6 +73,83 @@
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)
var/obj/item/bodypart/limb = get_bodypart(zone)
if(!limb)
Expand Down
17 changes: 11 additions & 6 deletions code/modules/mob/living/carbon/examine.dm
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,17 @@
else if(get_bodypart(BODY_ZONE_HEAD))
. += 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()
for(var/t in missing)
if(t==BODY_ZONE_HEAD)
Expand Down Expand Up @@ -68,12 +79,6 @@
else
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))
msg += "[t_He] seem[p_s()] to be clumsy and unable to think.\n"

Expand Down
23 changes: 0 additions & 23 deletions code/modules/mob/living/carbon/human/human.dm
Original file line number Diff line number Diff line change
Expand Up @@ -231,29 +231,6 @@
spreadFire(AM)

/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()
var/slot = text2num(href_list["item"])
if(slot in check_obscured_slots(TRUE))
Expand Down
15 changes: 0 additions & 15 deletions code/modules/mob/living/carbon/human/human_defense.dm
Original file line number Diff line number Diff line change
Expand Up @@ -169,21 +169,6 @@
hitpush = FALSE
skipcatch = 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 ..()

/mob/living/carbon/human/grippedby(mob/living/user, instant = FALSE)
Expand Down
29 changes: 0 additions & 29 deletions code/modules/mob/living/carbon/human/life.dm
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,6 @@
//heart attack stuff
handle_heart()

if(stat != DEAD)
//Stuff jammed in your limbs hurts
handle_embedded_objects()

dna.species.spec_life(src) // for mutantraces
else
for(var/i in all_wounds)
Expand Down Expand Up @@ -307,31 +303,6 @@
return TRUE
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()
var/we_breath = !HAS_TRAIT_FROM(src, TRAIT_NOBREATH, SPECIES_TRAIT)

Expand Down
33 changes: 33 additions & 0 deletions code/modules/mob/living/carbon/life.dm
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@
if(stat != DEAD)
handle_liver()

if(stat != DEAD)
//Stuff jammed in your limbs hurts
handle_embedded_objects()

else
. = ..()

Expand Down Expand Up @@ -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
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//
/////////////////////////////////////
Expand Down
5 changes: 1 addition & 4 deletions code/modules/spells/spell_types/summonitem.dm
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,8 @@
for(var/X in C.bodyparts)
var/obj/item/bodypart/part = X
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!"))
if(!C.has_embedded_objects())
C.clear_alert("embeddedobject")
SEND_SIGNAL(C, COMSIG_CLEAR_MOOD_EVENT, "embedded")
break

else
Expand Down
3 changes: 1 addition & 2 deletions code/modules/surgery/bodyparts/dismemberment.dm
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,7 @@
break

for(var/obj/item/I in embedded_objects)
embedded_objects -= I
I.forceMove(src)
phantom_owner.remove_embedded_object(I, src, TRUE, TRUE)
if(!phantom_owner.has_embedded_objects())
phantom_owner.clear_alert("embeddedobject")
SEND_SIGNAL(phantom_owner, COMSIG_CLEAR_MOOD_EVENT, "embedded")
Expand Down
5 changes: 3 additions & 2 deletions code/modules/surgery/bodyparts/helpers.dm
Original file line number Diff line number Diff line change
Expand Up @@ -161,18 +161,19 @@
for(var/X in bodyparts)
var/obj/item/bodypart/L = X
for(var/obj/item/I in L.embedded_objects)
remove_embedded_object(I, T, TRUE, TRUE)
L.embedded_objects -= I
I.forceMove(T)

clear_alert("embeddedobject")
SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "embedded")

/mob/living/carbon/proc/has_embedded_objects()
. = 0
. = FALSE
for(var/X in bodyparts)
var/obj/item/bodypart/L = X
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
Expand Down
Loading