From fb60301594506497e01ed9cb6776713cc55fb564 Mon Sep 17 00:00:00 2001 From: cib Date: Thu, 11 Oct 2012 13:49:30 -0700 Subject: [PATCH] Revert "Revert's cib's BS12 merge by XSI's orders" This reverts commit a6e7c085ef675a63347b3f592929c17599c88b24. Conflicts: baystation12.dme code/datums/organs/organ_external.dm code/game/gamemodes/events/ninja_equipment.dm code/modules/mob/living/carbon/human/examine.dm code/modules/mob/living/carbon/human/hud.dm code/modules/mob/living/carbon/human/human.dm code/modules/mob/living/carbon/human/human_defines.dm code/modules/mob/living/carbon/human/update_icons.dm code/modules/mob/mob_defines.dm code/setup.dm icons/mob/dam_human.dmi icons/mob/human.dmi --- baystation12.dme | 1 + code/controllers/configuration.dm | 14 + code/datums/organs/organ.dm | 9 +- code/datums/organs/organ_external.dm | 671 ++++++++++++++++-- code/datums/organs/organ_internal.dm | 3 + code/datums/organs/wound.dm | 196 +++++ code/defines/obj/weapon.dm | 4 + code/defines/procs/helpers.dm | 4 + code/game/dna.dm | 2 - code/game/gamemodes/events/ninja_equipment.dm | 11 +- code/game/mecha/mech_fabricator.dm | 14 +- code/game/objects/items/devices/PDA/PDA.dm | 4 +- code/game/objects/items/stacks/medical.dm | 19 +- code/game/objects/objs.dm | 1 + code/modules/mob/inventory.dm | 16 +- .../mob/living/carbon/carbon_defines.dm | 5 + .../mob/living/carbon/human/examine.dm | 160 ++++- code/modules/mob/living/carbon/human/hud.dm | 113 ++- code/modules/mob/living/carbon/human/human.dm | 63 +- .../mob/living/carbon/human/human_damage.dm | 20 +- .../mob/living/carbon/human/human_defense.dm | 4 +- .../mob/living/carbon/human/human_defines.dm | 3 +- .../mob/living/carbon/human/human_movement.dm | 7 + .../mob/living/carbon/human/inventory.dm | 51 +- code/modules/mob/living/carbon/human/life.dm | 68 ++ .../mob/living/carbon/human/update_icons.dm | 183 ++++- code/modules/mob/mob_defines.dm | 1 - code/modules/mob/mob_helpers.dm | 5 +- code/setup.dm | 35 +- config/game_options.txt | 15 + icons/mob/dam_human.dmi | Bin 4466 -> 9738 bytes icons/mob/dam_mask.dmi | Bin 0 -> 1503 bytes icons/mob/human.dmi | Bin 24562 -> 22013 bytes 33 files changed, 1545 insertions(+), 157 deletions(-) create mode 100644 code/datums/organs/wound.dm create mode 100644 icons/mob/dam_mask.dmi diff --git a/baystation12.dme b/baystation12.dme index 585de4dd5b2..f1bce8e78d4 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 447e00125e3..c3a4f0b7569 100644 --- a/code/defines/obj/weapon.dm +++ b/code/defines/obj/weapon.dm @@ -1556,6 +1556,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" @@ -1637,6 +1638,7 @@ icon_state = "knife" force = 10.0 throwforce = 10.0 + sharp = 1 /obj/item/weapon/kitchen/utensil/spoon name = "spoon" @@ -1659,6 +1661,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" @@ -1725,6 +1728,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 89be98f2f8a..bb74e36ca37 100755 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -840,8 +840,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 679ead3e9ec..f7312a84381 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -115,6 +115,9 @@ proc/isorgan(A) return 1 return 0 +proc/hasorgans(A) + return (ishuman(A) || ismonkey(A)) + /proc/hsl2rgb(h, s, l) return @@ -374,4 +377,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 de04520f410795d430333cf18c4d1de68bf8a5e7..c68299554c88736776d7bce2763b4ea93f4c1f8e 100644 GIT binary patch literal 9738 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 AIRF3v diff --git a/icons/mob/dam_mask.dmi b/icons/mob/dam_mask.dmi new file mode 100644 index 0000000000000000000000000000000000000000..5cf1e09f19b352e63f737ab31b7f43c4a9b654df GIT binary patch literal 1503 zcmV<51t9u~P)lXaA%~@1|t%R5s&%=a4edGVk|KWY#-+tfy%m3kh;s4A3 z-hSZWeB|PO;H<2y{KAL(!Gz`I<==ha%F4>`@9*M#-`;-W;C|!(m;e9D{{GGU{+j*$ z&Hv(j;*w3`S^xk50d!JMQvg8b*k%9#0NZ+0Sad{Xb7OL8aCB*JZU6vyoQ;&R4#FT5 zMd$Jrq@6WdU0sZg>0p1ML3u4iS`486zE~y)!`%6vuKBhDugQ?R;FftQee_D9u06N@lTvptOVmd9EL< z4Oz@!nClIVKo~+vEgs~u*iDf~iU~IX#SqH%O3eA2H5jHypq6S-Q=VHqA#o6vOy#*n z6;du*K*~W_vW3K9+}Bs0x*9Rx^KafhgTko4M^?P)PRqCS0h|6ymXVcprI9ES!igZ0ZM|0vY_pwV{&}dMnS6q1+71N*9Is%Vak3ALr>36(a*|2 zKkJU})d5O1{M64QdZ3?mN9*bUub_-qP*ugw*ZGc4Cu$5%A(1K(d$7C$D(}NWmyip3 zLC9r8i|7GC<-JA2k?e%`NQm;C5+J>G+HUARZn~fu3M2rxC2s&I zXys__0T{h~09;F8!XPT1L=5}&3D&R0=_m5j@!fRhxPyCzya}WUn(5+~I#LWCl>2Dy z(itu&w1hhx2CZlbj64Va5*IGcups~NI3qLrTqSP;2L#R5QeK^^)v?Mz&(M7PQX;8> zuJOWuShz;ro~efUCmx?C=D`s^roF3P_k1^R0{^X`dEH);XrRzLS-G}bvh3j$cP;4l z6m_$;>-jztgxkD)K?%G0dGNk@LY_Rk{W*IW53YlJ+q^oO(-JhX=>pzcCqWOl@bh0_ z{VQGBoeb88{$lAb7e23%EFu^U@s|D~*y9yDNfdVOmj?O%%j=}`){oCqX1g!s>G5vp zh99vG7(G3%-S=Lq932J-nnx>A2Qo*{0=v1_G+z>eD3bot zgShpfx8UWK{R(=r^MMADf41GvuhDmGzSVL*#}l5Jje`7H{$CxHJYUIgt8#E;T*DUD zkK#ZlaP`EUj){7Zg;5 zW}Ob5`dj;<5ieNeb;?q|jiQ^^1qDTP=Erp(8t@}nqG74u=hV&1om(@u5Ri({8XWZ= zS;1dCfmYo8lTz}MlM_QW`4A*$*5yt4uO8^;QBVZg;~(wWEF;68&QJgV002ovPDHLk FV1i2o28jRw literal 0 HcmV?d00001 diff --git a/icons/mob/human.dmi b/icons/mob/human.dmi index 3850c7365fdc1decfb7f2143abb45522cd51947b..dc9ca30eadc006e37e0b1928a140dfd932ef5086 100644 GIT binary patch literal 22013 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 A`v3p{ literal 24562 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