From 16172226372dc375e645f7916ae50a4f75e20362 Mon Sep 17 00:00:00 2001 From: MrMelbert Date: Tue, 25 Nov 2025 18:52:06 -0600 Subject: [PATCH 1/4] Mecha blood --- code/__DEFINES/mecha.dm | 6 ++ code/_globalvars/bitfields.dm | 1 + code/datums/stock_market_events.dm | 4 +- .../effects/decals/cleanable/humans.dm | 10 +-- .../effects/decals/cleanable/robots.dm | 4 +- code/modules/mob/living/blood.dm | 2 +- code/modules/mob/living/carbon/carbon.dm | 27 +++++-- code/modules/mob/living/living.dm | 81 ++++++++++++------- code/modules/vehicles/mecha/_mecha.dm | 47 +++++------ code/modules/vehicles/mecha/combat/honker.dm | 9 +-- code/modules/vehicles/mecha/mecha_damage.dm | 10 +++ code/modules/vehicles/mecha/mecha_defense.dm | 27 ++++++- code/modules/vehicles/mecha/mecha_helpers.dm | 11 ++- code/modules/vehicles/mecha/mecha_movement.dm | 28 ++++--- code/modules/vehicles/mecha/mecha_ui.dm | 1 + .../vehicles/mecha/medical/odysseus.dm | 2 +- code/modules/vehicles/mecha/working/ripley.dm | 6 +- .../code/modules/mob/living/blood.dm | 31 +++---- .../tgui/interfaces/Mecha/AlertPane.tsx | 2 + 19 files changed, 194 insertions(+), 115 deletions(-) diff --git a/code/__DEFINES/mecha.dm b/code/__DEFINES/mecha.dm index d5cc78ecd62f..87333246c4c7 100644 --- a/code/__DEFINES/mecha.dm +++ b/code/__DEFINES/mecha.dm @@ -3,6 +3,7 @@ #define MECHA_INT_SHORT_CIRCUIT (1<<2) #define MECHA_CABIN_AIR_BREACH (1<<3) #define MECHA_INT_CONTROL_LOST (1<<4) +#define MECHA_INT_FUEL_LINE (1<<5) #define PANEL_OPEN (1<<0) #define ID_LOCK_ON (1<<1) @@ -59,3 +60,8 @@ #define MECHA_AMMO_PUNCHING_GLOVE "Punching glove" #define MECHA_AMMO_BANANA_PEEL "Banana peel" #define MECHA_AMMO_MOUSETRAP "Mousetrap" + +// Flags for use_energy +#define OIL_MODIFIED_DRAIN (1<<0) +#define SERVO_MODIFIED_DRAIN (1<<1) +#define CAPACITOR_MODIFIED_DRAIN (1<<2) diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index 6e80d8c3c87a..33665d7bc69c 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -242,6 +242,7 @@ DEFINE_BITFIELD(internal_damage, list( "MECHA_CABIN_AIR_BREACH" = MECHA_CABIN_AIR_BREACH, "MECHA_INT_CONTROL_LOST" = MECHA_INT_CONTROL_LOST, "MECHA_INT_SHORT_CIRCUIT" = MECHA_INT_SHORT_CIRCUIT, + "MECHA_INT_FUEL_LINE" = MECHA_INT_FUEL_LINE, )) DEFINE_BITFIELD(mecha_flags, list( diff --git a/code/datums/stock_market_events.dm b/code/datums/stock_market_events.dm index 4907bf784f63..d0935b233350 100644 --- a/code/datums/stock_market_events.dm +++ b/code/datums/stock_market_events.dm @@ -8,7 +8,7 @@ "MODular Solutions", "SolGov", "Australicus Industrial Mining", - "Vey-Medical", + "Nanotrasen-DeForest Corporation", "Aussec Armory", "Dreamland Robotics" ) @@ -147,5 +147,3 @@ SSstock_market.materials_quantity[mat] = initial(mat.tradable_base_quantity) //Force the material to be available again. SSstock_market.materials_prices[mat] = initial(mat.value_per_unit) * SHEET_MATERIAL_AMOUNT //Force the price to be reset once the lockdown is over. create_news() - - diff --git a/code/game/objects/effects/decals/cleanable/humans.dm b/code/game/objects/effects/decals/cleanable/humans.dm index f5a219046648..899336ac8d4e 100644 --- a/code/game/objects/effects/decals/cleanable/humans.dm +++ b/code/game/objects/effects/decals/cleanable/humans.dm @@ -572,8 +572,6 @@ /// The turf we just came from, so we can back up when we hit a wall var/turf/prev_loc - /// The cached info about the blood - var/list/blood_dna_info /// Skip making the final blood splatter when we're done, like if we're not in a turf var/skip = FALSE /// How many tiles/items/people we can paint red @@ -594,7 +592,7 @@ /obj/effect/decal/cleanable/blood/hitsplatter/proc/expire() if(isturf(loc) && !skip) playsound(src, 'sound/effects/wounds/splatter.ogg', 60, TRUE, -1) - loc.add_blood_DNA(blood_dna_info) + loc.add_blood_DNA(GET_ATOM_BLOOD_DNA(src)) qdel(src) /// Set the splatter up to fly through the air until it rounds out of steam or hits something @@ -621,7 +619,7 @@ continue if(splatter_strength <= 0) break - iter_atom.add_blood_DNA(blood_dna_info) + iter_atom.add_blood_DNA(GET_ATOM_BLOOD_DNA(src)) if(isliving(iter_atom)) var/mob/living/splatted = iter_atom splatted.add_mood_event("splattered_with_blood", /datum/mood_event/splattered_with_blood) @@ -638,7 +636,7 @@ fly_trail.transform = fly_trail.transform.Turn((flight_dir == NORTHEAST || flight_dir == SOUTHWEST) ? 135 : 45) fly_trail.icon_state = pick("trails_1", "trails2") fly_trail.adjust_bloodiness(fly_trail.bloodiness * -0.66) - fly_trail.add_blood_DNA(blood_dna_info) + fly_trail.add_blood_DNA(GET_ATOM_BLOOD_DNA(src)) /obj/effect/decal/cleanable/blood/hitsplatter/proc/loop_done(datum/source) SIGNAL_HANDLER @@ -669,7 +667,6 @@ final_splatter.pixel_x = (dir == EAST ? 32 : (dir == WEST ? -32 : 0)) final_splatter.pixel_y = (dir == NORTH ? 32 : (dir == SOUTH ? -32 : 0)) final_splatter.add_blood_DNA(GET_ATOM_BLOOD_DNA(src)) - final_splatter.add_blood_DNA(blood_dna_info) else // This will only happen if prev_loc is not even a turf, which is highly unlikely. abstract_move(bumped_atom) expire() @@ -680,7 +677,6 @@ return var/obj/effect/decal/cleanable/blood/splatter/over_window/final_splatter = new final_splatter.add_blood_DNA(GET_ATOM_BLOOD_DNA(src)) - final_splatter.add_blood_DNA(blood_dna_info) final_splatter.forceMove(the_window) the_window.vis_contents += final_splatter the_window.bloodied = TRUE diff --git a/code/game/objects/effects/decals/cleanable/robots.dm b/code/game/objects/effects/decals/cleanable/robots.dm index 25d491285955..743b707e1699 100644 --- a/code/game/objects/effects/decals/cleanable/robots.dm +++ b/code/game/objects/effects/decals/cleanable/robots.dm @@ -15,7 +15,7 @@ /obj/effect/decal/cleanable/robot_debris/Initialize(mapload) . = ..() RegisterSignal(src, COMSIG_MOVABLE_PIPE_EJECTING, PROC_REF(on_pipe_eject)) - add_blood_DNA(list("UNKNOWN DNA" = /datum/blood_type/oil)) // NON-MODULE CHANGE : For bloody shoes // Yeah don't think about it too much + add_blood_DNA(list("CRUDE OIL" = /datum/blood_type/oil)) // NON-MODULE CHANGE : For bloody shoes // Yeah don't think about it too much /obj/effect/decal/cleanable/robot_debris/proc/streak(list/directions, mapload=FALSE) var/direction = pick(directions) @@ -87,7 +87,7 @@ /obj/effect/decal/cleanable/oil/Initialize(mapload, list/datum/disease/diseases) . = ..() AddElement(/datum/element/easy_ignite) // NON-MODULE CHANGE - add_blood_DNA(list("UNKNOWN DNA" = /datum/blood_type/oil)) // NON-MODULE CHANGE : For bloody shoes // Yeah don't think about it too much + add_blood_DNA(list("CRUDE OIL" = /datum/blood_type/oil)) // NON-MODULE CHANGE : For bloody shoes // Yeah don't think about it too much // /obj/effect/decal/cleanable/oil/attackby(obj/item/I, mob/living/user) // var/attacked_by_hot_thing = I.get_temperature() diff --git a/code/modules/mob/living/blood.dm b/code/modules/mob/living/blood.dm index 234fc130a46f..be50ad47b98a 100644 --- a/code/modules/mob/living/blood.dm +++ b/code/modules/mob/living/blood.dm @@ -278,7 +278,7 @@ //to add a splatter of blood or other mob liquid. /mob/living/proc/add_splatter_floor(turf/blood_turf = get_turf(src), small_drip) - return get_blood_type()?.make_blood_splatter(src, blood_turf, small_drip) + return get_blood_type()?.make_blood_splatter(blood_turf, small_drip, get_blood_dna_list(), get_static_viruses()) /mob/living/proc/do_splatter_effect(splat_dir = pick(GLOB.cardinals)) var/obj/effect/temp_visual/dir_setting/bloodsplatter/splatter = new(get_turf(src), splat_dir) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 1da646f47c64..92eea147e99f 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -1510,22 +1510,33 @@ return FALSE /** - * This proc is a helper for spraying blood for things like slashing/piercing wounds and dismemberment. + * Sprays out blood in a direction to a certain distance * - * The strength of the splatter in the second argument determines how much it can dirty and how far it can go + * This is on atom so that arbitrary objects can also spray blood (like meat), + * you just need to pass a blood_dna. * * Arguments: * * splatter_direction: Which direction the blood is flying * * splatter_strength: How many tiles it can go, and how many items it can pass over and dirty + * * blood_dna: A list of DNA info to add to the blood decal. Autoset for mobs. + * * static_viruses: A list of viruses to add to the blood decal */ -/mob/living/carbon/proc/spray_blood(splatter_direction, splatter_strength = 3) +/atom/proc/spray_blood(splatter_direction, splatter_strength = 3, blood_dna, list/static_viruses) if(!isturf(loc)) return - var/obj/effect/decal/cleanable/blood/hitsplatter/our_splatter = new(loc, get_static_viruses(), splatter_strength) - our_splatter.add_blood_DNA(GET_ATOM_BLOOD_DNA(src)) - our_splatter.blood_dna_info = get_blood_dna_list() - var/turf/targ = get_ranged_target_turf(src, splatter_direction, splatter_strength) - our_splatter.fly_towards(targ, splatter_strength) + if(!islist(blood_dna)) + CRASH("spray_blood called without a valid blood_dna list!") + + var/obj/effect/decal/cleanable/blood/hitsplatter/our_splatter = new(loc, static_viruses, splatter_strength) + our_splatter.add_blood_DNA(blood_dna) + our_splatter.fly_towards(get_ranged_target_turf(src, splatter_direction, splatter_strength), splatter_strength) + +/mob/living/carbon/spray_blood(splatter_direction, splatter_strength = 3, blood_dna, list/static_viruses) + if(isnull(blood_dna)) + blood_dna = get_blood_dna_list() + if(isnull(static_viruses)) + static_viruses = get_static_viruses() + return ..() /mob/living/carbon/dropItemToGround(obj/item/to_drop, force = FALSE, silent = FALSE, invdrop = TRUE, turf/newloc = null) if((to_drop in organs) || (to_drop in bodyparts)) //let's not do this, aight? diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 5348f59c0661..ff6cc4c437df 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1089,29 +1089,26 @@ /mob/living/carbon/alien/adult/lying_angle_on_movement(direct) return -/mob/living/proc/make_blood_trail(turf/target_turf, turf/start, was_facing, movement_direction) - if(!has_gravity() || !isturf(start) || HAS_TRAIT(src, TRAIT_NOBLOOD)) // NON-MODULE CHANGE - return - - var/base_bleed_rate = get_bleed_rate() - var/base_brute = getBruteLoss() - - var/brute_ratio = round(base_brute / (maxHealth * 4), 0.1) - var/bleeding_rate = round(base_bleed_rate / 4, 0.1) - // we only leave a trail if we're below a certain blood threshold - // the more brute damage we have, or the more we're bleeding, the less blood we need to leave a trail - if(blood_volume < max(BLOOD_VOLUME_NORMAL * (1 - max(bleeding_rate, brute_ratio)), 0)) +/** + * Leaves a trail of blood. + * + * This is on the atom level so you can have arbitrary objects leave "blood trails" if desired, + * you just need to pass a blood_dna. + * + * Arguments: + * * target_turf - The turf where the blood trail will be made + * * start - The turf where the mob started moving from + * * was_facing - The direction the mob was facing before moving + * * movement_direction - The direction the mob is moving towards + * * blood_to_add - The amount of blood to add to the trail + * * blood_dna - The DNA to add to the trail. Autoset for mobs. + * * static_viruses - The viruses to add to the trail + */ +/atom/proc/make_blood_trail(turf/target_turf, turf/start, was_facing, movement_direction, blood_to_add = BLOOD_AMOUNT_PER_DECAL * 0.1, blood_dna, list/static_viruses) + if(!has_gravity() || !isturf(start)) return - - var/blood_to_add = BLOOD_AMOUNT_PER_DECAL * 0.1 - if(body_position == LYING_DOWN) - blood_to_add += bleedDragAmount() - bleed(blood_to_add, drip = FALSE) - else - blood_to_add += base_bleed_rate - // if we're very damaged or bleeding a lot, add even more blood to the trail - if(base_brute >= 300 || base_bleed_rate >= 7) - blood_to_add *= 2 + if(!islist(blood_dna)) + CRASH("make_blood_trail called without a valid blood_dna list!") var/trail_dir = REVERSE_DIR(movement_direction) // the mob is performing a diagonal movement so we need to make a diagonal trail @@ -1150,24 +1147,54 @@ break if(isnull(trail)) - trail = new(start, get_static_viruses()) + trail = new(start, static_viruses) if(QDELETED(trail)) return trail.bloodiness = blood_to_add else - trail.add_viruses(get_static_viruses()) + trail.add_viruses(static_viruses) // update the holder with our new dna and bloodiness - trail.add_mob_blood(src) + trail.add_blood_DNA(blood_dna) trail.adjust_bloodiness(blood_to_add) // also update the trail component, this is what matters for its appearance var/obj/effect/decal/cleanable/blood/trail/trail_component = trail.add_dir_to_trail(trail_dir, blood_to_add) if(isnull(trail_component)) return - trail_component.add_mob_blood(src) + trail_component.add_blood_DNA(blood_dna) trail_component.adjust_bloodiness(blood_to_add) -/mob/living/carbon/human/make_blood_trail(turf/target_turf, turf/start, direction) +/mob/living/make_blood_trail(turf/target_turf, turf/start, was_facing, movement_direction, blood_to_add, blood_dna, list/static_viruses) + if(HAS_TRAIT(src, TRAIT_NOBLOOD)) + return + var/base_bleed_rate = get_bleed_rate() + var/base_brute = getBruteLoss() + + var/brute_ratio = round(base_brute / (maxHealth * 4), 0.1) + var/bleeding_rate = round(base_bleed_rate / 4, 0.1) + // we only leave a trail if we're below a certain blood threshold + // the more brute damage we have, or the more we're bleeding, the less blood we need to leave a trail + if(blood_volume < max(BLOOD_VOLUME_NORMAL * (1 - max(bleeding_rate, brute_ratio)), 0)) + return + + if(isnull(static_viruses)) + static_viruses = get_static_viruses() + if(isnull(blood_dna)) + blood_dna = get_blood_dna_list() + if(isnull(blood_to_add)) + blood_to_add = BLOOD_AMOUNT_PER_DECAL * 0.1 + blood_to_add += (body_position == LYING_DOWN) ? bleedDragAmount() : base_bleed_rate + // if we're very damaged or bleeding a lot, add even more blood to the trail + if(base_brute >= 300 || base_bleed_rate >= 7) + blood_to_add *= 2 + + // this is where people losing extra blood from being dragged is handled + if(body_position == LYING_DOWN) + bleed(blood_to_add, drip = FALSE) + + return ..() + +/mob/living/carbon/human/make_blood_trail(turf/target_turf, turf/start, direction, blood_to_add, blood_dna, list/static_viruses) if(!is_bleeding()) return return ..() diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm index f0acc84381ee..7ce1553e0cc3 100644 --- a/code/modules/vehicles/mecha/_mecha.dm +++ b/code/modules/vehicles/mecha/_mecha.dm @@ -93,7 +93,7 @@ /// % chance for internal damage to occur var/internal_damage_probability = 20 /// list of possibly dealt internal damage for this mech type - var/possible_int_damage = MECHA_INT_FIRE|MECHA_INT_TEMP_CONTROL|MECHA_CABIN_AIR_BREACH|MECHA_INT_CONTROL_LOST|MECHA_INT_SHORT_CIRCUIT + var/possible_int_damage = MECHA_INT_FIRE|MECHA_INT_TEMP_CONTROL|MECHA_CABIN_AIR_BREACH|MECHA_INT_CONTROL_LOST|MECHA_INT_SHORT_CIRCUIT|MECHA_INT_FUEL_LINE /// damage threshold above which we take component damage var/component_damage_threshold = 10 @@ -208,7 +208,19 @@ /// Module selected by default when mech UI is opened var/ui_selected_module_index - var/mecha_zoom_view_size = 4.5 //NON-MODULE CHANGE : customizable zoom size + //NON-MODULE CHANGE + /// Used for counting when to play footstep sounds + VAR_PRIVATE/footstep_count = 0 + /// How many steps can be taken before playing a footstep sound + var/steps_per_footstep = 1 + /// Abstract representation of our "blood", ie "oil" + var/oil_pool = 100 + /// Type of oil we leak + var/oil_type = /datum/blood_type/oil/heavy + /// Name of leaked oil when scanned by detectives, in other words Oil DNA + var/oil_name = "EXOSUIT-GRADE CRUDE OIL" + /// customized zoom view size + var/mecha_zoom_view_size = 4.5 /datum/armor/sealed_mecha melee = 20 @@ -221,7 +233,6 @@ . = ..() ui_view = new() ui_view.generate_view("mech_view_[REF(src)]") - RegisterSignal(src, COMSIG_MOVABLE_MOVED, PROC_REF(on_move)) RegisterSignal(src, COMSIG_LIGHT_EATER_ACT, PROC_REF(on_light_eater)) spark_system = new @@ -438,8 +449,6 @@ set_mouse_pointer() /obj/vehicle/sealed/mecha/proc/update_part_values() ///Updates the values given by scanning module and capacitor tier, called when a part is removed or inserted. - update_energy_drain() - if(capacitor) var/datum/armor/stock_armor = get_armor_by_type(armor_type) var/initial_energy = stock_armor.get_rating(ENERGY) @@ -558,6 +567,10 @@ use_energy(damage_energy_consumption) cell.maxcharge -= min(damage_energy_consumption, cell.maxcharge) + if((internal_damage & MECHA_INT_FUEL_LINE) && oil_pool >= 0.5 && isturf(loc) && SPT_PROB(round(oil_pool / 2, 0.1), seconds_per_tick)) + find_blood_type(oil_type)?.make_blood_splatter(loc, TRUE, list("[oil_name]" = oil_type)) + oil_pool -= 0.5 + /obj/vehicle/sealed/mecha/proc/process_cabin_air(seconds_per_tick) if(!(internal_damage & MECHA_INT_TEMP_CONTROL) && cabin_air && cabin_air.return_volume() > 0) var/heat_capacity = cabin_air.heat_capacity() @@ -621,7 +634,7 @@ diag_hud_set_mechstat() /obj/vehicle/sealed/mecha/proc/process_constant_power_usage(seconds_per_tick) - if(mecha_flags & LIGHTS_ON && !use_energy(light_power_drain * seconds_per_tick)) + if(mecha_flags & LIGHTS_ON && !use_energy(light_power_drain * seconds_per_tick, CAPACITOR_MODIFIED_DRAIN)) mecha_flags &= ~LIGHTS_ON set_light_on(mecha_flags & LIGHTS_ON) playsound(src,'sound/machines/clockcult/brass_skewer.ogg', 40, TRUE) @@ -695,9 +708,8 @@ if(internal_damage & MECHA_INT_CONTROL_LOST) target = pick(oview(1,src)) - if(!has_charge(melee_energy_drain)) + if(!use_energy(melee_energy_drain, CAPACITOR_MODIFIED_DRAIN|OIL_MODIFIED_DRAIN)) return - use_energy(melee_energy_drain) SEND_SIGNAL(user, COMSIG_MOB_USED_MECH_MELEE, src) target.mech_melee_attack(src, user) @@ -863,25 +875,6 @@ else movedelay = initial(movedelay) visible_message(span_notice("[src] cools down and the humming stops.")) - update_energy_drain() - -/// Update the energy drain according to parts and status -/obj/vehicle/sealed/mecha/proc/update_energy_drain() - if(servo) - step_energy_drain = initial(step_energy_drain) / servo.rating - else - step_energy_drain = 2 * initial(step_energy_drain) - if(overclock_mode) - step_energy_drain *= overclock_coeff - - if(capacitor) - phasing_energy_drain = initial(phasing_energy_drain) / capacitor.rating - melee_energy_drain = initial(melee_energy_drain) / capacitor.rating - light_power_drain = initial(light_power_drain) / capacitor.rating - else - phasing_energy_drain = initial(phasing_energy_drain) - melee_energy_drain = initial(melee_energy_drain) - light_power_drain = initial(light_power_drain) /// Toggle lights on/off /obj/vehicle/sealed/mecha/proc/toggle_lights(forced_state = null, mob/user) diff --git a/code/modules/vehicles/mecha/combat/honker.dm b/code/modules/vehicles/mecha/combat/honker.dm index 83934244638a..c7c0be0df80f 100644 --- a/code/modules/vehicles/mecha/combat/honker.dm +++ b/code/modules/vehicles/mecha/combat/honker.dm @@ -22,19 +22,14 @@ MECHA_POWER = 1, MECHA_ARMOR = 0, ) - var/squeak = TRUE + stepsound = SFX_CLOWN_STEP + steps_per_footstep = 2 /datum/armor/mecha_honker melee = -20 fire = 100 acid = 100 -/obj/vehicle/sealed/mecha/honker/play_stepsound() - if(squeak) - playsound(src, SFX_CLOWN_STEP, 70, 1) - squeak = !squeak - - //DARK H.O.N.K. /obj/vehicle/sealed/mecha/honker/dark diff --git a/code/modules/vehicles/mecha/mecha_damage.dm b/code/modules/vehicles/mecha/mecha_damage.dm index 8a06aaf298fa..22ac1bfaeacb 100644 --- a/code/modules/vehicles/mecha/mecha_damage.dm +++ b/code/modules/vehicles/mecha/mecha_damage.dm @@ -58,6 +58,8 @@ return "recalibrating coordination system..." if(MECHA_INT_SHORT_CIRCUIT) return "flushing internal capacitor..." + if(MECHA_INT_FUEL_LINE) + return "rejoining fuel line..." ///gets the successful finish balloon alert flufftext /obj/vehicle/sealed/mecha/proc/get_int_repair_fluff_end(flag) @@ -72,6 +74,8 @@ return "coordination re-established" if(MECHA_INT_SHORT_CIRCUIT) return "internal capacitor reset" + if(MECHA_INT_FUEL_LINE) + return "fuel line rejoined" ///gets the on-fail balloon alert flufftext /obj/vehicle/sealed/mecha/proc/get_int_repair_fluff_fail(flag) @@ -86,6 +90,8 @@ return "recalibration failed" if(MECHA_INT_SHORT_CIRCUIT) return "capacitor flush failure" + if(MECHA_INT_FUEL_LINE) + return "fuel line rejoin interrupted" /obj/vehicle/sealed/mecha/proc/set_internal_damage(int_dam_flag) internal_damage |= int_dam_flag @@ -106,5 +112,9 @@ to_chat(occupants, "[icon2html(src, occupants)][span_boldnotice("Control module reactivated.")]") if(MECHA_INT_SHORT_CIRCUIT) to_chat(occupants, "[icon2html(src, occupants)][span_boldnotice("Internal capacitor has been reset successfully.")]") + if(MECHA_INT_FUEL_LINE) + to_chat(occupants, "[icon2html(src, occupants)][span_boldnotice("Fuel line has been repaired.")]") + oil_pool = initial(oil_pool) + internal_damage &= ~int_dam_flag diag_hud_set_mechstat() diff --git a/code/modules/vehicles/mecha/mecha_defense.dm b/code/modules/vehicles/mecha/mecha_defense.dm index c744d3aead17..5a335b58a609 100644 --- a/code/modules/vehicles/mecha/mecha_defense.dm +++ b/code/modules/vehicles/mecha/mecha_defense.dm @@ -123,6 +123,8 @@ var/mob/living/hitmob = pick(occupants) return hitmob.bullet_act(hitting_projectile, def_zone, piercing_hit) //If the sides are open, the occupant can be hit + var/old_internals = internal_damage + . = ..() log_message("Hit by projectile. Type: [hitting_projectile]([hitting_projectile.damage_type]).", LOG_MECHA, color="red") @@ -135,6 +137,9 @@ armour_penetration = hitting_projectile.armour_penetration, ), def_zone) + if((internal_damage & MECHA_INT_FUEL_LINE) && !(old_internals & MECHA_INT_FUEL_LINE) && oil_pool >= 10) + spray_blood(REVERSE_DIR(hitting_projectile.dir), rand(2, 4), list("[oil_name]" = oil_type)) + oil_pool -= 2 /obj/vehicle/sealed/mecha/ex_act(severity, target) log_message("Affected by explosion of severity: [severity].", LOG_MECHA, color="red") @@ -317,6 +322,8 @@ if(!attacking_item.force) return + var/old_internals = internal_damage + var/damage_taken = take_damage(attacking_item.force * attacking_item.demolition_mod, attacking_item.damtype, MELEE, 1, get_dir(src, user)) try_damage_component(damage_taken, user.zone_selected) @@ -331,11 +338,23 @@ log_combat(user, src, "attacked", attacking_item) log_message("Attacked by [user]. Item - [attacking_item], Damage - [damage_taken]", LOG_MECHA) + if((internal_damage & MECHA_INT_FUEL_LINE) && !(old_internals & MECHA_INT_FUEL_LINE) && oil_pool >= 10) + spray_blood(get_dir(user, src), rand(2, 4), list("[oil_name]" = oil_type)) + oil_pool -= 2 + /obj/vehicle/sealed/mecha/attack_generic(mob/user, damage_amount, damage_type, damage_flag, effects, armor_penetration) + var/old_internals = internal_damage + . = ..() - if(.) - try_damage_component(., user.zone_selected) - diag_hud_set_mechhealth() + if(!.) + return + + try_damage_component(., user.zone_selected) + diag_hud_set_mechhealth() + + if((internal_damage & MECHA_INT_FUEL_LINE) && !(old_internals & MECHA_INT_FUEL_LINE) && oil_pool >= 10) + spray_blood(get_dir(user, src), rand(2, 4), list("[oil_name]" = oil_type)) + oil_pool -= 2 /obj/vehicle/sealed/mecha/examine(mob/user) . = ..() @@ -452,6 +471,8 @@ clear_internal_damage(MECHA_CABIN_AIR_BREACH) if(internal_damage & MECHA_INT_CONTROL_LOST) clear_internal_damage(MECHA_INT_CONTROL_LOST) + if(internal_damage & MECHA_INT_FUEL_LINE) + clear_internal_damage(MECHA_INT_FUEL_LINE) diag_hud_set_mechhealth() /obj/vehicle/sealed/mecha/narsie_act() diff --git a/code/modules/vehicles/mecha/mecha_helpers.dm b/code/modules/vehicles/mecha/mecha_helpers.dm index 03084c56957a..bfe76458f168 100644 --- a/code/modules/vehicles/mecha/mecha_helpers.dm +++ b/code/modules/vehicles/mecha/mecha_helpers.dm @@ -7,7 +7,16 @@ /obj/vehicle/sealed/mecha/proc/get_charge() return cell?.charge -/obj/vehicle/sealed/mecha/proc/use_energy(amount) +/obj/vehicle/sealed/mecha/proc/use_energy(amount, drain_flags = NONE) + if(drain_flags & CAPACITOR_MODIFIED_DRAIN) + amount *= (1 / (capacitor?.rating || 1)) + if(drain_flags & SERVO_MODIFIED_DRAIN) + amount *= (1 / (servo?.rating || 0.5)) + if(overclock_mode) + amount *= overclock_coeff + if(drain_flags & OIL_MODIFIED_DRAIN) + amount *= (2 - (oil_pool / initial(oil_pool))) + var/output = cell.use(amount) if (output) diag_hud_set_mechcell() diff --git a/code/modules/vehicles/mecha/mecha_movement.dm b/code/modules/vehicles/mecha/mecha_movement.dm index 375b47e59bbd..7dadabb88762 100644 --- a/code/modules/vehicles/mecha/mecha_movement.dm +++ b/code/modules/vehicles/mecha/mecha_movement.dm @@ -4,12 +4,26 @@ for(var/mob/living/occupant as anything in occupants) occupant.setDir(newdir) +//NON-MODULE CHANGE ///Called when the mech moves -/obj/vehicle/sealed/mecha/proc/on_move() - SIGNAL_HANDLER +/obj/vehicle/sealed/mecha/Move(atom/newloc, direct) + var/atom/old_loc = loc + var/old_dir = dir + . = ..() + if(!isturf(loc)) + return collect_ore() - play_stepsound() + + if(!(mecha_flags & QUIET_STEPS)) + footstep_count += 1 + if(footstep_count >= steps_per_footstep) + playsound(src, stepsound, 40, TRUE) + footstep_count = 0 + + if((internal_damage & MECHA_INT_FUEL_LINE) && loc != old_loc && oil_pool >= 10 && prob(30 + 0.75 * oil_pool)) + make_blood_trail(loc, old_loc, old_dir, dir, BLOOD_AMOUNT_PER_DECAL * (oil_pool > 66 ? 0.3 : 0.1), list("[oil_name]" = oil_type)) + oil_pool -= (oil_pool > 66 ? 3 : 1) ///Collects ore when we move, if there is an orebox and it is functional /obj/vehicle/sealed/mecha/proc/collect_ore() @@ -20,12 +34,6 @@ if(ore.Adjacent(src) && ((get_dir(src, ore) & dir) || ore.loc == loc)) ore.forceMove(ore_box) -///Plays the mech step sound effect. Split from movement procs so that other mechs (HONK) can override this one specific part. -/obj/vehicle/sealed/mecha/proc/play_stepsound() - if(mecha_flags & QUIET_STEPS) - return - playsound(src, stepsound, 40, TRUE) - // Do whatever you do to mobs to these fuckers too /obj/vehicle/sealed/mecha/Process_Spacemove(movement_dir = 0, continuous_move = FALSE) . = ..() @@ -98,7 +106,7 @@ to_chat(occupants, "[icon2html(src, occupants)][span_warning("Missing [english_list(missing_parts)].")]") TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_MESSAGE, 2 SECONDS) return FALSE - if(!use_energy(step_energy_drain)) + if(!use_energy(step_energy_drain, SERVO_MODIFIED_DRAIN|CAPACITOR_MODIFIED_DRAIN|OIL_MODIFIED_DRAIN)) if(TIMER_COOLDOWN_FINISHED(src, COOLDOWN_MECHA_MESSAGE)) to_chat(occupants, "[icon2html(src, occupants)][span_warning("Insufficient power to move!")]") TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_MESSAGE, 2 SECONDS) diff --git a/code/modules/vehicles/mecha/mecha_ui.dm b/code/modules/vehicles/mecha/mecha_ui.dm index 37163aa3ea56..a21031447c80 100644 --- a/code/modules/vehicles/mecha/mecha_ui.dm +++ b/code/modules/vehicles/mecha/mecha_ui.dm @@ -55,6 +55,7 @@ "MECHA_CABIN_AIR_BREACH" = MECHA_CABIN_AIR_BREACH, "MECHA_INT_CONTROL_LOST" = MECHA_INT_CONTROL_LOST, "MECHA_INT_SHORT_CIRCUIT" = MECHA_INT_SHORT_CIRCUIT, + "MECHA_INT_FUEL_LINE" = MECHA_INT_FUEL_LINE, ) var/list/regions = list() diff --git a/code/modules/vehicles/mecha/medical/odysseus.dm b/code/modules/vehicles/mecha/medical/odysseus.dm index 3199124edaa2..2ee32c4f53e1 100644 --- a/code/modules/vehicles/mecha/medical/odysseus.dm +++ b/code/modules/vehicles/mecha/medical/odysseus.dm @@ -1,5 +1,5 @@ /obj/vehicle/sealed/mecha/odysseus - desc = "These exosuits are developed and produced by Vey-Med. (© All rights reserved)." + desc = "A nimble DeForest Odysseus exosuit, designed and outfitted for frontline medical support and rapid response." name = "\improper Odysseus" icon_state = "odysseus" base_icon_state = "odysseus" diff --git a/code/modules/vehicles/mecha/working/ripley.dm b/code/modules/vehicles/mecha/working/ripley.dm index 8fdd836d780a..66ad280be890 100644 --- a/code/modules/vehicles/mecha/working/ripley.dm +++ b/code/modules/vehicles/mecha/working/ripley.dm @@ -20,7 +20,7 @@ mecha_flags = CAN_STRAFE | HAS_LIGHTS | MMI_COMPATIBLE wreckage = /obj/structure/mecha_wreckage/ripley mech_type = EXOSUIT_MODULE_RIPLEY - possible_int_damage = MECHA_INT_FIRE|MECHA_INT_CONTROL_LOST|MECHA_INT_SHORT_CIRCUIT + possible_int_damage = MECHA_INT_FIRE|MECHA_INT_CONTROL_LOST|MECHA_INT_SHORT_CIRCUIT|MECHA_INT_FUEL_LINE accesses = list(ACCESS_MECH_ENGINE, ACCESS_MECH_SCIENCE, ACCESS_MECH_MINING) enter_delay = 10 //can enter in a quarter of the time of other mechs exit_delay = 10 @@ -76,7 +76,7 @@ max_temperature = 30000 max_integrity = 250 mecha_flags = CAN_STRAFE | IS_ENCLOSED | HAS_LIGHTS | MMI_COMPATIBLE - possible_int_damage = MECHA_INT_FIRE|MECHA_INT_TEMP_CONTROL|MECHA_CABIN_AIR_BREACH|MECHA_INT_CONTROL_LOST|MECHA_INT_SHORT_CIRCUIT + possible_int_damage = MECHA_INT_FIRE|MECHA_INT_TEMP_CONTROL|MECHA_CABIN_AIR_BREACH|MECHA_INT_CONTROL_LOST|MECHA_INT_SHORT_CIRCUIT|MECHA_INT_FUEL_LINE armor_type = /datum/armor/mecha_ripley_mk2 wreckage = /obj/structure/mecha_wreckage/ripley/mk2 enter_delay = 40 @@ -101,7 +101,7 @@ max_temperature = 20000 max_integrity = 250 mech_type = EXOSUIT_MODULE_PADDY - possible_int_damage = MECHA_INT_FIRE|MECHA_INT_CONTROL_LOST|MECHA_INT_SHORT_CIRCUIT + possible_int_damage = MECHA_INT_FIRE|MECHA_INT_CONTROL_LOST|MECHA_INT_SHORT_CIRCUIT|MECHA_INT_FUEL_LINE accesses = list(ACCESS_MECH_SCIENCE, ACCESS_MECH_SECURITY) armor_type = /datum/armor/mecha_paddy wreckage = /obj/structure/mecha_wreckage/ripley/paddy diff --git a/maplestation_modules/code/modules/mob/living/blood.dm b/maplestation_modules/code/modules/mob/living/blood.dm index 46bba0cad24b..04dcb4676dbe 100644 --- a/maplestation_modules/code/modules/mob/living/blood.dm +++ b/maplestation_modules/code/modules/mob/living/blood.dm @@ -116,17 +116,17 @@ PROCESSING_SUBSYSTEM_DEF(blood_drying) * Helper proc to make a blood splatter from the passed mob of this type * * Arguments - * * bleeding - the mob bleeding the blood, note we assume this blood type is that mob's blood + * * dna - associative list of blood DNA to add to the blood splatter * * blood_turf - the turf to spawn the blood on * * drip - whether to spawn a drip or a splatter + * * viruses - list of viruses to add to the blood splatter */ -/datum/blood_type/proc/make_blood_splatter(mob/living/bleeding, turf/blood_turf, drip) +/datum/blood_type/proc/make_blood_splatter(turf/blood_turf, drip, list/dna = list("UNKNOWN" = type), list/viruses) if(isgroundlessturf(blood_turf)) blood_turf = GET_TURF_BELOW(blood_turf) if(isnull(blood_turf) || isclosedturf(blood_turf)) return - var/list/temp_blood_DNA if(drip) var/new_blood = /obj/effect/decal/cleanable/blood/drip::bloodiness // Only a certain number of drips (or one large splatter) can be on a given turf. @@ -134,14 +134,14 @@ PROCESSING_SUBSYSTEM_DEF(blood_drying) if(isnull(drop)) var/obj/effect/decal/cleanable/blood/splatter = locate() in blood_turf if(!QDELETED(splatter) && !splatter.dried) - splatter.add_mob_blood(bleeding) + splatter.add_blood_DNA(dna) splatter.adjust_bloodiness(new_blood) splatter.slow_dry(1 SECONDS * new_blood * BLOOD_PER_UNIT_MODIFIER) return splatter - drop = new(blood_turf, bleeding.get_static_viruses()) + drop = new(blood_turf, viruses) if(!QDELETED(drop)) - drop.add_mob_blood(bleeding) + drop.add_blood_DNA(dna) drop.random_icon_states -= drop.icon_state return drop @@ -154,32 +154,30 @@ PROCESSING_SUBSYSTEM_DEF(blood_drying) new_drop.color = color new_drop.vis_flags |= (VIS_INHERIT_LAYER|VIS_INHERIT_PLANE|VIS_INHERIT_ID) new_drop.appearance_flags |= (RESET_COLOR) - new_drop.add_mob_blood(bleeding) + new_drop.add_blood_DNA(dna) drop.gender = PLURAL drop.base_name = "drips of" drop.vis_contents += new_drop // Handle adding blood to the base atom drop.adjust_bloodiness(new_blood) - drop.add_mob_blood(bleeding) - drop.add_viruses(bleeding.get_static_viruses()) + drop.add_blood_DNA(dna) + drop.add_viruses(viruses) return drop - temp_blood_DNA = GET_ATOM_BLOOD_DNA(drop) //we transfer the dna from the drip to the splatter + dna |= GET_ATOM_BLOOD_DNA(drop) //we transfer the dna from the drip to the splatter qdel(drop)//the drip is replaced by a bigger splatter // Find a blood decal or create a new one. var/obj/effect/decal/cleanable/blood/splatter = locate() in blood_turf if(isnull(splatter) || splatter.dried) - splatter = new(blood_turf, bleeding.get_static_viruses()) + splatter = new(blood_turf, viruses) if(QDELETED(splatter)) //Give it up return null else splatter.adjust_bloodiness(BLOOD_AMOUNT_PER_DECAL) - splatter.add_viruses(bleeding.get_static_viruses()) + splatter.add_viruses(viruses) splatter.slow_dry(1 SECONDS * BLOOD_AMOUNT_PER_DECAL * BLOOD_PER_UNIT_MODIFIER) - splatter.add_mob_blood(bleeding) //give blood info to the blood decal. - if(LAZYLEN(temp_blood_DNA)) - splatter.add_blood_DNA(temp_blood_DNA) + splatter.add_blood_DNA(dna) //give blood info to the blood decal. return splatter /// A base type for all blood related to the crew, for organization's sake @@ -347,6 +345,9 @@ PROCESSING_SUBSYSTEM_DEF(blood_drying) blood.can_dry = FALSE blood.AddElement(/datum/element/easy_ignite) +/datum/blood_type/oil/heavy + name = "Heavy Oil" + /// A universal blood type which accepts everything /datum/blood_type/universal name = "U" diff --git a/tgui/packages/tgui/interfaces/Mecha/AlertPane.tsx b/tgui/packages/tgui/interfaces/Mecha/AlertPane.tsx index 1f435f1b4f35..5742c461c0c5 100644 --- a/tgui/packages/tgui/interfaces/Mecha/AlertPane.tsx +++ b/tgui/packages/tgui/interfaces/Mecha/AlertPane.tsx @@ -16,6 +16,7 @@ export const InternalDamageToDamagedDesc = { MECHA_CABIN_AIR_BREACH: 'Cabin breach detected', MECHA_INT_CONTROL_LOST: 'Motors damaged', MECHA_INT_SHORT_CIRCUIT: 'Circuits shorted', + MECHA_INT_FUEL_LINE: 'Fuel line cut', }; export const InternalDamageToNormalDesc = { @@ -24,6 +25,7 @@ export const InternalDamageToNormalDesc = { MECHA_CABIN_AIR_BREACH: 'Cabin sealing intact', MECHA_INT_CONTROL_LOST: 'Motors active', MECHA_INT_SHORT_CIRCUIT: 'Circuits operational', + MECHA_INT_FUEL_LINE: 'Fuel line intact', }; export const AlertPane = (props) => { From 34e8ef2f21860e0584342bbb4aa5ac85989dc293 Mon Sep 17 00:00:00 2001 From: MrMelbert Date: Mon, 1 Dec 2025 18:55:00 -0600 Subject: [PATCH 2/4] Blood renaming --- code/datums/wounds/internal_bleeding.dm | 2 +- code/modules/mob/living/blood.dm | 8 ++++---- code/modules/mob/living/living.dm | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/code/datums/wounds/internal_bleeding.dm b/code/datums/wounds/internal_bleeding.dm index ea8bec76c78e..2f0420b2d571 100644 --- a/code/datums/wounds/internal_bleeding.dm +++ b/code/datums/wounds/internal_bleeding.dm @@ -65,7 +65,7 @@ if(!victim || victim.stat == DEAD || HAS_TRAIT(victim, TRAIT_STASIS) || !victim.needs_heart()) return var/severity_mod = (severity + 1) - victim.bleed(bleed_amount * severity_mod * seconds_per_tick, drip = FALSE) + victim.bleed(bleed_amount * severity_mod * seconds_per_tick, leave_pool = FALSE) if(severity == WOUND_SEVERITY_TRIVIAL) if(highest_severity == WOUND_SEVERITY_TRIVIAL) var/percent = 0.01 diff --git a/code/modules/mob/living/blood.dm b/code/modules/mob/living/blood.dm index be50ad47b98a..6fb968293489 100644 --- a/code/modules/mob/living/blood.dm +++ b/code/modules/mob/living/blood.dm @@ -119,18 +119,18 @@ iter_part.update_part_wound_overlay() /// Makes a blood drop, leaking amt units of blood from the mob -/mob/living/proc/bleed(amt, drip = TRUE) +/mob/living/proc/bleed(amt, leave_pool = TRUE) return -/mob/living/carbon/bleed(amt, drip = TRUE) +/mob/living/carbon/bleed(amt, leave_pool = TRUE) if((status_flags & GODMODE) || HAS_TRAIT(src, TRAIT_NOBLOOD)) return blood_volume = max(blood_volume - amt, 0) - if(drip && isturf(loc) && prob(sqrt(amt) * BLOOD_DRIP_RATE_MOD)) + if(leave_pool && isturf(loc) && prob(sqrt(amt) * BLOOD_DRIP_RATE_MOD)) add_splatter_floor(loc, (amt <= 10)) -/mob/living/carbon/human/bleed(amt, drip = TRUE) +/mob/living/carbon/human/bleed(amt, leave_pool = TRUE) amt *= physiology.bleed_mod return ..() diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index ff6cc4c437df..3ca0d373ecbc 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1190,7 +1190,7 @@ // this is where people losing extra blood from being dragged is handled if(body_position == LYING_DOWN) - bleed(blood_to_add, drip = FALSE) + bleed(blood_to_add, leave_pool = FALSE) return ..() From be694f2db231af2532600c1e425e4e7d9dbf9870 Mon Sep 17 00:00:00 2001 From: MrMelbert Date: Thu, 11 Dec 2025 14:51:14 -0600 Subject: [PATCH 3/4] Fix --- code/modules/forensics/forensics_helpers.dm | 9 ++++++--- maplestation_modules/code/modules/mob/living/blood.dm | 9 ++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/code/modules/forensics/forensics_helpers.dm b/code/modules/forensics/forensics_helpers.dm index 1b7a4032d099..9f23c04849fd 100644 --- a/code/modules/forensics/forensics_helpers.dm +++ b/code/modules/forensics/forensics_helpers.dm @@ -123,10 +123,13 @@ return FALSE if(dried) return TRUE - // Imperfect, ends up with some blood types being double-set-up, but harmless (for now) - for(var/new_blood in blood_DNA_to_add) - var/datum/blood_type/blood = find_blood_type(blood_DNA_to_add[new_blood]) + var/list/unique_blood = list() + for(var/some_dna, blood_type in blood_DNA_to_add) + if(unique_blood[blood_type]) + continue + var/datum/blood_type/blood = find_blood_type(blood_type) blood.set_up_blood(src, first_dna == 0) + unique_blood[blood_type] = TRUE update_appearance() add_atom_colour(get_blood_dna_color(), FIXED_COLOUR_PRIORITY) return TRUE diff --git a/maplestation_modules/code/modules/mob/living/blood.dm b/maplestation_modules/code/modules/mob/living/blood.dm index 04dcb4676dbe..8b760aa25526 100644 --- a/maplestation_modules/code/modules/mob/living/blood.dm +++ b/maplestation_modules/code/modules/mob/living/blood.dm @@ -14,8 +14,9 @@ if(!blood_type_singletons) blood_type_singletons = list() for(var/datum/blood_type/blood_type_type as anything in subtypesof(/datum/blood_type)) - if(initial(blood_type_type.name)) - blood_type_singletons[blood_type_type] = new blood_type_type() + if(!blood_type_type::name) // future todo : make this use valid_subtypesof + continue + blood_type_singletons[blood_type_type.type_key()] = new blood_type_type() // either a blood type, or a reagent that has been instantiated as a blood type if(blood_type_singletons[name_reagent_or_typepath]) @@ -311,7 +312,7 @@ PROCESSING_SUBSYSTEM_DEF(blood_drying) if(!new_splat) return blood.can_dry = FALSE - RegisterSignals(blood, list(COMSIG_ATOM_ITEM_INTERACTION, COMSIG_ATOM_ITEM_INTERACTION_SECONDARY), PROC_REF(on_cleaned)) + RegisterSignals(blood, list(COMSIG_ATOM_ITEM_INTERACTION, COMSIG_ATOM_ITEM_INTERACTION_SECONDARY), PROC_REF(on_cleaned), override = TRUE) /datum/blood_type/crew/ethereal/proc/on_cleaned(obj/effect/decal/cleanable/source, mob/living/user, obj/item/tool, ...) SIGNAL_HANDLER @@ -343,6 +344,8 @@ PROCESSING_SUBSYSTEM_DEF(blood_drying) return // Oil blood will never dry and can be ignited with fire blood.can_dry = FALSE + // This is evil code, all it does is prevent easy ignte from being attached twice + blood.RemoveElement(/datum/element/easy_ignite) blood.AddElement(/datum/element/easy_ignite) /datum/blood_type/oil/heavy From b4348e3156321b3f4c70eb8701dc425c5946a1db Mon Sep 17 00:00:00 2001 From: MrMelbert Date: Thu, 11 Dec 2025 15:03:43 -0600 Subject: [PATCH 4/4] Fix --- maplestation_modules/code/modules/mob/living/blood.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/maplestation_modules/code/modules/mob/living/blood.dm b/maplestation_modules/code/modules/mob/living/blood.dm index 8b760aa25526..cff19989b1ed 100644 --- a/maplestation_modules/code/modules/mob/living/blood.dm +++ b/maplestation_modules/code/modules/mob/living/blood.dm @@ -16,7 +16,8 @@ for(var/datum/blood_type/blood_type_type as anything in subtypesof(/datum/blood_type)) if(!blood_type_type::name) // future todo : make this use valid_subtypesof continue - blood_type_singletons[blood_type_type.type_key()] = new blood_type_type() + var/datum/blood_type/blood_type_instance = new blood_type_type() + blood_type_singletons[blood_type_instance.type_key()] = blood_type_instance // either a blood type, or a reagent that has been instantiated as a blood type if(blood_type_singletons[name_reagent_or_typepath])