diff --git a/code/datums/diseases/mega_kingston.dm b/code/datums/diseases/mega_kingston.dm index 584e6ab5c646..57ff76eea179 100644 --- a/code/datums/diseases/mega_kingston.dm +++ b/code/datums/diseases/mega_kingston.dm @@ -43,9 +43,9 @@ Stage 3 - u r now catbeest if(prob(1) && prob(50)) var/mob/living/carbon/human/H=affected_mob to_chat(H, "You feel a wave of extreme pain and uncleanliness as your body morphs.") - H.set_species("Tajaran") + H.set_species("Tajaran", transfer_damage = TRUE) for(var/obj/item/W in H) H.drop_from_inventory(W) // TODO: // ghostize() - // StartAI(hostile=1,ranged=0) \ No newline at end of file + // StartAI(hostile=1,ranged=0) diff --git a/code/game/dna/genes/goon_disabilities.dm b/code/game/dna/genes/goon_disabilities.dm index 3601e948da83..399d3410c13e 100644 --- a/code/game/dna/genes/goon_disabilities.dm +++ b/code/game/dna/genes/goon_disabilities.dm @@ -321,11 +321,11 @@ to_chat(H, "You have no flesh left to melt!") return 0 if(isvox(H)) - H.set_species("Skeletal Vox") + H.set_species("Skeletal Vox", transfer_damage = TRUE) H.regenerate_icons() H.visible_message("[H.name]'s flesh melts right off! Holy shit!") H.drop_all() - else if(H.set_species("Skellington")) + else if(H.set_species("Skellington", transfer_damage = TRUE)) H.regenerate_icons() H.visible_message("[H.name]'s flesh melts right off! Holy shit!") H.drop_all() diff --git a/code/game/dna/genes/monkey.dm b/code/game/dna/genes/monkey.dm index bf65aef9b3d0..7693b832c54f 100644 --- a/code/game/dna/genes/monkey.dm +++ b/code/game/dna/genes/monkey.dm @@ -53,7 +53,7 @@ var/mob/living/carbon/human/O = new(src) if(Mo.greaterform) - O.set_species(Mo.greaterform) + O.set_species(Mo.greaterform) //Damage transfer is handled later in the code Mo.transferImplantsTo(O) if (M.dna.GetUIState(DNA_UI_GENDER)) diff --git a/code/game/objects/items/weapons/dice.dm b/code/game/objects/items/weapons/dice.dm index c50ec755b3b4..908ddf0c694f 100644 --- a/code/game/objects/items/weapons/dice.dm +++ b/code/game/objects/items/weapons/dice.dm @@ -146,7 +146,7 @@ to_chat(user, "A natural failure, your poor roll has cursed you. Better luck next time! ") h.flash_eyes(visual = 1) if(h.species.name != "Tajaran") - if(h.set_species("Tajaran")) + if(h.set_species("Tajaran", transfer_damage = TRUE)) h.regenerate_icons() to_chat(user, "You have been turned into a disgusting catbeast! ") else @@ -219,7 +219,7 @@ switch(pick(1,2,3)) if(1) if(h.species.name != "Unathi") - if(h.set_species("Unathi")) + if(h.set_species("Unathi", transfer_damage = TRUE)) h.regenerate_icons() to_chat(user, "You have been turned into a disgusting lizard! ") else @@ -227,7 +227,7 @@ E.droplimb(1) if(2) if(h.species.name != "Skrell") - if(h.set_species("Skrell")) + if(h.set_species("Skrell", transfer_damage = TRUE)) h.regenerate_icons() to_chat(user, "You have been turned into a disgusting squidman! ") else @@ -235,7 +235,7 @@ E.droplimb(1) if(3) if(h.species.name != "Vox") - if(h.set_species("Vox")) + if(h.set_species("Vox", transfer_damage = TRUE)) h.regenerate_icons() to_chat(user, "You have been turned into a dumb, diseased bird! ") else diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index c659cc9fc4a4..4d99cec3e87b 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -146,6 +146,8 @@ multicolor_skin_g = rand(0,255) multicolor_skin_b = rand(0,255) + create_reagents(1000) //Moved it here because it could sometimes lead to errors in set_species() in certain cases + if(!src.species) if(new_species_name) src.set_species(new_species_name) @@ -157,8 +159,6 @@ default_language = get_default_language() init_language = default_language - create_reagents(1000) - if(!dna) dna = new /datum/dna(null) dna.species=species.name @@ -1214,11 +1214,92 @@ else to_chat(usr, "You moved while counting. Try again.") -/mob/living/carbon/human/proc/set_species(var/new_species_name, var/force_organs, var/default_colour) +//Record_organ datum, stores as much info as it can about each organ +var/datum/record_organ //This is just a dummy proc, not storing any variables here even if it is "name" + +/datum/record_organ/proc/can_record(var/datum/organ/O) //To optimize things a little, see if the limb should be recorded in the first place + +/datum/record_organ/proc/record_values(var/datum/organ/O) + +/datum/record_organ/proc/apply_values(var/datum/organ/O) + +/datum/record_organ/external + var/name //This is only used for tracking which limb has to be affected, don't paste this over in apply_values + var/brute_damage + var/burn_damage + var/list/wounds = list() + var/status_flags + +/datum/record_organ/external/can_record(var/datum/organ/external/E) + return (E.brute_dam || E.burn_dam || E.wounds.len || E.status) + +/datum/record_organ/external/record_values(var/datum/organ/external/E) + if(E && istype(E)) + name = E.name + brute_damage = E.brute_dam + burn_damage = E.burn_dam + wounds = E.wounds.Copy() + E.wounds = list() //Because otherwise the wounds would get caught in the garbage collection and fully heal the mob as they get deleted + status_flags = E.status + +/datum/record_organ/external/apply_values(var/datum/organ/external/E) + if(E && istype(E)) + E.brute_dam = brute_damage + E.burn_dam = burn_damage + E.wounds = wounds.Copy() + wounds = list() //Now get rid of this here + E.status = status_flags + +/datum/record_organ/internal + var/name + var/damage + var/robotic + +/datum/record_organ/internal/can_record(var/datum/organ/internal/I) + return (I.damage || I.robotic) + +/datum/record_organ/internal/record_values(var/datum/organ/internal/I) + if(I && istype(I)) + name = I.name + damage = I.damage + robotic = I.robotic + +/datum/record_organ/internal/apply_values(var/datum/organ/internal/I) + if(I && istype(I)) + I.damage = damage + I.robotic = robotic + +/mob/living/carbon/human/proc/set_species(var/new_species_name, var/force_organs, var/default_colour, var/transfer_damage = 0, var/mob/living/carbon/human/target_override) set waitfor = FALSE + // Target override, in case we want to transfer stuff from a previous mob (the override) to the current one. + // Only applied to the damage transfer system. + var/mob/living/carbon/human/target = src + if(target_override && istype(target_override)) + target = target_override + + //A list of organs and their associated damages + //External and internal organs have different damage systems + var/list/recorded_external_damage = list() + var/list/recorded_internal_damage = list() + + if(transfer_damage) //Don't bother recording any of it if we're not transferring the damage + for(var/datum/organ/external/E in target.organs) //"organs" is actually external organs + var/datum/record_organ/external/external_data = new + if(external_data.can_record(E)) + external_data.record_values(E) + recorded_external_damage += external_data + for(var/datum/organ/internal/I in target.internal_organs) + var/datum/record_organ/internal/internal_data = new + if(internal_data.can_record(I)) + internal_data.record_values(I) + recorded_internal_damage += internal_data + if(new_species_name) if(src.species && src.species.name && (src.species.name == new_species_name)) + if(transfer_damage) + if(target != src) //This mob is a new mob, let's apply the damage from the previous mob + apply_stored_damages(recorded_external_damage, recorded_internal_damage) return else if(src.dna) new_species_name = src.dna.species @@ -1287,6 +1368,9 @@ if(dna) dna.species = new_species_name + //Now re-apply all the damages from before the transformation + if(transfer_damage) + apply_stored_damages(recorded_external_damage, recorded_internal_damage) if(my_appearance) var/list/valid_hair = valid_sprite_accessories(hair_styles_list, null, species.name) @@ -1306,6 +1390,23 @@ to_chat(src, "[species.species_intro]") return 1 +/mob/living/carbon/human/proc/apply_stored_damages(var/list/recorded_external_damage, var/list/recorded_internal_damage) + for(var/datum/organ/external/new_external in organs) + for(var/datum/record_organ/external/old_external in recorded_external_damage) + if(new_external.name == old_external.name) + old_external.apply_values(new_external) + recorded_external_damage -= old_external //Trim the list so it doesn't search as much + QDEL_NULL(old_external) + break //We found a matching record for this organ, move on to the next organ + for(var/datum/organ/internal/new_internal in internal_organs) + for(var/datum/record_organ/internal/old_internal in recorded_internal_damage) + if(new_internal.name == old_internal.name) + old_internal.apply_values(new_internal) + recorded_internal_damage -= old_internal + QDEL_NULL(old_internal) + break + src.handle_organs(TRUE) //Now update them + #define BLOODOODLE_NOSOURCE 0 #define BLOODOODLE_HANDS 1 #define BLOODOODLE_GLOVES 2 diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm index d4fd6c8eade5..5c35e1e5cae2 100644 --- a/code/modules/mob/living/carbon/human/human_damage.dm +++ b/code/modules/mob/living/carbon/human/human_damage.dm @@ -249,12 +249,7 @@ In most cases it makes more sense to use apply_damage() instead! And make sure t UpdateDamageIcon() // damage MANY external organs, in random order -/mob/living/carbon/human/take_overall_damage(var/brute, var/burn, var/sharp = 0, var/edge = 0, var/used_weapon = null) - if(species && species.burn_mod) - burn = burn*species.burn_mod - if(species && species.brute_mod) - brute = brute*species.brute_mod - +/mob/living/carbon/human/take_overall_damage(var/brute, var/burn, var/sharp = 0, var/edge = 0, var/used_weapon = null, var/no_damage_change = FALSE) if(status_flags & GODMODE) return 0 //godmode @@ -267,11 +262,14 @@ In most cases it makes more sense to use apply_damage() instead! And make sure t var/brute_was = picked.brute_dam var/burn_was = picked.burn_dam - - update |= picked.take_damage(brute,burn,sharp,edge,used_weapon) + //Multiplied damage is already handled at the limb level + update |= picked.take_damage(brute,burn,sharp,edge,used_weapon, no_damage_modifier = no_damage_change, spread_damage = FALSE) brute -= (picked.brute_dam - brute_was) + if(brute < 0) + brute = 0 burn -= (picked.burn_dam - burn_was) - + if(burn < 0) + burn = 0 parts -= picked updatehealth() hud_updateflag |= 1 << HEALTH_HUD diff --git a/code/modules/mob/living/carbon/human/life/handle_mutations_and_radiation.dm b/code/modules/mob/living/carbon/human/life/handle_mutations_and_radiation.dm index 7fab6c9a7213..4912b4c12231 100644 --- a/code/modules/mob/living/carbon/human/life/handle_mutations_and_radiation.dm +++ b/code/modules/mob/living/carbon/human/life/handle_mutations_and_radiation.dm @@ -279,7 +279,7 @@ qdel(src) return else - if(set_species("Ghoul")) + if(set_species("Ghoul", transfer_damage = TRUE)) to_chat(src, "You feel strangely at peace.") spawn(1 SECONDS) setCloneLoss(0) diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index e80c0d0a72f5..de9b244f0a28 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -148,12 +148,12 @@ comm.ai += O if(mind) mind.transfer_to(O) + O.mind.assigned_role = "AI" else O.key = key O.verbs += /mob/living/silicon/ai/proc/show_laws_verb O.verbs += /mob/living/silicon/ai/proc/ai_statuschange O.job = "AI" - O.mind.assigned_role = "AI" mob_rename_self(O,"ai", null, 1) . = O if(del_mob) @@ -187,7 +187,8 @@ if(!skipnaming) spawn() O.Namepick() - O.mind.assigned_role = "Cyborg" + if(O.mind) //Otherwise it would runtime if done against mindless mobs + O.mind.assigned_role = "Cyborg" qdel(src) return O @@ -215,7 +216,8 @@ if(!skipnaming) spawn() O.Namepick() - O.mind.assigned_role = "Mobile MMI" + if(O.mind) + O.mind.assigned_role = "Mobile MMI" qdel(src) return O @@ -291,7 +293,7 @@ new_human.randomise_appearance_for(new_human.gender) if(!new_species || !(new_species in all_species)) new_species = pick(whitelisted_species) - new_human.set_species(new_species) + new_human.set_species(new_species, transfer_damage = TRUE, target_override = src) //Transfer damage from the current mob to the new one new_human.regenerate_icons() if(isliving(src)) var/mob/living/L = src diff --git a/code/modules/organs/organ_external.dm b/code/modules/organs/organ_external.dm index 4bb2b6e82cd0..5f4dd69f264a 100644 --- a/code/modules/organs/organ_external.dm +++ b/code/modules/organs/organ_external.dm @@ -154,27 +154,32 @@ new I(owner.loc) droplimb(1, spawn_limb = 0, display_message = FALSE) -/datum/organ/external/proc/take_damage(brute, burn, sharp, edge, used_weapon = null, list/forbidden_limbs = list()) +/datum/organ/external/proc/take_damage(brute, burn, sharp, edge, used_weapon = null, list/forbidden_limbs = list(), var/no_damage_modifier, var/spread_damage = TRUE) if(cosmetic_only) return if(owner?.status_flags & GODMODE) return 0 //godmode + if(brute < 0) + brute = 0 + if(burn < 0) + burn = 0 if((brute <= 0) && (burn <= 0)) return 0 if(!is_existing()) //No limb there return 0 - if(!is_organic()) - brute *= 0.66 //~2/3 damage for ROBOLIMBS - burn *= (status & (ORGAN_PEG) ? 2 : 0.66) //~2/3 damage for ROBOLIMBS 2x for peg - else - var/datum/species/species = src.species || owner.species - if(species) - if(species.brute_mod) - brute *= species.brute_mod - if(species.burn_mod) - burn *= species.burn_mod + if(!no_damage_modifier) + if(!is_organic()) + brute *= 0.66 //~2/3 damage for ROBOLIMBS + burn *= (status & (ORGAN_PEG) ? 2 : 0.66) //~2/3 damage for ROBOLIMBS 2x for peg + else + var/datum/species/species = src.species || owner.species + if(species) + if(species.brute_mod) + brute *= species.brute_mod + if(species.burn_mod) + burn *= species.burn_mod //If limb took enough damage, try to cut or tear it off if(body_part != UPPER_TORSO && body_part != LOWER_TORSO) //As hilarious as it is, getting hit on the chest too much shouldn't effectively gib you. @@ -236,20 +241,20 @@ //If we can't inflict the full amount of damage, spread the damage in other ways //How much damage can we actually cause? var/can_inflict = max_damage * config.organ_health_multiplier - (brute_dam + burn_dam) - if(can_inflict) + if(can_inflict > 0) if(brute > 0) - //Inflict all burte damage we can + //Inflict all brute damage we can if(can_cut) createwound(CUT, min(brute,can_inflict)) else createwound(BRUISE, min(brute,can_inflict)) var/temp = can_inflict - //How much mroe damage can we inflict + //How much more damage can we inflict can_inflict = max(0, can_inflict - brute) //How much brute damage is left to inflict brute = max(0, brute - temp) - if(burn > 0 && can_inflict) + if(burn > 0 && (can_inflict > 0)) //Inflict all burn damage we can createwound(BURN, min(burn,can_inflict)) //How much burn damage is left to inflict @@ -259,18 +264,19 @@ if(!is_organic()) droplimb(1) //Non-organic limbs just drop off with no further complications else - //List organs we can pass it to - 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) - //And pass the pain around - var/datum/organ/external/target = pick(possible_points) - target.take_damage(brute, burn, sharp, edge, used_weapon, forbidden_limbs + src) + if(spread_damage) + //List organs we can pass it to + 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) + //And pass the pain around + var/datum/organ/external/target = pick(possible_points) + target.take_damage(brute, burn, sharp, edge, used_weapon, forbidden_limbs + src, no_damage_modifier = no_damage_modifier) //Sync the organ's damage with its wounds src.update_damages() @@ -341,7 +347,6 @@ return var/datum/species/species = src.species || owner.species - //First check whether we can widen an existing wound if(widenwound(type, damage)) update_damages() @@ -684,10 +689,11 @@ Note that amputating the affected organ does in fact remove the infection from t var/datum/species/species = src.species || owner.species 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.internal) //Internal wounds don't count for the total mob damage + if(W.damage_type == CUT || W.damage_type == BRUISE) + brute_dam += W.damage + else if(W.damage_type == BURN) + burn_dam += W.damage if(is_organic() && W.bleeding() && !(species.anatomy_flags & NO_BLOOD)) W.bleed_timer-- @@ -1678,8 +1684,8 @@ Note that amputating the affected organ does in fact remove the infection from t baseicon = 'icons/mob/human_races/o_robot.dmi' return new /icon(baseicon, "[icon_name]_[gender]") -/datum/organ/external/head/take_damage(brute, burn, sharp, edge, used_weapon = null, list/forbidden_limbs = list()) - ..(brute, burn, sharp, edge, used_weapon, forbidden_limbs) +/datum/organ/external/head/take_damage(brute, burn, sharp, edge, used_weapon = null, list/forbidden_limbs = list(), no_damage_modifier, spread_damage) + ..(brute, burn, sharp, edge, used_weapon, forbidden_limbs, no_damage_modifier, spread_damage) if(!disfigured) /* if(brute_dam > 40) diff --git a/code/modules/reagents/Chemistry-Recipes.dm b/code/modules/reagents/Chemistry-Recipes.dm index 9d8530dec4c0..71bdd50e2461 100644 --- a/code/modules/reagents/Chemistry-Recipes.dm +++ b/code/modules/reagents/Chemistry-Recipes.dm @@ -4086,11 +4086,11 @@ if(isskellington(H) || isskelevox(H) || islich(H)) bigBoned(H, created_volume) if(isvox(H)) //Copy paste of the melt power, ack ack - H.set_species("Skeletal Vox") + H.set_species("Skeletal Vox", transfer_damage = TRUE) H.regenerate_icons() H.visible_message("[H.name]'s skeleton jumps right out of their skin, forcefully!") H.drop_all() - else if(H.set_species("Skellington")) + else if(H.set_species("Skellington", transfer_damage = TRUE)) H.regenerate_icons() H.visible_message("[H.name]'s skeleton jumps right out of their skin, forcefully!") H.drop_all() diff --git a/code/modules/reagents/randomized_reagent.dm b/code/modules/reagents/randomized_reagent.dm index 75760479a851..3eb5999bcc57 100644 --- a/code/modules/reagents/randomized_reagent.dm +++ b/code/modules/reagents/randomized_reagent.dm @@ -156,7 +156,7 @@ return if(tf_catbeast && !iscatbeast(H)) - H.set_species("Tajaran") + H.set_species("Tajaran", transfer_damage = TRUE) H.regenerate_icons() H.emote("me", MESSAGE_HEAR, pick("meows", "mews")) playsound(H, 'sound/voice/catmeow.ogg', 100) diff --git a/code/modules/spells/general/shapeshift.dm b/code/modules/spells/general/shapeshift.dm index 3c8d95b08f58..866a64ac5378 100644 --- a/code/modules/spells/general/shapeshift.dm +++ b/code/modules/spells/general/shapeshift.dm @@ -32,12 +32,12 @@ if(humanform) identity = user.dna.Clone() appearance = user.my_appearance.Copy() - user.set_species("Vampire") + user.set_species("Vampire", transfer_damage = TRUE) user.name = "Nosferatu" user.real_name = "Nosferatu" humanform = FALSE else - user.set_species(identity.species, 0) + user.set_species(identity.species, 0, transfer_damage = TRUE) user.set_default_language(user.init_language) user.name = identity.real_name user.real_name = identity.real_name diff --git a/code/modules/virus2/effect/stage_4.dm b/code/modules/virus2/effect/stage_4.dm index 1ecf31260370..65f7188ef8c5 100644 --- a/code/modules/virus2/effect/stage_4.dm +++ b/code/modules/virus2/effect/stage_4.dm @@ -273,7 +273,7 @@ E.createwound(CUT, pick(2, 4, 6, 8, 10)) if(prob(30)) - if(H.set_species("Skellington")) + if(H.set_species("Skellington", transfer_damage = TRUE)) to_chat(mob, "A massive amount of flesh sloughs off your bones!") H.regenerate_icons() @@ -1106,7 +1106,7 @@ /datum/disease2/effect/catbeast/activate(var/mob/living/mob) if(ishuman(mob) && !iscatbeast(mob)) var/mob/living/carbon/human/H = mob - H.set_species("Tajaran") + H.set_species("Tajaran", transfer_damage = TRUE) H.regenerate_icons() @@ -1131,7 +1131,7 @@ /datum/disease2/effect/vox/activate(var/mob/living/mob) if(ishuman(mob) && !isvox(mob)) var/mob/living/carbon/human/H = mob - H.set_species("Vox") + H.set_species("Vox", transfer_damage = TRUE) H.regenerate_icons() @@ -1144,7 +1144,7 @@ /datum/disease2/effect/human/activate(var/mob/living/mob) if(ishuman(mob) && !isjusthuman(mob)) var/mob/living/carbon/human/H = mob - H.set_species("Human") + H.set_species("Human", transfer_damage = TRUE) H.regenerate_icons() /datum/disease2/effect/lizard @@ -1156,7 +1156,7 @@ /datum/disease2/effect/lizard/activate(var/mob/living/mob) if(ishuman(mob) && !isunathi(mob)) var/mob/living/carbon/human/H = mob - H.set_species("Unathi") + H.set_species("Unathi", transfer_damage = TRUE) H.regenerate_icons() /datum/disease2/effect/insectoid @@ -1168,7 +1168,7 @@ /datum/disease2/effect/insectoid/activate(var/mob/living/mob) if(ishuman(mob) && !isinsectoid(mob)) var/mob/living/carbon/human/H = mob - H.set_species("Insectoid") + H.set_species("Insectoid", transfer_damage = TRUE) H.regenerate_icons() if(prob(5)) mob.say("How about if I sleep a little bit longer and forget all this nonsense.") @@ -1182,7 +1182,7 @@ /datum/disease2/effect/grey/activate(var/mob/living/mob) if(ishuman(mob) && !isgrey(mob)) var/mob/living/carbon/human/H = mob - H.set_species("Grey") + H.set_species("Grey", transfer_damage = TRUE) H.regenerate_icons() /*