diff --git a/code/ATMOSPHERICS/atmospherics.dm b/code/ATMOSPHERICS/atmospherics.dm index 7f3368cc53..2acbeb5a7a 100644 --- a/code/ATMOSPHERICS/atmospherics.dm +++ b/code/ATMOSPHERICS/atmospherics.dm @@ -132,7 +132,7 @@ Pipelines + Other Objects -> Pipe network return null -/obj/machinery/atmospherics/proc/build_network() +/obj/machinery/atmospherics/proc/build_network(var/new_attachment) // Called to build a network from this node return null @@ -158,11 +158,14 @@ Pipelines + Other Objects -> Pipe network return null /obj/machinery/atmospherics/proc/can_unwrench() + +/* //Old version. We now handle unwrenching in the machinery itself. var/datum/gas_mixture/int_air = return_air() var/datum/gas_mixture/env_air = loc.return_air() if((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE) - return 0 - return 1 + return FALSE +*/ + return TRUE // Deconstruct into a pipe item. /obj/machinery/atmospherics/proc/deconstruct() @@ -191,13 +194,17 @@ Pipelines + Other Objects -> Pipe network atmos_init() if(QDELETED(src)) return // TODO - Eventually should get rid of the need for this. - build_network() var/list/nodes = get_neighbor_nodes_for_init() for(var/obj/machinery/atmospherics/A in nodes) A.atmos_init() - A.build_network() - // TODO - Should we do src.build_network() before or after the nodes? - // We've historically done before, but /tg does after. TODO research if there is a difference. + A.build_network(TRUE) + build_network() + + // There was a coder comment her from 7 years ago asking 'tg does it this way, should we?' and the answer was yes. + // By building the network BEFORE our nodes build their network, two things happened: + // 1. The network was built and none of the pipes got their temporary air vaiables, resulting in the pipes having no air in them + // 2. The previous network was nulled but never deleted, resulting in a memory leak. + // So now, we build our network AFTER the nodes build their network AND we delete the previous network. // This sets our piping layer. Hopefully its cool. /obj/machinery/atmospherics/proc/setPipingLayer(new_layer) @@ -232,3 +239,21 @@ Pipelines + Other Objects -> Pipe network // pixel_x = PIPE_PIXEL_OFFSET_X(piping_layer) // pixel_y = PIPE_PIXEL_OFFSET_Y(piping_layer) // layer = initial(layer) + PIPE_LAYER_OFFSET(piping_layer) + +/obj/machinery/atmospherics/proc/unsafe_pressure_release(mob/user, pressures = null) + if(!user) + return + if(!pressures) + var/datum/gas_mixture/int_air = return_air() + var/datum/gas_mixture/env_air = loc.return_air() + pressures = int_air.return_pressure() - env_air.return_pressure() + + user.visible_message(span_danger("[user] is sent flying by pressure!"),span_userdanger("The pressure sends you flying!")) + + // if get_dir(src, user) is not 0, target is the edge_target_turf on that dir + // otherwise, edge_target_turf uses a random cardinal direction + // range is pressures / 250 + // speed is pressures / 1250 + if(user.buckled) + user.buckled.unbuckle_mob(user, TRUE) + user.throw_at(get_edge_target_turf(user, get_dir(src, user) || pick(GLOB.cardinal)), pressures / 250, pressures / 1250) diff --git a/code/ATMOSPHERICS/pipes/pipe_base.dm b/code/ATMOSPHERICS/pipes/pipe_base.dm index 02c22f8a22..8030d97cc9 100644 --- a/code/ATMOSPHERICS/pipes/pipe_base.dm +++ b/code/ATMOSPHERICS/pipes/pipe_base.dm @@ -79,9 +79,11 @@ return parent.air -/obj/machinery/atmospherics/pipe/build_network() +/obj/machinery/atmospherics/pipe/build_network(new_attachment) if(QDELETED(src)) return + if(new_attachment) + QDEL_NULL(parent) if(!parent) parent = new /datum/pipeline() parent.build_pipeline(src) @@ -137,13 +139,28 @@ to_chat(user, span_warning("You cannot unwrench \the [src], it is too exerted due to internal pressure.")) add_fingerprint(user) return 1 + + //potential yeet + var/datum/gas_mixture/int_air = return_air() + var/datum/gas_mixture/env_air = loc.return_air() + var/unsafe_wrenching = FALSE + var/internal_pressure = int_air.return_pressure()-env_air.return_pressure() + + if (internal_pressure > 2*ONE_ATMOSPHERE) + to_chat(user, span_warning("As you begin unwrenching \the [src] a gush of air blows in your face... maybe you should reconsider?")) + unsafe_wrenching = TRUE //here we go + else + to_chat(user, span_notice("You begin to unfasten \the [src]...")) + playsound(src, W.usesound, 50, 1) - to_chat(user, span_notice("You begin to unfasten \the [src]...")) + if (do_after(user, 10 * W.toolspeed)) user.visible_message( \ span_infoplain(span_bold("\The [user]") + " unfastens \the [src]."), \ span_notice("You have unfastened \the [src]."), \ - "You hear a ratchet.") + span_hear("You hear a ratchet.")) + if(unsafe_wrenching) + unsafe_pressure_release(user, internal_pressure) deconstruct() /obj/machinery/atmospherics/pipe/proc/change_color(var/new_color) diff --git a/code/_helpers/atmospherics.dm b/code/_helpers/atmospherics.dm index 7e899ed316..c3f2ee0516 100644 --- a/code/_helpers/atmospherics.dm +++ b/code/_helpers/atmospherics.dm @@ -16,7 +16,7 @@ /proc/atmosanalyzer_scan(var/atom/target, var/datum/gas_mixture/mixture, var/mob/user) var/list/results = list() - if (mixture && mixture.total_moles > 0) + if(mixture && mixture.total_moles > 0) var/pressure = mixture.return_pressure() var/total_moles = mixture.total_moles results += span_notice("Pressure: [round(pressure,0.1)] kPa") @@ -42,10 +42,16 @@ return atmosanalyzer_scan(src, src.air_contents, user) /obj/machinery/atmospherics/pipe/atmosanalyze(var/mob/user) - return atmosanalyzer_scan(src, src.parent.air, user) + if(parent && parent.air) //Sometimes we may have a pipe that has no parent. This seems to happen if you add a pipe onto a pipeline, causing it to delete the parent for every pipe on that pipeline...Yeah. It's complicated and a bug. + return atmosanalyzer_scan(src, src.parent.air, user) +// This one is strange. The connector is not guaranteed to have a network (if you placed it down by itself) +// 'gases' is also a list. But the atmos analyzer wants you to give it a gas mixture. +// The 'gases' list holds ONE gas mixture. /obj/machinery/atmospherics/portables_connector/atmosanalyze(var/mob/user) - return atmosanalyzer_scan(src, src.network.gases, user) + if(network && network.gases) + var/list/datum/gas_mixture/analyzed_gas = network.gases[1] + return atmosanalyzer_scan(src, analyzed_gas, user) /obj/machinery/atmospherics/unary/atmosanalyze(var/mob/user) return atmosanalyzer_scan(src, src.air_contents, user) @@ -67,7 +73,7 @@ /obj/machinery/meter/atmosanalyze(var/mob/user) var/datum/gas_mixture/mixture = null - if(src.target) + if(target && target.parent) mixture = src.target.parent.air return atmosanalyzer_scan(src, mixture, user) diff --git a/code/_helpers/icons.dm b/code/_helpers/icons.dm index ae73126472..464ad55806 100644 --- a/code/_helpers/icons.dm +++ b/code/_helpers/icons.dm @@ -84,6 +84,8 @@ var/list/RGB2 = ReadRGB(rgb2) // add missing alpha if needed + if(!RGB1 || !RGB2) //Don't blend if we don't two! No use blending what we don't have! + return if(RGB1.len < RGB2.len) RGB1 += 255 else if(RGB2.len < RGB1.len) RGB2 += 255 var/usealpha = RGB1.len > 3 diff --git a/code/datums/diseases/_MobProcs.dm b/code/datums/diseases/_MobProcs.dm index 5c6ca8aded..4827f2a5be 100644 --- a/code/datums/diseases/_MobProcs.dm +++ b/code/datums/diseases/_MobProcs.dm @@ -49,7 +49,8 @@ continue if(istype(DD.vars[V],/list)) var/list/L = D.vars[V] - DD.vars[V] = L.Copy() + if(L) + DD.vars[V] = L.Copy() else DD.vars[V] = D.vars[V] diff --git a/code/game/objects/explosion_recursive.dm b/code/game/objects/explosion_recursive.dm index aebf6ba8e8..73a4220cf3 100644 --- a/code/game/objects/explosion_recursive.dm +++ b/code/game/objects/explosion_recursive.dm @@ -104,11 +104,14 @@ spread_power -= O.explosion_resistance var/turf/T = get_step(src, direction) - T.explosion_spread(spread_power, direction, explosion_turfs) - T = get_step(src, turn(direction,90)) - T.explosion_spread(spread_power, turn(direction,90), explosion_turfs) - T = get_step(src, turn(direction,-90)) - T.explosion_spread(spread_power, turn(direction,-90), explosion_turfs) + if(T) + T.explosion_spread(spread_power, direction, explosion_turfs) + T = get_step(src, turn(direction,90)) + if(T) + T.explosion_spread(spread_power, turn(direction,90), explosion_turfs) + T = get_step(src, turn(direction,-90)) + if(T) + T.explosion_spread(spread_power, turn(direction,-90), explosion_turfs) /turf/unsimulated/explosion_spread(power) return //So it doesn't get to the parent proc, which simulates explosions diff --git a/code/game/objects/items/devices/scanners/guide.dm b/code/game/objects/items/devices/scanners/guide.dm index ab4e2a8bf4..75b3ee90b8 100644 --- a/code/game/objects/items/devices/scanners/guide.dm +++ b/code/game/objects/items/devices/scanners/guide.dm @@ -14,6 +14,7 @@ /obj/item/healthanalyzer/proc/guide(var/mob/living/carbon/human/M, mob/living/user) +/* Enable this if you want non-medical users to be blocked from the guide. Kind of pointless, since the only ones that would really NEED the guide are non-medical users. var/obj/item/card/id/ourid = user?.GetIdCard() if(!ourid) return @@ -27,6 +28,7 @@ return if(!ishuman(M)) return +*/ var/dat = "" @@ -72,45 +74,45 @@ bloodloss = TRUE if(bleeding_external) - dat += span_bold("Surface bleeding") + " - Bandage immediately or apply brute-damage fixing chemicals (i.e. Bicaridine) if no bandages available.
" + dat += span_bold("Surface Bleeding") + " - Apply bandages or administer Bicaridine.
" if(bleeding_internal) - dat += span_bold("Internal bleeding") + " - Commence internal vein repair surgery or apply clotting chemicals (i.e. Myelamine).
" + dat += span_bold("Internal Bleeding") + " - Commence an internal vein repair operation or administer coagulants, such as Myelamine.
" if(M.getOxyLoss()) - dat += span_bold("Suffociation") + " - Give Dexalin or Dexalin Plus. Check for heart or lung damage.
" + dat += span_bold("Suffocation") + " - Administer Dexalin or Dexalin Plus. Check for heart or lung damage.
" if(infection) - dat += span_bold("Infection") + " - Give Spaceacillin. If severe, use Corophizine or overdose on Spaceacillin and monitor until well.
" + dat += span_bold("Infection") + " - Administer Spaceacillin. If severe, use Corophizine or overdose on Spaceacillin and monitor until well.
" if(M.getBrainLoss() >= 1) - dat += span_bold("Brain damage") + " - Commence brain repair surgery, apply Alkysine, or universal organ-repair chemicals. (i.e. Peridaxon).
" + dat += span_bold("Traumatic Brain Injury") + " - Commence brain repair surgery, administer Alkysine or universal organ-repair chemicals such as Peridaxon.
" if(M.radiation || M.accumulated_rads) - dat += span_bold("Radiation") + " - Give Hyronalin or Arithrazine. Monitor for genetic damage.
" + dat += span_bold("Radiation Exposure") + " - Administer Hyronalin or Arithrazine. Monitor for genetic damage.
" if(organ) - dat += span_bold("Organ damage") + " - Give Peridaxon. Perform full body scan for targeted organ repair surgery.
" + dat += span_bold("Organ Damage") + " - Administer Peridaxon. Perform a full body scan for targeted organ repair surgery.
" if(bloodloss) dat += span_bold("Low blood volume") + " - Commence blood transfusion via IV drip or provide blood-restorative chemicals (e.g.: Copper for zorren and skrell, iron for the rest)." if(M.getToxLoss()) - dat += span_bold("Toxins") + " - Give Dylovene or Carthatoline. Vomitting is normal and helpful. Tends to be a symptom of larger issues, such as infection.
" + dat += span_bold("Toxin Buildup") + " - Inject Dylovene or Carthatoline. Monitor for damage to the liver or kidneys.
" if(M.getBruteLoss()) - dat += span_bold("Brute trauma") + " - Bandage wounded body part. Give Bicaridine or Vermicetol.
" + dat += span_bold("Physical Trauma") + " - Bandage the wounded body part. Administer Bicaridine or Vermicetol depending on the severity.
" if(M.getFireLoss()) - dat += span_bold("Surface burn") + " - Salve wounded body part in ointment. Give Kelotane or Dermaline. Check for infections.
" + dat += span_bold("Burn Wounds") + " - Salve the wounded body part in ointment. Administer Kelotane or Dermaline. Check for infections.
" if(M.getCloneLoss()) - dat += span_bold("Genetic damage") + " - Utilize cryogenic pod with appropriate chemicals (i.e. Cryoxadone) and below 70 K, or give Rezadone.
" + dat += span_bold("Genetic Damage") + " - Utilize cryogenic pod with appropriate chemicals (i.e. Cryoxadone) and below 70 K, or give Rezadone.
" if(bone) dat += span_bold("Bone fracture") + " - Splint damaged area. Treat with bone repair surgery or Osteodaxon after treating brute damage.
" - if(M.viruses.len) + if(M.viruses && M.viruses.len) for(var/datum/disease/D in M.GetViruses()) if(D.visibility_flags & HIDDEN_SCANNER) continue else dat += span_bold("Viral Infection") + " - Inform a Virologist or the Chief Medical Officer and administer antiviral chemicals such as Spaceacillin. Limit exposure to other personnel.
" if(robotparts) - dat += span_bold("Robotic body parts") + " - Should not be repaired by medical personnel, refer to robotics if damaged." + dat += span_bold("Robotic Body Parts") + " - Inform the Robotics department." var/peeb if(dat) - peeb += span_boldnotice("GUIDANCE SYSTEM BEGIN") - peeb +="
" + peeb += span_notice(span_bold("GUIDANCE SYSTEM BEGIN")) + peeb += "
" peeb += dat - peeb += span_notice("For more detailed information about patient condition, use the stationary scanner in medbay.") + peeb += span_notice("For more detailed information on the patient's condition, utilize a body scanner at the closest medical bay.") user.show_message(peeb, 1) diff --git a/code/modules/games/cards.dm b/code/modules/games/cards.dm index e1e0e449ac..103efd1f04 100644 --- a/code/modules/games/cards.dm +++ b/code/modules/games/cards.dm @@ -68,7 +68,7 @@ /obj/item/deck/attack_hand(mob/user as mob) var/mob/living/carbon/human/H = user - if(istype(src.loc, /obj/item/storage) || src == H.r_store || src == H.l_store || src.loc == user) // so objects can be removed from storage containers or pockets. also added a catch-all, so if it's in the mob you'll pick it up. + if(ishuman(H) && (istype(src.loc, /obj/item/storage) || src == H.r_store || src == H.l_store || src.loc == user)) // so objects can be removed from storage containers or pockets. also added a catch-all, so if it's in the mob you'll pick it up. Human only, however! ..() else // but if they're not, or are in your hands, you can still draw cards. draw_card() diff --git a/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_blob.dm b/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_blob.dm index a293ef71c7..7ee90806c5 100644 --- a/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_blob.dm +++ b/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_blob.dm @@ -197,10 +197,10 @@ humanform.species.update_misc_tabs(src) /mob/living/simple_mob/protean_blob/updatehealth() + if(!humanform) + CRASH("A protean blob does not have a humanform! src = [src] ckey = [ckey]") if(humanform.nano_dead_check(src)) return - if(!humanform) - return ..() //Set the max maxHealth = humanform.getMaxHealth()*2 //HUMANS, and their 'double health', bleh. @@ -324,6 +324,8 @@ /mob/living/simple_mob/protean_blob/Life() . = ..() + if(!humanform) + CRASH("A protean_blob calling Life() has no humanform! Src = [src] ckey = [ckey]") if(!humanform.nano_dead_check(src)) if(. && istype(refactory) && humanform) if(!healing && (human_brute || human_burn) && refactory.get_stored_material(MAT_STEEL) >= 100) @@ -654,6 +656,8 @@ return ..() /mob/living/simple_mob/protean_blob/handle_mutations_and_radiation() + if(!humanform) + CRASH("A protean blob does not have a humanform! src = [src] ckey = [ckey]") humanform.handle_mutations_and_radiation() /mob/living/simple_mob/protean_blob/update_icon() diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/tunneler.dm b/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/tunneler.dm index 4c0ea17260..f9680ccd68 100644 --- a/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/tunneler.dm +++ b/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/tunneler.dm @@ -155,6 +155,8 @@ // Update T. T = get_step(src, get_dir(src, destination)) + if(!T) //There is no turf in that direction. + return FALSE //Hit a non-existant turf. if(T.check_density(ignore_mobs = TRUE)) to_chat(src, span_critical("You hit something really solid!")) playsound(src, "punch", 75, 1) diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index 27773e17ab..a6e90b82ec 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -187,6 +187,7 @@ client.prefs.dress_preview_mob(mannequin) var/mob/observer/dead/observer = new(mannequin) observer.moveToNullspace() //Let's not stay in our doomed mannequin + qdel(mannequin) //We're not used anymore, so goodbye! spawning = 1 if(client.media)