diff --git a/code/__DEFINES/atmospherics.dm b/code/__DEFINES/atmospherics.dm index c585a822ea4c..4823bdebc203 100644 --- a/code/__DEFINES/atmospherics.dm +++ b/code/__DEFINES/atmospherics.dm @@ -352,3 +352,6 @@ GLOBAL_LIST_INIT(pipe_paint_colors, list( "violet" = rgb(64,0,128), "yellow" = rgb(255,198,0) )) + +#define AIR_REF_PLANETARY_TURF (1<<0) //SIMULATION_DIFFUSE 0b1 +#define AIR_REF_OPEN_TURF (1<<1) //SIMULATION_ALL 0b10 diff --git a/code/__SANDCODE/DEFINES/chat.dm b/code/__SANDCODE/DEFINES/chat.dm index 79da5c479d6f..8a8cc84eefe7 100644 --- a/code/__SANDCODE/DEFINES/chat.dm +++ b/code/__SANDCODE/DEFINES/chat.dm @@ -1,2 +1,4 @@ /// Adds a generic box around whatever message you're sending in chat. Really makes things stand out. #define examine_block(str) ("
" + str + "
") + +#define MESSAGE_TYPE_INFO "info" diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 0a659bc48f8e..9180be964980 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -1590,3 +1590,7 @@ else //We inline a MAPTEXT() here, because there's no good way to statically add to a string like this active_hud.screentip_text.maptext = "[name][extra_context]" + +///Return the air if we can analyze it +/atom/proc/return_analyzable_air() + return null diff --git a/code/game/gamemodes/clown_ops/clown_weapons.dm b/code/game/gamemodes/clown_ops/clown_weapons.dm index 5891facfb70b..5224cc306e9e 100644 --- a/code/game/gamemodes/clown_ops/clown_weapons.dm +++ b/code/game/gamemodes/clown_ops/clown_weapons.dm @@ -137,7 +137,7 @@ ..() slipper.signal_enabled = active -/obj/item/shield/energy/bananium/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback) +/obj/item/shield/energy/bananium/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, quickstart = TRUE) if(active) if(iscarbon(thrower)) var/mob/living/carbon/C = thrower diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 4ca642843bf9..78b7de48fc6f 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -738,7 +738,7 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb playsound(src, drop_sound, YEET_SOUND_VOLUME, ignore_walls = FALSE) return hit_atom.hitby(src, 0, itempush, throwingdatum=throwingdatum) -/obj/item/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force, messy_throw = TRUE) +/obj/item/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force, messy_throw = TRUE, quickstart = TRUE) thrownby = WEAKREF(thrower) callback = CALLBACK(src, PROC_REF(after_throw), callback, (spin && messy_throw)) //replace their callback with our own . = ..(target, range, speed, thrower, spin, diagonals_first, callback, force) @@ -1077,7 +1077,7 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb dropped(M) return ..() -/obj/item/throw_at(atom/target, range, speed, mob/thrower, spin=TRUE, diagonals_first = FALSE, var/datum/callback/callback) +/obj/item/throw_at(atom/target, range, speed, mob/thrower, spin=TRUE, diagonals_first = FALSE, var/datum/callback/callback, quickstart = TRUE) if (HAS_TRAIT(src, TRAIT_NODROP)) return return ..() diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index 428e9cf67bac..0255afeeba10 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -725,16 +725,21 @@ GENETICS SCANNER amount += inaccurate return DisplayTimeText(max(1,amount)) -/proc/atmosanalyzer_scan(mixture, mob/living/user, atom/target = src, visible = TRUE) +/proc/atmosanalyzer_scan(mixture, mob/living/user, atom/target = src, silent = FALSE) + mixture = target.return_analyzable_air() + if(!mixture) + return FALSE + var/icon = target - if(visible) - user.visible_message("[user] has used the analyzer on [icon2html(icon, viewers(user))] [target].", "You use the analyzer on [icon2html(icon, user)] [target].") - var/results = "Results of analysis of [icon2html(icon, user)] [target]." + var/render_list = list() + if(!silent && isliving(user)) + user.visible_message("[user] uses the analyzer on [icon2html(icon, viewers(user))] [target].", "You use the analyzer on [icon2html(icon, user)] [target].") + render_list += "Results of analysis of [icon2html(icon, user)] [target]." var/list/airs = islist(mixture) ? mixture : list(mixture) for(var/g in airs) if(airs.len > 1) //not a unary gas mixture - results += "\nNode [airs.Find(g)]" + render_list += "Node [airs.Find(g)]" var/datum/gas_mixture/air_contents = g var/total_moles = air_contents.total_moles() @@ -744,30 +749,27 @@ GENETICS SCANNER var/cached_scan_results = air_contents.analyzer_results if(total_moles > 0) - results += "\nMoles: [round(total_moles, 0.01)] mol" - results += "\nVolume: [volume] L" - results += "\nPressure: [round(pressure,0.01)] kPa" + //WS Start -- Atmos Analyzer Reformat (Issue #419) + render_list += "Moles: [round(total_moles, 0.01)] mol\ + \nVolume: [volume] L\ + \nPressure: [round(pressure,0.01)] kPa\ + \nTemperature: [round(temperature - T0C,0.01)] °C ([round(temperature, 0.01)] K)" + //WS End for(var/id in air_contents.get_gases()) - if(air_contents.get_moles(id) >= 0.005) - var/gas_concentration = air_contents.get_moles(id)/total_moles - results += "\n[GLOB.gas_data.names[id]]: [round(gas_concentration*100, 0.01)] % ([round(air_contents.get_moles(id), 0.01)] mol)" - results += "\nTemperature: [round(temperature - T0C,0.01)] °C ([round(temperature, 0.01)] K)" + var/gas_concentration = air_contents.get_moles(id)/total_moles + render_list += "[GLOB.gas_data.names[id]]: [round(gas_concentration*100, 0.01)] % ([round(air_contents.get_moles(id), 0.01)] mol)" //WS Edit -- Atmos Analyzer Reformat (Issue #419) else - if(airs.len > 1) - results += "\nThis node is empty!" - else - results += "\n[target] is empty!" + render_list += airs.len > 1 ? "This node is empty!" : "[target] is empty!" if(cached_scan_results && cached_scan_results["fusion"]) //notify the user if a fusion reaction was detected - var/instability = round(cached_scan_results["fusion"], 0.01) - var/tier = instability2text(instability) - results += "\nLarge amounts of free neutrons detected in the air indicate that a fusion reaction took place." - results += "\nInstability of the last fusion reaction: [instability]\n This indicates it was [tier]" + render_list += "Large amounts of free neutrons detected in the air indicate that a fusion reaction took place.\ + \nInstability of the last fusion reaction: [round(cached_scan_results["fusion"], 0.01)]." - to_chat(user, examine_block(results)) - return + // we let the join apply newlines so we do need handholding + to_chat(user, examine_block(jointext(render_list, "\n")), type = MESSAGE_TYPE_INFO) + return TRUE /obj/item/analyzer/proc/scan_turf(mob/user, turf/location) diff --git a/code/game/objects/items/handcuffs.dm b/code/game/objects/items/handcuffs.dm index 230567d6ad12..6e8d340cfc9a 100644 --- a/code/game/objects/items/handcuffs.dm +++ b/code/game/objects/items/handcuffs.dm @@ -356,7 +356,7 @@ gender = NEUTER var/knockdown = 0 -/obj/item/restraints/legcuffs/bola/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback) +/obj/item/restraints/legcuffs/bola/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, quickstart = TRUE) if(!..()) return playsound(src.loc,'sound/weapons/bolathrow.ogg', 75, 1) diff --git a/code/game/objects/items/stunbaton.dm b/code/game/objects/items/stunbaton.dm index cc6e963473a4..7e7227d02bdd 100644 --- a/code/game/objects/items/stunbaton.dm +++ b/code/game/objects/items/stunbaton.dm @@ -378,7 +378,7 @@ throw_hit_chance = 99 //Have you prayed today? custom_materials = list(/datum/material/iron = 10000, /datum/material/glass = 4000, /datum/material/silver = 10000, /datum/material/gold = 2000) -/obj/item/melee/baton/boomerang/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force) +/obj/item/melee/baton/boomerang/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force, quickstart = TRUE) if(turned_on) if(ishuman(thrower)) var/mob/living/carbon/human/H = thrower diff --git a/code/game/objects/items/tanks/tanks.dm b/code/game/objects/items/tanks/tanks.dm index ad18d1049efb..e91d1b864f36 100644 --- a/code/game/objects/items/tanks/tanks.dm +++ b/code/game/objects/items/tanks/tanks.dm @@ -240,8 +240,8 @@ /obj/item/tank/return_air() return air_contents -// /obj/item/tank/return_analyzable_air() -// return air_contents +/obj/item/tank/return_analyzable_air() + return air_contents /obj/item/tank/assume_air(datum/gas_mixture/giver) air_contents.merge(giver) diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index 10b8c04367d1..554c96a52f44 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -99,7 +99,7 @@ /obj/proc/setAnchored(anchorvalue) set_anchored(anchorvalue) -/obj/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force, messy_throw = TRUE) +/obj/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force, messy_throw = TRUE, quickstart = TRUE) . = ..() if(obj_flags & FROZEN) visible_message("[src] shatters into a million pieces!") diff --git a/code/game/objects/structures/crates_lockers/crates/critter.dm b/code/game/objects/structures/crates_lockers/crates/critter.dm index 4b33f33c9931..101231c8d18f 100644 --- a/code/game/objects/structures/crates_lockers/crates/critter.dm +++ b/code/game/objects/structures/crates_lockers/crates/critter.dm @@ -34,8 +34,8 @@ if(manifest) . += "manifest" -/obj/structure/closet/crate/critter/return_air() +/obj/structure/closet/crate/critter/return_analyzable_air() if(tank) - return tank.air_contents + return tank.return_analyzable_air() else - return loc.return_air() + return null diff --git a/code/game/objects/structures/transit_tubes/transit_tube_pod.dm b/code/game/objects/structures/transit_tubes/transit_tube_pod.dm index bb0682f07881..9ff4156adfa6 100644 --- a/code/game/objects/structures/transit_tubes/transit_tube_pod.dm +++ b/code/game/objects/structures/transit_tubes/transit_tube_pod.dm @@ -150,6 +150,9 @@ /obj/structure/transit_tube_pod/return_air() return air_contents +/obj/structure/transit_tube_pod/return_analyzable_air() + return air_contents + /obj/structure/transit_tube_pod/assume_air(datum/gas_mixture/giver) return air_contents.merge(giver) diff --git a/code/game/world.dm b/code/game/world.dm index cabb344867ff..32ad111e251e 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -398,4 +398,3 @@ GLOBAL_LIST(topic_status_cache) var/init_result = call_ext(library, "init")("block") if (init_result != "0") CRASH("Error initializing byond-tracy: [init_result]") - diff --git a/code/modules/assembly/bomb.dm b/code/modules/assembly/bomb.dm index bc05d1095ae2..abacea242bbd 100644 --- a/code/modules/assembly/bomb.dm +++ b/code/modules/assembly/bomb.dm @@ -201,3 +201,9 @@ return T.assume_air(air_contents) air_update_turf() + +/obj/item/onetankbomb/return_analyzable_air() + if(bombtank) + return bombtank.return_analyzable_air() + else + return null diff --git a/code/modules/atmospherics/environmental/LINDA_fire.dm b/code/modules/atmospherics/environmental/LINDA_fire.dm index cfa3e7eb14e3..7757c53ea674 100644 --- a/code/modules/atmospherics/environmental/LINDA_fire.dm +++ b/code/modules/atmospherics/environmental/LINDA_fire.dm @@ -10,7 +10,9 @@ /turf/open/hotspot_expose(exposed_temperature, exposed_volume, soh) - if(!air) + //If the air doesn't exist we just return false + var/list/air_gases = air?.get_gases() + if(!air_gases) return if (air.get_oxidation_power(exposed_temperature) < 0.5 || air.get_moles(GAS_HYPERNOB) > 5) @@ -35,9 +37,11 @@ icon = 'icons/effects/fire.dmi' icon_state = "1" layer = GASFIRE_LAYER + blend_mode = BLEND_ADD + // light_system = MOVABLE_LIGHT light_range = LIGHT_RANGE_FIRE + light_power = 1 light_color = LIGHT_COLOR_FIRE - blend_mode = BLEND_ADD var/volume = 125 var/temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST @@ -55,6 +59,11 @@ setDir(pick(GLOB.cardinals)) air_update_turf() + var/static/list/loc_connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(on_entered), + ) + AddElement(/datum/element/connect_loc, loc_connections) + /obj/effect/hotspot/proc/perform_exposure() var/turf/open/location = loc if(!istype(location) || !(location.air)) @@ -62,15 +71,18 @@ location.active_hotspot = src - bypassing = volume > CELL_VOLUME*0.95 + bypassing = volume > CELL_VOLUME*0.95 || location.air.return_temperature() >= FUSION_TEMPERATURE_THRESHOLD if(bypassing) + if(temperature > location.air.return_temperature()) + location.air.set_temperature(temperature) //now actually starts fires like intended volume = location.air.reaction_results["fire"]*FIRE_GROWTH_RATE temperature = location.air.return_temperature() else var/datum/gas_mixture/affected = location.air.remove_ratio(volume/location.air.return_volume()) if(affected) //in case volume is 0 - affected.set_temperature(temperature) + if(temperature > affected.return_temperature()) + affected.set_temperature(temperature) //don't set the temperature lower than what it was affected.react(src) temperature = affected.return_temperature() volume = affected.reaction_results["fire"]*FIRE_GROWTH_RATE @@ -131,7 +143,7 @@ add_overlay(fusion_overlay) add_overlay(rainbow_overlay) - set_light(l_color = rgb(LERP(250,heat_r,greyscale_fire),LERP(160,heat_g,greyscale_fire),LERP(25,heat_b,greyscale_fire))) + set_light_color(rgb(LERP(250, heat_r, greyscale_fire), LERP(160, heat_g, greyscale_fire), LERP(25, heat_b, greyscale_fire))) heat_r /= 255 heat_g /= 255 @@ -210,8 +222,8 @@ T.to_be_destroyed = FALSE T.max_fire_temperature_sustained = 0 -/obj/effect/hotspot/Crossed(atom/movable/AM, oldLoc) - ..() +/obj/effect/hotspot/proc/on_entered(datum/source, atom/movable/AM, oldLoc) + SIGNAL_HANDLER if(isliving(AM)) var/mob/living/L = AM L.fire_act(temperature, volume) diff --git a/code/modules/atmospherics/environmental/LINDA_system.dm b/code/modules/atmospherics/environmental/LINDA_system.dm index a6a799753508..7c324a3f517a 100644 --- a/code/modules/atmospherics/environmental/LINDA_system.dm +++ b/code/modules/atmospherics/environmental/LINDA_system.dm @@ -18,7 +18,6 @@ /turf/open/CanAtmosPass(turf/T, vertical = FALSE) var/dir = vertical? get_dir_multiz(src, T) : get_dir(src, T) - var/opp = REVERSE_DIR(dir) . = TRUE if(vertical && !(zAirOut(dir, T) && T.zAirIn(dir, src))) . = FALSE @@ -26,15 +25,13 @@ . = FALSE if (T == src) return . - for(var/atom/movable/AM as anything in contents+T.contents) - var/turf/other = (AM.loc == src ? T : src) - if(!(vertical? (CANVERTICALATMOSPASS(AM, other)) : (CANATMOSPASS(AM, other)))) + for(var/obj/O in contents+T.contents) + var/turf/other = (O.loc == src ? T : src) + if(!(vertical? (CANVERTICALATMOSPASS(O, other)) : (CANATMOSPASS(O, other)))) . = FALSE - if(AM.BlockThermalConductivity()) //the direction and open/closed are already checked on CanAtmosPass() so there are no arguments - conductivity_blocked_directions |= dir - T.conductivity_blocked_directions |= opp - if(!.) - return . + +/turf/proc/block_all_conductivity() + conductivity_blocked_directions |= NORTH | SOUTH | EAST | WEST | UP | DOWN /atom/movable/proc/BlockThermalConductivity() // Objects that don't let heat through. return FALSE @@ -42,83 +39,117 @@ /turf/proc/ImmediateCalculateAdjacentTurfs() var/canpass = CANATMOSPASS(src, src) var/canvpass = CANVERTICALATMOSPASS(src, src) + + conductivity_blocked_directions = 0 + + var/src_contains_firelock = 1 + if(locate(/obj/machinery/door/firedoor) in src) + src_contains_firelock |= 2 + + var/list/atmos_adjacent_turfs = list() + for(var/direction in GLOB.cardinals_multiz) - var/turf/T = get_step_multiz(src, direction) - if(!istype(T)) + var/turf/current_turf = get_step_multiz(src, direction) + if(!isopenturf(current_turf)) + conductivity_blocked_directions |= direction + + if(current_turf) + atmos_adjacent_turfs -= current_turf + LAZYREMOVE(current_turf.atmos_adjacent_turfs, src) + continue - if(isopenturf(T) && !(blocks_air || T.blocks_air) && ((direction & (UP|DOWN))? (canvpass && CANVERTICALATMOSPASS(T, src)) : (canpass && CANATMOSPASS(T, src))) ) - LAZYINITLIST(atmos_adjacent_turfs) - LAZYINITLIST(T.atmos_adjacent_turfs) - atmos_adjacent_turfs[T] = ATMOS_ADJACENT_ANY - T.atmos_adjacent_turfs[src] = ATMOS_ADJACENT_ANY + + var/other_contains_firelock = 1 + if(locate(/obj/machinery/door/firedoor) in current_turf) + other_contains_firelock |= 2 + + //Conductivity Update + var/opp = REVERSE_DIR(direction) + //all these must be above zero for auxmos to even consider them + if(!thermal_conductivity || !heat_capacity || !current_turf.thermal_conductivity || !current_turf.heat_capacity) + conductivity_blocked_directions |= direction + current_turf.conductivity_blocked_directions |= opp else - if (atmos_adjacent_turfs) - atmos_adjacent_turfs -= T - if (T.atmos_adjacent_turfs) - T.atmos_adjacent_turfs -= src - UNSETEMPTY(T.atmos_adjacent_turfs) - T.set_sleeping(T.blocks_air) - T.__update_auxtools_turf_adjacency_info(isspaceturf(T.get_z_base_turf()), -1) + for(var/obj/O in contents + current_turf.contents) + if(O.BlockThermalConductivity()) //the direction and open/closed are already checked on CanAtmosPass() so there are no arguments + conductivity_blocked_directions |= direction + current_turf.conductivity_blocked_directions |= opp + break + //End Conductivity Update + + if(!(blocks_air || current_turf.blocks_air) && ((direction & (UP|DOWN))? (canvpass && CANVERTICALATMOSPASS(current_turf, src)) : (canpass && CANATMOSPASS(current_turf, src)))) + atmos_adjacent_turfs[current_turf] = other_contains_firelock | src_contains_firelock + LAZYSET(current_turf.atmos_adjacent_turfs, src, src_contains_firelock) + else + atmos_adjacent_turfs -= current_turf + LAZYREMOVE(current_turf.atmos_adjacent_turfs, src) + + current_turf.__update_auxtools_turf_adjacency_info() UNSETEMPTY(atmos_adjacent_turfs) src.atmos_adjacent_turfs = atmos_adjacent_turfs - for(var/t in atmos_adjacent_turfs) - var/turf/open/T = t - for(var/obj/machinery/door/firedoor/FD in T) - FD.UpdateAdjacencyFlags() - for(var/obj/machinery/door/firedoor/FD in src) - FD.UpdateAdjacencyFlags() - __update_auxtools_turf_adjacency_info(isspaceturf(get_z_base_turf())) - -/turf/proc/set_sleeping(should_sleep) - -//returns a list of adjacent turfs that can share air with this one. -//alldir includes adjacent diagonal tiles that can share -// air with both of the related adjacent cardinal tiles -/turf/proc/GetAtmosAdjacentTurfs(alldir = 0) + __update_auxtools_turf_adjacency_info() + +/turf/proc/clear_adjacencies() + block_all_conductivity() + for(var/turf/current_turf as anything in atmos_adjacent_turfs) + LAZYREMOVE(current_turf.atmos_adjacent_turfs, src) + current_turf.__update_auxtools_turf_adjacency_info() + + LAZYNULL(atmos_adjacent_turfs) + __update_auxtools_turf_adjacency_info() + +/** + * Returns a list of adjacent turfs that can share air with this one. + * alldir includes adjacent diagonal tiles that can share + * air with both of the related adjacent cardinal tiles + */ +/turf/proc/GetAtmosAdjacentTurfs(alldir = FALSE) var/adjacent_turfs if (atmos_adjacent_turfs) adjacent_turfs = atmos_adjacent_turfs.Copy() else - return list() // don't bother checking diagonals, diagonals are going to be cardinal checks anyways. + adjacent_turfs = list() if (!alldir) return adjacent_turfs - var/turf/other - var/turf/mid - for (var/d in GLOB.diagonals) - other = get_step(src, d) - if(!other) - continue - // NS step - mid = get_step(src, NSCOMPONENT(d)) - if((mid in adjacent_turfs) && (get_step(mid, EWCOMPONENT(d)) in adjacent_turfs)) - adjacent_turfs += other - continue - // EW step - mid = get_step(src, EWCOMPONENT(d)) - if((mid in adjacent_turfs) && (get_step(mid, NSCOMPONENT(d)) in adjacent_turfs)) - adjacent_turfs += other + var/turf/curloc = src + + for (var/direction in GLOB.diagonals_multiz) + var/matchingDirections = 0 + var/turf/S = get_step_multiz(curloc, direction) + if(!S) continue + + for (var/checkDirection in GLOB.cardinals_multiz) + var/turf/checkTurf = get_step(S, checkDirection) + if(!S.atmos_adjacent_turfs || !S.atmos_adjacent_turfs[checkTurf]) + continue + + if (adjacent_turfs[checkTurf]) + matchingDirections++ + + if (matchingDirections >= 2) + adjacent_turfs += S + break + return adjacent_turfs -/atom/proc/air_update_turf(command = 0) - if(!isturf(loc) && command) - return - var/turf/T = get_turf(loc) - if(!istype(T)) +/atom/proc/air_update_turf(calculate_adjacencies = FALSE) + var/turf/location = get_turf(src) + if(!location) return + location.air_update_turf(calculate_adjacencies) - T.air_update_turf(command) - -/turf/air_update_turf(command = 0) - if(command) - ImmediateCalculateAdjacentTurfs() +/turf/air_update_turf(calculate_adjacencies = FALSE) + if(!calculate_adjacencies) + return + ImmediateCalculateAdjacentTurfs() /atom/movable/proc/move_update_air(turf/T) - if(isturf(T)) - T.air_update_turf(1) - air_update_turf(1) + if(isturf(T)) + T.air_update_turf(TRUE) + air_update_turf(TRUE) /atom/proc/atmos_spawn_air(text) //because a lot of people loves to copy paste awful code lets just make an easy proc to spawn your plasma fires var/turf/open/T = get_turf(src) diff --git a/code/modules/atmospherics/environmental/LINDA_turf_tile.dm b/code/modules/atmospherics/environmental/LINDA_turf_tile.dm index c527d0d41631..d5c0a9fead1d 100644 --- a/code/modules/atmospherics/environmental/LINDA_turf_tile.dm +++ b/code/modules/atmospherics/environmental/LINDA_turf_tile.dm @@ -1,5 +1,4 @@ /turf - //used for temperature calculations //conductivity is divided by 10 when interacting with air for balance purposes var/thermal_conductivity = 0.05 var/heat_capacity = 1 @@ -21,24 +20,18 @@ var/pressure_direction = 0 var/turf/pressure_specific_target - var/datum/gas_mixture/turf/air + var/datum/gas_mixture/air var/obj/effect/hotspot/active_hotspot var/planetary_atmos = FALSE //air will revert to initial_gas_mix over time var/list/atmos_overlay_types //gas IDs of current active gas overlays -/turf/open/Initialize(mapload) - if(!blocks_air) - air = new(2500,src) - air.copy_from_turf(src) - if(planetary_atmos && !(initial_gas_mix in SSair.planetary)) - var/datum/gas_mixture/mix = new - mix.parse_gas_string(initial_gas_mix) - mix.mark_immutable() - SSair.planetary[initial_gas_mix] = mix - update_air_ref(planetary_atmos ? 1 : 2) - . = ..() +/turf/open/Initialize(mapload, inherited_virtual_z) + air = new(2500,src) + air.copy_from_turf(src) + update_air_ref(planetary_atmos ? AIR_REF_PLANETARY_TURF : AIR_REF_OPEN_TURF) + return ..() /turf/open/Destroy() if(active_hotspot) @@ -102,10 +95,14 @@ RETURN_TYPE(/datum/gas_mixture) return air +/turf/open/return_analyzable_air() + return return_air() + /turf/temperature_expose() if(return_temperature() > heat_capacity) to_be_destroyed = TRUE + /turf/open/proc/eg_reset_cooldowns() /turf/open/proc/eg_garbage_collect() /turf/open/proc/get_excited() @@ -127,6 +124,7 @@ src.atmos_overlay_types = null return + for(var/id in air.get_gases()) if (nonoverlaying_gases[id]) continue @@ -169,92 +167,79 @@ /////////////////////////////SIMULATION/////////////////////////////////// -/*#define LAST_SHARE_CHECK \ - var/last_share = our_air.get_last_share();\ - if(last_share > MINIMUM_AIR_TO_SUSPEND){\ - our_excited_group.reset_cooldowns();\ - cached_atmos_cooldown = 0;\ - } else if(last_share > MINIMUM_MOLES_DELTA_TO_MOVE) {\ - our_excited_group.dismantle_cooldown = 0;\ - cached_atmos_cooldown = 0;\ - } -*/ /turf/proc/process_cell(fire_count) - /turf/open/proc/equalize_pressure_in_zone(cyclenum) -/turf/open/proc/consider_firelocks(turf/T2) - var/reconsider_adj = FALSE - for(var/obj/machinery/door/firedoor/FD in T2) - if((FD.flags_1 & ON_BORDER_1) && get_dir(T2, src) != FD.dir) - continue - FD.emergency_pressure_stop() - reconsider_adj = TRUE + +/turf/proc/consider_firelocks(turf/T2) //TODO: Find out why this sometimes gets called. Possibly to do with atmos adjacency not being updated in auxmos? +/turf/open/consider_firelocks(turf/T2) + if(blocks_air) + return + for(var/obj/machinery/airalarm/alarm in src) + alarm.handle_decomp_alarm() for(var/obj/machinery/door/firedoor/FD in src) - if((FD.flags_1 & ON_BORDER_1) && get_dir(src, T2) != FD.dir) - continue FD.emergency_pressure_stop() - reconsider_adj = TRUE - if(reconsider_adj) - T2.ImmediateCalculateAdjacentTurfs() // We want those firelocks closed yesterday. + for(var/obj/machinery/door/firedoor/FD in T2) + FD.emergency_pressure_stop() /turf/proc/handle_decompression_floor_rip() + /turf/open/floor/handle_decompression_floor_rip(sum) - if(sum > 20 && prob(clamp(sum / 10, 0, 30))) + if(!blocks_air && sum > 20 && prob(clamp(sum / 10, 0, 30))) remove_tile() /turf/open/process_cell(fire_count) //////////////////////////SPACEWIND///////////////////////////// -/turf/proc/consider_pressure_difference() +/turf/proc/consider_pressure_difference(turf/T, difference) return /turf/open/consider_pressure_difference(turf/T, difference) + SSair.high_pressure_delta |= src if(difference > pressure_difference) pressure_direction = get_dir(src, T) pressure_difference = difference - SSair.high_pressure_delta[src] = TRUE /turf/open/proc/high_pressure_movements() - var/atom/movable/M + if(blocks_air) + return var/multiplier = 1 if(locate(/obj/structure/rack) in src) multiplier *= 0.1 else if(locate(/obj/structure/table) in src) multiplier *= 0.2 - for(var/thing in src) - M = thing - if (!M.anchored && !M.pulledby && M.last_high_pressure_movement_air_cycle < SSair.times_fired) + for(var/atom/movable/M as anything in src) + if(!M.anchored && !M.pulledby && M.last_high_pressure_movement_air_cycle < SSair.times_fired && (M.flags_1 & INITIALIZED_1) && !QDELETED(M)) M.experience_pressure_difference(pressure_difference * multiplier, pressure_direction, 0, pressure_specific_target) if(pressure_difference > 100) new /obj/effect/temp_visual/dir_setting/space_wind(src, pressure_direction, clamp(round(sqrt(pressure_difference) * 2), 10, 255)) - /atom/movable/var/pressure_resistance = 10 /atom/movable/var/last_high_pressure_movement_air_cycle = 0 /atom/movable/proc/experience_pressure_difference(pressure_difference, direction, pressure_resistance_prob_delta = 0, throw_target) - set waitfor = FALSE - if(SEND_SIGNAL(src, COMSIG_MOVABLE_PRE_PRESSURE_PUSH) & COMSIG_MOVABLE_BLOCKS_PRESSURE) - return - var/const/PROBABILITY_OFFSET = 40 var/const/PROBABILITY_BASE_PRECENT = 10 var/max_force = sqrt(pressure_difference)*(MOVE_FORCE_DEFAULT / 5) + set waitfor = 0 var/move_prob = 100 - if(pressure_resistance > 0) + if (pressure_resistance > 0) move_prob = (pressure_difference/pressure_resistance*PROBABILITY_BASE_PRECENT)-PROBABILITY_OFFSET move_prob += pressure_resistance_prob_delta - if(move_prob > PROBABILITY_OFFSET && prob(move_prob) && (move_resist != INFINITY) && (!anchored && (max_force >= (move_resist * MOVE_FORCE_PUSH_RATIO))) || (anchored && (max_force >= (move_resist * MOVE_FORCE_FORCEPUSH_RATIO)))) + if (move_prob > PROBABILITY_OFFSET && prob(move_prob) && (move_resist != INFINITY) && (!anchored && (max_force >= (move_resist * MOVE_FORCE_PUSH_RATIO))) || (anchored && (max_force >= (move_resist * MOVE_FORCE_FORCEPUSH_RATIO)))) var/move_force = max_force * clamp(move_prob, 0, 100) / 100 + if(ismob(src)) + var/mob/M = src + if(M.mob_negates_gravity()) + move_force = 0 if(move_force > 6000) // WALLSLAM HELL TIME OH BOY var/turf/throw_turf = get_ranged_target_turf(get_turf(src), direction, round(move_force / 2000)) if(throw_target && (get_dir(src, throw_target) & direction)) throw_turf = get_turf(throw_target) var/throw_speed = clamp(round(move_force / 3000), 1, 10) - throw_at(throw_turf, move_force / 3000, throw_speed) - else + throw_at(throw_turf, move_force / 3000, throw_speed, quickstart = FALSE) + else if(move_force > 0) step(src, direction) last_high_pressure_movement_air_cycle = SSair.times_fired diff --git a/code/modules/atmospherics/machinery/airalarm.dm b/code/modules/atmospherics/machinery/airalarm.dm index 0c1dcd22be55..fa991d703045 100644 --- a/code/modules/atmospherics/machinery/airalarm.dm +++ b/code/modules/atmospherics/machinery/airalarm.dm @@ -78,6 +78,8 @@ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 100, BOMB = 0, BIO = 100, RAD = 100, FIRE = 90, ACID = 30) resistance_flags = FIRE_PROOF + COOLDOWN_DECLARE(decomp_alarm) + var/danger_level = 0 var/mode = AALARM_MODE_SCRUBBING @@ -948,6 +950,14 @@ new /obj/item/stack/cable_coil(loc, 3) qdel(src) +/obj/machinery/airalarm/proc/handle_decomp_alarm() + if(!is_operational() || !COOLDOWN_FINISHED(src, decomp_alarm)) + return + var/area/A = get_base_area(src) + A.firealert(src) + playsound(loc, 'goon/sound/machinery/FireAlarm.ogg', 75) + COOLDOWN_START(src, decomp_alarm, 1 SECONDS) + #undef AALARM_MODE_SCRUBBING #undef AALARM_MODE_VENTING #undef AALARM_MODE_PANIC diff --git a/code/modules/atmospherics/machinery/components/components_base.dm b/code/modules/atmospherics/machinery/components/components_base.dm index f8866877feae..7841e31f1057 100644 --- a/code/modules/atmospherics/machinery/components/components_base.dm +++ b/code/modules/atmospherics/machinery/components/components_base.dm @@ -156,6 +156,11 @@ to_chat(user, "Access denied.") return UI_CLOSE +// Tool acts + +/obj/machinery/atmospherics/components/return_analyzable_air() + return airs + /obj/machinery/atmospherics/components/attack_ghost(mob/dead/observer/O) . = ..() atmosanalyzer_scan(airs, O, src, FALSE) diff --git a/code/modules/atmospherics/machinery/pipes/pipes.dm b/code/modules/atmospherics/machinery/pipes/pipes.dm index beb0988f8dc3..245e6661d898 100644 --- a/code/modules/atmospherics/machinery/pipes/pipes.dm +++ b/code/modules/atmospherics/machinery/pipes/pipes.dm @@ -51,6 +51,11 @@ /obj/machinery/atmospherics/pipe/return_air() return parent.air +/obj/machinery/atmospherics/pipe/return_analyzable_air() + if(air_temporary) + return air_temporary + return parent.air + /obj/machinery/atmospherics/pipe/remove_air(amount) return parent.air.remove(amount) diff --git a/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm b/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm index eb900b953a1d..65d3f7cef139 100644 --- a/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm +++ b/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm @@ -40,6 +40,9 @@ /obj/machinery/portable_atmospherics/return_air() return air_contents +/obj/machinery/portable_atmospherics/return_analyzable_air() + return air_contents + /obj/machinery/portable_atmospherics/proc/connect(obj/machinery/atmospherics/components/unary/portables_connector/new_port) //Make sure not already connected to something else if(connected_port || !new_port || new_port.connected_device) diff --git a/code/modules/mob/living/carbon/alien/special/facehugger.dm b/code/modules/mob/living/carbon/alien/special/facehugger.dm index 8342c4e948d5..4aeafe44744e 100644 --- a/code/modules/mob/living/carbon/alien/special/facehugger.dm +++ b/code/modules/mob/living/carbon/alien/special/facehugger.dm @@ -104,7 +104,7 @@ return Leap(AM) return FALSE -/obj/item/clothing/mask/facehugger/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback) +/obj/item/clothing/mask/facehugger/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, quickstart = TRUE) if(!..()) return if(stat == CONSCIOUS) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 64d5d0d7cb1b..62a7287a77a5 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1152,7 +1152,7 @@ return TRUE return FALSE -/mob/living/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force) +/mob/living/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force, quickstart = TRUE) stop_pulling() . = ..() diff --git a/code/modules/paperwork/paperplane.dm b/code/modules/paperwork/paperplane.dm index d36933909591..7b788350fc1d 100644 --- a/code/modules/paperwork/paperplane.dm +++ b/code/modules/paperwork/paperplane.dm @@ -94,7 +94,7 @@ return ..() -/obj/item/paperplane/throw_at(atom/target, range, speed, mob/thrower, spin=FALSE, diagonals_first = FALSE, datum/callback/callback) +/obj/item/paperplane/throw_at(atom/target, range, speed, mob/thrower, spin=FALSE, diagonals_first = FALSE, datum/callback/callback, quickstart = TRUE) . = ..(target, range, speed, thrower, FALSE, diagonals_first, callback) /obj/item/paperplane/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum) diff --git a/code/modules/power/singularity/collector.dm b/code/modules/power/singularity/collector.dm index 5e384bc62ff7..9b95d5ac9821 100644 --- a/code/modules/power/singularity/collector.dm +++ b/code/modules/power/singularity/collector.dm @@ -178,6 +178,12 @@ loaded_tank.analyzer_act(user, I) return TRUE +/obj/machinery/power/rad_collector/return_analyzable_air() + if(loaded_tank) + return loaded_tank.return_analyzable_air() + else + return null + /obj/machinery/power/rad_collector/examine(mob/user) . = ..() if(active) diff --git a/code/modules/spells/spell_types/wizard.dm b/code/modules/spells/spell_types/wizard.dm index 774f1820ea62..964eed22eb8e 100644 --- a/code/modules/spells/spell_types/wizard.dm +++ b/code/modules/spells/spell_types/wizard.dm @@ -345,7 +345,7 @@ M.electrocute_act(80, src, null, SHOCK_ILLUSION) qdel(src) -/obj/item/spellpacket/lightningbolt/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback) +/obj/item/spellpacket/lightningbolt/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, quickstart = TRUE) . = ..() if(ishuman(thrower)) var/mob/living/carbon/human/H = thrower diff --git a/modular_splurt/code/game/objects/items/lewd_items/shibola.dm b/modular_splurt/code/game/objects/items/lewd_items/shibola.dm index ba585fa28b7e..f2fd9f5ef32f 100644 --- a/modular_splurt/code/game/objects/items/lewd_items/shibola.dm +++ b/modular_splurt/code/game/objects/items/lewd_items/shibola.dm @@ -34,7 +34,7 @@ else return ..() -/obj/item/shibola/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback) +/obj/item/shibola/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, quickstart = TRUE) if(!..()) return playsound(src.loc,'sound/weapons/bolathrow.ogg', 75, 1) diff --git a/modular_splurt/code/game/objects/items/toys.dm b/modular_splurt/code/game/objects/items/toys.dm index 71b7218fd185..857b84d3cd00 100644 --- a/modular_splurt/code/game/objects/items/toys.dm +++ b/modular_splurt/code/game/objects/items/toys.dm @@ -98,7 +98,7 @@ if(vibrator && enabled) throwforce = 60 -/obj/item/toy/beach_ball/syndicate/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback) +/obj/item/toy/beach_ball/syndicate/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, quickstart = TRUE) if(ishuman(thrower)) throwforce = 0 . = ..() diff --git a/tgstation.dme b/tgstation.dme index fb5bb8baed38..9987f3529b02 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -6,7 +6,7 @@ // END_INTERNALS // BEGIN_FILE_DIR -#define FILE_DIR . +#define FILE_DIR . // END_FILE_DIR // BEGIN_PREFERENCES diff --git a/tgui/packages/tgui-panel/chat/constants.js b/tgui/packages/tgui-panel/chat/constants.js index 3c998973266e..f09156266632 100644 --- a/tgui/packages/tgui-panel/chat/constants.js +++ b/tgui/packages/tgui-panel/chat/constants.js @@ -65,7 +65,8 @@ export const MESSAGE_TYPES = [ type: MESSAGE_TYPE_INFO, name: 'Info', description: 'Non-urgent messages from the game and items', - selector: '.notice:not(.pm), .adminnotice, .info, .sinister, .cult, .infoplain, .announce, .hear, .smallnotice, .holoparasite', + selector: + '.notice:not(.pm), .adminnotice, .info, .sinister, .cult, .infoplain, .announce, .hear, .smallnotice, .holoparasite, .boldnotice', }, { type: MESSAGE_TYPE_WARNING,