it continues

This commit is contained in:
Timothy Teakettle
2020-07-17 22:38:28 +01:00
parent f187de33ad
commit a4478b0cda
52 changed files with 560 additions and 136 deletions

View File

@@ -25,9 +25,18 @@
var/list/mats_per_unit //list that tells you how much is in a single unit. var/list/mats_per_unit //list that tells you how much is in a single unit.
///Datum material type that this stack is made of ///Datum material type that this stack is made of
var/material_type var/material_type
max_integrity = 100
//NOTE: When adding grind_results, the amounts should be for an INDIVIDUAL ITEM - these amounts will be multiplied by the stack size in on_grind() //NOTE: When adding grind_results, the amounts should be for an INDIVIDUAL ITEM - these amounts will be multiplied by the stack size in on_grind()
var/obj/structure/table/tableVariant // we tables now (stores table variant to be built from this stack) var/obj/structure/table/tableVariant // we tables now (stores table variant to be built from this stack)
// The following are all for medical treatment, they're here instead of /stack/medical because sticky tape can be used as a makeshift bandage or splint
/// If set and this used as a splint for a broken bone wound, this is used as a multiplier for applicable slowdowns (lower = better) (also for speeding up burn recoveries)
var/splint_factor
/// How much blood flow this stack can absorb if used as a bandage on a cut wound, note that absorption is how much we lower the flow rate, not the raw amount of blood we suck up
var/absorption_capacity
/// How quickly we lower the blood flow on a cut wound we're bandaging. Expected lifetime of this bandage in ticks is thus absorption_capacity/absorption_rate, or until the cut heals, whichever comes first
var/absorption_rate
/obj/item/stack/on_grind() /obj/item/stack/on_grind()
for(var/i in 1 to grind_results.len) //This should only call if it's ground, so no need to check if grind_results exists for(var/i in 1 to grind_results.len) //This should only call if it's ground, so no need to check if grind_results exists
grind_results[grind_results[i]] *= get_amount() //Gets the key at position i, then the reagent amount of that key, then multiplies it by stack size grind_results[grind_results[i]] *= get_amount() //Gets the key at position i, then the reagent amount of that key, then multiplies it by stack size

View File

@@ -7,10 +7,13 @@
icon = 'icons/obj/tapes.dmi' icon = 'icons/obj/tapes.dmi'
icon_state = "tape_w" icon_state = "tape_w"
var/prefix = "sticky" var/prefix = "sticky"
w_class = WEIGHT_CLASS_TINY
full_w_class = WEIGHT_CLASS_TINY
item_flags = NOBLUDGEON item_flags = NOBLUDGEON
amount = 5 amount = 5
max_amount = 5 max_amount = 5
resistance_flags = FLAMMABLE resistance_flags = FLAMMABLE
splint_factor = 0.8
var/list/conferred_embed = EMBED_HARMLESS var/list/conferred_embed = EMBED_HARMLESS
var/overwrite_existing = FALSE var/overwrite_existing = FALSE
@@ -53,6 +56,7 @@
icon_state = "tape_y" icon_state = "tape_y"
prefix = "super sticky" prefix = "super sticky"
conferred_embed = EMBED_HARMLESS_SUPERIOR conferred_embed = EMBED_HARMLESS_SUPERIOR
splint_factor = 0.6
/obj/item/stack/sticky_tape/pointy /obj/item/stack/sticky_tape/pointy
name = "pointy tape" name = "pointy tape"
@@ -68,4 +72,14 @@
desc = "You didn't know tape could look so sinister. Welcome to Space Station 13." desc = "You didn't know tape could look so sinister. Welcome to Space Station 13."
icon_state = "tape_spikes" icon_state = "tape_spikes"
prefix = "super pointy" prefix = "super pointy"
conferred_embed = EMBED_POINTY_SUPERIOR conferred_embed = EMBED_POINTY_SUPERIOR
/obj/item/stack/sticky_tape/surgical
name = "surgical tape"
singular_name = "surgical tape"
desc = "Made for patching broken bones back together alongside bone gel, not for playing pranks."
//icon_state = "tape_spikes"
prefix = "surgical"
conferred_embed = list("embed_chance" = 30, "pain_mult" = 0, "jostle_pain_mult" = 0, "ignore_throwspeed_threshold" = TRUE)
splint_factor = 0.4
custom_price = 500

View File

@@ -369,6 +369,7 @@
new /obj/item/circular_saw(src) new /obj/item/circular_saw(src)
new /obj/item/surgicaldrill(src) new /obj/item/surgicaldrill(src)
new /obj/item/cautery(src) new /obj/item/cautery(src)
new /obj/item/bonesetter(src)
new /obj/item/surgical_drapes(src) new /obj/item/surgical_drapes(src)
new /obj/item/clothing/mask/surgical(src) new /obj/item/clothing/mask/surgical(src)
new /obj/item/reagent_containers/medspray/sterilizine(src) new /obj/item/reagent_containers/medspray/sterilizine(src)
@@ -391,6 +392,7 @@
new /obj/item/circular_saw(src) new /obj/item/circular_saw(src)
new /obj/item/surgicaldrill(src) new /obj/item/surgicaldrill(src)
new /obj/item/cautery(src) new /obj/item/cautery(src)
new /obj/item/bonesetter(src)
new /obj/item/surgical_drapes(src) new /obj/item/surgical_drapes(src)
new /obj/item/clothing/mask/surgical(src) new /obj/item/clothing/mask/surgical(src)
new /obj/item/reagent_containers/medspray/sterilizine(src) new /obj/item/reagent_containers/medspray/sterilizine(src)
@@ -485,6 +487,7 @@
new /obj/item/circular_saw(src) new /obj/item/circular_saw(src)
new /obj/item/surgicaldrill(src) new /obj/item/surgicaldrill(src)
new /obj/item/cautery(src) new /obj/item/cautery(src)
new /obj/item/bonesetter(src)
new /obj/item/surgical_drapes(src) new /obj/item/surgical_drapes(src)
new /obj/item/clothing/suit/straight_jacket(src) new /obj/item/clothing/suit/straight_jacket(src)
new /obj/item/clothing/mask/muzzle(src) new /obj/item/clothing/mask/muzzle(src)

View File

@@ -162,6 +162,7 @@
/obj/item/surgical_drapes, //for true paramedics /obj/item/surgical_drapes, //for true paramedics
/obj/item/scalpel, /obj/item/scalpel,
/obj/item/circular_saw, /obj/item/circular_saw,
/obj/item/bonesetter,
/obj/item/surgicaldrill, /obj/item/surgicaldrill,
/obj/item/retractor, /obj/item/retractor,
/obj/item/cautery, /obj/item/cautery,
@@ -181,7 +182,8 @@
/obj/item/implant, /obj/item/implant,
/obj/item/implanter, /obj/item/implanter,
/obj/item/pinpointer/crew, /obj/item/pinpointer/crew,
/obj/item/reagent_containers/chem_pack /obj/item/reagent_containers/chem_pack,
/obj/item/stack/sticky_tape //surgical tape
)) ))
/obj/item/storage/belt/medical/surgery_belt_adv /obj/item/storage/belt/medical/surgery_belt_adv
@@ -811,4 +813,3 @@
attack_verb = list("bashed", "slashes", "prods", "pokes") attack_verb = list("bashed", "slashes", "prods", "pokes")
fitting_swords = list(/obj/item/melee/rapier) fitting_swords = list(/obj/item/melee/rapier)
starting_sword = /obj/item/melee/rapier starting_sword = /obj/item/melee/rapier

View File

@@ -41,9 +41,26 @@
new /obj/item/stack/medical/suture(src) new /obj/item/stack/medical/suture(src)
new /obj/item/stack/medical/mesh(src) new /obj/item/stack/medical/mesh(src)
new /obj/item/stack/medical/mesh(src) new /obj/item/stack/medical/mesh(src)
new /obj/item/reagent_containers/hypospray/medipen(src) new /obj/item/reagent_containers/hypospray/medipen/ekit(src)
new /obj/item/healthanalyzer(src) new /obj/item/healthanalyzer(src)
/obj/item/storage/firstaid/emergency
icon_state = "medbriefcase"
name = "emergency first-aid kit"
desc = "A very simple first aid kit meant to secure and stabilize serious wounds for later treatment."
/obj/item/storage/firstaid/emergency/PopulateContents()
if(empty)
return
var/static/items_inside = list(
/obj/item/healthanalyzer/wound = 1,
/obj/item/stack/medical/gauze = 1,
/obj/item/stack/medical/suture/emergency = 1,
/obj/item/stack/medical/ointment = 1,
/obj/item/reagent_containers/hypospray/medipen/ekit = 2,
/obj/item/storage/pill_bottle/iron = 1)
generate_items_inside(items_inside,src)
/obj/item/storage/firstaid/ancient /obj/item/storage/firstaid/ancient
icon_state = "firstaid" icon_state = "firstaid"
desc = "A first aid kit with the ability to heal common types of injuries." desc = "A first aid kit with the ability to heal common types of injuries."
@@ -416,6 +433,7 @@
/obj/item/retractor, /obj/item/retractor,
/obj/item/cautery, /obj/item/cautery,
/obj/item/surgical_drapes, /obj/item/surgical_drapes,
/obj/item/bonesetter,
/obj/item/autosurgeon, /obj/item/autosurgeon,
/obj/item/organ, /obj/item/organ,
/obj/item/implant, /obj/item/implant,

View File

@@ -20,6 +20,7 @@ GLOBAL_LIST_EMPTY(rubber_toolbox_icons)
var/has_latches = TRUE var/has_latches = TRUE
var/can_rubberify = TRUE var/can_rubberify = TRUE
rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE //very protecc too rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE //very protecc too
wound_bonus = 5
/obj/item/storage/toolbox/greyscale /obj/item/storage/toolbox/greyscale
icon_state = "toolbox_default" icon_state = "toolbox_default"

View File

@@ -574,6 +574,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi'
force = 10 force = 10
wound_bonus = -10
throwforce = 12 throwforce = 12
attack_verb = list("beat", "smacked") attack_verb = list("beat", "smacked")
custom_materials = list(/datum/material/wood = MINERAL_MATERIAL_AMOUNT * 3.5) custom_materials = list(/datum/material/wood = MINERAL_MATERIAL_AMOUNT * 3.5)
@@ -626,7 +627,8 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
homerun_ready = 0 homerun_ready = 0
return return
else if(!target.anchored) else if(!target.anchored)
target.throw_at(throw_target, rand(1,2), 7, user) var/whack_speed = (prob(60) ? 1 : 4)
target.throw_at(throw_target, rand(1, 2), whack_speed, user) // sorry friends, 7 speed batting caused wounds to absolutely delete whoever you knocked your target into (and said target)
/obj/item/melee/baseball_bat/ablative /obj/item/melee/baseball_bat/ablative
name = "metal baseball bat" name = "metal baseball bat"

View File

@@ -10,6 +10,11 @@
var/damtype = BRUTE var/damtype = BRUTE
var/force = 0 var/force = 0
/// How good a given object is at causing wounds on carbons. Higher values equal better shots at creating serious wounds.
var/wound_bonus = 0
/// If this attacks a human with no wound armor on the affected body part, add this to the wound mod. Some attacks may be significantly worse at wounding if there's even a slight layer of armor to absorb some of it vs bare flesh
var/bare_wound_bonus = 0
var/datum/armor/armor var/datum/armor/armor
var/obj_integrity //defaults to max_integrity var/obj_integrity //defaults to max_integrity
var/max_integrity = 500 var/max_integrity = 500

View File

@@ -108,7 +108,7 @@
if (QDELETED(head)) if (QDELETED(head))
return return
playsound(src, 'sound/weapons/bladeslice.ogg', 100, 1) playsound(src, 'sound/weapons/guillotine.ogg', 100, TRUE)
if (blade_sharpness >= GUILLOTINE_DECAP_MIN_SHARP || head.brute_dam >= 100) if (blade_sharpness >= GUILLOTINE_DECAP_MIN_SHARP || head.brute_dam >= 100)
head.dismember() head.dismember()
log_combat(user, H, "beheaded", src) log_combat(user, H, "beheaded", src)

View File

@@ -71,7 +71,7 @@
if(user.grab_state < GRAB_AGGRESSIVE) if(user.grab_state < GRAB_AGGRESSIVE)
to_chat(user, "<span class='warning'>You need a better grip to do that!</span>") to_chat(user, "<span class='warning'>You need a better grip to do that!</span>")
return return
tablepush(user, pushed_mob) tablelimbsmash(user, pushed_mob)
if(user.a_intent == INTENT_HELP) if(user.a_intent == INTENT_HELP)
pushed_mob.visible_message("<span class='notice'>[user] begins to place [pushed_mob] onto [src]...</span>", \ pushed_mob.visible_message("<span class='notice'>[user] begins to place [pushed_mob] onto [src]...</span>", \
"<span class='userdanger'>[user] begins to place [pushed_mob] onto [src]...</span>") "<span class='userdanger'>[user] begins to place [pushed_mob] onto [src]...</span>")
@@ -114,29 +114,17 @@
"<span class='notice'>[user] places [pushed_mob] onto [src].</span>") "<span class='notice'>[user] places [pushed_mob] onto [src].</span>")
log_combat(user, pushed_mob, "placed") log_combat(user, pushed_mob, "placed")
/obj/structure/table/proc/tablepush(mob/living/user, mob/living/pushed_mob) /obj/structure/table/proc/tablelimbsmash(mob/living/user, mob/living/pushed_mob)
if(HAS_TRAIT(user, TRAIT_PACIFISM)) if(HAS_TRAIT(user, TRAIT_PACIFISM)) //this shouldnt even be possible anyway because you cant get them in an aggressive grab, but whatever
to_chat(user, "<span class='danger'>Throwing [pushed_mob] onto the table might hurt them!</span>") to_chat(user, "<span class='danger'>Throwing [pushed_mob] onto the table might hurt them!</span>")
return return
var/added_passtable = FALSE pushed_mob.Knockdown(30)
if(!pushed_mob.pass_flags & PASSTABLE) var/obj/item/bodypart/banged_limb = pushed_mob.get_bodypart(user.zone_selected) || pushed_mob.get_bodypart(BODY_ZONE_HEAD)
added_passtable = TRUE var/extra_wound = 0
pushed_mob.pass_flags |= PASSTABLE if(HAS_TRAIT(user, TRAIT_HULK))
pushed_mob.Move(src.loc) extra_wound = 20
if(added_passtable) banged_limb.receive_damage(30, wound_bonus = extra_wound)
pushed_mob.pass_flags &= ~PASSTABLE pushed_mob.apply_damage(60, STAMINA)
if(pushed_mob.loc != loc) //Something prevented the tabling
return
pushed_mob.DefaultCombatKnockdown(40)
pushed_mob.visible_message("<span class='danger'>[user] slams [pushed_mob] onto [src]!</span>", \
"<span class='userdanger'>[user] slams you onto [src]!</span>")
log_combat(user, pushed_mob, "tabled", null, "onto [src]")
if(!ishuman(pushed_mob))
return
var/mob/living/carbon/human/H = pushed_mob
if(iscatperson(H))
H.emote("nya")
SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "table", /datum/mood_event/table)
/obj/structure/table/shove_act(mob/living/target, mob/living/user) /obj/structure/table/shove_act(mob/living/target, mob/living/user)
if(CHECK_MOBILITY(target, MOBILITY_STAND)) if(CHECK_MOBILITY(target, MOBILITY_STAND))

View File

@@ -1276,7 +1276,7 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
if(!check_rights(R_ADMIN) || !check_rights(R_FUN)) if(!check_rights(R_ADMIN) || !check_rights(R_FUN))
return return
var/list/punishment_list = list(ADMIN_PUNISHMENT_PIE, ADMIN_PUNISHMENT_CUSTOM_PIE, ADMIN_PUNISHMENT_FIREBALL, ADMIN_PUNISHMENT_LIGHTNING, ADMIN_PUNISHMENT_BRAINDAMAGE, ADMIN_PUNISHMENT_BSA, ADMIN_PUNISHMENT_GIB, ADMIN_PUNISHMENT_SUPPLYPOD_QUICK, ADMIN_PUNISHMENT_SUPPLYPOD, ADMIN_PUNISHMENT_MAZING, ADMIN_PUNISHMENT_ROD) var/list/punishment_list = list(ADMIN_PUNISHMENT_PIE, ADMIN_PUNISHMENT_CUSTOM_PIE, ADMIN_PUNISHMENT_FIREBALL, ADMIN_PUNISHMENT_LIGHTNING, ADMIN_PUNISHMENT_BRAINDAMAGE, ADMIN_PUNISHMENT_BSA, ADMIN_PUNISHMENT_GIB, ADMIN_PUNISHMENT_SUPPLYPOD_QUICK, ADMIN_PUNISHMENT_SUPPLYPOD, ADMIN_PUNISHMENT_MAZING, ADMIN_PUNISHMENT_ROD, ADMIN_PUNISHMENT_CRACK, ADMIN_PUNISHMENT_BLEED, ADMIN_PUNISHMENT_SCARIFY)
var/punishment = input("Choose a punishment", "DIVINE SMITING") as null|anything in punishment_list var/punishment = input("Choose a punishment", "DIVINE SMITING") as null|anything in punishment_list
@@ -1341,7 +1341,7 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
if(ADMIN_PUNISHMENT_PIE) if(ADMIN_PUNISHMENT_PIE)
var/obj/item/reagent_containers/food/snacks/pie/cream/nostun/creamy = new(get_turf(target)) var/obj/item/reagent_containers/food/snacks/pie/cream/nostun/creamy = new(get_turf(target))
creamy.splat(target) creamy.splat(target)
if (ADMIN_PUNISHMENT_CUSTOM_PIE) if(ADMIN_PUNISHMENT_CUSTOM_PIE)
var/obj/item/reagent_containers/food/snacks/pie/cream/nostun/A = new() var/obj/item/reagent_containers/food/snacks/pie/cream/nostun/A = new()
if(!A.reagents) if(!A.reagents)
var/amount = input(usr, "Specify the reagent size of [A]", "Set Reagent Size", 50) as num|null var/amount = input(usr, "Specify the reagent size of [A]", "Set Reagent Size", 50) as num|null
@@ -1354,7 +1354,33 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
if(amount) if(amount)
A.reagents.add_reagent(chosen_id, amount) A.reagents.add_reagent(chosen_id, amount)
A.splat(target) A.splat(target)
if(ADMIN_PUNISHMENT_CRACK)
if(!iscarbon(target))
to_chat(usr,"<span class='warning'>This must be used on a carbon mob.</span>", confidential = TRUE)
return
var/mob/living/carbon/C = target
for(var/obj/item/bodypart/squish_part in C.bodyparts)
var/type_wound = pick(list(/datum/wound/brute/bone/critical, /datum/wound/brute/bone/severe, /datum/wound/brute/bone/critical, /datum/wound/brute/bone/severe, /datum/wound/brute/bone/moderate))
squish_part.force_wound_upwards(type_wound, smited=TRUE)
if(ADMIN_PUNISHMENT_BLEED)
if(!iscarbon(target))
to_chat(usr,"<span class='warning'>This must be used on a carbon mob.</span>", confidential = TRUE)
return
var/mob/living/carbon/C = target
for(var/obj/item/bodypart/slice_part in C.bodyparts)
var/type_wound = pick(list(/datum/wound/brute/cut/severe, /datum/wound/brute/cut/moderate))
slice_part.force_wound_upwards(type_wound, smited=TRUE)
type_wound = pick(list(/datum/wound/brute/cut/critical, /datum/wound/brute/cut/severe, /datum/wound/brute/cut/moderate))
slice_part.force_wound_upwards(type_wound, smited=TRUE)
type_wound = pick(list(/datum/wound/brute/cut/critical, /datum/wound/brute/cut/severe))
slice_part.force_wound_upwards(type_wound, smited=TRUE)
if(ADMIN_PUNISHMENT_SCARIFY)
if(!iscarbon(target))
to_chat(usr,"<span class='warning'>This must be used on a carbon mob.</span>", confidential = TRUE)
return
var/mob/living/carbon/C = target
C.generate_fake_scars(rand(1, 4))
to_chat(C, "<span class='warning'>You feel your body grow jaded and torn...</span>")
punish_log(target, punishment) punish_log(target, punishment)
/client/proc/punish_log(var/whom, var/punishment) /client/proc/punish_log(var/whom, var/punishment)

View File

@@ -36,6 +36,6 @@
M.adjust_fire_stacks(round(reac_volume/10)) M.adjust_fire_stacks(round(reac_volume/10))
M.IgniteMob() M.IgniteMob()
if(M) if(M)
M.apply_damage(0.8*reac_volume, BURN) M.apply_damage(0.8*reac_volume, BURN, wound_bonus=CANT_WOUND)
if(iscarbon(M)) if(iscarbon(M))
M.emote("scream") M.emote("scream")

View File

@@ -22,7 +22,7 @@
M.reagents.add_reagent("frostoil", 0.3*reac_volume) M.reagents.add_reagent("frostoil", 0.3*reac_volume)
M.reagents.add_reagent("ice", 0.3*reac_volume) M.reagents.add_reagent("ice", 0.3*reac_volume)
M.reagents.add_reagent("cryogenic_poison", 0.3*reac_volume) M.reagents.add_reagent("cryogenic_poison", 0.3*reac_volume)
M.apply_damage(0.2*reac_volume, BRUTE) M.apply_damage(0.2*reac_volume, BRUTE, wound_bonus=CANT_WOUND)
/datum/reagent/blob/cryogenic_poison/on_mob_life(mob/living/carbon/M) /datum/reagent/blob/cryogenic_poison/on_mob_life(mob/living/carbon/M)
M.adjustBruteLoss(0.3*REAGENTS_EFFECT_MULTIPLIER, 0) M.adjustBruteLoss(0.3*REAGENTS_EFFECT_MULTIPLIER, 0)

View File

@@ -30,4 +30,4 @@
if(prob(reac_volume*2)) if(prob(reac_volume*2))
M.emp_act(EMP_LIGHT) M.emp_act(EMP_LIGHT)
if(M) if(M)
M.apply_damage(reac_volume, BURN) M.apply_damage(reac_volume, BURN, wound_bonus=CANT_WOUND)

View File

@@ -33,8 +33,8 @@
if(ROLE_BLOB in L.faction) //no friendly fire if(ROLE_BLOB in L.faction) //no friendly fire
continue continue
var/aoe_volume = ..(L, TOUCH, initial_volume, 0, L.get_permeability_protection(), O) var/aoe_volume = ..(L, TOUCH, initial_volume, 0, L.get_permeability_protection(), O)
L.apply_damage(0.4*aoe_volume, BRUTE) L.apply_damage(0.4*aoe_volume, BRUTE, wound_bonus=CANT_WOUND)
if(M) if(M)
M.apply_damage(0.6*reac_volume, BRUTE) M.apply_damage(0.6*reac_volume, BRUTE, wound_bonus=CANT_WOUND)
else else
M.apply_damage(0.6*reac_volume, BRUTE) M.apply_damage(0.6*reac_volume, BRUTE, wound_bonus=CANT_WOUND)

View File

@@ -33,6 +33,6 @@
/datum/reagent/blob/networked_fibers/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message, touch_protection, mob/camera/blob/O) /datum/reagent/blob/networked_fibers/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message, touch_protection, mob/camera/blob/O)
reac_volume = ..() reac_volume = ..()
M.apply_damage(0.6*reac_volume, BRUTE) M.apply_damage(0.6*reac_volume, BRUTE, wound_bonus=CANT_WOUND)
if(M) if(M)
M.apply_damage(0.6*reac_volume, BURN) M.apply_damage(0.6*reac_volume, BURN, wound_bonus=CANT_WOUND)

View File

@@ -44,7 +44,7 @@
T.MakeSlippery(TURF_WET_LUBE, min_wet_time = 10 SECONDS, wet_time_to_add = 5 SECONDS) T.MakeSlippery(TURF_WET_LUBE, min_wet_time = 10 SECONDS, wet_time_to_add = 5 SECONDS)
M.adjust_fire_stacks(-(reac_volume / 10)) M.adjust_fire_stacks(-(reac_volume / 10))
M.ExtinguishMob() M.ExtinguishMob()
M.apply_damage(0.4*reac_volume, BRUTE) M.apply_damage(0.4*reac_volume, BRUTE, wound_bonus=CANT_WOUND)
if(M) if(M)
M.apply_damage(0.4*reac_volume, OXY) M.apply_damage(0.4*reac_volume, OXY)
if(M) if(M)

View File

@@ -31,4 +31,4 @@
/datum/reagent/blob/replicating_foam/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message, touch_protection, mob/camera/blob/O) /datum/reagent/blob/replicating_foam/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message, touch_protection, mob/camera/blob/O)
reac_volume = ..() reac_volume = ..()
M.apply_damage(0.7*reac_volume, BRUTE) M.apply_damage(0.7*reac_volume, BRUTE, wound_bonus=CANT_WOUND)

View File

@@ -32,4 +32,4 @@
/datum/reagent/blob/shifting_fragments/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message, touch_protection, mob/camera/blob/O) /datum/reagent/blob/shifting_fragments/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message, touch_protection, mob/camera/blob/O)
reac_volume = ..() reac_volume = ..()
M.apply_damage(0.7*reac_volume, BRUTE) M.apply_damage(0.7*reac_volume, BRUTE, wound_bonus=CANT_WOUND)

View File

@@ -30,9 +30,9 @@
/datum/reagent/blob/synchronous_mesh/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message, touch_protection, mob/camera/blob/O) /datum/reagent/blob/synchronous_mesh/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message, touch_protection, mob/camera/blob/O)
reac_volume = ..() reac_volume = ..()
M.apply_damage(0.2*reac_volume, BRUTE) M.apply_damage(0.2*reac_volume, BRUTE, wound_bonus=CANT_WOUND)
if(M && reac_volume) if(M && reac_volume)
for(var/obj/structure/blob/B in range(1, M)) //if the target is completely surrounded, this is 2.4*reac_volume bonus damage, total of 2.6*reac_volume for(var/obj/structure/blob/B in range(1, M)) //if the target is completely surrounded, this is 2.4*reac_volume bonus damage, total of 2.6*reac_volume
if(M) if(M)
B.blob_attack_animation(M) //show them they're getting a bad time B.blob_attack_animation(M) //show them they're getting a bad time
M.apply_damage(0.3*reac_volume, BRUTE) M.apply_damage(0.3*reac_volume, BRUTE, wound_bonus=CANT_WOUND)

View File

@@ -1,6 +1,6 @@
/obj/effect/proc_holder/changeling/fleshmend /obj/effect/proc_holder/changeling/fleshmend
name = "Fleshmend" name = "Fleshmend"
desc = "Our flesh rapidly regenerates, healing our burns, bruises, and shortness of breath. Functions while unconscious. This ability is loud, and might cause our blood to react violently to heat." desc = "Our flesh rapidly regenerates, healing our burns, bruises, and shortness of breath, as well as hiding all of our scars. Costs 20 chemicals."
helptext = "If we are on fire, the healing effect will not function. Does not regrow limbs or restore lost blood." helptext = "If we are on fire, the healing effect will not function. Does not regrow limbs or restore lost blood."
chemical_cost = 20 chemical_cost = 20
loudness = 2 loudness = 2

View File

@@ -165,6 +165,8 @@
hitsound = 'sound/weapons/bladeslice.ogg' hitsound = 'sound/weapons/bladeslice.ogg'
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
sharpness = IS_SHARP sharpness = IS_SHARP
wound_bonus = -60
bare_wound_bonus = 20
var/can_drop = FALSE var/can_drop = FALSE
var/fake = FALSE var/fake = FALSE
total_mass = TOTAL_MASS_HAND_REPLACEMENT total_mass = TOTAL_MASS_HAND_REPLACEMENT

View File

@@ -29,6 +29,9 @@
C.emote("scream") C.emote("scream")
C.regenerate_limbs(1) C.regenerate_limbs(1)
C.regenerate_organs() C.regenerate_organs()
for(var/i in C.all_wounds)
var/datum/wound/W = i
W.remove_wound()
if(!user.getorganslot(ORGAN_SLOT_BRAIN)) if(!user.getorganslot(ORGAN_SLOT_BRAIN))
var/obj/item/organ/brain/B var/obj/item/organ/brain/B
if(C.has_dna() && C.dna.species.mutant_brain) if(C.has_dna() && C.dna.species.mutant_brain)

View File

@@ -34,6 +34,8 @@
w_class = WEIGHT_CLASS_SMALL w_class = WEIGHT_CLASS_SMALL
force = 15 force = 15
throwforce = 25 throwforce = 25
wound_bonus = -30
bare_wound_bonus = 30
armour_penetration = 35 armour_penetration = 35
actions_types = list(/datum/action/item_action/cult_dagger) actions_types = list(/datum/action/item_action/cult_dagger)
@@ -53,8 +55,10 @@
flags_1 = CONDUCT_1 flags_1 = CONDUCT_1
sharpness = IS_SHARP sharpness = IS_SHARP
w_class = WEIGHT_CLASS_BULKY w_class = WEIGHT_CLASS_BULKY
force = 30 force = 30 // whoever balanced this got beat in the head by a bible too many times good lord
throwforce = 10 throwforce = 10
wound_bonus = -80
bare_wound_bonus = 30
hitsound = 'sound/weapons/bladeslice.ogg' hitsound = 'sound/weapons/bladeslice.ogg'
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "rended") attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "rended")

View File

@@ -34,8 +34,11 @@
healable = 0 healable = 0
environment_smash = ENVIRONMENT_SMASH_STRUCTURES environment_smash = ENVIRONMENT_SMASH_STRUCTURES
obj_damage = 50 obj_damage = 50
melee_damage_lower = 30 melee_damage_lower = 15 // reduced from 30 to 15 with wounds since they get big buffs to slicing wounds
melee_damage_upper = 30 melee_damage_upper = 15
wound_bonus = -10
bare_wound_bonus = 0
sharpness = TRUE
see_in_dark = 8 see_in_dark = 8
blood_volume = 0 //No bleeding on getting shot, for skeddadles blood_volume = 0 //No bleeding on getting shot, for skeddadles
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
@@ -43,13 +46,25 @@
var/playstyle_string = "<span class='big bold'>You are a slaughter demon,</span><B> a terrible creature from another realm. You have a single desire: To kill. \ var/playstyle_string = "<span class='big bold'>You are a slaughter demon,</span><B> a terrible creature from another realm. You have a single desire: To kill. \
You may use the \"Blood Crawl\" ability near blood pools to travel through them, appearing and disappearing from the station at will. \ You may use the \"Blood Crawl\" ability near blood pools to travel through them, appearing and disappearing from the station at will. \
Pulling a dead or unconscious mob while you enter a pool will pull them in with you, allowing you to feast and regain your health. \ Pulling a dead or unconscious mob while you enter a pool will pull them in with you, allowing you to feast and regain your health. \
You move quickly upon leaving a pool of blood, but the material world will soon sap your strength and leave you sluggish. </B>" You move quickly upon leaving a pool of blood, but the material world will soon sap your strength and leave you sluggish. \
You gain strength the more attacks you land on live humanoids, though this resets when you return to the blood zone. You can also \
launch a devastating slam attack with ctrl+shift+click, capable of smashing bones in one strike.</B>"
loot = list(/obj/effect/decal/cleanable/blood, \ loot = list(/obj/effect/decal/cleanable/blood, \
/obj/effect/decal/cleanable/blood/innards, \ /obj/effect/decal/cleanable/blood/innards, \
/obj/item/organ/heart/demon) /obj/item/organ/heart/demon)
del_on_death = 1 del_on_death = 1
deathmessage = "screams in anger as it collapses into a puddle of viscera!" deathmessage = "screams in anger as it collapses into a puddle of viscera!"
// How long it takes for the alt-click slam attack to come off cooldown
var/slam_cooldown_time = 45 SECONDS
// The actual instance var for the cooldown
var/slam_cooldown = 0
// How many times we have hit humanoid targets since we last bloodcrawled, scaling wounding power
var/current_hitstreak = 0
// How much both our wound_bonus and bare_wound_bonus go up per hitstreak hit
var/wound_bonus_per_hit = 5
// How much our wound_bonus hitstreak bonus caps at (peak demonry)
var/wound_bonus_hitstreak_max = 12
/mob/living/simple_animal/slaughter/Initialize() /mob/living/simple_animal/slaughter/Initialize()
..() ..()
@@ -58,6 +73,33 @@
if(istype(loc, /obj/effect/dummy/phased_mob/slaughter)) if(istype(loc, /obj/effect/dummy/phased_mob/slaughter))
bloodspell.phased = TRUE bloodspell.phased = TRUE
/mob/living/simple_animal/slaughter/CtrlShiftClickOn(atom/A)
if(!isliving(A))
return ..()
if(slam_cooldown + slam_cooldown_time > world.time)
to_chat(src, "<span class='warning'>Your slam ability is still on cooldown!</span>")
return
face_atom(A)
var/mob/living/victim = A
victim.take_bodypart_damage(brute=20, wound_bonus=wound_bonus) // don't worry, there's more punishment when they hit something
visible_message("<span class='danger'>[src] slams into [victim] with monstrous strength!</span>", "<span class='danger'>You slam into [victim] with monstrous strength!</span>", ignored_mobs=victim)
to_chat(victim, "<span class='userdanger'>[src] slams into you with monstrous strength, sending you flying like a ragdoll!</span>")
var/turf/yeet_target = get_edge_target_turf(victim, dir)
victim.throw_at(yeet_target, 10, 5, src)
slam_cooldown = world.time
log_combat(src, victim, "slaughter slammed")
/mob/living/simple_animal/slaughter/UnarmedAttack(atom/A, proximity)
if(iscarbon(A))
var/mob/living/carbon/target = A
if(target.stat != DEAD && target.mind && current_hitstreak < wound_bonus_hitstreak_max)
current_hitstreak++
wound_bonus += wound_bonus_per_hit
bare_wound_bonus += wound_bonus_per_hit
return ..()
/obj/effect/decal/cleanable/blood/innards /obj/effect/decal/cleanable/blood/innards
icon = 'icons/obj/surgery.dmi' icon = 'icons/obj/surgery.dmi'
name = "pile of viscera" name = "pile of viscera"

View File

@@ -14,6 +14,7 @@
/datum/antagonist/slaughter/greet() /datum/antagonist/slaughter/greet()
. = ..() . = ..()
owner.announce_objectives() owner.announce_objectives()
to_chat(owner, "<span class='warning'>You have a powerful alt-attack that slams people backwards that you can activate by shift+ctrl+clicking your target!</span>")
/datum/antagonist/slaughter/proc/forge_objectives() /datum/antagonist/slaughter/proc/forge_objectives()
if(summoner) if(summoner)

View File

@@ -33,6 +33,8 @@
var/escape_in_progress = FALSE var/escape_in_progress = FALSE
var/message_cooldown var/message_cooldown
var/breakout_time = 300 var/breakout_time = 300
///Cryo will continue to treat people with 0 damage but existing wounds, but will sound off when damage healing is done in case doctors want to directly treat the wounds instead
var/treating_wounds = FALSE
fair_market_price = 10 fair_market_price = 10
payment_department = ACCOUNT_MED payment_department = ACCOUNT_MED
@@ -174,15 +176,27 @@
return return
if(mob_occupant.health >= mob_occupant.getMaxHealth()) // Don't bother with fully healed people. if(mob_occupant.health >= mob_occupant.getMaxHealth()) // Don't bother with fully healed people.
on = FALSE if(iscarbon(mob_occupant))
update_icon() var/mob/living/carbon/C = mob_occupant
playsound(src, 'sound/machines/cryo_warning.ogg', volume) // Bug the doctors. if(C.all_wounds)
var/msg = "Patient fully restored." if(!treating_wounds) // if we have wounds and haven't already alerted the doctors we're only dealing with the wounds, let them know
if(autoeject) // Eject if configured. treating_wounds = TRUE
msg += " Auto ejecting patient now." playsound(src, 'sound/machines/cryo_warning.ogg', volume) // Bug the doctors.
open_machine() var/msg = "Patient vitals fully recovered, continuing automated wound treatment."
radio.talk_into(src, msg, radio_channel) radio.talk_into(src, msg, radio_channel)
return else // otherwise if we were only treating wounds and now we don't have any, turn off treating_wounds so we can boot 'em out
treating_wounds = FALSE
if(!treating_wounds)
on = FALSE
update_icon()
playsound(src, 'sound/machines/cryo_warning.ogg', volume) // Bug the doctors.
var/msg = "Patient fully restored."
if(autoeject) // Eject if configured.
msg += " Auto ejecting patient now."
open_machine()
radio.talk_into(src, msg, radio_channel)
return
var/datum/gas_mixture/air1 = airs[1] var/datum/gas_mixture/air1 = airs[1]

View File

@@ -75,3 +75,9 @@
desc = "The simple beach ball is one of Nanotrasen's most popular products. 'Why do we make beach balls? Because we can! (TM)' - Nanotrasen" desc = "The simple beach ball is one of Nanotrasen's most popular products. 'Why do we make beach balls? Because we can! (TM)' - Nanotrasen"
cost = 200 cost = 200
contains = list(/obj/item/toy/beach_ball) contains = list(/obj/item/toy/beach_ball)
/datum/supply_pack/goody/hell_single
name = "Hellgun Single-Pack"
desc = "Contains one hellgun, an old pattern of laser gun infamous for its ability to horribly disfigure targets with burns. Technically violates the Space Geneva Convention when used on humanoids."
cost = 1500
contains = list(/obj/item/gun/energy/laser/hellgun)

View File

@@ -114,7 +114,9 @@
/obj/item/storage/box/medsprays, /obj/item/storage/box/medsprays,
/obj/item/storage/box/syringes, /obj/item/storage/box/syringes,
/obj/item/storage/box/bodybags, /obj/item/storage/box/bodybags,
/obj/item/storage/pill_bottle/stimulant) /obj/item/storage/pill_bottle/stimulant,
/obj/item/stack/medical/bone_gel,
/obj/item/stack/medical/bone_gel)
crate_name = "medical supplies crate" crate_name = "medical supplies crate"
/datum/supply_pack/medical/adv_surgery_tools /datum/supply_pack/medical/adv_surgery_tools

View File

@@ -239,6 +239,13 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/autostand = TRUE var/autostand = TRUE
var/auto_ooc = FALSE var/auto_ooc = FALSE
/// If we have persistent scars enabled
var/persistent_scars = TRUE
/// We have 5 slots for persistent scars, if enabled we pick a random one to load (empty by default) and scars at the end of the shift if we survived as our original person
var/list/scars_list = list("1" = "", "2" = "", "3" = "", "4" = "", "5" = "")
/// Which of the 5 persistent scar slots we randomly roll to load for this round, if enabled. Actually rolled in [/datum/preferences/proc/load_character(slot)]
var/scars_index = 1
/datum/preferences/New(client/C) /datum/preferences/New(client/C)
parent = C parent = C
@@ -825,6 +832,9 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "<b>Socks Color:</b> <span style='border:1px solid #161616; background-color: #[socks_color];'>&nbsp;&nbsp;&nbsp;</span> <a href='?_src_=prefs;preference=socks_color;task=input'>Change</a><BR>" dat += "<b>Socks Color:</b> <span style='border:1px solid #161616; background-color: #[socks_color];'>&nbsp;&nbsp;&nbsp;</span> <a href='?_src_=prefs;preference=socks_color;task=input'>Change</a><BR>"
dat += "<b>Backpack:</b><a style='display:block;width:100px' href ='?_src_=prefs;preference=bag;task=input'>[backbag]</a>" dat += "<b>Backpack:</b><a style='display:block;width:100px' href ='?_src_=prefs;preference=bag;task=input'>[backbag]</a>"
dat += "<b>Jumpsuit:</b><BR><a href ='?_src_=prefs;preference=suit;task=input'>[jumpsuit_style]</a><BR>" dat += "<b>Jumpsuit:</b><BR><a href ='?_src_=prefs;preference=suit;task=input'>[jumpsuit_style]</a><BR>"
if(CAN_SCAR in pref_species.species_traits)
dat += "<BR><b>Temporal Scarring:</b><BR><a href='?_src_=prefs;preference=persistent_scars'>[(persistent_scars) ? "Enabled" : "Disabled"]</A>"
dat += "<a href='?_src_=prefs;preference=clear_scars'>Clear scar slots</A>"
dat += "<b>Uplink Location:</b><a style='display:block;width:100px' href ='?_src_=prefs;preference=uplink_loc;task=input'>[uplink_spawn_loc]</a>" dat += "<b>Uplink Location:</b><a style='display:block;width:100px' href ='?_src_=prefs;preference=uplink_loc;task=input'>[uplink_spawn_loc]</a>"
dat += "</td>" dat += "</td>"
@@ -2545,6 +2555,17 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if("hear_midis") if("hear_midis")
toggles ^= SOUND_MIDI toggles ^= SOUND_MIDI
if("persistent_scars")
persistent_scars = !persistent_scars
if("clear_scars")
to_chat(user, "<span class='notice'>All scar slots cleared. Please save character to confirm.</span>")
scars_list["1"] = ""
scars_list["2"] = ""
scars_list["3"] = ""
scars_list["4"] = ""
scars_list["5"] = ""
if("lobby_music") if("lobby_music")
toggles ^= SOUND_LOBBY toggles ^= SOUND_LOBBY
if((toggles & SOUND_LOBBY) && user.client && isnewplayer(user)) if((toggles & SOUND_LOBBY) && user.client && isnewplayer(user))

View File

@@ -453,6 +453,9 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
if(newtype) if(newtype)
pref_species = new newtype pref_species = new newtype
scars_index = rand(1,5)
//Character //Character
S["real_name"] >> real_name S["real_name"] >> real_name
S["nameless"] >> nameless S["nameless"] >> nameless
@@ -497,6 +500,12 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["feature_insect_markings"] >> features["insect_markings"] S["feature_insect_markings"] >> features["insect_markings"]
S["feature_horns_color"] >> features["horns_color"] S["feature_horns_color"] >> features["horns_color"]
S["feature_wings_color"] >> features["wings_color"] S["feature_wings_color"] >> features["wings_color"]
S["persistent_scars"] >> persistent_scars
S["scars1"] >> scars_list["1"]
S["scars2"] >> scars_list["2"]
S["scars3"] >> scars_list["3"]
S["scars4"] >> scars_list["4"]
S["scars5"] >> scars_list["5"]
//Custom names //Custom names
@@ -709,6 +718,13 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
features["silicon_flavor_text"] = copytext(features["silicon_flavor_text"], 1, MAX_FLAVOR_LEN) features["silicon_flavor_text"] = copytext(features["silicon_flavor_text"], 1, MAX_FLAVOR_LEN)
features["ooc_notes"] = copytext(features["ooc_notes"], 1, MAX_FLAVOR_LEN) features["ooc_notes"] = copytext(features["ooc_notes"], 1, MAX_FLAVOR_LEN)
persistent_scars = sanitize_integer(persistent_scars)
scars_list["1"] = sanitize_text(scars_list["1"])
scars_list["2"] = sanitize_text(scars_list["2"])
scars_list["3"] = sanitize_text(scars_list["3"])
scars_list["4"] = sanitize_text(scars_list["4"])
scars_list["5"] = sanitize_text(scars_list["5"])
joblessrole = sanitize_integer(joblessrole, 1, 3, initial(joblessrole)) joblessrole = sanitize_integer(joblessrole, 1, 3, initial(joblessrole))
//Validate job prefs //Validate job prefs
for(var/j in job_preferences) for(var/j in job_preferences)
@@ -840,6 +856,13 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["vore_taste"] , vore_taste) WRITE_FILE(S["vore_taste"] , vore_taste)
WRITE_FILE(S["belly_prefs"] , belly_prefs) WRITE_FILE(S["belly_prefs"] , belly_prefs)
WRITE_FILE(S["persistent_scars"] , persistent_scars)
WRITE_FILE(S["scars1"] , scars_list["1"])
WRITE_FILE(S["scars2"] , scars_list["2"])
WRITE_FILE(S["scars3"] , scars_list["3"])
WRITE_FILE(S["scars4"] , scars_list["4"])
WRITE_FILE(S["scars5"] , scars_list["5"])
//gear loadout //gear loadout
if(chosen_gear.len) if(chosen_gear.len)
var/text_to_save = chosen_gear.Join("|") var/text_to_save = chosen_gear.Join("|")

View File

@@ -4,7 +4,7 @@
max_integrity = 200 max_integrity = 200
integrity_failure = 0.4 integrity_failure = 0.4
block_priority = BLOCK_PRIORITY_CLOTHING block_priority = BLOCK_PRIORITY_CLOTHING
var/damaged_clothes = 0 //similar to machine's BROKEN stat and structure's broken var var/damaged_clothes = CLOTHING_PRISTINE //similar to machine's BROKEN stat and structure's broken var
var/flash_protect = 0 //What level of bright light protection item has. 1 = Flashers, Flashes, & Flashbangs | 2 = Welding | -1 = OH GOD WELDING BURNT OUT MY RETINAS var/flash_protect = 0 //What level of bright light protection item has. 1 = Flashers, Flashes, & Flashbangs | 2 = Welding | -1 = OH GOD WELDING BURNT OUT MY RETINAS
var/tint = 0 //Sets the item's level of visual impairment tint, normally set to the same as flash_protect var/tint = 0 //Sets the item's level of visual impairment tint, normally set to the same as flash_protect
var/up = 0 //but separated to allow items to protect but not impair vision, like space helmets var/up = 0 //but separated to allow items to protect but not impair vision, like space helmets
@@ -28,6 +28,9 @@
var/clothing_flags = NONE var/clothing_flags = NONE
// What items can be consumed to repair this clothing (must by an /obj/item/stack)
var/repairable_by = /obj/item/stack/sheet/cloth
//Var modification - PLEASE be careful with this I know who you are and where you live //Var modification - PLEASE be careful with this I know who you are and where you live
var/list/user_vars_to_edit //VARNAME = VARVALUE eg: "name" = "butts" var/list/user_vars_to_edit //VARNAME = VARVALUE eg: "name" = "butts"
var/list/user_vars_remembered //Auto built by the above + dropped() + equipped() var/list/user_vars_remembered //Auto built by the above + dropped() + equipped()
@@ -45,7 +48,17 @@
var/list/species_restricted = null var/list/species_restricted = null
//Basically syntax is species_restricted = list("Species Name","Species Name") //Basically syntax is species_restricted = list("Species Name","Species Name")
//Add a "exclude" string to do the opposite, making it only only species listed that can't wear it. //Add a "exclude" string to do the opposite, making it only only species listed that can't wear it.
//You append this to clothing objects. //You append this to clothing objects
// How much clothing damage has been dealt to each of the limbs of the clothing, assuming it covers more than one limb
var/list/damage_by_parts
// How much integrity is in a specific limb before that limb is disabled (for use in [/obj/item/clothing/proc/take_damage_zone], and only if we cover multiple zones.) Set to 0 to disable shredding.
var/limb_integrity = 0
// How many zones (body parts, not precise) we have disabled so far, for naming purposes
var/zones_disabled
.
/obj/item/clothing/Initialize() /obj/item/clothing/Initialize()
. = ..() . = ..()
@@ -83,15 +96,105 @@
return ..() return ..()
/obj/item/clothing/attackby(obj/item/W, mob/user, params) /obj/item/clothing/attackby(obj/item/W, mob/user, params)
if(damaged_clothes && istype(W, /obj/item/stack/sheet/cloth)) if(damaged_clothes && istype(W, repairable_by))
var/obj/item/stack/sheet/cloth/C = W var/obj/item/stack/S = W
C.use(1) switch(damaged_clothes)
update_clothes_damaged_state(FALSE) if(CLOTHING_DAMAGED)
obj_integrity = max_integrity S.use(1)
to_chat(user, "<span class='notice'>You fix the damage on [src] with [C].</span>") repair(user, params)
if(CLOTHING_SHREDDED)
if(S.amount < 3)
to_chat(user, "<span class='warning'>You require 3 [S.name] to repair [src].</span>")
return
to_chat(user, "<span class='notice'>You begin fixing the damage to [src] with [S]...</span>")
if(do_after(user, 6 SECONDS, TRUE, src))
if(S.use(3))
repair(user, params)
return 1 return 1
return ..() return ..()
// Set the clothing's integrity back to 100%, remove all damage to bodyparts, and generally fix it up
/obj/item/clothing/proc/repair(mob/user, params)
damaged_clothes = CLOTHING_PRISTINE
update_clothes_damaged_state()
obj_integrity = max_integrity
name = initial(name) // remove "tattered" or "shredded" if there's a prefix
body_parts_covered = initial(body_parts_covered)
slot_flags = initial(slot_flags)
damage_by_parts = null
if(user)
UnregisterSignal(user, COMSIG_MOVABLE_MOVED)
to_chat(user, "<span class='notice'>You fix the damage on [src].</span>")
/**
* take_damage_zone() is used for dealing damage to specific bodyparts on a worn piece of clothing, meant to be called from [/obj/item/bodypart/proc/check_woundings_mods()]
*
* This proc only matters when a bodypart that this clothing is covering is harmed by a direct attack (being on fire or in space need not apply), and only if this clothing covers
* more than one bodypart to begin with. No point in tracking damage by zone for a hat, and I'm not cruel enough to let you fully break them in a few shots.
* Also if limb_integrity is 0, then this clothing doesn't have bodypart damage enabled so skip it.
*
* Arguments:
* * def_zone: The bodypart zone in question
* * damage_amount: Incoming damage
* * damage_type: BRUTE or BURN
* * armour_penetration: If the attack had armour_penetration
*/
/obj/item/clothing/proc/take_damage_zone(def_zone, damage_amount, damage_type, armour_penetration)
if(!def_zone || !limb_integrity || (initial(body_parts_covered) in GLOB.bitflags)) // the second check sees if we only cover one bodypart anyway and don't need to bother with this
return
var/list/covered_limbs = body_parts_covered2organ_names(body_parts_covered) // what do we actually cover?
if(!(def_zone in covered_limbs))
return
var/damage_dealt = take_damage(damage_amount * 0.1, damage_type, armour_penetration, FALSE) * 10 // only deal 10% of the damage to the general integrity damage, then multiply it by 10 so we know how much to deal to limb
LAZYINITLIST(damage_by_parts)
damage_by_parts[def_zone] += damage_dealt
if(damage_by_parts[def_zone] > limb_integrity)
disable_zone(def_zone, damage_type)
/**
* disable_zone() is used to disable a given bodypart's protection on our clothing item, mainly from [/obj/item/clothing/proc/take_damage_zone()]
*
* This proc disables all protection on the specified bodypart for this piece of clothing: it'll be as if it doesn't cover it at all anymore (because it won't!)
* If every possible bodypart has been disabled on the clothing, we put it out of commission entirely and mark it as shredded, whereby it will have to be repaired in
* order to equip it again. Also note we only consider it damaged if there's more than one bodypart disabled.
*
* Arguments:
* * def_zone: The bodypart zone we're disabling
* * damage_type: Only really relevant for the verb for describing the breaking, and maybe obj_destruction()
*/
/obj/item/clothing/proc/disable_zone(def_zone, damage_type)
var/list/covered_limbs = body_parts_covered2organ_names(body_parts_covered)
if(!(def_zone in covered_limbs))
return
var/zone_name = parse_zone(def_zone)
var/break_verb = ((damage_type == BRUTE) ? "torn" : "burned")
if(iscarbon(loc))
var/mob/living/carbon/C = loc
C.visible_message("<span class='danger'>The [zone_name] on [C]'s [src.name] is [break_verb] away!</span>", "<span class='userdanger'>The [zone_name] on your [src.name] is [break_verb] away!</span>", vision_distance = COMBAT_MESSAGE_RANGE)
RegisterSignal(C, COMSIG_MOVABLE_MOVED, .proc/bristle)
zones_disabled++
for(var/i in zone2body_parts_covered(def_zone))
body_parts_covered &= ~i
if(body_parts_covered == NONE) // if there are no more parts to break then the whole thing is kaput
obj_destruction((damage_type == BRUTE ? "melee" : "laser")) // melee/laser is good enough since this only procs from direct attacks anyway and not from fire/bombs
return
damaged_clothes = CLOTHING_DAMAGED
switch(zones_disabled)
if(1)
name = "damaged [initial(name)]"
if(2)
name = "mangy [initial(name)]"
if(3 to INFINITY) // take better care of your shit, dude
name = "tattered [initial(name)]"
update_clothes_damaged_state()
/obj/item/clothing/Destroy() /obj/item/clothing/Destroy()
user_vars_remembered = null //Oh god somebody put REFERENCES in here? not to worry, we'll clean it up user_vars_remembered = null //Oh god somebody put REFERENCES in here? not to worry, we'll clean it up
return ..() return ..()
@@ -100,6 +203,7 @@
..() ..()
if(!istype(user)) if(!istype(user))
return return
UnregisterSignal(user, COMSIG_MOVABLE_MOVED)
if(LAZYLEN(user_vars_remembered)) if(LAZYLEN(user_vars_remembered))
for(var/variable in user_vars_remembered) for(var/variable in user_vars_remembered)
if(variable in user.vars) if(variable in user.vars)
@@ -112,7 +216,9 @@
if (!istype(user)) if (!istype(user))
return return
if(slot_flags & slotdefine2slotbit(slot)) //Was equipped to a valid slot for this item? if(slot_flags & slotdefine2slotbit(slot)) //Was equipped to a valid slot for this item?
if (LAZYLEN(user_vars_to_edit)) if(iscarbon(user) && LAZYLEN(zones_disabled))
RegisterSignal(user, COMSIG_MOVABLE_MOVED, .proc/bristle)
if(LAZYLEN(user_vars_to_edit))
for(var/variable in user_vars_to_edit) for(var/variable in user_vars_to_edit)
if(variable in user.vars) if(variable in user.vars)
LAZYSET(user_vars_remembered, variable, user.vars[variable]) LAZYSET(user_vars_remembered, variable, user.vars[variable])
@@ -120,8 +226,19 @@
/obj/item/clothing/examine(mob/user) /obj/item/clothing/examine(mob/user)
. = ..() . = ..()
if(damaged_clothes) if(damaged_clothes == CLOTHING_SHREDDED)
. += "<span class='warning'>It looks damaged!</span>" . += "<span class='warning'><b>It is completely shredded and requires mending before it can be worn again!</b></span>"
return
for(var/zone in damage_by_parts)
var/pct_damage_part = damage_by_parts[zone] / limb_integrity * 100
var/zone_name = parse_zone(zone)
switch(pct_damage_part)
if(100 to INFINITY)
. += "<span class='warning'><b>The [zone_name] is useless and requires mending!</b></span>"
if(60 to 99)
. += "<span class='warning'>The [zone_name] is heavily shredded!</span>"
if(30 to 59)
. += "<span class='danger'>The [zone_name] is partially shredded.</span>"
var/datum/component/storage/pockets = GetComponent(/datum/component/storage) var/datum/component/storage/pockets = GetComponent(/datum/component/storage)
if(pockets) if(pockets)
var/list/how_cool_are_your_threads = list("<span class='notice'>") var/list/how_cool_are_your_threads = list("<span class='notice'>")
@@ -139,8 +256,8 @@
. += how_cool_are_your_threads.Join() . += how_cool_are_your_threads.Join()
/obj/item/clothing/obj_break(damage_flag) /obj/item/clothing/obj_break(damage_flag)
if(!damaged_clothes) damaged_clothes = CLOTHING_DAMAGED
update_clothes_damaged_state(TRUE) update_clothes_damaged_state()
if(ismob(loc)) //It's not important enough to warrant a message if nobody's wearing it if(ismob(loc)) //It's not important enough to warrant a message if nobody's wearing it
var/mob/M = loc var/mob/M = loc
to_chat(M, "<span class='warning'>Your [name] starts to fall apart!</span>") to_chat(M, "<span class='warning'>Your [name] starts to fall apart!</span>")
@@ -222,16 +339,25 @@ BLIND // can't see anything
/obj/item/clothing/obj_destruction(damage_flag) /obj/item/clothing/obj_destruction(damage_flag)
if(damage_flag == "bomb" || damage_flag == "melee") if(damage_flag == "bomb")
var/turf/T = get_turf(src) var/turf/T = get_turf(src)
spawn(1) //so the shred survives potential turf change from the explosion. spawn(1) //so the shred survives potential turf change from the explosion.
var/obj/effect/decal/cleanable/shreds/Shreds = new(T) var/obj/effect/decal/cleanable/shreds/Shreds = new(T)
Shreds.desc = "The sad remains of what used to be [name]." Shreds.desc = "The sad remains of what used to be [name]."
deconstruct(FALSE) deconstruct(FALSE)
else if(!(damage_flag in list("acid", "fire")))
damaged_clothes = CLOTHING_SHREDDED
body_parts_covered = NONE
name = "shredded [initial(name)]"
slot_flags = NONE
update_clothes_damaged_state()
if(ismob(loc))
var/mob/M = loc
M.visible_message("<span class='danger'>[M]'s [src.name] falls off, completely shredded!</span>", "<span class='warning'><b>Your [src.name] falls off, completely shredded!</b></span>", vision_distance = COMBAT_MESSAGE_RANGE)
M.dropItemToGround(src)
else else
..() ..()
//Species-restricted clothing check. - Thanks Oraclestation, BS13, /vg/station etc. //Species-restricted clothing check. - Thanks Oraclestation, BS13, /vg/station etc.
/obj/item/clothing/mob_can_equip(mob/M, slot, disable_warning = TRUE) /obj/item/clothing/mob_can_equip(mob/M, slot, disable_warning = TRUE)
@@ -265,3 +391,12 @@ BLIND // can't see anything
return FALSE return FALSE
return TRUE return TRUE
/// If we're a clothing with at least 1 shredded/disabled zone, give the wearer a periodic heads up letting them know their clothes are damaged
/obj/item/clothing/proc/bristle(mob/living/L)
if(!istype(L))
return
if(prob(0.2))
to_chat(L, "<span class='warning'>The damaged threads on your [src.name] chafe!</span>")

View File

@@ -34,7 +34,7 @@
if(blood_DNA) if(blood_DNA)
. += mutable_appearance('icons/effects/blood.dmi', "bloodyhands", color = blood_DNA_to_color()) . += mutable_appearance('icons/effects/blood.dmi', "bloodyhands", color = blood_DNA_to_color())
/obj/item/clothing/gloves/update_clothes_damaged_state(damaging = TRUE) /obj/item/clothing/gloves/update_clothes_damaged_state()
..() ..()
if(ismob(loc)) if(ismob(loc))
var/mob/M = loc var/mob/M = loc

View File

@@ -56,7 +56,7 @@
if(blood_DNA) if(blood_DNA)
. += mutable_appearance('icons/effects/blood.dmi', "helmetblood", color = blood_DNA_to_color()) . += mutable_appearance('icons/effects/blood.dmi', "helmetblood", color = blood_DNA_to_color())
/obj/item/clothing/head/update_clothes_damaged_state(damaging = TRUE) /obj/item/clothing/head/update_clothes_damaged_state()
..() ..()
if(ismob(loc)) if(ismob(loc))
var/mob/M = loc var/mob/M = loc

View File

@@ -37,7 +37,7 @@
if(blood_DNA) if(blood_DNA)
. += mutable_appearance('icons/effects/blood.dmi', "maskblood", color = blood_DNA_to_color()) . += mutable_appearance('icons/effects/blood.dmi', "maskblood", color = blood_DNA_to_color())
/obj/item/clothing/mask/update_clothes_damaged_state(damaging = TRUE) /obj/item/clothing/mask/update_clothes_damaged_state()
..() ..()
if(ismob(loc)) if(ismob(loc))
var/mob/M = loc var/mob/M = loc

View File

@@ -85,7 +85,7 @@
restore_offsets(user) restore_offsets(user)
. = ..() . = ..()
/obj/item/clothing/shoes/update_clothes_damaged_state(damaging = TRUE) /obj/item/clothing/shoes/update_clothes_damaged_state()
..() ..()
if(ismob(loc)) if(ismob(loc))
var/mob/M = loc var/mob/M = loc

View File

@@ -10,6 +10,7 @@
var/blood_overlay_type = "suit" var/blood_overlay_type = "suit"
var/togglename = null var/togglename = null
var/suittoggled = FALSE var/suittoggled = FALSE
limb_integrity = 0 // disabled for most exo-suits
mutantrace_variation = STYLE_DIGITIGRADE mutantrace_variation = STYLE_DIGITIGRADE
/obj/item/clothing/suit/worn_overlays(isinhands = FALSE, icon_file, used_state, style_flags = NONE) /obj/item/clothing/suit/worn_overlays(isinhands = FALSE, icon_file, used_state, style_flags = NONE)
@@ -28,7 +29,7 @@
if(A.above_suit) if(A.above_suit)
. += U.accessory_overlay . += U.accessory_overlay
/obj/item/clothing/suit/update_clothes_damaged_state(damaging = TRUE) /obj/item/clothing/suit/update_clothes_damaged_state()
..() ..()
if(ismob(loc)) if(ismob(loc))
var/mob/M = loc var/mob/M = loc

View File

@@ -8,7 +8,8 @@
equip_delay_other = 40 equip_delay_other = 40
max_integrity = 250 max_integrity = 250
resistance_flags = NONE resistance_flags = NONE
armor = list("melee" = 30, "bullet" = 30, "laser" = 30, "energy" = 10, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50) armor = list("melee" = 30, "bullet" = 30, "laser" = 30, "energy" = 10, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50, "wound" = 15)
/obj/item/clothing/suit/armor/Initialize() /obj/item/clothing/suit/armor/Initialize()
. = ..() . = ..()
@@ -57,7 +58,7 @@
icon_state = "hos" icon_state = "hos"
item_state = "greatcoat" item_state = "greatcoat"
body_parts_covered = CHEST|GROIN|ARMS|LEGS body_parts_covered = CHEST|GROIN|ARMS|LEGS
armor = list("melee" = 30, "bullet" = 30, "laser" = 30, "energy" = 10, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 70, "acid" = 90) armor = list("melee" = 30, "bullet" = 30, "laser" = 30, "energy" = 10, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 70, "acid" = 90, "wound" = 20)
cold_protection = CHEST|GROIN|LEGS|ARMS cold_protection = CHEST|GROIN|LEGS|ARMS
heat_protection = CHEST|GROIN|LEGS|ARMS heat_protection = CHEST|GROIN|LEGS|ARMS
strip_delay = 80 strip_delay = 80
@@ -123,7 +124,7 @@
icon_state = "capcarapace" icon_state = "capcarapace"
item_state = "armor" item_state = "armor"
body_parts_covered = CHEST|GROIN body_parts_covered = CHEST|GROIN
armor = list("melee" = 50, "bullet" = 40, "laser" = 50, "energy" = 10, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 90) armor = list("melee" = 50, "bullet" = 40, "laser" = 50, "energy" = 10, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 90, "wound" = 10)
dog_fashion = null dog_fashion = null
resistance_flags = FIRE_PROOF resistance_flags = FIRE_PROOF
@@ -147,7 +148,7 @@
body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
armor = list("melee" = 50, "bullet" = 10, "laser" = 10, "energy" = 10, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 80, "acid" = 80) armor = list("melee" = 50, "bullet" = 10, "laser" = 10, "energy" = 10, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 80, "acid" = 80, "wound" = 30)
blocks_shove_knockdown = TRUE blocks_shove_knockdown = TRUE
strip_delay = 80 strip_delay = 80
equip_delay_other = 60 equip_delay_other = 60
@@ -158,7 +159,7 @@
icon_state = "bonearmor" icon_state = "bonearmor"
item_state = "bonearmor" item_state = "bonearmor"
blood_overlay_type = "armor" blood_overlay_type = "armor"
armor = list("melee" = 35, "bullet" = 25, "laser" = 25, "energy" = 10, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50) armor = list("melee" = 35, "bullet" = 25, "laser" = 25, "energy" = 10, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50, "wound" = 10)
body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS
/obj/item/clothing/suit/armor/bulletproof /obj/item/clothing/suit/armor/bulletproof
@@ -167,7 +168,7 @@
icon_state = "bulletproof" icon_state = "bulletproof"
item_state = "armor" item_state = "armor"
blood_overlay_type = "armor" blood_overlay_type = "armor"
armor = list("melee" = 15, "bullet" = 60, "laser" = 10, "energy" = 10, "bomb" = 40, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50) armor = list("melee" = 15, "bullet" = 60, "laser" = 10, "energy" = 10, "bomb" = 40, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50 "wound" = 20)
strip_delay = 70 strip_delay = 70
equip_delay_other = 50 equip_delay_other = 50
mutantrace_variation = STYLE_DIGITIGRADE|STYLE_NO_ANTHRO_ICON mutantrace_variation = STYLE_DIGITIGRADE|STYLE_NO_ANTHRO_ICON
@@ -285,7 +286,7 @@
desc = "A classic suit of armour, able to be made from many different materials." desc = "A classic suit of armour, able to be made from many different materials."
icon_state = "knight_greyscale" icon_state = "knight_greyscale"
item_state = "knight_greyscale" item_state = "knight_greyscale"
armor = list("melee" = 35, "bullet" = 10, "laser" = 10, "energy" = 10, "bomb" = 10, "bio" = 10, "rad" = 10, "fire" = 40, "acid" = 40) armor = list("melee" = 35, "bullet" = 10, "laser" = 10, "energy" = 10, "bomb" = 10, "bio" = 10, "rad" = 10, "fire" = 40, "acid" = 40, "wound" = 15)
material_flags = MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS //Can change color and add prefix material_flags = MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS //Can change color and add prefix
/obj/item/clothing/suit/armor/vest/durathread /obj/item/clothing/suit/armor/vest/durathread
@@ -304,7 +305,7 @@
desc = "A bulletproof vest with forest camo. Good thing there's plenty of forests to hide in around here, right?" desc = "A bulletproof vest with forest camo. Good thing there's plenty of forests to hide in around here, right?"
icon_state = "rus_armor" icon_state = "rus_armor"
item_state = "rus_armor" item_state = "rus_armor"
armor = list("melee" = 25, "bullet" = 30, "laser" = 0, "energy" = 15, "bomb" = 10, "bio" = 0, "rad" = 20, "fire" = 20, "acid" = 50) armor = list("melee" = 25, "bullet" = 30, "laser" = 0, "energy" = 15, "bomb" = 10, "bio" = 0, "rad" = 20, "fire" = 20, "acid" = 50, "wound" = 10)
/obj/item/clothing/suit/armor/vest/russian_coat /obj/item/clothing/suit/armor/vest/russian_coat
name = "russian battle coat" name = "russian battle coat"
@@ -315,4 +316,4 @@
body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT
armor = list("melee" = 25, "bullet" = 20, "laser" = 20, "energy" = 10, "bomb" = 20, "bio" = 50, "rad" = 20, "fire" = -10, "acid" = 50) armor = list("melee" = 25, "bullet" = 20, "laser" = 20, "energy" = 10, "bomb" = 20, "bio" = 50, "rad" = 20, "fire" = -10, "acid" = 50, "wound" = 10)

View File

@@ -73,7 +73,7 @@
gas_transfer_coefficient = 0.01 gas_transfer_coefficient = 0.01
permeability_coefficient = 0.01 permeability_coefficient = 0.01
body_parts_covered = CHEST|GROIN|ARMS|LEGS body_parts_covered = CHEST|GROIN|ARMS|LEGS
armor = list("melee" = 30, "bullet" = 20, "laser" = 20, "energy" = 20, "bomb" = 20, "bio" = 20, "rad" = 20, "fire" = 100, "acid" = 100) armor = list("melee" = 30, "bullet" = 20, "laser" = 20, "energy" = 20, "bomb" = 20, "bio" = 20, "rad" = 20, "fire" = 100, "acid" = 100, "wound" = 20)
allowed = list(/obj/item/teleportation_scroll) allowed = list(/obj/item/teleportation_scroll)
flags_inv = HIDEJUMPSUIT flags_inv = HIDEJUMPSUIT
strip_delay = 50 strip_delay = 50

View File

@@ -5,8 +5,9 @@
permeability_coefficient = 0.9 permeability_coefficient = 0.9
block_priority = BLOCK_PRIORITY_UNIFORM block_priority = BLOCK_PRIORITY_UNIFORM
slot_flags = ITEM_SLOT_ICLOTHING slot_flags = ITEM_SLOT_ICLOTHING
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0) armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0, "wound" = 5)
mutantrace_variation = STYLE_DIGITIGRADE|USE_TAUR_CLIP_MASK mutantrace_variation = STYLE_DIGITIGRADE|USE_TAUR_CLIP_MASK
limb_integrity = 30
var/fitted = FEMALE_UNIFORM_FULL // For use in alternate clothing styles for women var/fitted = FEMALE_UNIFORM_FULL // For use in alternate clothing styles for women
var/has_sensor = HAS_SENSORS // For the crew computer var/has_sensor = HAS_SENSORS // For the crew computer
var/random_sensor = TRUE var/random_sensor = TRUE
@@ -39,7 +40,7 @@
if(!attach_accessory(I, user)) if(!attach_accessory(I, user))
return ..() return ..()
/obj/item/clothing/under/update_clothes_damaged_state(damaging = TRUE) /obj/item/clothing/under/update_clothes_damaged_state()
..() ..()
if(ismob(loc)) if(ismob(loc))
var/mob/M = loc var/mob/M = loc

View File

@@ -34,8 +34,9 @@
mutantrace_variation = STYLE_DIGITIGRADE|STYLE_NO_ANTHRO_ICON mutantrace_variation = STYLE_DIGITIGRADE|STYLE_NO_ANTHRO_ICON
/obj/item/clothing/under/rank/cargo/miner /obj/item/clothing/under/rank/cargo/miner
desc = "It's a snappy jumpsuit with a sturdy set of overalls. It is very dirty."
name = "shaft miner's jumpsuit" name = "shaft miner's jumpsuit"
desc = "It's a snappy jumpsuit with a sturdy set of overalls. It is very dirty."
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 80, "acid" = 0, "wound" = 10)
icon_state = "miner" icon_state = "miner"
item_state = "miner" item_state = "miner"

View File

@@ -19,6 +19,7 @@
/obj/item/clothing/under/rank/captain/suit /obj/item/clothing/under/rank/captain/suit
name = "captain's suit" name = "captain's suit"
desc = "A green suit and yellow necktie. Exemplifies authority." desc = "A green suit and yellow necktie. Exemplifies authority."
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0, "wound" = 15)
icon_state = "green_suit" icon_state = "green_suit"
item_state = "dg_suit" item_state = "dg_suit"
can_adjust = FALSE can_adjust = FALSE

View File

@@ -19,7 +19,7 @@
desc = "A tactical security jumpsuit for officers complete with Nanotrasen belt buckle." desc = "A tactical security jumpsuit for officers complete with Nanotrasen belt buckle."
icon_state = "rsecurity" icon_state = "rsecurity"
item_state = "r_suit" item_state = "r_suit"
armor = list("melee" = 10, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 30, "acid" = 30) armor = list("melee" = 10, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 30, "acid" = 30, "wound" = 10)
/obj/item/clothing/under/rank/security/officer/grey /obj/item/clothing/under/rank/security/officer/grey
name = "grey security jumpsuit" name = "grey security jumpsuit"
@@ -67,7 +67,7 @@
desc = "A formal security suit for officers complete with Nanotrasen belt buckle." desc = "A formal security suit for officers complete with Nanotrasen belt buckle."
icon_state = "rwarden" icon_state = "rwarden"
item_state = "r_suit" item_state = "r_suit"
armor = list("melee" = 10, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 30, "acid" = 30) armor = list("melee" = 10, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 30, "acid" = 30, "wound" = 10)
/obj/item/clothing/under/rank/security/warden/grey /obj/item/clothing/under/rank/security/warden/grey
name = "grey security suit" name = "grey security suit"
@@ -101,7 +101,7 @@
desc = "Someone who wears this means business." desc = "Someone who wears this means business."
icon_state = "detective" icon_state = "detective"
item_state = "det" item_state = "det"
armor = list("melee" = 10, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 30, "acid" = 30) armor = list("melee" = 10, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 30, "acid" = 30, "wound" = 10)
/obj/item/clothing/under/rank/security/detective/skirt /obj/item/clothing/under/rank/security/detective/skirt
name = "detective's suitskirt" name = "detective's suitskirt"
@@ -138,7 +138,7 @@
desc = "A security jumpsuit decorated for those few with the dedication to achieve the position of Head of Security." desc = "A security jumpsuit decorated for those few with the dedication to achieve the position of Head of Security."
icon_state = "rhos" icon_state = "rhos"
item_state = "r_suit" item_state = "r_suit"
armor = list("melee" = 10, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50) armor = list("melee" = 10, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50, "wound" = 10)
strip_delay = 60 strip_delay = 60
/obj/item/clothing/under/rank/security/head_of_security/skirt /obj/item/clothing/under/rank/security/head_of_security/skirt

View File

@@ -313,6 +313,8 @@ h1.alert, h2.alert {color: #000000;}
.rose {color: #ff5050;} .rose {color: #ff5050;}
.info {color: #0000CC;} .info {color: #0000CC;}
.notice {color: #000099;} .notice {color: #000099;}
.tinynotice {color: #6685f5; font-style: italic; font-size: 85%;}
.smallnotice {color: #6685f5; font-style: italic; font-size: 90%;}
.boldnotice {color: #000099; font-weight: bold;} .boldnotice {color: #000099; font-weight: bold;}
.adminnotice {color: #0000ff;} .adminnotice {color: #0000ff;}
.adminhelp {color: #ff0000; font-weight: bold;} .adminhelp {color: #ff0000; font-weight: bold;}

View File

@@ -90,6 +90,7 @@
icon_state = "deathnettle" icon_state = "deathnettle"
force = 30 force = 30
throwforce = 15 throwforce = 15
wound_bonus = CANT_WOUND
/obj/item/reagent_containers/food/snacks/grown/nettle/death/add_juice() /obj/item/reagent_containers/food/snacks/grown/nettle/death/add_juice()
..() ..()

View File

@@ -45,7 +45,7 @@
shoes = /obj/item/clothing/shoes/sneakers/brown shoes = /obj/item/clothing/shoes/sneakers/brown
suit = /obj/item/clothing/suit/toggle/labcoat/cmo suit = /obj/item/clothing/suit/toggle/labcoat/cmo
l_hand = /obj/item/storage/firstaid/regular l_hand = /obj/item/storage/firstaid/regular
suit_store = /obj/item/flashlight/pen suit_store = /obj/item/flashlight/pen/paramedic
backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1) backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1)
backpack = /obj/item/storage/backpack/medic backpack = /obj/item/storage/backpack/medic

View File

@@ -36,7 +36,7 @@
suit = /obj/item/clothing/suit/toggle/labcoat/paramedic suit = /obj/item/clothing/suit/toggle/labcoat/paramedic
belt = /obj/item/storage/belt/medical belt = /obj/item/storage/belt/medical
l_hand = /obj/item/storage/firstaid/regular l_hand = /obj/item/storage/firstaid/regular
suit_store = /obj/item/flashlight/pen suit_store = /obj/item/flashlight/pen/paramedic
id = /obj/item/card/id id = /obj/item/card/id
r_pocket = /obj/item/pinpointer/crew r_pocket = /obj/item/pinpointer/crew
l_pocket = /obj/item/pda/medical l_pocket = /obj/item/pda/medical

View File

@@ -26,7 +26,7 @@
cold_protection = HEAD cold_protection = HEAD
max_heat_protection_temperature = FIRE_HELM_MAX_TEMP_PROTECT max_heat_protection_temperature = FIRE_HELM_MAX_TEMP_PROTECT
heat_protection = HEAD heat_protection = HEAD
armor = list("melee" = 30, "bullet" = 20, "laser" = 20, "energy" = 20, "bomb" = 50, "bio" = 100, "rad" = 50, "fire" = 50, "acid" = 50) armor = list("melee" = 30, "bullet" = 20, "laser" = 20, "energy" = 20, "bomb" = 50, "bio" = 100, "rad" = 50, "fire" = 50, "acid" = 50, "wound" = 10)
resistance_flags = FIRE_PROOF resistance_flags = FIRE_PROOF
/obj/item/clothing/suit/hooded/explorer/standard /obj/item/clothing/suit/hooded/explorer/standard
@@ -50,7 +50,7 @@
visor_flags_inv = HIDEFACIALHAIR visor_flags_inv = HIDEFACIALHAIR
visor_flags_cover = MASKCOVERSMOUTH visor_flags_cover = MASKCOVERSMOUTH
actions_types = list(/datum/action/item_action/adjust) actions_types = list(/datum/action/item_action/adjust)
armor = list("melee" = 10, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 5, "bio" = 50, "rad" = 0, "fire" = 20, "acid" = 40) armor = list("melee" = 10, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 5, "bio" = 50, "rad" = 0, "fire" = 20, "acid" = 40, "wound" = 5)
resistance_flags = FIRE_PROOF resistance_flags = FIRE_PROOF
/obj/item/clothing/mask/gas/explorer/attack_self(mob/user) /obj/item/clothing/mask/gas/explorer/attack_self(mob/user)

View File

@@ -558,12 +558,25 @@
client.prefs.random_character() client.prefs.random_character()
client.prefs.real_name = client.prefs.pref_species.random_name(gender,1) client.prefs.real_name = client.prefs.pref_species.random_name(gender,1)
client.prefs.copy_to(H) client.prefs.copy_to(H)
var/cur_scar_index = client.prefs.scars_index
if(client.prefs.persistent_scars && client.prefs.scars_list["[cur_scar_index]"])
var/scar_string = client.prefs.scars_list["[cur_scar_index]"]
var/valid_scars = ""
for(var/scar_line in splittext(scar_string, ";"))
if(H.load_scar(scar_line))
valid_scars += "[scar_line];"
client.prefs.scars_list["[cur_scar_index]"] = valid_scars
client.prefs.save_character()
client.prefs.copy_to(H, antagonist = is_antag)
H.dna.update_dna_identity() H.dna.update_dna_identity()
if(mind) if(mind)
if(transfer_after) if(transfer_after)
mind.late_joiner = TRUE mind.late_joiner = TRUE
mind.active = 0 //we wish to transfer the key manually mind.active = 0 //we wish to transfer the key manually
mind.transfer_to(H) //won't transfer key since the mind is not active mind.transfer_to(H) //won't transfer key since the mind is not active
mind.original_character = H
H.name = real_name H.name = real_name

View File

@@ -5,12 +5,27 @@
#define EXOTIC_BLEED_MULTIPLIER 4 //Multiplies the actually bled amount by this number for the purposes of turf reaction calculations. #define EXOTIC_BLEED_MULTIPLIER 4 //Multiplies the actually bled amount by this number for the purposes of turf reaction calculations.
/mob/living/carbon/human/proc/suppress_bloodloss(amount) /mob/living/carbon/monkey/handle_blood()
if(bleedsuppress) if(bodytemperature <= TCRYO || (HAS_TRAIT(src, TRAIT_HUSK))) //cryosleep or husked people do not pump the blood.
return var/temp_bleed = 0
else for(var/X in bodyparts)
bleedsuppress = TRUE var/obj/item/bodypart/BP = X
addtimer(CALLBACK(src, .proc/resume_bleeding), amount) temp_bleed += BP.get_bleed_rate()
BP.generic_bleedstacks = max(0, BP.generic_bleedstacks - 1)
bleed(temp_bleed)
var/temp_bleed = 0
for(var/X in bodyparts)
var/obj/item/bodypart/BP = X
temp_bleed += BP.get_bleed_rate()
BP.generic_bleedstacks = max(0, BP.generic_bleedstacks - 1)
bleed(temp_bleed)
//Blood regeneration if there is some space
if(blood_volume < BLOOD_VOLUME_NORMAL)
blood_volume += 0.1 // regenerate blood VERY slowly
if(blood_volume < BLOOD_VOLUME_OKAY)
adjustOxyLoss(round((BLOOD_VOLUME_NORMAL - blood_volume) * 0.02, 1))
/mob/living/carbon/human/proc/resume_bleeding() /mob/living/carbon/human/proc/resume_bleeding()
bleedsuppress = 0 bleedsuppress = 0
@@ -29,8 +44,7 @@
// Takes care blood loss and regeneration // Takes care blood loss and regeneration
/mob/living/carbon/human/handle_blood() /mob/living/carbon/human/handle_blood()
if(NOBLOOD in dna.species.species_traits) if(NOBLOOD in dna.species.species_traits || bleedsuppress || (HAS_TRAIT(src, TRAIT_FAKEDEATH)))
bleed_rate = 0
return return
if(bleed_rate < 0) if(bleed_rate < 0)
@@ -87,24 +101,11 @@
//Bleeding out //Bleeding out
for(var/X in bodyparts) for(var/X in bodyparts)
var/obj/item/bodypart/BP = X var/obj/item/bodypart/BP = X
var/brutedamage = BP.brute_dam temp_bleed += BP.get_bleed_rate()
BP.generic_bleedstacks = max(0, BP.generic_bleedstacks - 1)
if(BP.status == BODYPART_ROBOTIC) //for the moment, synth limbs won't bleed, but soon, my pretty. if(temp_bleed)
continue bleed(temp_bleed)
//We want an accurate reading of .len
listclearnulls(BP.embedded_objects)
for(var/obj/item/embeddies in BP.embedded_objects)
if(!embeddies.isEmbedHarmless())
temp_bleed += 0.5
if(brutedamage >= 20)
temp_bleed += (brutedamage * 0.013)
bleed_rate = max(bleed_rate - 0.5, temp_bleed)//if no wounds, other bleed effects (heparin) naturally decreases
if(bleed_rate && !bleedsuppress && !(HAS_TRAIT(src, TRAIT_FAKEDEATH)))
bleed(bleed_rate)
//Makes a blood drop, leaking amt units of blood from the mob //Makes a blood drop, leaking amt units of blood from the mob
/mob/living/carbon/proc/bleed(amt) /mob/living/carbon/proc/bleed(amt)
@@ -128,9 +129,11 @@
/mob/living/proc/restore_blood() /mob/living/proc/restore_blood()
blood_volume = initial(blood_volume) blood_volume = initial(blood_volume)
/mob/living/carbon/human/restore_blood() /mob/living/carbon/restore_blood()
blood_volume = (BLOOD_VOLUME_NORMAL * blood_ratio) blood_volume = (BLOOD_VOLUME_NORMAL * blood_ratio)
bleed_rate = 0 for(var/i in bodyparts)
var/obj/item/bodypart/BP = i
BP.generic_bleedstacks = 0
/**************************************************** /****************************************************
BLOOD TRANSFERS BLOOD TRANSFERS

View File

@@ -331,6 +331,8 @@
max_traumas = TRAUMA_LIMIT_BASIC max_traumas = TRAUMA_LIMIT_BASIC
if(TRAUMA_RESILIENCE_SURGERY) if(TRAUMA_RESILIENCE_SURGERY)
max_traumas = TRAUMA_LIMIT_SURGERY max_traumas = TRAUMA_LIMIT_SURGERY
if(TRAUMA_RESILIENCE_WOUND)
max_traumas = TRAUMA_LIMIT_WOUND
if(TRAUMA_RESILIENCE_LOBOTOMY) if(TRAUMA_RESILIENCE_LOBOTOMY)
max_traumas = TRAUMA_LIMIT_LOBOTOMY max_traumas = TRAUMA_LIMIT_LOBOTOMY
if(TRAUMA_RESILIENCE_MAGIC) if(TRAUMA_RESILIENCE_MAGIC)
@@ -389,7 +391,7 @@
return return
var/trauma_type = pick(possible_traumas) var/trauma_type = pick(possible_traumas)
gain_trauma(trauma_type, resilience) return gain_trauma(trauma_type, resilience)
//Cure a random trauma of a certain resilience level //Cure a random trauma of a certain resilience level
/obj/item/organ/brain/proc/cure_trauma_type(brain_trauma_type = /datum/brain_trauma, resilience = TRAUMA_RESILIENCE_BASIC) /obj/item/organ/brain/proc/cure_trauma_type(brain_trauma_type = /datum/brain_trauma, resilience = TRAUMA_RESILIENCE_BASIC)

View File

@@ -88,11 +88,32 @@
for(var/datum/surgery/S in surgeries) for(var/datum/surgery/S in surgeries)
if(S.next_step(user,user.a_intent)) if(S.next_step(user,user.a_intent))
return 1 return 1
if(!all_wounds || !(user.a_intent == INTENT_HELP || user == src))
return ..()
// The following priority/nonpriority searching is so that if we have two wounds on a limb that use the same item for treatment (gauze can bandage cuts AND splint broken bones),
// we prefer whichever wound is not already treated (ignore the splinted broken bone for the open cut). If there's no priority wounds that this can treat, go through the
// non-priority ones randomly.
var/list/nonpriority_wounds = list()
for(var/datum/wound/W in shuffle(all_wounds))
if(!W.treat_priority)
nonpriority_wounds += W
else if(W.treat_priority && W.try_treating(I, user))
return 1
for(var/datum/wound/W in shuffle(nonpriority_wounds))
if(W.try_treating(I, user))
return 1
return ..() return ..()
/mob/living/carbon/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum) /mob/living/carbon/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
. = ..() . = ..()
var/hurt = TRUE var/hurt = TRUE
var/extra_speed = 0
if(throwingdatum.thrower != src)
extra_speed = min(max(0, throwingdatum.speed - initial(throw_speed)), 3)
if(GetComponent(/datum/component/tackler)) if(GetComponent(/datum/component/tackler))
return return
if(throwingdatum?.thrower && iscyborg(throwingdatum.thrower)) if(throwingdatum?.thrower && iscyborg(throwingdatum.thrower))
@@ -102,18 +123,18 @@
if(hit_atom.density && isturf(hit_atom)) if(hit_atom.density && isturf(hit_atom))
if(hurt) if(hurt)
DefaultCombatKnockdown(20) DefaultCombatKnockdown(20)
take_bodypart_damage(10) take_bodypart_damage(10 + 5 * extra_speed, check_armor = TRUE, wound_bonus = extra_speed)
if(iscarbon(hit_atom) && hit_atom != src) if(iscarbon(hit_atom) && hit_atom != src)
var/mob/living/carbon/victim = hit_atom var/mob/living/carbon/victim = hit_atom
if(victim.movement_type & FLYING) if(victim.movement_type & FLYING)
return return
if(hurt) if(hurt)
victim.take_bodypart_damage(10) victim.take_bodypart_damage(10 + 5 * extra_speed, check_armor = TRUE, wound_bonus = extra_speed * 5)
take_bodypart_damage(10) take_bodypart_damage(10 + 5 * extra_speed, check_armor = TRUE, wound_bonus = extra_speed * 5)
victim.DefaultCombatKnockdown(20) victim.DefaultCombatKnockdown(20)
DefaultCombatKnockdown(20) DefaultCombatKnockdown(20)
visible_message("<span class='danger'>[src] crashes into [victim], knocking them both over!</span>",\ visible_message("<span class='danger'>[src] crashes into [victim] [extra_speed ? "really hard" : ""], knocking them both over!</span>",\
"<span class='userdanger'>You violently crash into [victim]!</span>") "<span class='userdanger'>You violently crash into [victim] [extra_speed ? "extra hard" : ""]!</span>")
playsound(src,'sound/weapons/punch1.ogg',50,1) playsound(src,'sound/weapons/punch1.ogg',50,1)
@@ -196,12 +217,18 @@
adjustStaminaLossBuffered(I.getweight(src, STAM_COST_THROW_MULT, SKILL_THROW_STAM_COST)) adjustStaminaLossBuffered(I.getweight(src, STAM_COST_THROW_MULT, SKILL_THROW_STAM_COST))
if(thrown_thing) if(thrown_thing)
visible_message("<span class='danger'>[src] has thrown [thrown_thing].</span>") var/power_throw = 0
log_message("has thrown [thrown_thing]", LOG_ATTACK) if(HAS_TRAIT(src, TRAIT_HULK))
power_throw++
if(pulling && grab_state >= GRAB_NECK)
power_throw++
visible_message("<span class='danger'>[src] throws [thrown_thing][power_throw ? " really hard!" : "."]</span>", \
"<span class='danger'>You throw [thrown_thing][power_throw ? " really hard!" : "."]</span>")
log_message("has thrown [thrown_thing] [power_throw ? "really hard" : ""]", LOG_ATTACK)
do_attack_animation(target, no_effect = 1) do_attack_animation(target, no_effect = 1)
playsound(loc, 'sound/weapons/punchmiss.ogg', 50, 1, -1) playsound(loc, 'sound/weapons/punchmiss.ogg', 50, 1, -1)
newtonian_move(get_dir(target, src)) newtonian_move(get_dir(target, src))
thrown_thing.safe_throw_at(target, thrown_thing.throw_range, thrown_thing.throw_speed, src, null, null, null, move_force, random_turn) thrown_thing.safe_throw_at(target, thrown_thing.throw_range, thrown_thing.throw_speed + power_throw, src, null, null, null, move_force)
/mob/living/carbon/restrained(ignore_grab) /mob/living/carbon/restrained(ignore_grab)
. = (handcuffed || (!ignore_grab && pulledby && pulledby.grab_state >= GRAB_AGGRESSIVE)) . = (handcuffed || (!ignore_grab && pulledby && pulledby.grab_state >= GRAB_AGGRESSIVE))
@@ -892,6 +919,9 @@
var/datum/disease/D = thing var/datum/disease/D = thing
if(D.severity != DISEASE_SEVERITY_POSITIVE) if(D.severity != DISEASE_SEVERITY_POSITIVE)
D.cure(FALSE) D.cure(FALSE)
for(var/thing in all_wounds)
var/datum/wound/W = thing
W.remove_wound()
if(admin_revive) if(admin_revive)
regenerate_limbs() regenerate_limbs()
regenerate_organs() regenerate_organs()
@@ -982,6 +1012,10 @@
if(SANITY_NEUTRAL to SANITY_GREAT) if(SANITY_NEUTRAL to SANITY_GREAT)
. *= 0.90 . *= 0.90
for(var/i in status_effects)
var/datum/status_effect/S = i
. *= S.interact_speed_modifier()
/mob/living/carbon/proc/create_internal_organs() /mob/living/carbon/proc/create_internal_organs()
for(var/X in internal_organs) for(var/X in internal_organs)
@@ -1170,3 +1204,47 @@
if(wear_mask) if(wear_mask)
if(wear_mask.flags_inv & HIDEEYES) if(wear_mask.flags_inv & HIDEEYES)
LAZYOR(., SLOT_GLASSES) LAZYOR(., SLOT_GLASSES)
// if any of our bodyparts are bleeding
/mob/living/carbon/proc/is_bleeding()
for(var/i in bodyparts)
var/obj/item/bodypart/BP = i
if(BP.get_bleed_rate())
return TRUE
// get our total bleedrate
/mob/living/carbon/proc/get_total_bleed_rate()
var/total_bleed_rate = 0
for(var/i in bodyparts)
var/obj/item/bodypart/BP = i
total_bleed_rate += BP.get_bleed_rate()
return total_bleed_rate
/**
* generate_fake_scars()- for when you want to scar someone, but you don't want to hurt them first. These scars don't count for temporal scarring (hence, fake)
*
* If you want a specific wound scar, pass that wound type as the second arg, otherwise you can pass a list like WOUND_LIST_CUT to generate a random cut scar.
*
* Arguments:
* * num_scars- A number for how many scars you want to add
* * forced_type- Which wound or category of wounds you want to choose from, WOUND_LIST_BONE, WOUND_LIST_CUT, or WOUND_LIST_BURN (or some combination). If passed a list, picks randomly from the listed wounds. Defaults to all 3 types
*/
/mob/living/carbon/proc/generate_fake_scars(num_scars, forced_type)
for(var/i in 1 to num_scars)
var/datum/scar/S = new
var/obj/item/bodypart/BP = pick(bodyparts)
var/wound_type
if(forced_type)
if(islist(forced_type))
wound_type = pick(forced_type)
else
wound_type = forced_type
else
wound_type = pick(WOUND_LIST_BONE + WOUND_LIST_CUT + WOUND_LIST_BURN)
var/datum/wound/W = new wound_type
S.generate(BP, W)
S.fake = TRUE
QDEL_NULL(W)