diff --git a/code/WorkInProgress/autopsy.dm b/code/WorkInProgress/autopsy.dm new file mode 100644 index 00000000000..7d1b647c876 --- /dev/null +++ b/code/WorkInProgress/autopsy.dm @@ -0,0 +1,189 @@ +/datum/autopsy_data_scanner + var/weapon = null // this is the DEFINITE weapon type that was used + var/list/organs_scanned = list() // this maps a number of scanned organs to + // the wounds to those organs with this data's weapon type + var/organ_names = "" + +/datum/autopsy_data + var/weapon = null + var/pretend_weapon = null + var/damage = 0 + var/hits = 0 + var/time_inflicted = 0 + + proc/copy() + var/datum/autopsy_data/W = new() + W.weapon = weapon + W.pretend_weapon = pretend_weapon + W.damage = damage + W.hits = hits + W.time_inflicted = time_inflicted + return W + +/obj/item/weapon/autopsy_scanner/proc/add_data(var/datum/organ/external/O) + if(!O.autopsy_data.len && !O.trace_chemicals.len) return + + for(var/V in O.autopsy_data) + var/datum/autopsy_data/W = O.autopsy_data[V] + + if(!W.pretend_weapon) + /* + // the more hits, the more likely it is that we get the right weapon type + if(prob(50 + W.hits * 10 + W.damage)) + */ + + // Buffing this stuff up for now! + if(1) + W.pretend_weapon = W.weapon + else + W.pretend_weapon = pick("mechanical toolbox", "wirecutters", "revolver", "crowbar", "fire extinguisher", "tomato soup", "oxygen tank", "emergency oxygen tank", "laser", "bullet") + + + var/datum/autopsy_data_scanner/D = wdata[V] + if(!D) + D = new() + D.weapon = W.weapon + wdata[V] = D + + if(!D.organs_scanned[O.name]) + if(D.organ_names == "") + D.organ_names = O.display_name + else + D.organ_names += ", [O.display_name]" + + del D.organs_scanned[O.name] + D.organs_scanned[O.name] = W.copy() + + for(var/V in O.trace_chemicals) + if(O.trace_chemicals[V] > 0 && !chemtraces.Find(V)) + chemtraces += V + +/obj/item/weapon/autopsy_scanner/verb/print_data() + set src in view(usr, 1) + set name = "Print Data" + if(usr.stat) + usr << "No." + return + + if(wdata.len == 0 && chemtraces.len == 0) + usr << "* There is no data about any wounds in the scanner's database. You may have to scan more bodyparts, or otherwise this wound type may not be in the scanner's database." + return + + var/scan_data = "" + + if(timeofdeath) + scan_data += "Time since death: [round((world.time - timeofdeath) / (60*10))] minutes

" + + var/n = 1 + for(var/wdata_idx in wdata) + var/datum/autopsy_data_scanner/D = wdata[wdata_idx] + var/total_hits = 0 + var/total_score = 0 + var/list/weapon_chances = list() // maps weapon names to a score + var/age = 0 + + for(var/wound_idx in D.organs_scanned) + var/datum/autopsy_data/W = D.organs_scanned[wound_idx] + total_hits += W.hits + + var/wname = W.pretend_weapon + + if(wname in weapon_chances) weapon_chances[wname] += W.damage + else weapon_chances[wname] = max(W.damage, 1) + total_score+=W.damage + + + var/wound_age = world.time - W.time_inflicted + age = max(age, wound_age) + + var/damage_desc + + var/damaging_weapon = (total_score != 0) + + // total score happens to be the total damage + switch(total_score) + if(0) + damage_desc = "Unknown" + if(1 to 5) + damage_desc = "negligible" + if(5 to 15) + damage_desc = "light" + if(15 to 30) + damage_desc = "moderate" + if(30 to 1000) + damage_desc = "severe" + + if(!total_score) total_score = D.organs_scanned.len + + scan_data += "Weapon #[n]
" + if(damaging_weapon) + scan_data += "Severity: [damage_desc]
" + scan_data += "Hits by weapon: [total_hits]
" + scan_data += "Age of wound: [round(age / (60*10))] minutes
" + scan_data += "Affected limbs: [D.organ_names]
" + scan_data += "Possible weapons:
" + for(var/weapon_name in weapon_chances) + scan_data += "\t[100*weapon_chances[weapon_name]/total_score]% [weapon_name]
" + + scan_data += "
" + + n++ + + if(chemtraces.len) + scan_data += "Trace Chemicals:
" + for(var/chemID in chemtraces) + scan_data += chemID + scan_data += "
" + + for(var/mob/O in viewers(usr)) + O.show_message("\red \the [src] rattles and prints out a sheet of paper.", 1) + + sleep(10) + + var/obj/item/weapon/paper/P = new(usr.loc) + P.name = "Autopsy Data ([target_name])" + P.info = "[scan_data]" + P.overlays += "paper_words" + + if(istype(usr,/mob/living/carbon)) + // place the item in the usr's hand if possible + if(!usr.r_hand) + P.loc = usr + usr.r_hand = P + P.layer = 20 + else if(!usr.l_hand) + P.loc = usr + usr.l_hand = P + P.layer = 20 + + if(istype(usr,/mob/living/carbon/human)) + usr:update_inv_l_hand() + usr:update_inv_r_hand() + +/obj/item/weapon/autopsy_scanner/attack(mob/living/carbon/human/M as mob, mob/living/carbon/user as mob) + if(!istype(M)) + return + + if(!can_operate(M)) + return + + if(target_name != M.name) + target_name = M.name + src.wdata = list() + user << "\red A new patient has been registered.. Purging data for previous patient." + + src.timeofdeath = M.timeofdeath + + var/datum/organ/external/S = M.organs[user.zone_sel.selecting] + if(!S) + usr << "You can't scan this body part." + return + if(!S.open) + usr << "You have to cut the limb open first!" + return + for(var/mob/O in viewers(M)) + O.show_message("\red [user.name] scans the wounds on [M.name]'s [S.display_name] with \the [src.name]", 1) + + src.add_data(S) + + return 1 diff --git a/code/datums/organs/organ.dm b/code/datums/organs/organ.dm index ba7b1bf014c..7c219e899b6 100644 --- a/code/datums/organs/organ.dm +++ b/code/datums/organs/organ.dm @@ -1,6 +1,11 @@ /datum/organ var/name = "organ" var/mob/living/carbon/human/owner = null + var/list/datum/autopsy_data/autopsy_data = list() + + var/list/trace_chemicals = list() // traces of chemicals in the organ, + // links chemical IDs to number of ticks for which they'll stay in the blood + ///datum/organ/proc/process() // return 0 @@ -12,4 +17,4 @@ return 0 proc/receive_chem(chemical as obj) - return 0 \ No newline at end of file + return 0 diff --git a/code/datums/organs/organ_external.dm b/code/datums/organs/organ_external.dm index 8e31e6db0f2..4e44edf173d 100644 --- a/code/datums/organs/organ_external.dm +++ b/code/datums/organs/organ_external.dm @@ -122,6 +122,8 @@ if(status & ORGAN_BROKEN) owner.emote("scream") + + if(used_weapon) add_autopsy_data(used_weapon, brute + burn) owner.updatehealth() @@ -519,6 +521,17 @@ if(T) T.robotize() + proc/add_autopsy_data(var/used_weapon, var/damage) + var/datum/autopsy_data/W = autopsy_data[used_weapon] + if(!W) + W = new() + W.weapon = used_weapon + autopsy_data[used_weapon] = W + + W.hits += 1 + W.damage += damage + W.time_inflicted = world.time + /datum/organ/external/chest name = "chest" icon_name = "chest" diff --git a/code/defines/obj/weapon.dm b/code/defines/obj/weapon.dm index 8bf17c2e040..5e3a7af556f 100644 --- a/code/defines/obj/weapon.dm +++ b/code/defines/obj/weapon.dm @@ -1964,3 +1964,17 @@ icon_state = "capacitor" desc = "A debug item for research." origin_tech = "materials=8;programming=8;magnets=8;powerstorage=8;bluespace=8;combat=8;biotech=8;syndicate=8" + +/obj/item/weapon/autopsy_scanner + name = "autopsy scanner" + desc = "Extracts information on wounds." + icon = 'icons/obj/autopsy_scanner.dmi' + icon_state = "" + flags = FPRINT | TABLEPASS | CONDUCT + w_class = 1.0 + origin_tech = "materials=1;biotech=1" + +/obj/item/weapon/autopsy_scanner/var/list/datum/autopsy_data_scanner/wdata = list() +/obj/item/weapon/autopsy_scanner/var/list/datum/autopsy_data_scanner/chemtraces = list() +/obj/item/weapon/autopsy_scanner/var/target_name = null +/obj/item/weapon/autopsy_scanner/var/timeofdeath = null diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 0ef35d726dc..2024fefdbc7 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -141,7 +141,7 @@ shock_damage *= siemens_coeff if (shock_damage<1) return 0 - src.take_overall_damage(0,shock_damage) + src.take_overall_damage(0,shock_damage,used_weapon="Electrocution") //src.burn_skin(shock_damage) //src.adjustFireLoss(shock_damage) //burn_skin will do this for us //src.updatehealth() diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 0199d048ba2..a8f55c066f8 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -272,34 +272,36 @@ // 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) + update |= take_blast.take_damage(b_loss * 0.9, f_loss * 0.9, used_weapon = "Explosive blast") // distribute the remaining 10% on all limbs equally b_loss *= 0.1 f_loss *= 0.1 + var/weapon_message = "Explosive Blast" + for(var/datum/organ/external/temp in organs) switch(temp.name) if("head") - update |= temp.take_damage(b_loss * 0.2, f_loss * 0.2) + update |= temp.take_damage(b_loss * 0.2, f_loss * 0.2, used_weapon = weapon_message) if("chest") - update |= temp.take_damage(b_loss * 0.4, f_loss * 0.4) + update |= temp.take_damage(b_loss * 0.4, f_loss * 0.4, used_weapon = weapon_message) if("l_arm") - update |= temp.take_damage(b_loss * 0.05, f_loss * 0.05) + update |= temp.take_damage(b_loss * 0.05, f_loss * 0.05, used_weapon = weapon_message) if("r_arm") - update |= temp.take_damage(b_loss * 0.05, f_loss * 0.05) + update |= temp.take_damage(b_loss * 0.05, f_loss * 0.05, used_weapon = weapon_message) if("l_leg") - update |= temp.take_damage(b_loss * 0.05, f_loss * 0.05) + update |= temp.take_damage(b_loss * 0.05, f_loss * 0.05, used_weapon = weapon_message) if("r_leg") - update |= temp.take_damage(b_loss * 0.05, f_loss * 0.05) + update |= temp.take_damage(b_loss * 0.05, f_loss * 0.05, used_weapon = weapon_message) if("r_foot") - update |= temp.take_damage(b_loss * 0.05, f_loss * 0.05) + update |= temp.take_damage(b_loss * 0.05, f_loss * 0.05, used_weapon = weapon_message) if("l_foot") - update |= temp.take_damage(b_loss * 0.05, f_loss * 0.05) + update |= temp.take_damage(b_loss * 0.05, f_loss * 0.05, used_weapon = weapon_message) if("r_arm") - update |= temp.take_damage(b_loss * 0.05, f_loss * 0.05) + update |= temp.take_damage(b_loss * 0.05, f_loss * 0.05, used_weapon = weapon_message) if("l_arm") - update |= temp.take_damage(b_loss * 0.05, f_loss * 0.05) + update |= temp.take_damage(b_loss * 0.05, f_loss * 0.05, used_weapon = weapon_message) if(update) UpdateDamageIcon() @@ -945,11 +947,11 @@ return gender /mob/living/carbon/human/proc/increase_germ_level(n) - if(gloves) - gloves.germ_level += n - else - germ_level += n - + if(gloves) + gloves.germ_level += n + else + germ_level += n + /mob/living/carbon/human/revive() for (var/datum/organ/external/O in organs) O.status &= ~ORGAN_BROKEN diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm index c748488b635..301406f9d4c 100644 --- a/code/modules/mob/living/carbon/human/human_damage.dm +++ b/code/modules/mob/living/carbon/human/human_damage.dm @@ -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, var/sharp = 0) +/mob/living/carbon/human/take_overall_damage(var/brute, var/burn, var/sharp = 0, var/used_weapon = null) 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,sharp) + update |= picked.take_damage(brute,burn,sharp,used_weapon) brute -= (picked.brute_dam - brute_was) burn -= (picked.burn_dam - burn_was) @@ -154,7 +154,7 @@ zone = "head" return organs_by_name[zone] -/mob/living/carbon/human/apply_damage(var/damage = 0,var/damagetype = BRUTE, var/def_zone = null, var/blocked = 0, var/sharp = 0) +/mob/living/carbon/human/apply_damage(var/damage = 0,var/damagetype = BRUTE, var/def_zone = null, var/blocked = 0, var/sharp = 0, var/used_weapon = null) if((damagetype != BRUTE) && (damagetype != BURN)) ..(damage, damagetype, def_zone, blocked) return 1 @@ -176,10 +176,10 @@ switch(damagetype) if(BRUTE) - if(organ.take_damage(damage, 0, sharp)) + if(organ.take_damage(damage, 0, sharp, used_weapon)) UpdateDamageIcon() if(BURN) - if(organ.take_damage(0, damage, sharp)) + if(organ.take_damage(0, damage, sharp, used_weapon)) 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 8ea99b9fc95..21928e3e188 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -133,7 +133,7 @@ emp_act if(armor >= 2) return 0 if(!I.force) return 0 - apply_damage(I.force, I.damtype, affecting, armor , I.sharp) + apply_damage(I.force, I.damtype, affecting, armor , I.sharp, I.name) var/bloody = 0 if(((I.damtype == BRUTE) || (I.damtype == HALLOSS)) && prob(25 + (I.force * 2))) diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index ea79c01a5b2..d486c602a54 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -459,15 +459,18 @@ radiation = 0 else + var/damage = 0 switch(radiation) if(1 to 49) radiation-- if(prob(25)) adjustToxLoss(1) + damage = 1 updatehealth() if(50 to 74) radiation -= 2 + damage = 1 adjustToxLoss(1) if(prob(5)) radiation -= 5 @@ -479,13 +482,18 @@ if(75 to 100) radiation -= 3 adjustToxLoss(3) + damage = 1 if(prob(1)) src << "\red You mutate!" randmutb(src) domutcheck(src,null) emote("gasp") updatehealth() - + + if(damage && organs.len) + var/V = pick(organs) + var/datum/organ/external/O = organs[V] + if(istype(O)) O.add_autopsy_data("Radiation Poisoning", damage) proc/breathe() if(reagents.has_reagent("lexorin")) return @@ -688,22 +696,22 @@ switch(breath.temperature) if(-INFINITY to 120) - apply_damage(COLD_GAS_DAMAGE_LEVEL_3, BURN, "head") + apply_damage(COLD_GAS_DAMAGE_LEVEL_3, BURN, "head", used_weapon = "Excessive Cold") fire_alert = max(fire_alert, 1) if(120 to 200) - apply_damage(COLD_GAS_DAMAGE_LEVEL_2, BURN, "head") + apply_damage(COLD_GAS_DAMAGE_LEVEL_2, BURN, "head", used_weapon = "Excessive Cold") fire_alert = max(fire_alert, 1) if(200 to 260) - apply_damage(COLD_GAS_DAMAGE_LEVEL_1, BURN, "head") + apply_damage(COLD_GAS_DAMAGE_LEVEL_1, BURN, "head", used_weapon = "Excessive Cold") fire_alert = max(fire_alert, 1) if(360 to 400) - apply_damage(HEAT_GAS_DAMAGE_LEVEL_1, BURN, "head") + apply_damage(HEAT_GAS_DAMAGE_LEVEL_1, BURN, "head", used_weapon = "Excessive Heat") fire_alert = max(fire_alert, 2) if(400 to 1000) - apply_damage(HEAT_GAS_DAMAGE_LEVEL_2, BURN, "head") + apply_damage(HEAT_GAS_DAMAGE_LEVEL_2, BURN, "head", used_weapon = "Excessive Heat") fire_alert = max(fire_alert, 2) if(1000 to INFINITY) - apply_damage(HEAT_GAS_DAMAGE_LEVEL_3, BURN, "head") + apply_damage(HEAT_GAS_DAMAGE_LEVEL_3, BURN, "head", used_weapon = "Excessive Heat") fire_alert = max(fire_alert, 2) if(oxyloss >= 50 && prob(oxyloss / 5)) @@ -1063,6 +1071,21 @@ dizziness = max(0, dizziness - 3) jitteriness = max(0, jitteriness - 3) + + if(life_tick % 10 == 0) + // handle trace chemicals for autopsy + for(var/V in organs) + var/datum/organ/O = organs[V] + for(var/chemID in O.trace_chemicals) + O.trace_chemicals[chemID] = O.trace_chemicals[chemID] - 1 + if(O.trace_chemicals[chemID] <= 0) + O.trace_chemicals.Remove(chemID) + for(var/datum/reagent/A in reagents.reagent_list) + // add chemistry traces to a random organ + var/V = pick(organs) + var/datum/organ/O = organs[V] + O.trace_chemicals[A.name] = 100 + updatehealth() return //TODO: DEFERRED diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 74ce8062ee8..a509e98a625 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -57,6 +57,6 @@ P.on_hit(src,2) return 2 if(!P.nodamage) - apply_damage((P.damage/(absorb+1)), P.damage_type, def_zone) + apply_damage((P.damage/(absorb+1)), P.damage_type, def_zone, used_weapon = P.name) P.on_hit(src, absorb) - return absorb \ No newline at end of file + return absorb diff --git a/code/modules/mob/mob_grab.dm b/code/modules/mob/mob_grab.dm index eda167dfd9f..3f16dc09a45 100644 --- a/code/modules/mob/mob_grab.dm +++ b/code/modules/mob/mob_grab.dm @@ -112,6 +112,12 @@ killing = 0 hud1.icon_state = "disarm/kill" return + + if(ishuman(affecting)) + var/mob/living/carbon/human/H = affecting + var/datum/organ/external/head = H.get_organ("head") + head.add_autopsy_data("Strangulation", 0) + affecting.Weaken(5) // Should keep you down unless you get help. affecting.Stun(5) // It will hamper your voice, being choked and all. affecting.losebreath = min(affecting.losebreath + 2, 3) @@ -293,4 +299,4 @@ /obj/item/weapon/grab/Del() del(hud1) ..() - return \ No newline at end of file + return