diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm
index 499be494056..71c6bac6979 100644
--- a/code/__DEFINES/combat.dm
+++ b/code/__DEFINES/combat.dm
@@ -63,6 +63,17 @@
#define THROWN_PROJECTILE_ATTACK 4
#define LEAP_ATTACK 5
+//Embedded objects
+#define EMBEDDED_PAIN_CHANCE 15 //Chance for embedded objects to cause pain (damage user)
+#define EMBEDDED_ITEM_FALLOUT 5 //Chance for embedded object to fall out (causing pain but removing the object)
+#define EMBED_CHANCE 45 //Chance for an object to embed into somebody when thrown (if it's sharp)
+#define EMBEDDED_PAIN_MULTIPLIER 2 //Coefficient of multiplication for the damage the item does while embedded (this*item.w_class)
+#define EMBEDDED_FALL_PAIN_MULTIPLIER 5 //Coefficient of multiplication for the damage the item does when it falls out (this*item.w_class)
+#define EMBEDDED_IMPACT_PAIN_MULTIPLIER 4 //Coefficient of multiplication for the damage the item does when it first embeds (this*item.w_class)
+#define EMBED_THROWSPEED_THRESHOLD 4 //The minimum value of an item's throw_speed for it to embed (Unless it has embedded_ignore_throwspeed_threshold set to 1)
+#define EMBEDDED_UNSAFE_REMOVAL_PAIN_MULTIPLIER 8 //Coefficient of multiplication for the damage the item does when removed without a surgery (this*item.w_class)
+#define EMBEDDED_UNSAFE_REMOVAL_TIME 30 //A Time in ticks, total removal time = (this*item.w_class)
+
//Gun Stuff
#define SAWN_INTACT 0
#define SAWN_OFF 1
diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm
index a27e3f8e96a..d708813b139 100644
--- a/code/__DEFINES/is_helpers.dm
+++ b/code/__DEFINES/is_helpers.dm
@@ -2,9 +2,19 @@
#define isatom(A) istype(A, /atom)
#define ismovableatom(A) istype(A, /atom/movable)
-// Mobs
+// Mobs
#define ismegafauna(A) istype(A, /mob/living/simple_animal/hostile/megafauna)
+//Objects
+
+var/list/static/global/pointed_types = typecacheof(list(
+ /obj/item/weapon/pen,
+ /obj/item/weapon/screwdriver,
+ /obj/item/weapon/reagent_containers/syringe,
+ /obj/item/weapon/kitchen/utensil/fork))
+
+#define is_pointed(W) (is_type_in_typecache(W, pointed_types))
+
//Turfs
#define issimulatedturf(A) istype(A, /turf/simulated)
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index 82b2ea8b419..c90db77effb 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -1081,6 +1081,21 @@ proc/get_mob_with_client_list()
return get_turf(location)
+//For objects that should embed, but make no sense being is_sharp or is_pointed()
+//e.g: rods
+var/list/can_embed_types = typecacheof(list(
+ /obj/item/stack/rods,
+ /obj/item/pipe))
+
+/proc/can_embed(obj/item/W)
+ if(is_sharp(W))
+ return 1
+ if(is_pointed(W))
+ return 1
+
+ if(is_type_in_typecache(W, can_embed_types))
+ return 1
+
//Quick type checks for some tools
var/global/list/common_tools = list(
/obj/item/stack/cable_coil,
@@ -1199,22 +1214,6 @@ var/global/list/common_tools = list(
if(O.edge) return 1
return 0
-//Returns 1 if the given item is capable of popping things like balloons, inflatable barriers, or cutting police tape.
-/proc/can_puncture(obj/item/W as obj) // For the record, WHAT THE HELL IS THIS METHOD OF DOING IT?
- if(!istype(W)) return 0
- if(!W) return 0
- if(W.sharp) return 1
- return ( \
- W.sharp || \
- istype(W, /obj/item/weapon/screwdriver) || \
- istype(W, /obj/item/weapon/pen) || \
- istype(W, /obj/item/weapon/weldingtool) || \
- istype(W, /obj/item/weapon/lighter/zippo) || \
- istype(W, /obj/item/weapon/match) || \
- istype(W, /obj/item/clothing/mask/cigarette) || \
- istype(W, /obj/item/weapon/shovel) \
- )
-
/proc/is_surgery_tool(obj/item/W as obj)
return ( \
istype(W, /obj/item/weapon/scalpel) || \
@@ -1891,4 +1890,4 @@ var/global/list/g_fancy_list_of_types = null
var/num = pick(num_sample)
num_sample -= num
result += (1 << num)
- return result
+ return result
diff --git a/code/datums/spells/summonitem.dm b/code/datums/spells/summonitem.dm
index 32472fe1ec0..bb650eb17f9 100644
--- a/code/datums/spells/summonitem.dm
+++ b/code/datums/spells/summonitem.dm
@@ -79,6 +79,14 @@
add_logs(target, C, "magically debrained", addition="INTENT: [uppertext(target.a_intent)]")*/
if(C.stomach_contents && item_to_retrive in C.stomach_contents)
C.stomach_contents -= item_to_retrive
+ for(var/X in C.bodyparts)
+ var/obj/item/organ/external/part = X
+ if(item_to_retrive in part.embedded_objects)
+ part.embedded_objects -= item_to_retrive
+ to_chat(C, "The [item_to_retrive] that was embedded in your [part] has myseriously vanished. How fortunate!")
+ if(!C.has_embedded_objects())
+ C.clear_alert("embeddedobject")
+ break
else
if(istype(item_to_retrive.loc,/obj/machinery/portable_atmospherics/)) //Edge cases for moved machinery
diff --git a/code/game/gamemodes/changeling/powers/revive.dm b/code/game/gamemodes/changeling/powers/revive.dm
index 5fd98986332..9077f623a2c 100644
--- a/code/game/gamemodes/changeling/powers/revive.dm
+++ b/code/game/gamemodes/changeling/powers/revive.dm
@@ -39,10 +39,6 @@
var/obj/item/organ/external/O = H.bodyparts_by_name[organ_name]
if(!O)
continue
- for(var/obj/item/weapon/shard/shrapnel/s in O.implants)
- O.implants -= s
- H.contents -= s
- qdel(s)
O.brute_dam = 0
O.burn_dam = 0
O.damage_state = "00"
@@ -58,6 +54,7 @@
for(var/obj/item/organ/internal/IO in H.internal_organs)
IO.damage = 0
IO.trace_chemicals.Cut()
+ H.remove_all_embedded_objects()
H.updatehealth()
to_chat(user, "We have regenerated.")
diff --git a/code/game/gamemodes/miniantags/borer/borer.dm b/code/game/gamemodes/miniantags/borer/borer.dm
index ea92b93f473..77a0803a706 100644
--- a/code/game/gamemodes/miniantags/borer/borer.dm
+++ b/code/game/gamemodes/miniantags/borer/borer.dm
@@ -361,11 +361,6 @@
host = M
forceMove(M)
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- var/obj/item/organ/external/head = H.get_organ("head")
- head.implants += src
-
host.status_flags |= PASSEMOTES
RemoveBorerActions()
@@ -746,11 +741,6 @@
controlling = FALSE
- if(ishuman(host))
- var/mob/living/carbon/human/H = host
- var/obj/item/organ/external/head = H.get_organ("head")
- head.implants -= src
-
reset_perspective(null)
machine = null
diff --git a/code/game/gamemodes/wizard/artefact.dm b/code/game/gamemodes/wizard/artefact.dm
index 1dd20906704..8e635e5d027 100644
--- a/code/game/gamemodes/wizard/artefact.dm
+++ b/code/game/gamemodes/wizard/artefact.dm
@@ -780,7 +780,7 @@ var/global/list/multiverse = list()
to_chat(target, "You suddenly feel very hot")
target.bodytemperature += 50
GiveHint(target)
- else if(can_puncture(I))
+ else if(is_pointed(I))
to_chat(target, "You feel a stabbing pain in [parse_zone(user.zone_sel.selecting)]!")
target.Weaken(2)
GiveHint(target)
diff --git a/code/game/machinery/adv_med.dm b/code/game/machinery/adv_med.dm
index 41dc37ab43f..6d7264e9256 100644
--- a/code/game/machinery/adv_med.dm
+++ b/code/game/machinery/adv_med.dm
@@ -398,7 +398,7 @@
organData["broken"] = E.min_broken_damage
var/shrapnelData[0]
- for(var/obj/I in E.implants)
+ for(var/obj/I in E.embedded_objects)
var/shrapnelSubData[0]
shrapnelSubData["name"] = I.name
@@ -605,7 +605,7 @@
infected = "Septic:"
var/unknown_body = 0
- for(var/I in e.implants)
+ for(var/I in e.embedded_objects)
unknown_body++
if(unknown_body || e.hidden)
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 00eb1bd6884..469dcd1863a 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -63,6 +63,17 @@ var/global/image/fire_overlay = image("icon" = 'icons/goonstation/effects/fire.d
var/mob/thrownby = null
+ //So items can have custom embedd values
+ //Because customisation is king
+ var/embed_chance = EMBED_CHANCE
+ var/embedded_fall_chance = EMBEDDED_ITEM_FALLOUT
+ var/embedded_pain_chance = EMBEDDED_PAIN_CHANCE
+ var/embedded_pain_multiplier = EMBEDDED_PAIN_MULTIPLIER //The coefficient of multiplication for the damage this item does while embedded (this*w_class)
+ var/embedded_fall_pain_multiplier = EMBEDDED_FALL_PAIN_MULTIPLIER //The coefficient of multiplication for the damage this item does when falling out of a limb (this*w_class)
+ var/embedded_impact_pain_multiplier = EMBEDDED_IMPACT_PAIN_MULTIPLIER //The coefficient of multiplication for the damage this item does when first embedded (this*w_class)
+ var/embedded_unsafe_removal_pain_multiplier = EMBEDDED_UNSAFE_REMOVAL_PAIN_MULTIPLIER //The coefficient of multiplication for the damage removing this without surgery causes (this*w_class)
+ var/embedded_unsafe_removal_time = EMBEDDED_UNSAFE_REMOVAL_TIME //A time in ticks, multiplied by the w_class.
+
var/toolspeed = 1 // If this item is a tool, the speed multiplier
/* Species-specific sprites, concept stolen from Paradise//vg/.
diff --git a/code/game/objects/items/latexballoon.dm b/code/game/objects/items/latexballoon.dm
index 5f55a5acdcc..dccc8f041f6 100644
--- a/code/game/objects/items/latexballoon.dm
+++ b/code/game/objects/items/latexballoon.dm
@@ -59,5 +59,5 @@
var/obj/item/weapon/tank/T = W
blow(T, user)
return
- if(is_sharp(W) || is_hot(W) || can_puncture(W))
+ if(is_sharp(W) || is_hot(W) || is_pointed(W))
burst()
diff --git a/code/game/objects/items/policetape.dm b/code/game/objects/items/policetape.dm
index 127f3f82c41..31da04bc799 100644
--- a/code/game/objects/items/policetape.dm
+++ b/code/game/objects/items/policetape.dm
@@ -174,7 +174,7 @@ var/list/tape_roll_applications = list()
breaktape(/obj/item/weapon/wirecutters,user)
/obj/item/tape/proc/breaktape(obj/item/weapon/W as obj, mob/user as mob)
- if(user.a_intent == I_HELP && ((!can_puncture(W) && src.allowed(user))))
+ if(user.a_intent == I_HELP && ((!is_pointed(W) && src.allowed(user))))
to_chat(user, "You can't break the [src] with that!")
return
user.visible_message("[user] breaks the [src]!", "You break the [src]!")
diff --git a/code/game/objects/structures/inflatable.dm b/code/game/objects/structures/inflatable.dm
index 14f1357af87..2cdcfc18376 100644
--- a/code/game/objects/structures/inflatable.dm
+++ b/code/game/objects/structures/inflatable.dm
@@ -96,7 +96,7 @@
/obj/structure/inflatable/attackby(obj/item/weapon/W as obj, mob/user as mob, params)
if(!istype(W))
return
- if(can_puncture(W))
+ if(is_pointed(W))
visible_message("[user] pierces [src] with [W]!")
deflate(1)
if(W.damtype == BRUTE || W.damtype == BURN)
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index 141d760287a..eb17146192c 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -244,6 +244,10 @@
if(status == "")
status = "OK"
src.show_message(text("\t []My [] is [].",status=="OK"?"":"",org.name,status),1)
+
+ for(var/obj/item/I in org.embedded_objects)
+ to_chat(src, "\t There is \a [I] embedded in your [org.name]!")
+
if(staminaloss)
if(staminaloss > 30)
to_chat(src, "You're completely exhausted.")
diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm
index 69e86de81e6..e2d44bfba5c 100644
--- a/code/modules/mob/living/carbon/human/death.dm
+++ b/code/modules/mob/living/carbon/human/death.dm
@@ -90,8 +90,10 @@
if(src) qdel(src)
/mob/living/carbon/human/death(gibbed)
- if(stat == DEAD) return
- if(healths) healths.icon_state = "health5"
+ if(stat == DEAD)
+ return
+ if(healths)
+ healths.icon_state = "health5"
if(!gibbed)
emote("deathgasp") //let the world KNOW WE ARE DEAD
@@ -102,21 +104,8 @@
set_heartattack(FALSE)
//Handle species-specific deaths.
- if(species) species.handle_death(src)
-
- //Handle brain slugs.
- var/obj/item/organ/external/head = get_organ("head")
- var/mob/living/simple_animal/borer/B
-
- if(istype(head))
- for(var/I in head.implants)
- if(istype(I,/mob/living/simple_animal/borer))
- B = I
- if(B)
- if(B.controlling && B.host == src)
- B.detach()
-
- verbs -= /mob/living/carbon/proc/release_control
+ if(species)
+ species.handle_death(src)
callHook("death", list(src, gibbed))
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index 693973ab42d..2215df8d3f4 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -382,6 +382,9 @@
else
wound_flavor_text["[temp.limb_name]"] = ""
+ for(var/obj/item/I in temp.embedded_objects)
+ msg += "[t_He] [t_has] \a \icon[I] [I] embedded in [t_his] [temp.name]!\n"
+
//Handles the text strings being added to the actual description.
//If they have something that covers the limb, and it is not missing, put flavortext. If it is covered but bleeding, add other flavortext.
var/display_chest = 0
@@ -438,9 +441,6 @@
if(display_gloves)
msg += "[src] has blood running from under [t_his] gloves!\n"
-
- for(var/implant in get_visible_implants(0))
- msg += "[src] has \a [implant] sticking out of [t_his] flesh!\n"
if(digitalcamo)
msg += "[t_He] [t_is] repulsively uncanny!\n"
if(!(skipface || ( wear_mask && ( wear_mask.flags_inv & HIDEFACE || wear_mask.flags_cover & MASKCOVERSMOUTH) ) ) && is_thrall(src) && in_range(user,src))
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 000a7a52bd0..3a233c869db 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -8,7 +8,6 @@
//why are these here and not in human_defines.dm
//var/list/hud_list[10]
var/datum/species/species //Contains icon generation and language information, set during New().
- var/embedded_flag //To check if we've need to roll for damage on movement while an item is imbedded in us.
var/obj/item/weapon/rig/wearing_rig // This is very not good, but it's much much better than calling get_rig() every update_canmove() call.
/mob/living/carbon/human/New(var/new_loc, var/new_species = null, var/delay_ready_dna = 0)
@@ -700,6 +699,28 @@
if(G && G.pickpocket)
thief_mode = 1
+ if(href_list["embedded_object"])
+ var/obj/item/organ/external/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.embedded_unsafe_removal_time*I.w_class
+ usr.visible_message("[usr] attempts to remove [I] from their [L.name].","You attempt to remove [I] from your [L.name]... (It will take [time_taken/10] seconds.)")
+ 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.embedded_unsafe_removal_pain_multiplier*I.w_class)//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 their [L.name]!","You successfully remove [I] from your [L.name].")
+ if(!has_embedded_objects())
+ clear_alert("embeddedobject")
+ return
+
if(href_list["item"])
var/slot = text2num(href_list["item"])
if(slot in check_obscured_slots())
@@ -1348,16 +1369,6 @@
else
..()
-/mob/living/carbon/human/get_visible_implants(var/class = 0)
-
- var/list/visible_implants = list()
- for(var/obj/item/organ/external/organ in bodyparts)
- for(var/obj/item/weapon/O in organ.implants)
- if(!istype(O,/obj/item/weapon/implant) && (O.w_class > class) && !istype(O,/obj/item/weapon/shard/shrapnel))
- visible_implants += O
-
- return(visible_implants)
-
/mob/living/carbon/human/generate_name()
name = species.makeName(gender,src)
real_name = name
@@ -1365,29 +1376,6 @@
dna.real_name = name
return name
-/mob/living/carbon/human/proc/handle_embedded_objects()
-
- for(var/obj/item/organ/external/organ in bodyparts)
- if(organ.status & ORGAN_SPLINTED) //Splints prevent movement.
- continue
- for(var/obj/item/weapon/O in organ.implants)
- if(!istype(O,/obj/item/weapon/implant) && prob(5)) //Moving with things stuck in you could be bad.
- // All kinds of embedded objects cause bleeding.
- var/msg = null
- switch(rand(1,3))
- if(1)
- msg ="A spike of pain jolts your [organ.name] as you bump [O] inside."
- if(2)
- msg ="Your movement jostles [O] in your [organ.name] painfully."
- if(3)
- msg ="[O] in your [organ.name] twists painfully as you move."
- to_chat(src, msg)
-
- organ.take_damage(rand(1,3), 0, 0)
- if(!(organ.status & ORGAN_ROBOT)) //There is no blood in protheses.
- organ.status |= ORGAN_BLEEDING
- src.adjustToxLoss(rand(1,3))
-
/mob/living/carbon/human/verb/check_pulse()
set category = null
set name = "Check pulse"
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 585ac587ffc..747351b9755 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -46,13 +46,14 @@ emp_act
var/armor = getarmor_organ(organ, "bullet")
if((P.embed && prob(20 + max(P.damage - armor, -10))))
var/obj/item/weapon/shard/shrapnel/SP = new()
- (SP.name) = "[P.name] shrapnel"
+ SP.name = "[P.name] shrapnel"
if(P.ammo_casing && P.ammo_casing.caliber)
- (SP.desc) = "[SP.desc] It looks like it is a [P.ammo_casing.caliber] caliber round."
+ SP.desc = "[SP.desc] It looks like it is a [P.ammo_casing.caliber] caliber round."
else
- (SP.desc) = "[SP.desc] The round's caliber is unidentifiable."
- (SP.loc) = organ
- organ.embed(SP)
+ SP.desc = "[SP.desc] The round's caliber is unidentifiable."
+ throw_alert("embeddedobject", /obj/screen/alert/embeddedobject)
+ organ.embedded_objects |= SP
+ SP.forceMove(src)
organ.add_autopsy_data(P.name, P.damage) // Add the bullet's name to the autopsy data
@@ -297,21 +298,6 @@ emp_act
if(Iforce > 10 || Iforce >= 5 && prob(33))
forcesay(hit_appends) //forcesay checks stat already
-/* //Melee weapon embedded object code. Commented out, as most people on the forums seem to find this annoying and think it does not contribute to general gameplay. - Dave
- if(I.damtype == BRUTE && !I.is_robot_module())
- var/damage = I.force
- if(armor)
- damage /= armor+1
-
- //blunt objects should really not be embedding in things unless a huge amount of force is involved
- var/embed_chance = weapon_sharp? damage/I.w_class : damage/(I.w_class*3)
- var/embed_threshold = weapon_sharp? 5*I.w_class : 15*I.w_class
-
- //Sharp objects will always embed if they do enough damage.
- if(((weapon_sharp && damage > (10*I.w_class)) || (damage > embed_threshold && prob(embed_chance))) && (I.no_embed == 0) )
- affecting.embed(I)
- return 1*/
-
//this proc handles being hit by a thrown atom
/mob/living/carbon/human/hitby(atom/movable/AM, skipcatch = 0, hitpush = 1, blocked = 0)
var/obj/item/I
@@ -325,24 +311,19 @@ emp_act
hitpush = 0
skipcatch = 1
blocked = 1
- /*else if(I)
+ else if(I)
if(I.throw_speed >= EMBED_THROWSPEED_THRESHOLD)
- if(!I.is_robot_module())
- var/armor = run_armor_check(affecting, "melee", "Your armor has protected your [hit_area].", "Your armor has softened hit to your [hit_area].", I.armour_penetration) //I guess "melee" is the best fit here
- var/sharp = is_sharp(I)
- var/damage = throwpower * (I.throw_speed / 5)
- if(armor)
- damage /= armor + 1
-
- //blunt objects should really not be embedding in things unless a huge amount of force is involved
- var/embed_chance = sharp? damage / I.w_class : damage/(I.w_class * 3)
- var/embed_threshold = sharp? 5 * I.w_class : 15 * I.w_class
-
- //Sharp objects will always embed if they do enough damage.
- //Thrown sharp objects have some momentum already and have a small chance to embed even if the damage is below the threshold
-
- if(((sharp && prob(damage / (10 * I.w_class) * 100)) || (damage > embed_threshold && prob(embed_chance))) && (I.no_embed == 0))
- affecting.embed(I)*/
+ if(can_embed(I))
+ if(prob(I.embed_chance))
+ throw_alert("embeddedobject", /obj/screen/alert/embeddedobject)
+ var/obj/item/organ/external/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.take_damage(I.w_class*I.embedded_impact_pain_multiplier)
+ visible_message("[I] embeds itself in [src]'s [L.name]!","[I] embeds itself in your [L.name]!")
+ hitpush = 0
+ skipcatch = 1 //can't catch the now embedded item
return ..()
/mob/living/carbon/human/proc/bloody_hands(var/mob/living/source, var/amount = 2)
diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm
index 00dbc50e8d0..f7504c5cbad 100644
--- a/code/modules/mob/living/carbon/human/life.dm
+++ b/code/modules/mob/living/carbon/human/life.dm
@@ -40,6 +40,10 @@
if(!client)
species.handle_npc(src)
+ if(stat != DEAD)
+ //Stuff jammed in your limbs hurts
+ handle_embedded_objects()
+
if(stat == DEAD)
handle_decay()
@@ -839,13 +843,6 @@
blinded = 1
stat = UNCONSCIOUS
- if(embedded_flag && !(mob_master.current_cycle % 10))
- var/list/E
- E = get_visible_implants(0)
- if(!E.len)
- embedded_flag = 0
-
-
//Vision //god knows why this is here
var/obj/item/organ/vision
if(species.vision_organ)
@@ -958,6 +955,22 @@
adjustToxLoss(-3)
lastpuke = 0
+/mob/living/carbon/human/proc/handle_embedded_objects()
+ for(var/X in bodyparts)
+ var/obj/item/organ/external/BP = X
+ for(var/obj/item/I in BP.embedded_objects)
+ if(prob(I.embedded_pain_chance))
+ BP.take_damage(I.w_class*I.embedded_pain_multiplier)
+ to_chat(src, "[I] embedded in your [BP.name] hurts!")
+
+ if(prob(I.embedded_fall_chance))
+ BP.take_damage(I.w_class*I.embedded_fall_pain_multiplier)
+ BP.embedded_objects -= I
+ I.loc = get_turf(src)
+ visible_message("[I] falls out of [name]'s [BP.name]!","[I] falls out of your [BP.name]!")
+ if(!has_embedded_objects())
+ clear_alert("embeddedobject")
+
/mob/living/carbon/human/handle_changeling()
if(mind)
if(mind.changeling)
diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm
index c1d1a169c1d..d658863450d 100644
--- a/code/modules/mob/living/carbon/human/species/species.dm
+++ b/code/modules/mob/living/carbon/human/species/species.dm
@@ -399,9 +399,6 @@
if(has_gravity(H))
gravity = 1
- if(H.embedded_flag)
- H.handle_embedded_objects() //Moving with objects stuck in you can cause bad times.
-
if(!ignoreslow && gravity)
if(slowdown)
. = slowdown
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 06b6440f756..c1fb31a255b 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -512,6 +512,7 @@
human_mob.restore_blood()
human_mob.shock_stage = 0
human_mob.decaylevel = 0
+ human_mob.remove_all_embedded_objects()
restore_all_organs()
surgeries.Cut() //End all surgeries.
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index cb86d417fbc..f4dce4b362b 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -1048,104 +1048,6 @@ var/list/slot_equipment_priority = list( \
/mob/proc/get_species()
return ""
-/mob/proc/get_visible_implants(var/class = 0)
- var/list/visible_implants = list()
- for(var/obj/item/O in embedded)
- if(O.w_class > class)
- visible_implants += O
- return visible_implants
-
-/mob/proc/yank_out_object()
- set category = "Object"
- set name = "Yank out object"
- set desc = "Remove an embedded item at the cost of bleeding and pain."
- set src in view(1)
-
- if(!isliving(usr) || usr.next_move > world.time)
- return
- usr.changeNext_move(CLICK_CD_RESIST)
-
- if(usr.stat == 1)
- to_chat(usr, "You are unconcious and cannot do that!")
- return
-
- if(usr.restrained())
- to_chat(usr, "You are restrained and cannot do that!")
- return
-
- var/mob/S = src
- var/mob/U = usr
- var/list/valid_objects = list()
- var/self = null
-
- if(S == U)
- self = 1 // Removing object from yourself.
-
- valid_objects = get_visible_implants(0)
- if(!valid_objects.len)
- if(self)
- to_chat(src, "You have nothing stuck in your body that is large enough to remove.")
- else
- to_chat(U, "[src] has nothing stuck in their wounds that is large enough to remove.")
- return
-
- var/obj/item/weapon/selection = input("What do you want to yank out?", "Embedded objects") in valid_objects
-
- if(self)
- visible_message("[usr] appears to be trying to extract an object from their body.")
- to_chat(src, "You attempt to get a good grip on [selection] in your body.")
- else
- visible_message("[usr] attempts to get a good grip on [selection] in [S]'s body.")
- to_chat(U, "You attempt to get a good grip on [selection] in [S]'s body.")
-
- if(!do_after(U, 80, target = S))
- return
- if(!selection || !S || !U)
- return
-
- if(self)
- visible_message("[src] rips [selection] out of their body.","You rip [selection] out of your body.")
- else
- visible_message("[usr] rips [selection] out of [src]'s body.","[usr] rips [selection] out of your body.")
- valid_objects = get_visible_implants(0)
- if(valid_objects.len == 1) //Yanking out last object - removing verb.
- src.verbs -= /mob/proc/yank_out_object
-
- if(ishuman(src))
-
- var/mob/living/carbon/human/H = src
- var/obj/item/organ/external/affected
-
- for(var/obj/item/organ/external/organ in H.bodyparts) //Grab the organ holding the implant.
- for(var/obj/item/weapon/O in organ.implants)
- if(O == selection)
- affected = organ
-
- affected.implants -= selection
- H.shock_stage+=10
-
- if(prob(10)) //I'M SO ANEMIC I COULD JUST -DIE-.
- var/datum/wound/internal_bleeding/I = new ()
- affected.wounds += I
- H.custom_pain("Something tears wetly in your [affected] as [selection] is pulled free!", 1)
-
- if(ishuman(U))
- var/mob/living/carbon/human/human_user = U
- human_user.bloody_hands(H)
-
- selection.forceMove(get_turf(src))
- if(!(U.l_hand && U.r_hand))
- U.put_in_hands(selection)
-
- for(var/obj/item/weapon/O in pinned)
- if(O == selection)
- pinned -= O
- if(!pinned.len)
- anchored = 0
- return 1
-
-
-
/mob/dead/observer/verb/respawn()
set name = "Respawn as NPC"
set category = "Ghost"
diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm
index 2988363ffb9..a5d0ab00a4d 100644
--- a/code/modules/mob/mob_defines.dm
+++ b/code/modules/mob/mob_defines.dm
@@ -54,7 +54,6 @@
var/unacidable = 0
var/can_strip = 1
var/list/pinned = list() //List of things pinning this creature to walls (see living_defense.dm)
- var/list/embedded = list() //Embedded items, since simple mobs don't have organs.
var/list/languages = list() // For speaking/listening.
var/list/abilities = list() // For species-derived or admin-given powers.
var/list/speak_emote = list("says") // Verbs used when speaking. Defaults to 'say' if speak_emote is null.
@@ -196,5 +195,5 @@
var/list/permanent_huds = list()
var/list/actions = list()
-
+
var/list/progressbars = null //for stacking do_after bars
diff --git a/code/modules/surgery/implant.dm b/code/modules/surgery/implant.dm
index 498976c4635..2a4f4ad20ea 100644
--- a/code/modules/surgery/implant.dm
+++ b/code/modules/surgery/implant.dm
@@ -199,14 +199,14 @@
affected.wounds += I
affected.owner.custom_pain("You feel something rip in your [affected.name]!", 1)
user.drop_item()
- target.internal_organs += tool
+ affected.hidden = tool
tool.forceMove(affected)
return 1
else
if(IC)
user.visible_message("[user] pulls [IC] out of [target]'s [target_zone]!", "You pull [IC] out of [target]'s [target_zone].")
user.put_in_hands(IC)
- target.internal_organs -= IC
+ affected.hidden = null
return 1
else
to_chat(user, "You don't find anything in [target]'s [target_zone].")
@@ -214,18 +214,18 @@
//////////////////////////////////////////////////////////////////
-// IMPLANT/ITEM REMOVAL SURGERY //
+// IMPLANT REMOVAL SURGERY //
//////////////////////////////////////////////////////////////////
/datum/surgery/cavity_implant_rem
name = "Implant Removal"
steps = list(/datum/surgery_step/generic/cut_open, /datum/surgery_step/generic/clamp_bleeders, /datum/surgery_step/generic/retract_skin,/datum/surgery_step/cavity/implant_removal,/datum/surgery_step/cavity/close_space,/datum/surgery_step/generic/cauterize/)
- possible_locs = list("chest")//head is for borers..i can put it elsewhere
+ possible_locs = list("chest")
/datum/surgery/cavity_implant_rem/synth
name = "Implant Removal"
steps = list(/datum/surgery_step/robotics/external/unscrew_hatch,/datum/surgery_step/robotics/external/open_hatch,/datum/surgery_step/cavity/implant_removal,/datum/surgery_step/robotics/external/close_hatch)
- possible_locs = list("chest")//head is for borers..i can put it elsewhere
+ possible_locs = list("chest")
/datum/surgery/cavity_implant_rem/can_start(mob/user, mob/living/carbon/human/target)
if(!istype(target))
@@ -295,102 +295,4 @@
else
user.visible_message(" [user] could not find anything inside [target]'s [affected.name], and pulls \the [tool] out.", \
"You could not find anything inside [target]'s [affected.name].")
- return 1
-
-/datum/surgery_step/cavity/implant_removal/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool,datum/surgery/surgery)
- ..()
- var/obj/item/organ/external/chest/affected = target.get_organ(target_zone)
- if(affected.implants.len)
- var/fail_prob = 10
- fail_prob += 100 - tool_quality(tool)
- if(prob(fail_prob))
- var/obj/item/weapon/implant/imp = affected.implants[1]
- user.visible_message(" Something beeps inside [target]'s [affected.name]!")
- playsound(imp.loc, 'sound/items/countdown.ogg', 75, 1, -3)
- spawn(25)
- imp.activate()
- return 0
-
-
-//////////////////////////////////////////////////////////////////
-// EMBEDDED ITEM REOMOVAL //
-//////////////////////////////////////////////////////////////////
-
-/datum/surgery/embedded_removal
- name = "Removal of Embedded Objects"
- steps = list(/datum/surgery_step/generic/cut_open, /datum/surgery_step/generic/clamp_bleeders, /datum/surgery_step/generic/retract_skin, /datum/surgery_step/remove_object, /datum/surgery_step/generic/cauterize)
- possible_locs = list("r_arm","l_arm","r_leg","l_leg","r_hand","r_foot","l_hand","l_foot","groin","chest","head")
-
-/datum/surgery/embedded_removal/synth
- steps = list(/datum/surgery_step/robotics/external/unscrew_hatch,/datum/surgery_step/robotics/external/open_hatch, /datum/surgery_step/remove_object, /datum/surgery_step/robotics/external/close_hatch)
- possible_locs = list("r_arm","l_arm","r_leg","l_leg","r_hand","r_foot","l_hand","l_foot","groin","chest","head")
-
-
-/datum/surgery/embedded_removal/can_start(mob/user, mob/living/carbon/human/target)
- if(!istype(target))
- return 0
- var/obj/item/organ/external/affected = target.get_organ(user.zone_sel.selecting)
- if(!affected)
- return 0
- if(affected.status & ORGAN_ROBOT)
- return 0
- return 1
-
-/datum/surgery/embedded_removal/synth/can_start(mob/user, mob/living/carbon/human/target)
- if(!istype(target))
- return 0
- var/obj/item/organ/external/affected = target.get_organ(user.zone_sel.selecting)
- if(!affected)
- return 0
- if(!(affected.status & ORGAN_ROBOT))
- return 0
- return 1
-
-/datum/surgery_step/remove_object
- name = "remove embedded objects"
- time = 32
- allowed_tools = list(
- /obj/item/weapon/scalpel/laser/manager = 100, \
- /obj/item/weapon/hemostat = 100, \
- /obj/item/stack/cable_coil = 75, \
- /obj/item/device/assembly/mousetrap = 20
- )
- var/obj/item/organ/external/L = null
-
-
-/datum/surgery_step/remove_object/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool, datum/surgery/surgery)
- L = target.get_organ(target_zone)
- if(L)
- user.visible_message("[user] looks for objects embedded in [target]'s [target_zone].", "You look for objects embedded in [target]'s [target_zone]...")
- else
- user.visible_message("[user] looks for [target]'s [target_zone].", "You look for [target]'s [target_zone]...")
-
-
-/datum/surgery_step/remove_object/end_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool, datum/surgery/surgery)
- if(L)
- if(ishuman(target))
- var/mob/living/carbon/human/H = target
- var/objects = 0
- for(var/obj/item/I in L.implants)
- if(!istype(I,/obj/item/weapon/implant))
- objects++
- I.forceMove(get_turf(H))
- L.implants -= I
-
- //Handle possessive brain borers.
- if(H.has_brain_worms() && target_zone == "head")//remove worms outside the loop
- var/mob/living/simple_animal/borer/worm = H.has_brain_worms()
- if(worm.controlling)
- target.release_control()
- worm.detach()
- worm.leave_host()
- user.visible_message("a slug like creature wiggles out of [H]'s [target_zone]!")
-
- if(objects > 0)
- user.visible_message("[user] sucessfully removes [objects] objects from [H]'s [L.limb_name]!", "You sucessfully remove [objects] objects from [H]'s [L.limb_name].")
- else
- to_chat(user, "You find no objects embedded in [H]'s [L.limb_name]!")
- else
- to_chat(user, "You can't find [target]'s [target_zone], let alone any objects embedded in it!")
-
- return 1
+ return 1
\ No newline at end of file
diff --git a/code/modules/surgery/organs/organ_external.dm b/code/modules/surgery/organs/organ_external.dm
index 151636a9a50..ec184269051 100644
--- a/code/modules/surgery/organs/organ_external.dm
+++ b/code/modules/surgery/organs/organ_external.dm
@@ -58,7 +58,7 @@
var/encased // Needs to be opened with a saw to access the organs.
var/obj/item/hidden = null
- var/list/implants = list()
+ var/list/embedded_objects = list()
// how often wounds should be updated, a higher number means less often
var/wound_update_accuracy = 1
@@ -104,7 +104,7 @@
QDEL_LIST(wounds)
- QDEL_LIST(implants)
+ QDEL_LIST(embedded_objects)
QDEL_NULL(hidden)
@@ -358,12 +358,6 @@ This function completely restores a damaged organ to perfect condition.
for(var/obj/item/organ/external/EO in contents)
EO.rejuvenate()
- // remove embedded objects and drop them on the floor
- for(var/obj/implanted_object in implants)
- if(!istype(implanted_object,/obj/item/weapon/implant)) // We don't want to remove REAL implants. Just shrapnel etc.
- implanted_object.loc = owner.loc
- implants -= implanted_object
-
owner.updatehealth()
update_icon()
if(!owner)
@@ -907,20 +901,6 @@ Note that amputating the affected organ does in fact remove the infection from t
/obj/item/organ/external/proc/is_malfunctioning()
return ((status & ORGAN_ROBOT) && (brute_dam + burn_dam) >= 10 && prob(brute_dam + burn_dam))
-/obj/item/organ/external/proc/embed(var/obj/item/weapon/W, var/silent = 0)
- if(!owner || loc != owner)
- return
- if(!silent)
- owner.visible_message("\The [W] sticks in the wound!")
- implants += W
- owner.embedded_flag = 1
- owner.verbs += /mob/proc/yank_out_object
- W.add_blood(owner)
- if(ismob(W.loc))
- var/mob/living/H = W.loc
- H.drop_item()
- W.loc = owner
-
/obj/item/organ/external/proc/open_enough_for_surgery()
return (encased ? (open == 3) : (open == 2))
@@ -931,14 +911,17 @@ Note that amputating the affected organ does in fact remove the infection from t
var/is_robotic = status & ORGAN_ROBOT
var/mob/living/carbon/human/victim = owner
+ for(var/obj/item/I in embedded_objects)
+ embedded_objects -= I
+ I.forceMove(src)
+ if(!owner.has_embedded_objects())
+ owner.clear_alert("embeddedobject")
+
. = ..()
status |= ORGAN_DESTROYED
victim.bad_external_organs -= src
- for(var/implant in implants) //todo: check if this can be left alone
- qdel(implant)
-
// Attached organs also fly off.
if(!ignore_children)
for(var/obj/item/organ/external/O in children)
@@ -1018,3 +1001,22 @@ Note that amputating the affected organ does in fact remove the infection from t
..() // Parent call loads in the DNA
if(data["dna"])
sync_colour_to_dna()
+
+//Remove all embedded objects from all limbs on the carbon mob
+/mob/living/carbon/human/proc/remove_all_embedded_objects()
+ var/turf/T = get_turf(src)
+
+ for(var/X in bodyparts)
+ var/obj/item/organ/external/L = X
+ for(var/obj/item/I in L.embedded_objects)
+ L.embedded_objects -= I
+ I.forceMove(T)
+
+ clear_alert("embeddedobject")
+
+/mob/living/carbon/human/proc/has_embedded_objects()
+ . = 0
+ for(var/X in bodyparts)
+ var/obj/item/organ/external/L = X
+ for(var/obj/item/I in L.embedded_objects)
+ return 1
\ No newline at end of file
diff --git a/code/modules/surgery/remove_embedded_object.dm b/code/modules/surgery/remove_embedded_object.dm
new file mode 100644
index 00000000000..468fe9f7654
--- /dev/null
+++ b/code/modules/surgery/remove_embedded_object.dm
@@ -0,0 +1,42 @@
+/datum/surgery/embedded_removal
+ name = "removal of embedded objects"
+ steps = list(/datum/surgery_step/generic/cut_open, /datum/surgery_step/generic/clamp_bleeders, /datum/surgery_step/generic/retract_skin, /datum/surgery_step/remove_object)
+ possible_locs = list("head", "chest", "l_arm", "l_hand", "r_arm", "r_hand","r_leg", "r_foot", "l_leg", "l_foot", "groin")
+
+
+/datum/surgery_step/remove_object
+ name = "remove embedded objects"
+ time = 32
+ accept_hand = 1
+ var/obj/item/organ/external/L = null
+
+
+/datum/surgery_step/remove_object/begin_step(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
+ L = surgery.organ_ref
+ if(L)
+ user.visible_message("[user] looks for objects embedded in [target]'s [parse_zone(user.zone_sel.selecting)].", "You look for objects embedded in [target]'s [parse_zone(user.zone_sel.selecting)]...")
+ else
+ user.visible_message("[user] looks for [target]'s [parse_zone(user.zone_sel.selecting)].", "You look for [target]'s [parse_zone(user.zone_sel.selecting)]...")
+
+
+/datum/surgery_step/remove_object/end_step(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
+ if(L)
+ if(ishuman(target))
+ var/mob/living/carbon/human/H = target
+ var/objects = 0
+ for(var/obj/item/I in L.embedded_objects)
+ objects++
+ I.forceMove(get_turf(H))
+ L.embedded_objects -= I
+ if(!H.has_embedded_objects())
+ H.clear_alert("embeddedobject")
+
+ if(objects > 0)
+ user.visible_message("[user] sucessfully removes [objects] objects from [H]'s [L]!", "You successfully remove [objects] objects from [H]'s [L.name].")
+ else
+ to_chat(user, "You find no objects embedded in [H]'s [L]!")
+
+ else
+ to_chat(user, "You can't find [target]'s [parse_zone(user.zone_sel.selecting)], let alone any objects embedded in it!")
+
+ return 1
\ No newline at end of file
diff --git a/paradise.dme b/paradise.dme
index 869bffe601b..99e7a6f4913 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -2135,6 +2135,7 @@
#include "code\modules\surgery\limb_reattach.dm"
#include "code\modules\surgery\organs_internal.dm"
#include "code\modules\surgery\other.dm"
+#include "code\modules\surgery\remove_embedded_object.dm"
#include "code\modules\surgery\rig_removal.dm"
#include "code\modules\surgery\robotics.dm"
#include "code\modules\surgery\slime.dm"