diff --git a/baystation12.dme b/baystation12.dme
index adee96a64aa..4ed90e79467 100644
--- a/baystation12.dme
+++ b/baystation12.dme
@@ -355,6 +355,7 @@
#include "code\datums\organs\organ.dm"
#include "code\datums\organs\organ_external.dm"
#include "code\datums\organs\organ_internal.dm"
+#include "code\datums\organs\wound.dm"
#include "code\datums\spells\area_teleport.dm"
#include "code\datums\spells\conjure.dm"
#include "code\datums\spells\emplosion.dm"
diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm
index d1d8d6d20ec..acd85c1ab7a 100644
--- a/code/controllers/configuration.dm
+++ b/code/controllers/configuration.dm
@@ -75,6 +75,12 @@
var/health_threshold_crit = 0
var/health_threshold_dead = -100
+ var/organ_health_multiplier = 1
+ var/organ_regeneration_multiplier = 1
+
+ var/bones_can_break = 0
+ var/limbs_can_break = 0
+
var/revival_pod_plants = 1
var/revival_cloning = 1
var/revival_brain_life = -1
@@ -377,6 +383,14 @@
config.metroid_delay = value
if("animal_delay")
config.animal_delay = value
+ if("organ_health_multiplier")
+ config.organ_health_multiplier = value / 100
+ if("organ_regeneration_multiplier")
+ config.organ_regeneration_multiplier = value / 100
+ if("bones_can_break")
+ config.bones_can_break = value
+ if("limbs_can_break")
+ config.limbs_can_break = value
else
diary << "Unknown setting in configuration: '[name]'"
diff --git a/code/datums/organs/organ.dm b/code/datums/organs/organ.dm
index 81b45f51287..ba7b1bf014c 100644
--- a/code/datums/organs/organ.dm
+++ b/code/datums/organs/organ.dm
@@ -1,8 +1,6 @@
-//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33
-
/datum/organ
var/name = "organ"
- var/mob/owner = null
+ var/mob/living/carbon/human/owner = null
///datum/organ/proc/process()
// return 0
@@ -10,5 +8,8 @@
///datum/organ/proc/receive_chem(chemical as obj)
// return 0
+ proc/process()
+ return 0
-
+ proc/receive_chem(chemical as obj)
+ return 0
\ No newline at end of file
diff --git a/code/datums/organs/organ_external.dm b/code/datums/organs/organ_external.dm
index b5c67d5496b..81a8715c54b 100644
--- a/code/datums/organs/organ_external.dm
+++ b/code/datums/organs/organ_external.dm
@@ -1,142 +1,661 @@
+/****************************************************
+ EXTERNAL ORGANS
+****************************************************/
/datum/organ/external
name = "external"
var/icon_name = null
var/body_part = null
- var/brutestate = 0
- var/burnstate = 0
+
+ var/damage_state = "00"
var/brute_dam = 0
var/burn_dam = 0
var/max_damage = 0
-// var/bandaged = 0
-// var/wound_size = 0
-// var/max_size = 0
+ var/max_size = 0
+ var/tmp/list/obj/item/weapon/implant/implant
+
+ var/display_name
+ var/list/wounds = list()
+ var/number_wounds = 0 // cache the number of wounds, which is NOT wounds.len!
+
+ var/tmp/perma_injury = 0
+ var/tmp/perma_dmg = 0
+ var/tmp/destspawn = 0 //Has it spawned the broken limb?
+ var/tmp/amputated = 0 // Whether this has been cleanly amputated, thus causing no pain
+ var/min_broken_damage = 30
+
+ var/datum/organ/external/parent
+ var/list/datum/organ/external/children
+
+ var/damage_msg = "\red You feel an intense pain"
+
+ var/status = 0
+ var/broken_description
+ var/open = 0
+ var/stage = 0
+
+ proc/take_damage(brute, burn, sharp, used_weapon = null, list/forbidden_limbs = list())
+ // TODO: this proc needs to be rewritten to not update damages directly
+ if((brute <= 0) && (burn <= 0))
+ return 0
+ if(status & ORGAN_DESTROYED)
+ return 0
+ if(status & ORGAN_ROBOT)
+ brute *= 0.66 //~2/3 damage for ROBOLIMBS
+ burn *= 0.66 //~2/3 damage for ROBOLIMBS
+
+ //if(owner && !(status & ORGAN_ROBOT))
+ // owner.pain(display_name, (brute+burn)*3, 1, burn > brute)
+
+ if(sharp)
+ var/nux = brute * rand(10,15)
+ if(config.limbs_can_break && brute_dam >= max_damage * config.organ_health_multiplier)
+ if(prob(5 * brute))
+ status |= ORGAN_DESTROYED
+ droplimb()
+ return
+
+ else if(prob(nux))
+ createwound( CUT, brute )
+ if(!(status & ORGAN_ROBOT))
+ owner << "You feel something wet on your [display_name]"
+
+ else if(brute > 20)
+ if(config.limbs_can_break && brute_dam >= max_damage * config.organ_health_multiplier)
+ if(prob(5 * brute))
+ status |= ORGAN_DESTROYED
+ droplimb()
+ return
+
+ // If the limbs can break, make sure we don't exceed the maximum damage a limb can take before breaking
+ if((brute_dam + burn_dam + brute + burn) < max_damage || !config.limbs_can_break)
+ if(brute)
+ brute_dam += brute
+ if( (prob(brute*2) && !sharp) || sharp )
+ createwound( CUT, brute )
+ else if(!sharp)
+ createwound( BRUISE, brute )
+ if(burn)
+ burn_dam += burn
+ createwound( BURN, burn )
+ else
+ var/can_inflict = max_damage * config.organ_health_multiplier - (brute_dam + burn_dam) //How much damage can we actually cause?
+ if(can_inflict)
+ if (brute > 0 && burn > 0)
+ brute = can_inflict/2
+ burn = can_inflict/2
+ var/ratio = brute / (brute + burn)
+ brute_dam += ratio * can_inflict
+ burn_dam += (1 - ratio) * can_inflict
+ else
+ if (brute > 0)
+ brute = can_inflict
+ brute_dam += brute
+ createwound(BRUISE, brute)
+ else
+ burn = can_inflict
+ burn_dam += burn
+ createwound(BRUISE, brute)
+ else if(!(status & ORGAN_ROBOT))
+ var/passed_dam = (brute + burn) - can_inflict //Getting how much overdamage we have.
+ var/list/datum/organ/external/possible_points = list()
+ if(parent)
+ possible_points += parent
+ if(children)
+ possible_points += children
+ if(forbidden_limbs.len)
+ possible_points -= forbidden_limbs
+ if(!possible_points.len)
+ message_admins("Oh god WHAT! [owner]'s [src] was unable to find an organ to pass overdamage too!")
+ else
+ var/datum/organ/external/target = pick(possible_points)
+ if(brute)
+ target.take_damage(passed_dam, 0, sharp, used_weapon, forbidden_limbs + src)
+ else
+ target.take_damage(0, passed_dam, sharp, used_weapon, forbidden_limbs + src)
+ else
+ droplimb(1) //Robot limbs just kinda fail at full damage.
+
+
+ if(status & ORGAN_BROKEN)
+ owner.emote("scream")
+
+ owner.updatehealth()
+
+ // sync the organ's damage with its wounds
+ src.update_damages()
+
+ var/result = update_icon()
+ return result
+
+
+
+ proc/heal_damage(brute, burn, internal = 0, robo_repair = 0)
+ if(status & ORGAN_ROBOT && !robo_repair)
+ return
+
+ // heal damage on the individual wounds
+ for(var/datum/wound/W in wounds)
+ if(brute == 0 && burn == 0)
+ break
+
+ // heal brute damage
+ if(W.damage_type == CUT || W.damage_type == BRUISE)
+ brute = W.heal_damage(brute)
+ else if(W.damage_type == BURN)
+ burn = W.heal_damage(burn)
+
+ // sync organ damage with wound damages
+ update_damages()
+
+ if(internal)
+ status &= ~ORGAN_BROKEN
+ perma_injury = 0
+
+ // sync the organ's damage with its wounds
+ src.update_damages()
+
+ owner.updatehealth()
+ var/result = update_icon()
+ return result
+
+ proc/update_damages()
+ number_wounds = 0
+ brute_dam = 0
+ burn_dam = 0
+ status &= ~ORGAN_BLEEDING
+ for(var/datum/wound/W in wounds)
+ if(W.damage_type == CUT || W.damage_type == BRUISE)
+ brute_dam += W.damage
+ else if(W.damage_type == BURN)
+ burn_dam += W.damage
+
+ if(!W.bandaged && W.damage > 4)
+ status |= ORGAN_BLEEDING
+
+ number_wounds += W.amount
+
+ proc/update_wounds()
+ for(var/datum/wound/W in wounds)
+ // wounds can disappear after 10 minutes at the earliest
+ if(W.damage == 0 && W.created + 10 * 10 * 60 <= world.time)
+ wounds -= W
+ // let the GC handle the deletion of the wound
+ if(W.is_treated())
+ // slow healing
+ var/amount = 0.2
+ if(W.bandaged) amount++
+ if(W.salved) amount++
+ if(W.disinfected) amount++
+ // amount of healing is spread over all the wounds
+ W.heal_damage((amount * W.amount * config.organ_regeneration_multiplier) / (5*owner.number_wounds+1))
+
+ // sync the organ's damage with its wounds
+ src.update_damages()
+
+
+ proc/get_damage() //returns total damage
+ return max(brute_dam + burn_dam - perma_injury, perma_injury) //could use health?
+
+ proc/get_damage_brute()
+ return max(brute_dam+perma_injury, perma_injury)
+
+ proc/get_damage_fire()
+ return burn_dam
+
+ process()
+ // process wounds, doing healing etc., only do this every 4 ticks to save processing power
+ if(owner.life_tick % 4 == 0)
+ update_wounds()
+ if(status & ORGAN_DESTROYED)
+ if(!destspawn && config.limbs_can_break)
+ droplimb()
+ return
+ if(!(status & ORGAN_BROKEN))
+ perma_dmg = 0
+ if(parent)
+ if(parent.status & ORGAN_DESTROYED)
+ status |= ORGAN_DESTROYED
+ owner.update_body(1)
+ return
+ if(config.bones_can_break && brute_dam > min_broken_damage * config.organ_health_multiplier && !(status & ORGAN_ROBOT))
+ if(!(status & ORGAN_BROKEN))
+ owner.visible_message("\red You hear a loud cracking sound coming from \the [owner].","\red Something feels like it shattered in your [display_name]!","You hear a sickening crack.")
+ owner.emote("scream")
+ status |= ORGAN_BROKEN
+ broken_description = pick("broken","fracture","hairline fracture")
+ perma_injury = brute_dam
+ return
+
+// new damage icon system
+// returns just the brute/burn damage code
+ proc/damage_state_text()
+ if(status & ORGAN_DESTROYED)
+ return "--"
+
+ var/tburn = 0
+ var/tbrute = 0
+
+ if(burn_dam ==0)
+ tburn =0
+ else if (burn_dam < (max_damage * 0.25 / 2))
+ tburn = 1
+ else if (burn_dam < (max_damage * 0.75 / 2))
+ tburn = 2
+ else
+ tburn = 3
+
+ if (brute_dam == 0)
+ tbrute = 0
+ else if (brute_dam < (max_damage * 0.25 / 2))
+ tbrute = 1
+ else if (brute_dam < (max_damage * 0.75 / 2))
+ tbrute = 2
+ else
+ tbrute = 3
+ return "[tbrute][tburn]"
+
+
+// new damage icon system
+// adjusted to set damage_state to brute/burn code only (without r_name0 as before)
+ proc/update_icon()
+ var/n_is = damage_state_text()
+ if (n_is != damage_state)
+ damage_state = n_is
+ owner.update_body(1)
+ return 1
+ return 0
+
+ proc/droplimb(var/override = 0,var/no_explode = 0)
+ if(override)
+ status |= ORGAN_DESTROYED
+ if(status & ORGAN_DESTROYED)
+ if(status & ORGAN_SPLINTED)
+ status &= ~ORGAN_SPLINTED
+ if(implant)
+ for(var/implants in implant)
+ del(implants)
+ //owner.unlock_medal("Lost something?", 0, "Lose a limb.", "easy")
+
+ // If any organs are attached to this, destroy them
+ for(var/datum/organ/external/O in owner.organs)
+ if(O.parent == src)
+ O.droplimb(1)
+
+ var/obj/item/weapon/organ/H
+ switch(body_part)
+ if(UPPER_TORSO)
+ owner.gib()
+ if(LOWER_TORSO)
+ owner << "\red You are now sterile."
+ if(HEAD)
+ H = new /obj/item/weapon/organ/head(owner.loc, owner)
+ if(ishuman(owner))
+ if(owner.gender == FEMALE)
+ H.icon_state = "head_f_l"
+ H.overlays += owner.generate_head_icon()
+ H:transfer_identity(owner)
+ H.pixel_x = -10
+ H.pixel_y = 6
+ H.name = "[owner.real_name]'s head"
+
+ owner.u_equip(owner.glasses)
+ owner.u_equip(owner.head)
+ owner.u_equip(owner.ears)
+ owner.u_equip(owner.wear_mask)
+
+ owner.regenerate_icons()
+
+ owner.death()
+ if(ARM_RIGHT)
+ H = new /obj/item/weapon/organ/r_arm(owner.loc, owner)
+ if(ismonkey(owner))
+ H.icon_state = "r_arm_l"
+ if(ARM_LEFT)
+ H = new /obj/item/weapon/organ/l_arm(owner.loc, owner)
+ if(ismonkey(owner))
+ H.icon_state = "l_arm_l"
+ if(LEG_RIGHT)
+ H = new /obj/item/weapon/organ/r_leg(owner.loc, owner)
+ if(ismonkey(owner))
+ H.icon_state = "r_leg_l"
+ if(LEG_LEFT)
+ H = new /obj/item/weapon/organ/l_leg(owner.loc, owner)
+ if(ismonkey(owner))
+ H.icon_state = "l_leg_l"
+ if(HAND_RIGHT)
+ H = new /obj/item/weapon/organ/r_hand(owner.loc, owner)
+ if(ismonkey(owner))
+ H.icon_state = "r_hand_l"
+ owner.u_equip(owner.gloves)
+ if(HAND_LEFT)
+ H = new /obj/item/weapon/organ/l_hand(owner.loc, owner)
+ if(ismonkey(owner))
+ H.icon_state = "l_hand_l"
+ owner.u_equip(owner.gloves)
+ if(FOOT_RIGHT)
+ H = new /obj/item/weapon/organ/r_foot/(owner.loc, owner)
+ if(ismonkey(owner))
+ H.icon_state = "r_foot_l"
+ owner.u_equip(owner.shoes)
+ if(FOOT_LEFT)
+ H = new /obj/item/weapon/organ/l_foot(owner.loc, owner)
+ if(ismonkey(owner))
+ H.icon_state = "l_foot_l"
+ owner.u_equip(owner.shoes)
+ if(ismonkey(owner))
+ H.icon = 'monkey.dmi'
+ var/lol = pick(cardinal)
+ step(H,lol)
+ destspawn = 1
+ if(status & ORGAN_ROBOT)
+ owner.visible_message("\red \The [owner]'s [display_name] explodes violently!",\
+ "\red Your [display_name] explodes!",\
+ "You hear an explosion followed by a scream!")
+ if(!no_explode)
+ explosion(get_turf(owner),-1,-1,2,3)
+ var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread()
+ spark_system.set_up(5, 0, src)
+ spark_system.attach(src)
+ spark_system.start()
+ spawn(10)
+ del(spark_system)
+ else
+ owner.visible_message("\red [owner.name]'s [display_name] flies off in an arc.",\
+ "Your [display_name] goes flying off!",\
+ "You hear a terrible sound of ripping tendons and flesh.")
+
+ // force the icon to rebuild
+ owner.regenerate_icons()
+
+ proc/createwound(var/type = CUT, var/damage)
+ if(hasorgans(owner))
+ var/wound_type
+ var/size = min( max( 1, damage/10 ) , 6)
+
+ // first check whether we can widen an existing wound
+ if(wounds.len > 0 && prob(25))
+ if((type == CUT || type == BRUISE) && damage >= 5)
+ var/datum/wound/W = pick(wounds)
+ if(W.amount == 1 && W.started_healing())
+ W.open_wound()
+ owner.visible_message("\red The wound on [owner.name]'s [display_name] widens with a nasty ripping voice.",\
+ "\red The wound on your [display_name] widens with a nasty ripping voice.",\
+ "You hear a nasty ripping noise, as if flesh is being torn apart.")
+
+ return
+
+ if(damage == 0) return
+
+ // the wound we will create
+ var/datum/wound/W
+
+ switch(type)
+ if(CUT)
+ src.status |= ORGAN_BLEEDING
+ var/list/size_names = list(/datum/wound/cut, /datum/wound/deep_cut, /datum/wound/flesh_wound, /datum/wound/gaping_wound, /datum/wound/big_gaping_wound, /datum/wound/massive_wound)
+ wound_type = size_names[size]
+
+ W = new wound_type(damage)
+
+ if(BRUISE)
+ var/list/size_names = list(/datum/wound/bruise/tiny_bruise, /datum/wound/bruise/small_bruise, /datum/wound/bruise/moderate_bruise, /datum/wound/bruise/large_bruise, /datum/wound/bruise/huge_bruise, /datum/wound/bruise/monumental_bruise)
+ wound_type = size_names[size]
+
+ W = new wound_type(damage)
+ if(BURN)
+ var/list/size_names = list(/datum/wound/moderate_burn, /datum/wound/large_burn, /datum/wound/severe_burn, /datum/wound/deep_burn, /datum/wound/carbonised_area)
+ wound_type = size_names[size]
+
+ W = new wound_type(damage)
+
+
+
+ // check whether we can add the wound to an existing wound
+ for(var/datum/wound/other in wounds)
+ if(other.desc == W.desc)
+ // okay, add it!
+ other.damage += W.damage
+ other.amount += 1
+ W = null // to signify that the wound was added
+ break
+
+ // if we couldn't add the wound to another wound, ignore
+ if(W)
+ wounds += W
+
+ proc/emp_act(severity)
+ if(!(status & ORGAN_ROBOT))
+ return
+ if(prob(30*severity))
+ take_damage(4(4-severity), 0, 1, used_weapon = "EMP")
+ else
+ droplimb(1)
+
+ proc/getDisplayName()
+ switch(name)
+ if("l_leg")
+ return "left leg"
+ if("r_leg")
+ return "right leg"
+ if("l_arm")
+ return "left arm"
+ if("r_arm")
+ return "right arm"
+ if("l_foot")
+ return "left foot"
+ if("r_foot")
+ return "right foot"
+ if("l_hand")
+ return "left hand"
+ if("r_hand")
+ return "right hand"
+ else
+ return name
/datum/organ/external/chest
name = "chest"
icon_name = "chest"
+ display_name = "chest"
max_damage = 150
+ min_broken_damage = 75
body_part = UPPER_TORSO
+/datum/organ/external/groin
+ name = "groin"
+ icon_name = "diaper"
+ display_name = "groin"
+ max_damage = 115
+ min_broken_damage = 70
+ body_part = LOWER_TORSO
+
/datum/organ/external/head
name = "head"
icon_name = "head"
- max_damage = 125
+ display_name = "head"
+ max_damage = 75
+ min_broken_damage = 40
body_part = HEAD
+ var/disfigured = 0
/datum/organ/external/l_arm
name = "l_arm"
+ display_name = "left arm"
icon_name = "l_arm"
max_damage = 75
+ min_broken_damage = 30
body_part = ARM_LEFT
/datum/organ/external/l_leg
name = "l_leg"
+ display_name = "left leg"
icon_name = "l_leg"
max_damage = 75
+ min_broken_damage = 30
body_part = LEG_LEFT
/datum/organ/external/r_arm
name = "r_arm"
+ display_name = "right arm"
icon_name = "r_arm"
max_damage = 75
+ min_broken_damage = 30
body_part = ARM_RIGHT
/datum/organ/external/r_leg
name = "r_leg"
+ display_name = "right leg"
icon_name = "r_leg"
max_damage = 75
+ min_broken_damage = 30
body_part = LEG_RIGHT
-/*Leaving these here in case we want to use them later
/datum/organ/external/l_foot
- name = "l foot"
+ name = "l_foot"
+ display_name = "left foot"
icon_name = "l_foot"
+ max_damage = 40
+ min_broken_damage = 15
body_part = FOOT_LEFT
/datum/organ/external/r_foot
- name = "r foot"
+ name = "r_foot"
+ display_name = "right foot"
icon_name = "r_foot"
+ max_damage = 40
+ min_broken_damage = 15
body_part = FOOT_RIGHT
/datum/organ/external/r_hand
- name = "r hand"
+ name = "r_hand"
+ display_name = "right hand"
icon_name = "r_hand"
+ max_damage = 40
+ min_broken_damage = 15
body_part = HAND_RIGHT
/datum/organ/external/l_hand
- name = "l hand"
+ name = "l_hand"
+ display_name = "left hand"
icon_name = "l_hand"
+ max_damage = 40
+ min_broken_damage = 15
body_part = HAND_LEFT
-/datum/organ/external/groin
- name = "groin"
- icon_name = "groin"
- body_part = LOWER_TORSO
-*/
+/****************************************************
+ EXTERNAL ORGAN ITEMS
+****************************************************/
-//Applies brute and burn damage to the organ. Returns 1 if the damage-icon states changed at all.
-//Damage will not exceed max_damage using this proc
-//Cannot apply negative damage
-/datum/organ/external/proc/take_damage(brute, burn)
- if(owner && owner.nodamage) return 0 //godmode
- brute = max(brute,0)
- burn = max(burn,0)
+obj/item/weapon/organ
+ icon = 'human.dmi'
- var/can_inflict = max_damage - (brute_dam + burn_dam)
- if(!can_inflict) return 0
+obj/item/weapon/organ/New(loc, mob/living/carbon/human/H)
+ ..(loc)
+ if(!istype(H))
+ return
+ if(H.dna)
+ if(!blood_DNA)
+ blood_DNA = list()
+ blood_DNA[H.dna.unique_enzymes] = H.dna.b_type
- if((brute + burn) < can_inflict)
- brute_dam += brute
- burn_dam += burn
+ var/icon/I = new /icon(icon, icon_state)
+
+ if (H.s_tone >= 0)
+ I.Blend(rgb(H.s_tone, H.s_tone, H.s_tone), ICON_ADD)
else
- if(brute > 0)
- if(burn > 0)
- brute = round( (brute/(brute+burn)) * can_inflict, 1 )
- burn = can_inflict - brute //gets whatever damage is left over
- brute_dam += brute
- burn_dam += burn
+ I.Blend(rgb(-H.s_tone, -H.s_tone, -H.s_tone), ICON_SUBTRACT)
+ icon = I
+
+obj/item/weapon/organ/head
+ name = "head"
+ icon_state = "head_m_l"
+ var/mob/living/carbon/brain/brainmob
+ var/brain_op_stage = 0
+
+obj/item/weapon/organ/head/New()
+ ..()
+ spawn(5)
+ if(brainmob && brainmob.client)
+ brainmob.client.screen.len = null //clear the hud
+
+obj/item/weapon/organ/head/proc/transfer_identity(var/mob/living/carbon/human/H)//Same deal as the regular brain proc. Used for human-->head
+ brainmob = new(src)
+ brainmob.name = H.real_name
+ brainmob.real_name = H.real_name
+ brainmob.dna = H.dna
+ if(H.mind)
+ H.mind.transfer_to(brainmob)
+ brainmob.container = src
+
+obj/item/weapon/organ/head/attackby(obj/item/weapon/W as obj, mob/user as mob)
+ if(istype(W,/obj/item/weapon/scalpel))
+ switch(brain_op_stage)
+ if(0)
+ for(var/mob/O in (oviewers(brainmob) - user))
+ O.show_message("\red [brainmob] is beginning to have \his head cut open with [src] by [user].", 1)
+ brainmob << "\red [user] begins to cut open your head with [src]!"
+ user << "\red You cut [brainmob]'s head open with [src]!"
+
+ brain_op_stage = 1
+
+ if(2)
+ for(var/mob/O in (oviewers(brainmob) - user))
+ O.show_message("\red [brainmob] is having \his connections to the brain delicately severed with [src] by [user].", 1)
+ brainmob << "\red [user] begins to cut open your head with [src]!"
+ user << "\red You cut [brainmob]'s head open with [src]!"
+
+ brain_op_stage = 3.0
else
- brute_dam += can_inflict
- else
- if(burn > 0)
- burn_dam += can_inflict
+ ..()
+ else if(istype(W,/obj/item/weapon/circular_saw))
+ switch(brain_op_stage)
+ if(1)
+ for(var/mob/O in (oviewers(brainmob) - user))
+ O.show_message("\red [brainmob] has \his skull sawed open with [src] by [user].", 1)
+ brainmob << "\red [user] begins to saw open your head with [src]!"
+ user << "\red You saw [brainmob]'s head open with [src]!"
+
+ brain_op_stage = 2
+ if(3)
+ for(var/mob/O in (oviewers(brainmob) - user))
+ O.show_message("\red [brainmob] has \his spine's connection to the brain severed with [src] by [user].", 1)
+ brainmob << "\red [user] severs your brain's connection to the spine with [src]!"
+ user << "\red You sever [brainmob]'s brain's connection to the spine with [src]!"
+
+ user.attack_log += "\[[time_stamp()]\] Debrained [brainmob.name] ([brainmob.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)])"
+ brainmob.attack_log += "\[[time_stamp()]\] Debrained by [user.name] ([user.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)])"
+ log_admin("ATTACK: [brainmob] ([brainmob.ckey]) debrained [user] ([user.ckey]).")
+ message_admins("ATTACK: [brainmob] ([brainmob.ckey]) debrained [user] ([user.ckey]).")
+
+ var/obj/item/brain/B = new(loc)
+ B.transfer_identity(brainmob)
+
+ brain_op_stage = 4.0
else
- return 0
- return update_icon()
+ ..()
+ else
+ ..()
-
-//Heals brute and burn damage for the organ. Returns 1 if the damage-icon states changed at all.
-//Damage cannot go below zero.
-//Cannot remove negative damage (i.e. apply damage)
-/datum/organ/external/proc/heal_damage(brute, burn)
- brute = max(brute, 0)
- burn = max(burn, 0)
- brute_dam = max(brute_dam - brute, 0)
- burn_dam = max(burn_dam - burn, 0)
- return update_icon()
-
-
-//Returns total damage...kinda pointless really
-/datum/organ/external/proc/get_damage()
- return brute_dam + burn_dam
-
-
-//Updates an organ's brute/burn states for use by updateDamageIcon()
-//Returns 1 if we need to update overlays. 0 otherwise.
-/datum/organ/external/proc/update_icon()
- var/tbrute = round( (brute_dam/max_damage)*3, 1 )
- var/tburn = round( (burn_dam/max_damage)*3, 1 )
- if((tbrute != brutestate) || (tburn != burnstate))
- brutestate = tbrute
- burnstate = tburn
- return 1
- return 0
-
-//Returns a display name for the organ
-/datum/organ/external/proc/getDisplayName()
- switch(name)
- if("l_leg") return "left leg"
- if("r_leg") return "right leg"
- if("l_arm") return "left arm"
- if("r_arm") return "right arm"
- else return name
+obj/item/weapon/organ/l_arm
+ name = "left arm"
+ icon_state = "l_arm_l"
+obj/item/weapon/organ/l_foot
+ name = "left foot"
+ icon_state = "l_foot_l"
+obj/item/weapon/organ/l_hand
+ name = "left hand"
+ icon_state = "l_hand_l"
+obj/item/weapon/organ/l_leg
+ name = "left leg"
+ icon_state = "l_leg_l"
+obj/item/weapon/organ/r_arm
+ name = "right arm"
+ icon_state = "r_arm_l"
+obj/item/weapon/organ/r_foot
+ name = "right foot"
+ icon_state = "r_foot_l"
+obj/item/weapon/organ/r_hand
+ name = "right hand"
+ icon_state = "r_hand_l"
+obj/item/weapon/organ/r_leg
+ name = "right leg"
+ icon_state = "r_leg_l"
\ No newline at end of file
diff --git a/code/datums/organs/organ_internal.dm b/code/datums/organs/organ_internal.dm
index 5d7fd2547bd..c6490c71c86 100644
--- a/code/datums/organs/organ_internal.dm
+++ b/code/datums/organs/organ_internal.dm
@@ -1,3 +1,6 @@
+/****************************************************
+ INTERNAL ORGANS
+****************************************************/
/datum/organ/internal
name = "internal"
var/damage = 0
diff --git a/code/datums/organs/wound.dm b/code/datums/organs/wound.dm
new file mode 100644
index 00000000000..1caf45b7587
--- /dev/null
+++ b/code/datums/organs/wound.dm
@@ -0,0 +1,196 @@
+
+/****************************************************
+ WOUNDS
+****************************************************/
+/datum/wound
+ // stages such as "cut", "deep cut", etc.
+ var/list/stages
+ // number representing the current stage
+ var/current_stage = 0
+
+ // description of the wound
+ var/desc = ""
+
+ // amount of damage this wound causes
+ var/damage = 0
+
+ // amount of damage the current wound type requires(less means we need to apply the next healing stage)
+ var/min_damage = 0
+
+ // one of CUT, BRUISE, BURN
+ var/damage_type = CUT
+
+ // whether this wound needs a bandage/salve to heal at all
+ var/needs_treatment = 0
+
+ // is the wound bandaged?
+ var/tmp/bandaged = 0
+ // is the wound salved?
+ var/tmp/salved = 0
+ // is the wound disinfected?
+ var/tmp/disinfected = 0
+ var/tmp/created = 0
+
+ // number of wounds of this type
+ var/tmp/amount = 1
+
+ // helper lists
+ var/tmp/list/desc_list = list()
+ var/tmp/list/damage_list = list()
+ New(var/damage)
+
+ created = world.time
+
+ // reading from a list("stage" = damage) is pretty difficult, so build two separate
+ // lists from them instead
+ for(var/V in stages)
+ desc_list += V
+ damage_list += stages[V]
+
+ src.damage = damage
+
+ // initialize with the first stage
+ next_stage()
+
+ // this will ensure the size of the wound matches the damage
+ src.heal_damage(0)
+
+ // returns 1 if there's a next stage, 0 otherwise
+ proc/next_stage()
+ if(current_stage + 1 > src.desc_list.len)
+ return 0
+
+ current_stage++
+
+ src.min_damage = damage_list[current_stage]
+ src.desc = desc_list[current_stage]
+ return 1
+
+ // returns 1 if the wound has started healing
+ proc/started_healing()
+ return (current_stage > 1)
+
+ // checks whether the wound has been appropriately treated
+ // always returns 1 for wounds that don't need to be treated
+ proc/is_treated()
+ if(!needs_treatment) return 1
+
+ if(damage_type == BRUISE || damage_type == CUT)
+ return bandaged
+ else if(damage_type == BURN)
+ return salved
+
+ // heal the given amount of damage, and if the given amount of damage was more
+ // than what needed to be healed, return how much heal was left
+ proc/heal_damage(amount)
+ var/healed_damage = min(src.damage, amount)
+ amount -= healed_damage
+ src.damage -= healed_damage
+
+ while(src.damage / src.amount < damage_list[current_stage] && current_stage < src.desc_list.len)
+ current_stage++
+ desc = desc_list[current_stage]
+
+ // return amount of healing still leftover, can be used for other wounds
+ return amount
+
+ // opens the wound again
+ proc/open_wound()
+ if(current_stage > 1)
+ // e.g. current_stage is 2, then reset it to 0 and do next_stage(), bringing it to 1
+ src.current_stage -= 2
+ next_stage()
+ src.damage = src.min_damage + 5
+
+/** CUTS **/
+/datum/wound/cut
+ // link wound descriptions to amounts of damage
+ stages = list("cut" = 5, "healing cut" = 2, "small scab" = 0)
+
+/datum/wound/deep_cut
+ stages = list("deep cut" = 15, "clotted cut" = 8, "scab" = 2, "fresh skin" = 0)
+
+/datum/wound/flesh_wound
+ stages = list("flesh wound" = 25, "blood soaked clot" = 15, "large scab" = 5, "fresh skin" = 0)
+
+/datum/wound/gaping_wound
+ stages = list("gaping wound" = 50, "large blood soaked clot" = 25, "large clot" = 15, "small angry scar" = 5, \
+ "small straight scar" = 0)
+
+/datum/wound/big_gaping_wound
+ stages = list("big gaping wound" = 60, "gauze wrapped wound" = 50, "blood soaked bandage" = 25,\
+ "large angry scar" = 10, "large straight scar" = 0)
+
+ needs_treatment = 1 // this only heals when bandaged
+
+/datum/wound/massive_wound
+ stages = list("massive wound" = 70, "massive blood soaked bandage" = 40, "huge bloody mess" = 20,\
+ "massive angry scar" = 10, "massive jagged scar" = 0)
+
+ needs_treatment = 1 // this only heals when bandaged
+
+/** BRUISES **/
+/datum/wound/bruise
+ stages = list("monumental bruise" = 80, "huge bruise" = 50, "large bruise" = 30,\
+ "moderate bruise" = 20, "small bruise" = 10, "tiny bruise" = 5)
+
+ needs_treatment = 1 // this only heals when bandaged
+ damage_type = BRUISE
+
+/datum/wound/bruise/monumental_bruise
+
+// implement sub-paths by starting at a later stage
+/datum/wound/bruise/huge_bruise
+ current_stage = 1
+
+/datum/wound/bruise/large_bruise
+ current_stage = 2
+
+/datum/wound/bruise/moderate_bruise
+ current_stage = 3
+ needs_treatment = 0
+
+/datum/wound/bruise/small_bruise
+ current_stage = 4
+ needs_treatment = 0
+
+/datum/wound/bruise/tiny_bruise
+ current_stage = 5
+ needs_treatment = 0
+
+/** BURNS **/
+/datum/wound/moderate_burn
+ stages = list("moderate burn" = 5, "moderate salved burn" = 2, "fresh skin" = 0)
+
+ needs_treatment = 1 // this only heals when bandaged
+
+ damage_type = BURN
+
+/datum/wound/large_burn
+ stages = list("large burn" = 15, "large salved burn" = 5, "fresh skin" = 0)
+
+ needs_treatment = 1 // this only heals when bandaged
+
+ damage_type = BURN
+
+/datum/wound/severe_burn
+ stages = list("severe burn" = 30, "severe salved burn" = 10, "burn scar" = 0)
+
+ needs_treatment = 1 // this only heals when bandaged
+
+ damage_type = BURN
+
+/datum/wound/deep_burn
+ stages = list("deep burn" = 40, "deep salved burn" = 15, "large burn scar" = 0)
+
+ needs_treatment = 1 // this only heals when bandaged
+
+ damage_type = BURN
+
+
+/datum/wound/carbonised_area
+ stages = list("carbonised area" = 50, "treated carbonised area" = 20, "massive burn scar" = 0)
+
+ needs_treatment = 1 // this only heals when bandaged
+
+ damage_type = BURN
\ No newline at end of file
diff --git a/code/defines/obj/weapon.dm b/code/defines/obj/weapon.dm
index 67f4121bb9b..29fec512a38 100644
--- a/code/defines/obj/weapon.dm
+++ b/code/defines/obj/weapon.dm
@@ -1543,6 +1543,7 @@
m_amt = 12000
origin_tech = "materials=1"
attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
+ sharp = 1
/obj/item/weapon/kitchenknife/ritual
name = "ritual knife"
@@ -1624,6 +1625,7 @@
icon_state = "knife"
force = 10.0
throwforce = 10.0
+ sharp = 1
/obj/item/weapon/kitchen/utensil/spoon
name = "spoon"
@@ -1646,6 +1648,7 @@
g_amt = 5000
origin_tech = "materials=1;biotech=1"
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
+ sharp = 1
/obj/item/weapon/retractor
name = "retractor"
@@ -1712,6 +1715,7 @@
g_amt = 10000
origin_tech = "materials=1;biotech=1"
attack_verb = list("attacked", "slashed", "sawed", "cut")
+ sharp = 1
/obj/item/weapon/syntiflesh
name = "syntiflesh"
diff --git a/code/defines/procs/helpers.dm b/code/defines/procs/helpers.dm
index eef49339f24..787bfe1356c 100644
--- a/code/defines/procs/helpers.dm
+++ b/code/defines/procs/helpers.dm
@@ -1229,6 +1229,10 @@ proc/get_mob_with_client_list()
else if (zone == "r_leg") return "right leg"
else if (zone == "l_foot") return "left foot"
else if (zone == "r_foot") return "right foot"
+ else if (zone == "l_hand") return "left hand"
+ else if (zone == "r_hand") return "right hand"
+ else if (zone == "l_foot") return "left foot"
+ else if (zone == "r_foot") return "right foot"
else return zone
diff --git a/code/game/dna.dm b/code/game/dna.dm
index 0ea61c118e2..eec31a2565c 100644
--- a/code/game/dna.dm
+++ b/code/game/dna.dm
@@ -505,8 +505,6 @@
for(var/obj/T in (M.contents-implants))
del(T)
- //for(var/R in M.organs)
- // del(M.organs[text("[]", R)])
O.loc = M.loc
diff --git a/code/game/gamemodes/events/ninja_equipment.dm b/code/game/gamemodes/events/ninja_equipment.dm
index e8becec1849..b1c1be2aa86 100644
--- a/code/game/gamemodes/events/ninja_equipment.dm
+++ b/code/game/gamemodes/events/ninja_equipment.dm
@@ -844,15 +844,16 @@ ________________________________________________________________________________
U << "\red Procedure interrupted. Protocol terminated."
return
else if(istype(I, /obj/item/weapon/disk/tech_disk))//If it's a data disk, we want to copy the research on to the suit.
- if(I:stored)//If it has something on it.
+ var/obj/item/weapon/disk/tech_disk/tdisk = I
+ if(tdisk.stored)//If it has something on it.
U << "Research information detected, processing..."
if(do_after(U,s_delay))
for(var/datum/tech/current_data in stored_research)
- if(current_data.id==I:stored.id)
- if(current_data.levelERROR: \black Procedure interrupted. Process terminated."
diff --git a/code/game/mecha/mech_fabricator.dm b/code/game/mecha/mech_fabricator.dm
index bbd096d7616..8689b09b431 100644
--- a/code/game/mecha/mech_fabricator.dm
+++ b/code/game/mecha/mech_fabricator.dm
@@ -400,11 +400,17 @@
/obj/machinery/mecha_part_fabricator/proc/process_queue()
var/obj/item/part = listgetindex(src.queue, 1)
if(!part)
- remove_from_queue(1)
- return process_queue()
+ if(remove_from_queue(1))
+ return process_queue()
+ else
+ // Most likely means we have an empty queue, so stop processing
+ return 0
if(!(part.vars.Find("construction_time")) || !(part.vars.Find("construction_cost")))//If it shouldn't be printed
- remove_from_queue(1)//Take it out of the quene
- return process_queue()//Then reprocess it
+ if(remove_from_queue(1))//Take it out of the quene
+ return process_queue()//Then reprocess it
+ else
+ // Most likely means we have an empty queue, so stop processing
+ return 0
temp = null
while(part)
if(stat&(NOPOWER|BROKEN))
diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm
index bf66310d975..1a1c49a1d62 100755
--- a/code/game/objects/items/devices/PDA/PDA.dm
+++ b/code/game/objects/items/devices/PDA/PDA.dm
@@ -838,8 +838,8 @@ var/global/list/obj/item/device/pda/PDAs = list()
C.loc = src
user << "You insert [C] into [src]."
cartridge = C
- if(C:radio)
- C:radio.hostpda = src
+ if(cartridge.radio)
+ cartridge.radio.hostpda = src
else if(istype(C, /obj/item/weapon/card/id))
var/obj/item/weapon/card/id/idcard = C
diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm
index 31882fca830..57ffa477306 100644
--- a/code/game/objects/items/stacks/medical.dm
+++ b/code/game/objects/items/stacks/medical.dm
@@ -50,8 +50,23 @@
if(!istype(affecting, /datum/organ/external) || affecting:burn_dam <= 0)
affecting = H.get_organ("head")
- if (affecting.heal_damage(src.heal_brute, src.heal_burn))
- H.UpdateDamageIcon()
+ // If we're targetting arms or legs, also heal the respective hand/foot
+ if(affecting.name in list("l_arm","r_arm","l_leg","r_leg"))
+ var/datum/organ/external/child
+ if(affecting.name == "l_arm")
+ child = H.get_organ("l_hand")
+ else if(affecting.name == "r_arm")
+ child = H.get_organ("r_hand")
+ else if(affecting.name == "r_leg")
+ child = H.get_organ("r_foot")
+ else if(affecting.name == "l_leg")
+ child = H.get_organ("l_foot")
+
+ if (affecting.heal_damage(src.heal_brute, src.heal_burn) || child.heal_damage(src.heal_brute, src.heal_burn))
+ H.UpdateDamageIcon()
+ else
+ if (affecting.heal_damage(src.heal_brute, src.heal_burn))
+ H.UpdateDamageIcon()
M.updatehealth()
else
M.heal_organ_damage((src.heal_brute/2), (src.heal_burn/2))
diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm
index 41fe32d6777..b48b2475ebe 100644
--- a/code/game/objects/objs.dm
+++ b/code/game/objects/objs.dm
@@ -10,6 +10,7 @@
animate_movement = 2
var/throwforce = 1
var/list/attack_verb = list() //Used in attackby() to say how something was attacked "[x] has been [z.attack_verb] by [y] with [z]"
+ var/sharp = 0 // whether this object cuts
/obj/proc/process()
processing_objects.Remove(src)
diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm
index 12cc5a26c8e..4457c5e1526 100644
--- a/code/modules/mob/inventory.dm
+++ b/code/modules/mob/inventory.dm
@@ -16,9 +16,6 @@
if(hand) return r_hand
else return l_hand
-/mob/proc/equipped()
- return get_active_hand()
-
//Puts the item into your l_hand if possible and calls all necessary triggers/updates. returns 1 on success.
/mob/proc/put_in_l_hand(var/obj/item/W)
if(lying) return 0
@@ -216,3 +213,16 @@
//if(hasvar(src,"r_hand")) if(src:r_hand) items += src:r_hand
return items
+
+/** BS12's proc to get the item in the active hand. Couldn't find the /tg/ equivalent. **/
+/mob/proc/equipped()
+ if(issilicon(src))
+ if(isrobot(src))
+ if(src:module_active)
+ return src:module_active
+ else
+ if (hand)
+ return l_hand
+ else
+ return r_hand
+ return
diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm
index 22142887241..0f1fedb8de4 100644
--- a/code/modules/mob/living/carbon/carbon_defines.dm
+++ b/code/modules/mob/living/carbon/carbon_defines.dm
@@ -10,3 +10,8 @@
var/silent = null //Can't talk. Value goes down every life proc.
var/last_eating = 0 //Not sure what this does... I found it hidden in food.dm
+
+ var/life_tick = 0 // The amount of life ticks that have processed on this mob.
+
+ // total amount of wounds on mob, used to spread out healing and the like over all wounds
+ var/number_wounds = 0
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index 80661056a13..593192da1bc 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -212,26 +212,26 @@
else//Brain is gone, doesn't matter if they are AFK or present
msg += "It appears that [t_his] brain is missing...\n"
- var/temp = getBruteLoss() //no need to calculate each of these twice
+ var/temp_dam = getBruteLoss() //no need to calculate each of these twice
msg += ""
- if(temp)
- if(temp < 30)
+ if(temp_dam)
+ if(temp_dam < 30)
msg += "[t_He] [t_has] minor bruising.\n"
else
msg += "[t_He] [t_has] severe bruising!\n"
- temp = getFireLoss()
- if(temp)
- if(temp < 30)
+ temp_dam = getFireLoss()
+ if(temp_dam)
+ if(temp_dam < 30)
msg += "[t_He] [t_has] minor burns.\n"
else
msg += "[t_He] [t_has] severe burns!\n"
- temp = getCloneLoss()
- if(temp)
- if(temp < 30)
+ temp_dam = getCloneLoss()
+ if(temp_dam)
+ if(temp_dam < 30)
msg += "[t_He] [t_has] minor genetic deformities.\n"
else
msg += "[t_He] [t_has] severe genetic deformities.\n"
@@ -256,6 +256,148 @@
else if(!client && brain_op_stage != 4 && stat != DEAD)
msg += "[t_He] [t_has] a vacant, braindead stare...\n"
+ msg += ""
+
+ if(nutrition < 100)
+ msg += "[t_He] [t_is] severely malnourished.\n"
+ else if(nutrition >= 500)
+ if(usr.nutrition < 100)
+ msg += "[t_He] [t_is] plump and delicious looking - Like a fat little piggy. A tasty piggy.\n"
+ else
+ msg += "[t_He] [t_is] quite chubby.\n"
+ msg += ""
+
+ var/list/wound_flavor_text = list()
+ var/list/is_destroyed = list()
+ var/list/is_bleeding = list()
+ for(var/datum/organ/external/temp in organs)
+ if(temp)
+ if(temp.status & ORGAN_DESTROYED)
+ is_destroyed["[temp.display_name]"] = 1
+ wound_flavor_text["[temp.display_name]"] = "[t_He] is missing [t_his] [temp.display_name].\n"
+ continue
+ if(temp.status & ORGAN_ROBOT)
+ if(!(temp.brute_dam + temp.burn_dam))
+ wound_flavor_text["[temp.display_name]"] = "[t_He] has a robot [temp.display_name]!\n"
+ continue
+ else
+ wound_flavor_text["[temp.display_name]"] = "[t_He] has a robot [temp.display_name], it has"
+ if(temp.brute_dam) switch(temp.brute_dam)
+ if(0 to 20)
+ wound_flavor_text["[temp.display_name]"] += " some dents"
+ if(21 to INFINITY)
+ wound_flavor_text["[temp.display_name]"] += pick(" a lot of dents"," severe denting")
+ if(temp.brute_dam && temp.burn_dam)
+ wound_flavor_text["[temp.display_name]"] += " and"
+ if(temp.burn_dam) switch(temp.burn_dam)
+ if(0 to 20)
+ wound_flavor_text["[temp.display_name]"] += " some burns"
+ if(21 to INFINITY)
+ wound_flavor_text["[temp.display_name]"] += pick(" a lot of burns"," severe melting")
+ wound_flavor_text["[temp.display_name]"] += "!\n"
+ else if(temp.wounds.len > 0)
+ var/list/wound_descriptors = list()
+ for(var/datum/wound/W in temp.wounds)
+ if(W.desc in wound_descriptors)
+ wound_descriptors[W.desc] += W.amount
+ continue
+ wound_descriptors[W.desc] = W.amount
+ var/list/flavor_text = list()
+ var/list/no_exclude = list("gaping wound", "big gaping wound", "massive wound", "large bruise",\
+ "huge bruise", "massive bruise", "severe burn", "large burn", "deep burn", "carbonised area")
+ for(var/wound in wound_descriptors)
+ switch(wound_descriptors[wound])
+ if(1)
+ if(!flavor_text.len)
+ flavor_text += "[t_He] has[prob(10) && !(wound in no_exclude) ? " what might be" : ""] a [wound]"
+ else
+ flavor_text += "[prob(10) && !(wound in no_exclude) ? " what might be" : ""] a [wound]"
+ if(2)
+ if(!flavor_text.len)
+ flavor_text += "[t_He] has[prob(10) && !(wound in no_exclude) ? " what might be" : ""] a pair of [wound]s"
+ else
+ flavor_text += "[prob(10) && !(wound in no_exclude) ? " what might be" : ""] a pair of [wound]s"
+ if(3 to 5)
+ if(!flavor_text.len)
+ flavor_text += "[t_He] has several [wound]s"
+ else
+ flavor_text += " several [wound]s"
+ if(6 to INFINITY)
+ if(!flavor_text.len)
+ flavor_text += "[t_He] has a bunch of [wound]s"
+ else
+ flavor_text += " a ton of [wound]\s"
+ var/flavor_text_string = ""
+ for(var/text = 1, text <= flavor_text.len, text++)
+ if(text == flavor_text.len && flavor_text.len > 1)
+ flavor_text_string += ", and"
+ else if(flavor_text.len > 1 && text > 1)
+ flavor_text_string += ","
+ flavor_text_string += flavor_text[text]
+ flavor_text_string += " on [t_his] [temp.display_name].
"
+ wound_flavor_text["[temp.display_name]"] = flavor_text_string
+ if(temp.status & ORGAN_BLEEDING)
+ is_bleeding["[temp.display_name]"] = 1
+ else
+ wound_flavor_text["[temp.display_name]"] = ""
+
+ //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
+ var/display_shoes = 0
+ var/display_gloves = 0
+ if(wound_flavor_text["head"] && (is_destroyed["head"] || (!skipmask && !(wear_mask && istype(wear_mask, /obj/item/clothing/mask/gas)))))
+ msg += wound_flavor_text["head"]
+ else if(is_bleeding["head"])
+ msg += "[src] has blood running down [t_his] face!\n"
+ if(wound_flavor_text["chest"] && !w_uniform && !skipjumpsuit) //No need. A missing chest gibs you.
+ msg += wound_flavor_text["chest"]
+ else if(is_bleeding["chest"])
+ display_chest = 1
+ if(wound_flavor_text["left arm"] && (is_destroyed["left arm"] || (!w_uniform && !skipjumpsuit)))
+ msg += wound_flavor_text["left arm"]
+ else if(is_bleeding["left arm"])
+ display_chest = 1
+ if(wound_flavor_text["left hand"] && (is_destroyed["left hand"] || (!gloves && !skipgloves)))
+ msg += wound_flavor_text["left hand"]
+ else if(is_bleeding["left hand"])
+ display_gloves = 1
+ if(wound_flavor_text["right arm"] && (is_destroyed["right arm"] || (!w_uniform && !skipjumpsuit)))
+ msg += wound_flavor_text["right arm"]
+ else if(is_bleeding["right arm"])
+ display_chest = 1
+ if(wound_flavor_text["right hand"] && (is_destroyed["right hand"] || (!gloves && !skipgloves)))
+ msg += wound_flavor_text["right hand"]
+ else if(is_bleeding["right hand"])
+ display_gloves = 1
+ if(wound_flavor_text["groin"] && (is_destroyed["groin"] || (!w_uniform && !skipjumpsuit)))
+ msg += wound_flavor_text["groin"]
+ else if(is_bleeding["groin"])
+ display_chest = 1
+ if(wound_flavor_text["left leg"] && (is_destroyed["left leg"] || (!w_uniform && !skipjumpsuit)))
+ msg += wound_flavor_text["left leg"]
+ else if(is_bleeding["left leg"])
+ display_chest = 1
+ if(wound_flavor_text["left foot"]&& (is_destroyed["left foot"] || (!shoes && !skipshoes)))
+ msg += wound_flavor_text["left foot"]
+ else if(is_bleeding["left foot"])
+ display_shoes = 1
+ if(wound_flavor_text["right leg"] && (is_destroyed["right leg"] || (!w_uniform && !skipjumpsuit)))
+ msg += wound_flavor_text["right leg"]
+ else if(is_bleeding["right leg"])
+ display_chest = 1
+ if(wound_flavor_text["right foot"]&& (is_destroyed["right foot"] || (!shoes && !skipshoes)))
+ msg += wound_flavor_text["right foot"]
+ else if(is_bleeding["right foot"])
+ display_shoes = 1
+ if(display_chest)
+ msg += "[src] has blood soaking through from under [t_his] clothing!\n"
+ if(display_shoes)
+ msg += "[src] has blood running from [t_his] shoes!\n"
+ if(display_gloves)
+ msg += "[src] has blood running from under [t_his] gloves!\n"
+
+
if(digitalcamo)
msg += "[t_He] [t_is] repulsively uncanny!\n"
diff --git a/code/modules/mob/living/carbon/human/hud.dm b/code/modules/mob/living/carbon/human/hud.dm
index 817529aff0c..32a4b6bce07 100644
--- a/code/modules/mob/living/carbon/human/hud.dm
+++ b/code/modules/mob/living/carbon/human/hud.dm
@@ -320,7 +320,118 @@
mymob.flash.screen_loc = "1,1 to 15,15"
mymob.flash.layer = 17
- mymob.zone_sel = new /obj/screen/zone_sel()
+ mymob.pain = new /obj/screen( null )
+
+/*
+ mymob.hands = new /obj/screen( null )
+ mymob.hands.icon = ui_style
+ mymob.hands.icon_state = "hand"
+ mymob.hands.name = "hand"
+ mymob.hands.screen_loc = ui_hand
+ mymob.hands.dir = NORTH
+
+ mymob.sleep = new /obj/screen( null )
+ mymob.sleep.icon = ui_style
+ mymob.sleep.icon_state = "sleep0"
+ mymob.sleep.name = "sleep"
+ mymob.sleep.screen_loc = ui_sleep
+
+ mymob.rest = new /obj/screen( null )
+ mymob.rest.icon = ui_style
+ mymob.rest.icon_state = "rest0"
+ mymob.rest.name = "rest"
+ mymob.rest.screen_loc = ui_rest
+*/
+
+ /*/Monkey blockers
+
+ using = new src.h_type( src )
+ using.name = "blocked"
+ using.icon_state = "blocked"
+ using.screen_loc = ui_ears
+ using.layer = 20
+ src.mon_blo += using
+
+ using = new src.h_type( src )
+ using.name = "blocked"
+ using.icon_state = "blocked"
+ using.screen_loc = ui_belt
+ using.layer = 20
+ src.mon_blo += using
+
+ using = new src.h_type( src )
+ using.name = "blocked"
+ using.icon_state = "blocked"
+ using.screen_loc = ui_shoes
+ using.layer = 20
+ src.mon_blo += using
+
+ using = new src.h_type( src )
+ using.name = "blocked"
+ using.icon_state = "blocked"
+ using.screen_loc = ui_storage2
+ using.layer = 20
+ src.mon_blo += using
+
+ using = new src.h_type( src )
+ using.name = "blocked"
+ using.icon_state = "blocked"
+ using.screen_loc = ui_glasses
+ using.layer = 20
+ src.mon_blo += using
+
+ using = new src.h_type( src )
+ using.name = "blocked"
+ using.icon_state = "blocked"
+ using.screen_loc = ui_gloves
+ using.layer = 20
+ src.mon_blo += using
+
+ using = new src.h_type( src )
+ using.name = "blocked"
+ using.icon_state = "blocked"
+ using.screen_loc = ui_storage1
+ using.layer = 20
+ src.mon_blo += using
+
+ using = new src.h_type( src )
+ using.name = "blocked"
+ using.icon_state = "blocked"
+ using.screen_loc = ui_headset
+ using.layer = 20
+ src.mon_blo += using
+
+ using = new src.h_type( src )
+ using.name = "blocked"
+ using.icon_state = "blocked"
+ using.screen_loc = ui_oclothing
+ using.layer = 20
+ src.mon_blo += using
+
+ using = new src.h_type( src )
+ using.name = "blocked"
+ using.icon_state = "blocked"
+ using.screen_loc = ui_iclothing
+ using.layer = 20
+ src.mon_blo += using
+
+ using = new src.h_type( src )
+ using.name = "blocked"
+ using.icon_state = "blocked"
+ using.screen_loc = ui_id
+ using.layer = 20
+ src.mon_blo += using
+
+ using = new src.h_type( src )
+ using.name = "blocked"
+ using.icon_state = "blocked"
+ using.screen_loc = ui_head
+ using.layer = 20
+ src.mon_blo += using
+//Monkey blockers
+*/
+
+ mymob.zone_sel = new /obj/screen/zone_sel( null )
mymob.zone_sel.icon = ui_style
mymob.zone_sel.overlays = null
mymob.zone_sel.overlays += image('icons/mob/zone_sel.dmi', "[mymob.zone_sel.selecting]")
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index aa7d07b8273..685c392563c 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -21,9 +21,43 @@
dna = new /datum/dna(null)
//initialise organs
- organs = newlist(/datum/organ/external/chest, /datum/organ/external/head, /datum/organ/external/l_arm,
- /datum/organ/external/r_arm, /datum/organ/external/r_leg, /datum/organ/external/l_leg,
- /datum/organ/internal/skeleton, /datum/organ/internal/skin)
+ organs = list()
+ organs_by_name["chest"] = new/datum/organ/external/chest()
+ organs_by_name["head"] = new/datum/organ/external/head()
+ organs_by_name["l_arm"] = new/datum/organ/external/l_arm()
+ organs_by_name["r_arm"] = new/datum/organ/external/r_arm()
+ organs_by_name["r_leg"] = new/datum/organ/external/r_leg()
+ organs_by_name["l_leg"] = new/datum/organ/external/l_leg()
+ organs_by_name["l_hand"] = new/datum/organ/external/l_hand()
+ organs_by_name["r_hand"] = new/datum/organ/external/r_hand()
+ organs_by_name["l_foot"] = new/datum/organ/external/l_foot()
+ organs_by_name["r_foot"] = new/datum/organ/external/r_foot()
+
+ // connect feet to legs and hands to arms
+ var/datum/organ/external/organ = organs_by_name["l_hand"]
+ organ.parent = organs_by_name["l_arm"]
+ organ = organs_by_name["r_hand"]
+ organ.parent = organs_by_name["r_arm"]
+ organ = organs_by_name["l_foot"]
+ organ.parent = organs_by_name["l_leg"]
+ organ = organs_by_name["r_foot"]
+ organ.parent = organs_by_name["r_leg"]
+ organ = organs_by_name["r_foot"]
+ organ.parent = organs_by_name["r_leg"]
+ organ = organs_by_name["head"]
+ organ.parent = organs_by_name["chest"]
+ organ = organs_by_name["r_leg"]
+ organ.parent = organs_by_name["chest"]
+ organ = organs_by_name["l_leg"]
+ organ.parent = organs_by_name["chest"]
+ organ = organs_by_name["r_arm"]
+ organ.parent = organs_by_name["chest"]
+ organ = organs_by_name["l_arm"]
+ organ.parent = organs_by_name["chest"]
+
+ for(var/name in organs_by_name)
+ organs += organs_by_name[name]
+
for(var/datum/organ/external/O in organs)
O.owner = src
@@ -196,6 +230,15 @@
Paralyse(10)
var/update = 0
+
+ // focus most of the blast on one organ
+ var/datum/organ/external/take_blast = pick(organs)
+ update |= take_blast.take_damage(b_loss * 0.9, f_loss * 0.9)
+
+ // distribute the remaining 10% on all limbs equally
+ b_loss *= 0.1
+ f_loss *= 0.1
+
for(var/datum/organ/external/temp in organs)
switch(temp.name)
if("head")
@@ -210,6 +253,14 @@
update |= temp.take_damage(b_loss * 0.05, f_loss * 0.05)
if("r_leg")
update |= temp.take_damage(b_loss * 0.05, f_loss * 0.05)
+ if("r_foot")
+ update |= temp.take_damage(b_loss * 0.05, f_loss * 0.05)
+ if("l_foot")
+ update |= temp.take_damage(b_loss * 0.05, f_loss * 0.05)
+ if("r_arm")
+ update |= temp.take_damage(b_loss * 0.05, f_loss * 0.05)
+ if("l_arm")
+ update |= temp.take_damage(b_loss * 0.05, f_loss * 0.05)
if(update) UpdateDamageIcon()
@@ -519,8 +570,8 @@
//Returns "Unknown" if facially disfigured and real_name if not. Useful for setting name when polyacided or when updating a human's name variable
/mob/living/carbon/human/proc/get_face_name()
- var/datum/organ/external/O = get_organ("head")
- if( (status_flags&DISFIGURED) || (O.brutestate+O.burnstate)>2 || !real_name ) //disfigured. use id-name if possible
+ var/datum/organ/external/head/head = get_organ("head")
+ if( !head || head.disfigured || (head.status & ORGAN_DESTROYED) || !real_name ) //disfigured. use id-name if possible
return "Unknown"
return real_name
@@ -679,4 +730,4 @@
xylophone = 1
spawn(1200)
xylophone=0
- return
+ return
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm
index 13672c0baf3..09e160363cb 100644
--- a/code/modules/mob/living/carbon/human/human_damage.dm
+++ b/code/modules/mob/living/carbon/human/human_damage.dm
@@ -86,11 +86,11 @@
//Damages ONE external organ, organ gets randomly selected from damagable ones.
//It automatically updates damage overlays if necesary
//It automatically updates health status
-/mob/living/carbon/human/take_organ_damage(var/brute, var/burn)
+/mob/living/carbon/human/take_organ_damage(var/brute, var/burn, var/sharp = 0)
var/list/datum/organ/external/parts = get_damageable_organs()
if(!parts.len) return
var/datum/organ/external/picked = pick(parts)
- if(picked.take_damage(brute,burn))
+ if(picked.take_damage(brute,burn,sharp))
UpdateDamageIcon()
updatehealth()
@@ -116,7 +116,7 @@
if(update) UpdateDamageIcon()
// damage MANY external organs, in random order
-/mob/living/carbon/human/take_overall_damage(var/brute, var/burn)
+/mob/living/carbon/human/take_overall_damage(var/brute, var/burn, var/sharp = 0)
if(nodamage) return //godmode
var/list/datum/organ/external/parts = get_damageable_organs()
var/update = 0
@@ -126,7 +126,7 @@
var/brute_was = picked.brute_dam
var/burn_was = picked.burn_dam
- update |= picked.take_damage(brute,burn)
+ update |= picked.take_damage(brute,burn,sharp)
brute -= (picked.brute_dam - brute_was)
burn -= (picked.burn_dam - burn_was)
@@ -150,13 +150,9 @@
/mob/living/carbon/human/proc/get_organ(var/zone)
if(!zone) zone = "chest"
- for(var/datum/organ/external/O in organs)
- if(O.name == zone)
- return O
- return null
+ return organs_by_name[zone]
-
-/mob/living/carbon/human/apply_damage(var/damage = 0,var/damagetype = BRUTE, var/def_zone = null, var/blocked = 0)
+/mob/living/carbon/human/apply_damage(var/damage = 0,var/damagetype = BRUTE, var/def_zone = null, var/blocked = 0, var/sharp = 0)
if((damagetype != BRUTE) && (damagetype != BURN))
..(damage, damagetype, def_zone, blocked)
return 1
@@ -178,10 +174,10 @@
switch(damagetype)
if(BRUTE)
- if(organ.take_damage(damage, 0))
+ if(organ.take_damage(damage, 0, sharp))
UpdateDamageIcon()
if(BURN)
- if(organ.take_damage(0, damage))
+ if(organ.take_damage(0, damage, sharp))
UpdateDamageIcon()
updatehealth()
return 1
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index f33eabe1fe5..86061af9f16 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -112,7 +112,7 @@ emp_act
var/datum/organ/external/affecting = get_organ(ran_zone(user.zone_sel.selecting))
- var/hit_area = parse_zone(affecting.name)
+ var/hit_area = affecting.display_name
if((user != src) && check_shields(I.force, "the [I.name]"))
return 0
@@ -126,7 +126,7 @@ emp_act
if(armor >= 2) return 0
if(!I.force) return 0
- apply_damage(I.force, I.damtype, affecting, armor , I)
+ apply_damage(I.force, I.damtype, affecting, armor , I.sharp)
var/bloody = 0
if(((I.damtype == BRUTE) || (I.damtype == HALLOSS)) && prob(25 + (I.force * 2)))
diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm
index df425ef3224..1cf5788612d 100644
--- a/code/modules/mob/living/carbon/human/human_defines.dm
+++ b/code/modules/mob/living/carbon/human/human_defines.dm
@@ -49,9 +49,10 @@
var/icon/lying_icon = null
var/list/organs = list() //Gets filled up in the constructor (human.dm, New() proc, line 24. I'm sick and tired of missing comments. -Agouri
+ var/list/organs_by_name = list() // map organ names to organs
var/miming = null //Toggle for the mime's abilities.
var/failed_last_breath = 0 //This is used to determine if the mob failed a breath. If they did fail a brath, they will attempt to breathe each tick, otherwise just once per 4 ticks.
- var/xylophone = 0 //For the spoooooooky xylophone cooldown
+ var/xylophone = 0 //For the spoooooooky xylophone cooldown
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm
index d516a2cb1ec..a7e58ec5c82 100644
--- a/code/modules/mob/living/carbon/human/human_movement.dm
+++ b/code/modules/mob/living/carbon/human/human_movement.dm
@@ -19,6 +19,13 @@
if(shoes)
tally += shoes.slowdown
+ for(var/organ_name in list("l_foot","r_foot","l_leg","r_leg"))
+ var/datum/organ/external/E = get_organ(organ_name)
+ if(!E || (E.status & ORGAN_DESTROYED))
+ tally += 4
+ else if(E.status & ORGAN_BROKEN)
+ tally += 1.5
+
if(FAT in src.mutations)
tally += 1.5
if (bodytemperature < 283.222)
diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm
index 2dedb506969..38815dfe274 100644
--- a/code/modules/mob/living/carbon/human/inventory.dm
+++ b/code/modules/mob/living/carbon/human/inventory.dm
@@ -6,6 +6,54 @@
del(W)
return null
+
+/mob/living/carbon/human/proc/has_organ(name)
+ var/datum/organ/external/O = organs_by_name[name]
+
+ return (O && !(O.status & ORGAN_DESTROYED) )
+
+/mob/living/carbon/human/proc/has_organ_for_slot(slot)
+ switch(slot)
+ if(slot_back)
+ return has_organ("chest")
+ if(slot_wear_mask)
+ return has_organ("head")
+ if(slot_handcuffed)
+ return has_organ("l_hand") && has_organ("r_hand")
+ if(slot_legcuffed)
+ return has_organ("l_leg") && has_organ("r_leg")
+ if(slot_l_hand)
+ return has_organ("l_hand")
+ if(slot_r_hand)
+ return has_organ("r_hand")
+ if(slot_belt)
+ return has_organ("chest")
+ if(slot_wear_id)
+ // the only relevant check for this is the uniform check
+ return 1
+ if(slot_ears)
+ return has_organ("head")
+ if(slot_glasses)
+ return has_organ("head")
+ if(slot_gloves)
+ return has_organ("l_hand") && has_organ("r_hand")
+ if(slot_head)
+ return has_organ("head")
+ if(slot_shoes)
+ return has_organ("r_foot") && has_organ("l_foot")
+ if(slot_wear_suit)
+ return has_organ("chest")
+ if(slot_w_uniform)
+ return has_organ("chest")
+ if(slot_l_store)
+ return has_organ("chest")
+ if(slot_r_store)
+ return has_organ("chest")
+ if(slot_s_store)
+ return has_organ("chest")
+ if(slot_in_backpack)
+ return 1
+
/mob/living/carbon/human/u_equip(obj/item/W as obj)
if(!W) return 0
@@ -124,6 +172,7 @@
/mob/living/carbon/human/equip_to_slot(obj/item/W as obj, slot, redraw_mob = 1)
if(!slot) return
if(!istype(W)) return
+ if(!has_organ_for_slot(slot)) return
if(W == src.l_hand)
src.l_hand = null
@@ -607,7 +656,7 @@ It can still be worn/put on as normal.
if(target.r_store)
target.u_equip(target.r_store) //At this stage l_store is already processed by the code above, we only need to process r_store.
else
- if(item) //Placing an item on the mob
+ if(item && target.has_organ_for_slot(slot_to_process)) //Placing an item on the mob
if(item.mob_can_equip(target, slot_to_process, 0))
source.u_equip(item)
target.equip_to_slot_if_possible(item, slot_to_process, 0, 1, 1)
diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm
index da773aab9de..4d5f22160b6 100644
--- a/code/modules/mob/living/carbon/human/life.dm
+++ b/code/modules/mob/living/carbon/human/life.dm
@@ -53,6 +53,8 @@
fire_alert = 0 //Reset this here, because both breathe() and handle_environment() have a chance to set it.
//TODO: seperate this out
+ // update the current life tick, can be used to e.g. only do something every 4 ticks
+ life_tick++
var/datum/gas_mixture/environment = loc.return_air()
//No need to update all of these procs if the guy is dead.
@@ -167,6 +169,71 @@
if(3)
emote("drool")
+ proc/handle_organs()
+ // take care of organ related updates, such as broken and missing limbs
+
+ // recalculate number of wounds
+ number_wounds = 0
+ for(var/datum/organ/external/E in organs)
+ if(!E)
+ world << name
+ continue
+ number_wounds += E.number_wounds
+
+ var/leg_tally = 2
+ for(var/datum/organ/external/E in organs)
+ E.process()
+ if(E.status & ORGAN_ROBOT && prob(E.brute_dam + E.burn_dam))
+ if(E.name == "l_hand" || E.name == "l_arm")
+ if(hand && equipped())
+ drop_item()
+ emote("custom v drops what they were holding, their [E.display_name?"[E.display_name]":"[E]"] malfunctioning!")
+ var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread()
+ spark_system.set_up(5, 0, src)
+ spark_system.attach(src)
+ spark_system.start()
+ spawn(10)
+ del(spark_system)
+ else if(E.name == "r_hand" || E.name == "r_arm")
+ if(!hand && equipped())
+ drop_item()
+ emote("custom v drops what they were holding, their [E.display_name?"[E.display_name]":"[E]"] malfunctioning!")
+ var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread()
+ spark_system.set_up(5, 0, src)
+ spark_system.attach(src)
+ spark_system.start()
+ spawn(10)
+ del(spark_system)
+ else if(E.name == "l_leg" || E.name == "l_foot" \
+ || E.name == "r_leg" || E.name == "r_foot" && !lying)
+ leg_tally-- // let it fail even if just foot&leg
+ if(E.status & ORGAN_BROKEN || E.status & ORGAN_DESTROYED)
+ if(E.name == "l_hand" || E.name == "l_arm")
+ if(hand && equipped())
+ if(E.status & ORGAN_SPLINTED && prob(10))
+ drop_item()
+ emote("scream")
+ else
+ drop_item()
+ emote("scream")
+ else if(E.name == "r_hand" || E.name == "r_arm")
+ if(!hand && equipped())
+ if(E.status & ORGAN_SPLINTED && prob(10))
+ drop_item()
+ emote("scream")
+ else
+ drop_item()
+ emote("scream")
+ else if(E.name == "l_leg" || E.name == "l_foot" \
+ || E.name == "r_leg" || E.name == "r_foot" && !lying)
+ if(!(E.status & ORGAN_SPLINTED))
+ leg_tally-- // let it fail even if just foot&leg
+ // standing is poor
+ if(leg_tally <= 0 && !paralysis && !(lying || resting) && prob(5))
+ emote("scream")
+ emote("collapse")
+ paralysis = 10
+
proc/handle_mutations_and_radiation()
if(getFireLoss())
@@ -820,6 +887,7 @@
silent = 0
else //ALIVE. LIGHTS ARE ON
updatehealth() //TODO
+ handle_organs()
if(health <= config.health_threshold_dead || brain_op_stage == 4.0)
death()
blinded = 1
diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm
index bda35bc5d71..6486154e9c3 100644
--- a/code/modules/mob/living/carbon/human/update_icons.dm
+++ b/code/modules/mob/living/carbon/human/update_icons.dm
@@ -123,6 +123,7 @@ Please contact me on #coderbus IRC. ~Carn x
/mob/living/carbon/human
var/list/overlays_lying[TOTAL_LAYERS]
var/list/overlays_standing[TOTAL_LAYERS]
+ var/previous_damage_appearance // store what the body last looked like, so we only have to update it if something changed
//UPDATES OVERLAYS FROM OVERLAYS_LYING/OVERLAYS_STANDING
@@ -160,47 +161,132 @@ Please contact me on #coderbus IRC. ~Carn x
for(var/image/I in overlays_standing)
overlays += I
-
+var/global/list/damage_icon_parts = list()
+proc/get_damage_icon_part(damage_state, body_part)
+ if(damage_icon_parts["[damage_state]/[body_part]"] == null)
+ var/icon/DI = new /icon('icons/mob/dam_human.dmi', damage_state) // the damage icon for whole human
+ DI.Blend(new /icon('dam_mask.dmi', body_part), ICON_MULTIPLY) // mask with this organ's pixels
+ damage_icon_parts["[damage_state]/[body_part]"] = DI
+ return DI
+ else
+ return damage_icon_parts["[damage_state]/[body_part]"]
//DAMAGE OVERLAYS
//constructs damage icon for each organ from mask * damage field and saves it in our overlays_ lists
/mob/living/carbon/human/UpdateDamageIcon(var/update_icons=1)
- var/image/standing = image("icon" = 'icons/mob/dam_human.dmi', "icon_state" = "blank")
- var/image/lying = image("icon" = 'icons/mob/dam_human.dmi', "icon_state" = "blank2")
- for(var/datum/organ/external/O in organs)
- if(O.brutestate)
- standing.overlays += "[O.icon_name]_[O.brutestate]0" //we're adding icon_states of the base image as overlays
- lying.overlays += "[O.icon_name]2_[O.brutestate]0"
- if(O.burnstate)
- standing.overlays += "[O.icon_name]_0[O.burnstate]"
- lying.overlays += "[O.icon_name]2_0[O.burnstate]"
+ // first check whether something actually changed about damage appearance
+ var/damage_appearance = ""
+
+ for(var/datum/organ/external/O in organs)
+ if(O.status & ORGAN_DESTROYED) damage_appearance += "d"
+ else
+ damage_appearance += O.damage_state
+
+ if(damage_appearance == previous_damage_appearance)
+ // nothing to do here
+ return
+
+ previous_damage_appearance = damage_appearance
+
+ var/icon/standing = new /icon('dam_human.dmi', "00")
+ var/icon/lying = new /icon('dam_human.dmi', "00-2")
+
+ var/image/standing_image = new /image("icon" = standing)
+ var/image/lying_image = new /image("icon" = lying)
+
+
+ // blend the individual damage states with our icons
+ for(var/datum/organ/external/O in organs)
+ if(!(O.status & ORGAN_DESTROYED))
+ O.update_icon()
+ if(O.damage_state == "00") continue
+
+ var/icon/DI = get_damage_icon_part(O.damage_state, O.icon_name)
+
+ standing_image.overlays += DI
+
+ DI = get_damage_icon_part("[O.damage_state]-2", "[O.icon_name]2")
+ lying_image.overlays += DI
+
+
+ overlays_standing[DAMAGE_LAYER] = standing_image
+ overlays_lying[DAMAGE_LAYER] = lying_image
- overlays_standing[DAMAGE_LAYER] = standing
- overlays_lying[DAMAGE_LAYER] = lying
if(update_icons) update_icons()
//BASE MOB SPRITE
/mob/living/carbon/human/proc/update_body(var/update_icons=1)
+
if(stand_icon) del(stand_icon)
if(lying_icon) del(lying_icon)
-// if(dna && dna.mutantrace) return
- //var/husk = (HUSK in src.mutations) //100% unnecessary -Agouri
- //var/fat = (FAT in src.mutations)
+ if(dna && dna.mutantrace) return
+
var/g = "m"
if(gender == FEMALE) g = "f"
+ var/husk = (HUSK in src.mutations)
+ var/obese = (FAT in src.mutations)
+
+ // whether to draw the individual limbs
+ var/individual_limbs = 1
+
//Base mob icon
- if(HUSK in src.mutations)
- stand_icon = new /icon('icons/mob/human.dmi', "husk_s")
- lying_icon = new /icon('icons/mob/human.dmi', "husk_l")
- else if(FAT in src.mutations)
+ if(obese)
+ // Sorry, no dismemberment for fat people.
stand_icon = new /icon('icons/mob/human.dmi', "fatbody_s")
lying_icon = new /icon('icons/mob/human.dmi', "fatbody_l")
+ individual_limbs = 0
+ // If dismemberment is on, draw individual limbs
+ else if(config.limbs_can_break)
+ stand_icon = new /icon('icons/mob/human.dmi', "torso_[g]_s")
+ lying_icon = new /icon('icons/mob/human.dmi', "torso_[g]_l")
+ // Otherwise just draw the full body.
else if(SKELETON in src.mutations)
stand_icon = new /icon('icons/mob/human.dmi', "skeleton_s")
lying_icon = new /icon('icons/mob/human.dmi', "skeleton_l")
else
stand_icon = new /icon('icons/mob/human.dmi', "body_[g]_s")
lying_icon = new /icon('icons/mob/human.dmi', "body_[g]_l")
+ individual_limbs = 0
+
+ // Draw each individual limb
+ if(individual_limbs)
+ stand_icon.Blend(new /icon('icons/mob/human.dmi', "chest_[g]_s"), ICON_OVERLAY)
+ lying_icon.Blend(new /icon('icons/mob/human.dmi', "chest_[g]_l"), ICON_OVERLAY)
+
+ var/datum/organ/external/head = get_organ("head")
+ if(head && !(head.status & ORGAN_DESTROYED))
+ stand_icon.Blend(new /icon('icons/mob/human.dmi', "head_[g]_s"), ICON_OVERLAY)
+ lying_icon.Blend(new /icon('icons/mob/human.dmi', "head_[g]_l"), ICON_OVERLAY)
+
+ for(var/datum/organ/external/part in organs)
+ if(!istype(part, /datum/organ/external/groin) \
+ && !istype(part, /datum/organ/external/chest) \
+ && !istype(part, /datum/organ/external/head) \
+ && !(part.status & ORGAN_DESTROYED))
+ var/icon/temp = new /icon('human.dmi', "[part.icon_name]_s")
+ if(part.status & ORGAN_ROBOT) temp.MapColors(rgb(77,77,77), rgb(150,150,150), rgb(28,28,28), rgb(0,0,0))
+ stand_icon.Blend(temp, ICON_OVERLAY)
+ temp = new /icon('human.dmi', "[part.icon_name]_l")
+ if(part.status & ORGAN_ROBOT) temp.MapColors(rgb(77,77,77), rgb(150,150,150), rgb(28,28,28), rgb(0,0,0))
+ lying_icon.Blend(temp , ICON_OVERLAY)
+
+ stand_icon.Blend(new /icon('human.dmi', "groin_[g]_s"), ICON_OVERLAY)
+ lying_icon.Blend(new /icon('human.dmi', "groin_[g]_l"), ICON_OVERLAY)
+
+ if (husk)
+ var/icon/husk_s = new /icon('human.dmi', "husk_s")
+ var/icon/husk_l = new /icon('human.dmi', "husk_l")
+
+ for(var/datum/organ/external/part in organs)
+ if(!istype(part, /datum/organ/external/groin) \
+ && !istype(part, /datum/organ/external/chest) \
+ && !istype(part, /datum/organ/external/head) \
+ && (part.status & ORGAN_DESTROYED))
+ husk_s.Blend(new /icon('dam_mask.dmi', "[part.icon_name]"), ICON_SUBTRACT)
+ husk_l.Blend(new /icon('dam_mask.dmi', "[part.icon_name]2"), ICON_SUBTRACT)
+
+ stand_icon.Blend(husk_s, ICON_OVERLAY)
+ lying_icon.Blend(husk_l, ICON_OVERLAY)
//Skin tone
if((SKELETON in src.mutations) == 0)
@@ -219,6 +305,13 @@ Please contact me on #coderbus IRC. ~Carn x
eyes_l.Blend(rgb(r_eyes, g_eyes, b_eyes), ICON_ADD)
stand_icon.Blend(eyes_s, ICON_OVERLAY)
lying_icon.Blend(eyes_l, ICON_OVERLAY)
+ // Note: These used to be in update_face(), and the fact they're here will make it difficult to create a disembodied head
+ var/icon/eyes_s = new/icon('icons/mob/human_face.dmi', "eyes_s")
+ var/icon/eyes_l = new/icon('icons/mob/human_face.dmi', "eyes_l")
+ eyes_s.Blend(rgb(r_eyes, g_eyes, b_eyes), ICON_ADD)
+ eyes_l.Blend(rgb(r_eyes, g_eyes, b_eyes), ICON_ADD)
+ stand_icon.Blend(eyes_s, ICON_OVERLAY)
+ lying_icon.Blend(eyes_l, ICON_OVERLAY)
//Mouth (lipstick!)
if(lip_style && (SKELETON in src.mutations) == 0)
@@ -227,20 +320,26 @@ Please contact me on #coderbus IRC. ~Carn x
//Underwear
if(underwear >0 && underwear < 12)
- if((FAT in src.mutations) == 0 && (SKELETON in src.mutations) == 0)
- stand_icon.Blend(new /icon('icons/mob/human.dmi', "underwear[underwear]_[g]_s"), ICON_OVERLAY)
- lying_icon.Blend(new /icon('icons/mob/human.dmi', "underwear[underwear]_[g]_l"), ICON_OVERLAY)
+ if(!obese)
+ stand_icon.Blend(new /icon('human.dmi', "underwear[underwear]_[g]_s"), ICON_OVERLAY)
+ lying_icon.Blend(new /icon('human.dmi', "underwear[underwear]_[g]_l"), ICON_OVERLAY)
if(update_icons) update_icons()
//tail update_tail_showing(0)
+
//HAIR OVERLAY
/mob/living/carbon/human/proc/update_hair(var/update_icons=1)
//Reset our hair
overlays_lying[HAIR_LAYER] = null
overlays_standing[HAIR_LAYER] = null
- //mutantraces (xeno crew) can have hair. masks and helmets can obscure our hair too.
- if( (head && (head.flags & BLOCKHAIR)) || (wear_mask && (wear_mask.flags & BLOCKHAIR)) )
+ var/datum/organ/external/head/head = get_organ("head")
+ if( !head || (head.status & ORGAN_DESTROYED) )
+ if(update_icons) update_icons()
+ return
+
+ //mutants don't have hair. masks and helmets can obscure our hair too.
+ if( (dna && dna.mutantrace) || (head && (head.status & BLOCKHAIR)) || (wear_mask && (wear_mask.flags & BLOCKHAIR)))
if(update_icons) update_icons()
return
@@ -367,6 +466,7 @@ Please contact me on #coderbus IRC. ~Carn x
update_inv_handcuffed(0)
update_inv_legcuffed(0)
update_inv_pockets(0)
+ UpdateDamageIcon()
update_icons()
//Hud Stuff
update_hud()
@@ -688,6 +788,41 @@ Please contact me on #coderbus IRC. ~Carn x
if(update_icons)
update_icons()
+// Used mostly for creating head items
+/mob/living/carbon/human/proc/generate_head_icon()
+//gender no longer matters for the mouth, although there should probably be seperate base head icons.
+// var/g = "m"
+// if (gender == FEMALE) g = "f"
+
+ //base icons
+ var/icon/face_lying = new /icon('icons/mob/human_face.dmi',"bald_l")
+
+ if(f_style)
+ var/datum/sprite_accessory/facial_hair_style = facial_hair_styles_list[f_style]
+ if(facial_hair_style)
+ var/icon/facial_l = new/icon("icon" = facial_hair_style.icon, "icon_state" = "[facial_hair_style.icon_state]_l")
+ facial_l.Blend(rgb(r_facial, g_facial, b_facial), ICON_ADD)
+ face_lying.Blend(facial_l, ICON_OVERLAY)
+
+ if(h_style)
+ var/datum/sprite_accessory/hair_style = hair_styles_list[h_style]
+ if(hair_style)
+ var/icon/hair_l = new/icon("icon" = hair_style.icon, "icon_state" = "[hair_style.icon_state]_l")
+ hair_l.Blend(rgb(r_hair, g_hair, b_hair), ICON_ADD)
+ face_lying.Blend(hair_l, ICON_OVERLAY)
+
+ //Eyes
+ // Note: These used to be in update_face(), and the fact they're here will make it difficult to create a disembodied head
+ var/icon/eyes_l = new/icon('icons/mob/human_face.dmi', "eyes_l")
+ eyes_l.Blend(rgb(r_eyes, g_eyes, b_eyes), ICON_ADD)
+ face_lying.Blend(eyes_l, ICON_OVERLAY)
+
+ if(lip_style)
+ face_lying.Blend(new/icon('icons/mob/human_face.dmi', "lips_[lip_style]_l"), ICON_OVERLAY)
+
+ var/image/face_lying_image = new /image(icon = face_lying)
+ return face_lying_image
+
//Human Overlays Indexes/////////
#undef MUTANTRACE_LAYER
#undef MUTATIONS_LAYER
diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm
index c97f5f0dcc3..b8be9342e5e 100644
--- a/code/modules/mob/mob_defines.dm
+++ b/code/modules/mob/mob_defines.dm
@@ -219,4 +219,3 @@
var/tajaran_talk_understand = 0
var/soghun_talk_understand = 0
var/skrell_talk_understand = 0
-
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index 2a0310752c6..c292aaaa67f 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -120,6 +120,9 @@ proc/isorgan(A)
return 1
return 0
+proc/hasorgans(A)
+ return (ishuman(A) || ismonkey(A))
+
/proc/hsl2rgb(h, s, l)
return
@@ -379,4 +382,4 @@ var/list/intents = list("help","disarm","grab","hurt")
if(a_intent == "hurt")
hud_used.action_intent.icon_state = "harm"
else
- hud_used.action_intent.icon_state = "help"
\ No newline at end of file
+ hud_used.action_intent.icon_state = "help"
diff --git a/code/setup.dm b/code/setup.dm
index 0f463beda8c..8bcfabb16ab 100644
--- a/code/setup.dm
+++ b/code/setup.dm
@@ -529,4 +529,37 @@ var/list/TAGGERLOCATIONS = list("Disposals",
"Bar", "Kitchen", "Hydroponics", "Janitor Closet","Genetics")
#define MIN_PLAYER_AGE 19
-#define MAX_PLAYER_AGE 60
\ No newline at end of file
+#define MAX_PLAYER_AGE 60
+
+//Damage things
+#define CUT "cut"
+#define BRUISE "bruise"
+#define BRUTE "brute"
+#define BURN "fire"
+#define TOX "tox"
+#define OXY "oxy"
+#define CLONE "clone"
+#define HALLOSS "halloss"
+
+#define STUN "stun"
+#define WEAKEN "weaken"
+#define PARALYZE "paralize"
+#define IRRADIATE "irradiate"
+#define STUTTER "stutter"
+#define SLUR "slur"
+#define EYE_BLUR "eye_blur"
+#define DROWSY "drowsy"
+
+/////////////////
+//ORGAN DEFINES//
+/////////////////
+#define ORGAN_CUT_AWAY 1
+#define ORGAN_GAUZED 2
+#define ORGAN_ATTACHABLE 4
+#define ORGAN_BLEEDING 8
+#define ORGAN_BANDAGED 16
+#define ORGAN_BROKEN 32
+#define ORGAN_DESTROYED 64
+#define ORGAN_ROBOT 128
+#define ORGAN_SPLINTED 256
+#define SALVED 512
\ No newline at end of file
diff --git a/config/game_options.txt b/config/game_options.txt
index 9ec32a29484..55bb346aca0 100644
--- a/config/game_options.txt
+++ b/config/game_options.txt
@@ -6,6 +6,21 @@ HEALTH_THRESHOLD_CRIT 0
## level of health at which a mob becomes dead
HEALTH_THRESHOLD_DEAD -100
+## Determines whether bones can be broken through excessive damage to the organ
+## 0 means bones can't break, 1 means they can
+BONES_CAN_BREAK 0
+## Determines whether limbs can be amputated through excessive damage to the organ
+## 0 means limbs can't be amputated, 1 means they can
+LIMBS_CAN_BREAK 0
+
+## multiplier which enables organs to take more damage before bones breaking or limbs being destroyed
+## 100 means normal, 50 means half
+ORGAN_HEALTH_MULTIPLIER 100
+
+## multiplier which influences how fast organs regenerate naturally
+## 100 means normal, 50 means half
+ORGAN_REGENERATION_MULTIPLIER 100
+
### REVIVAL ###
## whether pod plants work or not
diff --git a/icons/mob/dam_human.dmi b/icons/mob/dam_human.dmi
index de04520f410..c68299554c8 100644
Binary files a/icons/mob/dam_human.dmi and b/icons/mob/dam_human.dmi differ
diff --git a/icons/mob/dam_mask.dmi b/icons/mob/dam_mask.dmi
new file mode 100644
index 00000000000..5cf1e09f19b
Binary files /dev/null and b/icons/mob/dam_mask.dmi differ
diff --git a/icons/mob/human.dmi b/icons/mob/human.dmi
index 3850c7365fd..dc9ca30eadc 100644
Binary files a/icons/mob/human.dmi and b/icons/mob/human.dmi differ