diff --git a/code/controllers/subsystem/SSthrowing.dm b/code/controllers/subsystem/SSthrowing.dm index 1618b44f061..1cd7f739106 100644 --- a/code/controllers/subsystem/SSthrowing.dm +++ b/code/controllers/subsystem/SSthrowing.dm @@ -243,13 +243,9 @@ SUBSYSTEM_DEF(throwing) return thrownthing.throwing = null if(!hit) - for(var/atom/movable/obstacle as anything in get_turf(thrownthing)) //looking for our target on the turf we land on. - if(obstacle == target) - hit = TRUE - thrownthing.throw_impact(obstacle, src) - if(QDELETED(thrownthing)) //throw_impact can delete things, such as glasses smashing - return //deletion should already be handled by on_thrownthing_qdel() - break + if(get_turf(target) == get_turf(thrownthing)) + hit = TRUE + thrownthing.throw_impact(target, src) if(!hit) thrownthing.throw_impact(get_turf(thrownthing), src) // we haven't hit something yet and we still must, let's hit the ground. if(QDELETED(thrownthing)) //throw_impact can delete things, such as glasses smashing diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 8b7b67c6934..49b3b9a4f81 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -529,9 +529,10 @@ return FALSE /atom/movable/CanPass(atom/movable/mover, turf/target, height=1.5) - if(mover in buckled_mobs) + // This condition is copied from atom to avoid an extra parent call, because this is a very hot proc. + if(!density || !height) return TRUE - return ..() + return LAZYIN(buckled_mobs, mover) /atom/movable/proc/get_spacemove_backup() var/atom/movable/dense_object_backup diff --git a/code/game/sound.dm b/code/game/sound.dm index 2e2e4621906..b493d741a37 100644 --- a/code/game/sound.dm +++ b/code/game/sound.dm @@ -61,25 +61,32 @@ falloff_distance - Distance at which falloff begins. Sound is at peak volume (in var/sound/S = sound(get_sfx(soundin)) var/maxdistance = SOUND_RANGE + extrarange - var/list/listeners = GLOB.player_list - if(!ignore_walls) //these sounds don't carry through walls - listeners = listeners & hearers(maxdistance, turf_source) - - for(var/P in listeners) - var/mob/M = P - if(!M || !M.client) + var/list/possible_listeners = list() + var/list/desired_turfs = list() + for(var/mob/P as anything in GLOB.player_list) + if(isnull(P) || !P.client) + continue + var/turf/T = get_turf(P) + if(!T || T.z != turf_source.z || get_dist(T, turf_source) > maxdistance) continue - var/turf/T = get_turf(M) // These checks need to be changed if z-levels are ever further refactored - if(!T) - continue - if(T.z != turf_source.z) - continue + possible_listeners += P + desired_turfs |= T - var/distance = get_dist(M, turf_source) + var/list/listeners = list() + if(ignore_walls) + listeners = possible_listeners + else if(length(possible_listeners)) + var/list/turf_vis = list() + for(var/turf/T as anything in desired_turfs) + turf_vis[T] = inLineOfSight(T.x, T.y, turf_source.x, turf_source.y, T.z) - if(distance <= maxdistance) - M.playsound_local(turf_source, soundin, vol, vary, frequency, falloff_exponent, channel, pressure_affected, S, maxdistance, falloff_distance, 1, use_reverb) + for(var/mob/P in possible_listeners) + if(turf_vis[get_turf(P)]) + listeners += P + + for(var/mob/M as anything in listeners) + M.playsound_local(turf_source, soundin, vol, vary, frequency, falloff_exponent, channel, pressure_affected, S, maxdistance, falloff_distance, 1, use_reverb) /mob/proc/playsound_local(turf/turf_source, soundin, vol as num, vary, frequency, falloff_exponent = SOUND_FALLOFF_EXPONENT, channel = 0, pressure_affected = TRUE, sound/S, max_distance, falloff_distance = SOUND_DEFAULT_FALLOFF_DISTANCE, distance_multiplier = 1, use_reverb = TRUE) if(!client || !can_hear()) diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 8fd61b81973..32be3935c90 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -195,16 +195,22 @@ // First, make sure it can leave its square if(isturf(mover.loc)) // Nothing but border objects stop you from leaving a tile, only one loop is needed - for(var/obj/obstacle in mover.loc) - if(!obstacle.CheckExit(mover, src) && obstacle != mover && obstacle != forget) + // This as anything looks odd, since we check istype shortly after, but it's so we can save an istype check for items, which are far more common than other objects. + for(var/obj/obstacle as anything in mover.loc) + if(isitem(obstacle) || !istype(obstacle) || obstacle == mover || obstacle == forget) + continue + if(!obstacle.CheckExit(mover, src)) mover.Bump(obstacle, TRUE) return FALSE var/list/large_dense = list() - //Next, check objects to block entry that are on the border - for(var/atom/movable/border_obstacle in src) + // Next, check for border obstacles on this turf + // Everyting inside a turf is an atom/movable. + for(var/atom/movable/border_obstacle as anything in src) + if(isitem(border_obstacle) || border_obstacle == forget || isnull(border_obstacle)) + continue if(border_obstacle.flags & ON_BORDER) - if(!border_obstacle.CanPass(mover, mover.loc, 1) && (forget != border_obstacle)) + if(!border_obstacle.CanPass(mover, mover.loc, 1)) mover.Bump(border_obstacle, TRUE) return FALSE else @@ -215,14 +221,15 @@ mover.Bump(src, TRUE) return FALSE - //Finally, check objects/mobs to block entry that are not on the border + // Finally, check objects/mobs that block entry and are not on the border var/atom/movable/tompost_bump var/top_layer = FALSE - for(var/atom/movable/obstacle in large_dense) - if(!obstacle.CanPass(mover, mover.loc, 1) && (forget != obstacle)) - if(obstacle.layer > top_layer) - tompost_bump = obstacle - top_layer = obstacle.layer + for(var/atom/movable/obstacle as anything in large_dense) + if(obstacle.layer <= top_layer) + continue + if(!obstacle.CanPass(mover, mover.loc, 1)) + tompost_bump = obstacle + top_layer = obstacle.layer if(tompost_bump) mover.Bump(tompost_bump, TRUE) return FALSE diff --git a/code/modules/atmospherics/machinery/datum_pipeline.dm b/code/modules/atmospherics/machinery/datum_pipeline.dm index 416e4556d7a..d55f9da5e81 100644 --- a/code/modules/atmospherics/machinery/datum_pipeline.dm +++ b/code/modules/atmospherics/machinery/datum_pipeline.dm @@ -12,9 +12,14 @@ /datum/pipeline/Destroy() SSair.pipenets -= src + var/datum/gas_mixture/ghost = null if(air && air.volume) - temporarily_store_air() + ghost = air + air = null for(var/obj/machinery/atmospherics/pipe/P in members) + if(QDELETED(P)) + continue + P.ghost_pipeline = ghost P.parent = null for(var/obj/machinery/atmospherics/A in other_atmosmch) A.nullifyPipenet(src) @@ -28,13 +33,14 @@ /datum/pipeline/proc/build_pipeline(obj/machinery/atmospherics/base) var/volume = 0 + var/list/ghost_pipelines = list() if(istype(base, /obj/machinery/atmospherics/pipe)) var/obj/machinery/atmospherics/pipe/E = base volume = E.volume members += E - if(E.air_temporary) - air = E.air_temporary - E.air_temporary = null + if(E.ghost_pipeline) + ghost_pipelines[E.ghost_pipeline] = E.volume + E.ghost_pipeline = null else addMachineryMember(base) if(!air) @@ -59,15 +65,26 @@ volume += item.volume item.parent = src - if(item.air_temporary) - air.merge(item.air_temporary) - item.air_temporary = null + if(item.ghost_pipeline) + if(!ghost_pipelines[item.ghost_pipeline]) + ghost_pipelines[item.ghost_pipeline] = item.volume + else + ghost_pipelines[item.ghost_pipeline] += item.volume + item.ghost_pipeline = null else P.setPipenet(src, borderline) addMachineryMember(P) possible_expansions -= borderline + for(var/datum/gas_mixture/ghost in ghost_pipelines) + var/collected_ghost_volume = ghost_pipelines[ghost] + var/collected_fraction = collected_ghost_volume / ghost.volume + + var/datum/gas_mixture/ghost_copy = new() + ghost_copy.copy_from(ghost) + air.merge(ghost_copy.remove_ratio(collected_fraction)) + air.volume = volume /datum/pipeline/proc/addMachineryMember(obj/machinery/atmospherics/A) @@ -114,22 +131,6 @@ /obj/machinery/atmospherics/pipe/addMember(obj/machinery/atmospherics/A) parent.addMember(A, src) -/datum/pipeline/proc/temporarily_store_air() - //Update individual gas_mixtures by volume ratio - - for(var/obj/machinery/atmospherics/pipe/member in members) - member.air_temporary = new - member.air_temporary.volume = member.volume - - member.air_temporary.set_oxygen(air.oxygen() * member.volume / air.volume) - member.air_temporary.set_nitrogen(air.nitrogen() * member.volume / air.volume) - member.air_temporary.set_toxins(air.toxins() * member.volume / air.volume) - member.air_temporary.set_carbon_dioxide(air.carbon_dioxide() * member.volume / air.volume) - member.air_temporary.set_sleeping_agent(air.sleeping_agent() * member.volume / air.volume) - member.air_temporary.set_agent_b(air.agent_b() * member.volume / air.volume) - - member.air_temporary.set_temperature(air.temperature()) - /datum/pipeline/proc/temperature_interact(turf/target, share_volume, thermal_conductivity) var/datum/milla_safe/pipeline_temperature_interact/milla = new() milla.invoke_async(src, target, share_volume, thermal_conductivity) diff --git a/code/modules/atmospherics/machinery/pipes/pipe.dm b/code/modules/atmospherics/machinery/pipes/pipe.dm index 4df99320cf5..f820852aab1 100644 --- a/code/modules/atmospherics/machinery/pipes/pipe.dm +++ b/code/modules/atmospherics/machinery/pipes/pipe.dm @@ -1,5 +1,5 @@ /obj/machinery/atmospherics/pipe - var/datum/gas_mixture/air_temporary //used when reconstructing a pipeline that broke + var/datum/gas_mixture/ghost_pipeline // used when reconstructing a pipeline that broke var/datum/pipeline/parent var/volume = 0 force = 20 @@ -23,7 +23,10 @@ /obj/machinery/atmospherics/pipe/Destroy() var/turf/T = get_turf(src) - T.blind_release_air(air_temporary) + if(ghost_pipeline) + var/datum/gas_mixture/ghost_copy = new() + ghost_copy.copy_from(ghost_pipeline) + T.blind_release_air(ghost_copy.remove(volume / ghost_pipeline.volume)) for(var/obj/machinery/atmospherics/meter/meter in T) if(meter.target == src)